aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js2
-rw-r--r--src/library.js3464
-rw-r--r--src/library_gl.js7
-rw-r--r--src/library_jansson.js2
-rw-r--r--src/library_openal.js596
-rw-r--r--src/library_path.js134
-rw-r--r--src/library_sdl.js168
-rw-r--r--src/modules.js2
-rw-r--r--src/postamble.js94
-rw-r--r--src/preamble.js73
-rw-r--r--src/settings.js1684
-rw-r--r--src/utility.js6
12 files changed, 3914 insertions, 2318 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index b1f0b585..1a752305 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -338,7 +338,7 @@ function analyzer(data, sidePass) {
if (subItem != item && (!(subItem.intertype in UNUNFOLDABLE) ||
(subItem.intertype == 'value' && isNumber(subItem.ident) && isIllegalType(subItem.type)))) {
if (item.intertype == 'phi') {
- assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue', 'We can only unfold illegal constants in phis');
+ assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue' || subItem.intertype in PARSABLE_LLVM_FUNCTIONS, 'We can only unfold some expressions in phis');
// we must handle this in the phi itself, if we unfold normally it will not be pushed back with the phi
} else {
var tempIdent = '$$etemp$' + (tempId++);
diff --git a/src/library.js b/src/library.js
index 61237d07..78222b9a 100644
--- a/src/library.js
+++ b/src/library.js
@@ -28,8 +28,9 @@ LibraryManager.library = {
stderr: 'allocate(1, "i32*", ALLOC_STATIC)',
_impure_ptr: 'allocate(1, "i32*", ALLOC_STATIC)',
- $FS__deps: ['$ERRNO_CODES', '__setErrNo', 'stdin', 'stdout', 'stderr', '_impure_ptr'],
- $FS__postset: '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' +
+ $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
@@ -41,288 +42,685 @@ LibraryManager.library = {
'Module["FS_createLink"] = FS.createLink;' +
'Module["FS_createDevice"] = FS.createDevice;',
$FS: {
- // The path to the current folder.
- currentPath: '/',
- // The inode to assign to the next created object.
- nextInode: 2,
- // Currently opened file or directory streams. Padded with null so the zero
- // index is unused, as the indices are used as pointers. This is not split
- // into separate fileStreams and folderStreams lists because the pointers
- // must be interchangeable, e.g. when used in fdopen().
- // streams is kept as a dense array. It may contain |null| to fill in
- // holes, however.
+ root: null,
+ nodes: [null],
+ devices: [null],
streams: [null],
-#if ASSERTIONS
- checkStreams: function() {
- for (var i in FS.streams) if (FS.streams.hasOwnProperty(i)) assert(i >= 0 && i < FS.streams.length); // no keys not in dense span
- for (var i = 0; i < FS.streams.length; i++) assert(typeof FS.streams[i] == 'object'); // no non-null holes in dense span
- },
-#endif
+ 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,
- createFileHandle: function(stream, fd) {
- if (typeof stream === 'undefined') {
- stream = null;
- }
- if (!fd) {
- if (stream && stream.socket) {
- for (var i = 1; i < 64; i++) {
- if (!FS.streams[i]) {
- fd = i;
- break;
- }
- }
- assert(fd, 'ran out of low fds for sockets');
- } else {
- fd = Math.max(FS.streams.length, 64);
- for (var i = FS.streams.length; i < fd; i++) {
- FS.streams[i] = null; // Keep dense
- }
+
+ ErrnoError: function (errno) {
+ this.errno = errno;
+ for (var key in ERRNO_CODES) {
+ if (ERRNO_CODES[key] === errno) {
+ this.code = key;
+ break;
}
}
- // Close WebSocket first if we are about to replace the fd (i.e. dup2)
- if (FS.streams[fd] && FS.streams[fd].socket && FS.streams[fd].socket.close) {
- FS.streams[fd].socket.close();
+ 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;
}
- FS.streams[fd] = stream;
- return fd;
+ return (parentid + hash) % FS.name_table.length;
},
- removeFileHandle: function(fd) {
- FS.streams[fd] = null;
+ hashAddNode: function (node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ node.name_next = FS.name_table[hash];
+ FS.name_table[hash] = node;
},
- joinPath: function(parts, forceRelative) {
- var ret = parts[0];
- for (var i = 1; i < parts.length; i++) {
- if (ret[ret.length-1] != '/') ret += '/';
- ret += parts[i];
+ 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;
+ }
}
- if (forceRelative && ret[0] == '/') ret = ret.substr(1);
- return ret;
},
- // Converts any path to an absolute path. Resolves embedded "." and ".."
- // parts.
- absolutePath: function(relative, base) {
- if (typeof relative !== 'string') return null;
- if (base === undefined) base = FS.currentPath;
- if (relative && relative[0] == '/') base = '';
- var full = base + '/' + relative;
- var parts = full.split('/').reverse();
- var absolute = [''];
- while (parts.length) {
- var part = parts.pop();
- if (part == '' || part == '.') {
- // Nothing.
- } else if (part == '..') {
- if (absolute.length > 1) absolute.pop();
- } else {
- absolute.push(part);
+ 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;
}
}
- return absolute.length == 1 ? '/' : absolute.join('/');
+ // if we failed to find it in the cache, call into the VFS
+ return VFS.lookup(parent, name);
},
- // Analyzes a relative or absolute path returning a description, containing:
- // isRoot: Whether the path points to the root.
- // exists: Whether the object at the path exists.
- // error: If !exists, this will contain the errno code of the cause.
- // name: The base name of the object (null if !parentExists).
- // path: The absolute path to the object, with all links resolved.
- // object: The filesystem record of the object referenced by the path.
- // parentExists: Whether the parent of the object exist and is a folder.
- // parentPath: The absolute path to the parent folder.
- // parentObject: The filesystem record of the parent folder.
- analyzePath: function(path, dontResolveLastLink, linksVisited) {
- var ret = {
- isRoot: false,
- exists: false,
- error: 0,
- name: null,
- path: null,
- object: null,
- parentExists: false,
- parentPath: null,
- parentObject: null
+ 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 FS_LOG
- var inputPath = path;
- function log() {
- 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 + '}');
+ 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);
}
-#endif
- path = FS.absolutePath(path);
- if (path == '/') {
- ret.isRoot = true;
- ret.exists = ret.parentExists = true;
- ret.name = '/';
- ret.path = ret.parentPath = '/';
- ret.object = ret.parentObject = FS.root;
- } else if (path !== null) {
- linksVisited = linksVisited || 0;
- path = path.slice(1).split('/');
- var current = FS.root;
- var traversed = [''];
- while (path.length) {
- if (path.length == 1 && current.isFolder) {
- ret.parentExists = true;
- ret.parentPath = traversed.length == 1 ? '/' : traversed.join('/');
- ret.parentObject = current;
- ret.name = path[0];
- }
- var target = path.shift();
- if (!current.isFolder) {
- ret.error = ERRNO_CODES.ENOTDIR;
- break;
- } else if (!current.read) {
- ret.error = ERRNO_CODES.EACCES;
- break;
- } else if (!current.contents.hasOwnProperty(target)) {
- ret.error = ERRNO_CODES.ENOENT;
- break;
- }
- current = current.contents[target];
- if (current.link && !(dontResolveLastLink && path.length == 0)) {
- if (linksVisited > 40) { // Usual Linux SYMLOOP_MAX.
- ret.error = ERRNO_CODES.ELOOP;
- break;
+
+ // 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);
}
- var link = FS.absolutePath(current.link, traversed.join('/'));
- ret = FS.analyzePath([link].concat(path).join('/'),
- dontResolveLastLink, linksVisited + 1);
-#if FS_LOG
- log();
-#endif
- return ret;
- }
- traversed.push(target);
- if (path.length == 0) {
- ret.exists = true;
- ret.path = traversed.join('/');
- ret.object = current;
}
}
}
-#if FS_LOG
- log();
-#endif
- return ret;
+
+ return { path: current_path, node: current };
},
- // Finds the file system object at a given path. If dontResolveLastLink is
- // set to true and the object is a symbolic link, it will be returned as is
- // instead of being resolved. Links embedded in the path are still resolved.
- findObject: function(path, dontResolveLastLink) {
- FS.ensureRoot();
- var ret = FS.analyzePath(path, dontResolveLastLink);
- if (ret.exists) {
- return ret.object;
+ 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 {
- ___setErrNo(ret.error);
- return null;
+ 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));
},
- // Creates a file system record: file, link, device or folder.
- createObject: function(parent, name, properties, canRead, canWrite) {
-#if FS_LOG
- Module['print']('FS.createObject("' + parent + '", ' +
- '"' + name + '", ' +
- JSON.stringify(properties) + ', ' +
- canRead + ', ' +
- canWrite + ')');
-#endif
- if (!parent) parent = '/';
- if (typeof parent === 'string') parent = FS.findObject(parent);
- if (!parent) {
- ___setErrNo(ERRNO_CODES.EACCES);
- throw new Error('Parent path must exist.');
+ //
+ // 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);
}
- if (!parent.isFolder) {
- ___setErrNo(ERRNO_CODES.ENOTDIR);
- throw new Error('Parent must be a folder.');
+ },
+ 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;
+ }
}
- if (!parent.write && !FS.ignorePermissions) {
- ___setErrNo(ERRNO_CODES.EACCES);
- throw new Error('Parent folder must be writeable.');
+ 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 (!name || name == '.' || name == '..') {
- ___setErrNo(ERRNO_CODES.ENOENT);
- throw new Error('Name must not be empty.');
+ if (Module['stdout']) {
+ FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+ } else {
+ VFS.symlink('/dev/tty', '/dev/stdout');
}
- if (parent.contents.hasOwnProperty(name)) {
- ___setErrNo(ERRNO_CODES.EEXIST);
- throw new Error("Can't overwrite object.");
+ if (Module['stderr']) {
+ FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+ } else {
+ VFS.symlink('/dev/tty1', '/dev/stderr');
}
- parent.contents[name] = {
- read: canRead === undefined ? true : canRead,
- write: canWrite === undefined ? false : canWrite,
- timestamp: Date.now(),
- inodeNumber: FS.nextInode++
- };
- for (var key in properties) {
- if (properties.hasOwnProperty(key)) {
- parent.contents[name][key] = properties[key];
+ // 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);
}
+ },
- return parent.contents[name];
+ //
+ // 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);
},
- // Creates a folder.
- createFolder: function(parent, name, canRead, canWrite) {
- var properties = {isFolder: true, isDevice: false, contents: {}};
- return FS.createObject(parent, name, properties, canRead, canWrite);
+ standardizePath: function (path) {
+ return PATH.normalize(path);
},
- // Creates a folder and all its missing parents.
- createPath: function(parent, path, canRead, canWrite) {
- var current = FS.findObject(parent);
- if (current === null) throw new Error('Invalid parent.');
- path = path.split('/').reverse();
- while (path.length) {
- var part = path.pop();
+ 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;
- if (!current.contents.hasOwnProperty(part)) {
- FS.createFolder(current, part, canRead, canWrite);
+ var current = PATH.join(parent, part);
+ try {
+ VFS.mkdir(current, 0777);
+ } catch (e) {
+ // ignore EEXIST
}
- current = current.contents[part];
+ parent = current;
}
return current;
},
-
- // Creates a file record, given specific properties.
- createFile: function(parent, name, properties, canRead, canWrite) {
- properties.isFolder = false;
- return FS.createObject(parent, name, properties, canRead, canWrite);
+ 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);
},
- // Creates a file record from existing data.
- createDataFile: function(parent, name, data, canRead, canWrite) {
- if (typeof data === 'string') {
- var dataArray = new Array(data.length);
- for (var i = 0, len = data.length; i < len; ++i) dataArray[i] = data.charCodeAt(i);
- data = dataArray;
- }
- var properties = {
- isDevice: false,
- contents: data.subarray ? data.subarray(0) : data // as an optimization, create a new array wrapper (not buffer) here, to help JS engines understand this object
- };
- return FS.createFile(parent, name, properties, canRead, canWrite);
+ 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.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);
+ return VFS.symlink(target, path);
+ },
+ // Makes sure a file's contents are loaded. Returns whether the file has
+ // been loaded successfully. No-op for files that have been loaded already.
+ forceLoadFile: function(obj) {
+ if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+ var success = true;
+ if (typeof XMLHttpRequest !== 'undefined') {
+ throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+ } else if (Module['read']) {
+ // Command-line.
+ try {
+ // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+ // read() will try to parse UTF8.
+ obj.contents = intArrayFromString(Module['read'](obj.url), true);
+ } catch (e) {
+ success = false;
+ }
+ } else {
+ throw new Error('Cannot load without read() or XMLHttpRequest.');
+ }
+ if (!success) ___setErrNo(ERRNO_CODES.EIO);
+ return success;
},
// 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) {
-
if (typeof XMLHttpRequest !== 'undefined') {
if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
// Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
@@ -341,7 +739,6 @@ LibraryManager.library = {
LazyUint8Array.prototype.setDataGetter = function(getter) {
this.getter = getter;
}
-
LazyUint8Array.prototype.cacheLength = function() {
// Find length
var xhr = new XMLHttpRequest();
@@ -423,7 +820,45 @@ LibraryManager.library = {
var properties = { isDevice: false, url: url };
}
- return FS.createFile(parent, name, properties, canRead, canWrite);
+ var node = FS.createFile(parent, name, properties, canRead, canWrite);
+ // This is a total hack, but I want to get this lazy file code out of the
+ // core of MEMFS. If we want to keep this lazy file concept I feel it should
+ // be its own thin LAZYFS proxying calls to MEMFS.
+ if (properties.contents) {
+ node.contents = properties.contents;
+ } else if (properties.url) {
+ node.contents = null;
+ node.url = properties.url;
+ }
+ // override each stream op with one that tries to force load the lazy file first
+ var stream_ops = {};
+ var keys = Object.keys(node.stream_ops);
+ keys.forEach(function (key) {
+ var fn = node.stream_ops[key];
+ stream_ops[key] = function () {
+ if (!FS.forceLoadFile(node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EIO);
+ }
+ return fn.apply(null, arguments);
+ };
+ });
+ // use a custom read function
+ stream_ops.read = function (stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ var size = Math.min(contents.length - position, length);
+ if (contents.slice) { // normal array
+ for (var i = 0; i < size; i++) {
+ buffer[offset + i] = contents[position + i];
+ }
+ } else {
+ for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+ buffer[offset + i] = contents.get(position + i);
+ }
+ }
+ return size;
+ };
+ node.stream_ops = stream_ops;
+ return node;
},
// 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.
@@ -469,216 +904,839 @@ LibraryManager.library = {
} else {
processData(url);
}
+ }
+ },
+
+ $VFS__deps: ['$FS'],
+ $VFS: {
+ mount: function (type, opts, mountpoint) {
+ var mount = {
+ type: type,
+ opts: opts,
+ mountpoint: mountpoint,
+ root: null
+ };
+ var lookup;
+ if (mountpoint) {
+ lookup = FS.lookupPath(mountpoint, { follow: false });
+ }
+ // create a root node for the fs
+ var root = type.mount(mount);
+ root.mount = mount;
+ mount.root = root;
+ // assign the mount info to the mountpoint's node
+ if (lookup) {
+ lookup.node.mount = mount;
+ lookup.node.mounted = true;
+ // compatibility update FS.root if we mount to /
+ if (mountpoint === '/') {
+ FS.root = mount.root;
+ }
+ }
+ return root;
},
- // Creates a link to a specific local path.
- createLink: function(parent, name, target, canRead, canWrite) {
- var properties = {isDevice: false, link: target};
- return FS.createFile(parent, name, properties, canRead, canWrite);
+ lookup: function (parent, name) {
+ return parent.node_ops.lookup(parent, name);
},
- // Creates a character device with input and output callbacks:
- // input: Takes no parameters, returns a byte value or null if no data is
- // currently available.
- // output: Takes a byte value; doesn't return anything. Can also be passed
- // null to perform a flush of any cached data.
- createDevice: function(parent, name, input, output) {
- if (!(input || output)) {
- throw new Error('A device must have at least one callback defined.');
- }
- var ops = {isDevice: true, input: input, output: output};
- return FS.createFile(parent, name, ops, Boolean(input), Boolean(output));
+ // generic function for all node creation
+ mknod: function (path, mode, dev) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var err = FS.mayCreate(parent, name);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ if (!parent.node_ops.mknod) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ return parent.node_ops.mknod(parent, name, mode, dev);
},
- // Makes sure a file's contents are loaded. Returns whether the file has
- // been loaded successfully. No-op for files that have been loaded already.
- forceLoadFile: function(obj) {
- if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
- var success = true;
- if (typeof XMLHttpRequest !== 'undefined') {
- throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
- } else if (Module['read']) {
- // Command-line.
- try {
- // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
- // read() will try to parse UTF8.
- obj.contents = intArrayFromString(Module['read'](obj.url), true);
- } catch (e) {
- success = false;
+ // helpers to create specific types of nodes
+ create: function (path, mode) {
+ mode &= {{{ cDefine('S_IALLUGO') }}};
+ mode |= {{{ cDefine('S_IFREG') }}};
+ return VFS.mknod(path, mode, 0);
+ },
+ mkdir: function (path, mode) {
+ mode &= {{{ cDefine('S_IRWXUGO') }}} | {{{ cDefine('S_ISVTX') }}};
+ mode |= {{{ cDefine('S_IFDIR') }}};
+ return VFS.mknod(path, mode, 0);
+ },
+ mkdev: function (path, mode, dev) {
+ mode |= {{{ cDefine('S_IFCHR') }}};
+ return VFS.mknod(path, mode, dev);
+ },
+ symlink: function (oldpath, newpath) {
+ var lookup = FS.lookupPath(newpath, { parent: true });
+ var parent = lookup.node;
+ var newname = PATH.basename(newpath);
+ var err = FS.mayCreate(parent, newname);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ if (!parent.node_ops.symlink) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ return parent.node_ops.symlink(parent, newname, oldpath);
+ },
+ rename: function (old_path, new_path) {
+ var old_dirname = PATH.dirname(old_path);
+ var new_dirname = PATH.dirname(new_path);
+ var old_name = PATH.basename(old_path);
+ var new_name = PATH.basename(new_path);
+ // parents must exist
+ var lookup, old_dir, new_dir;
+ try {
+ lookup = FS.lookupPath(old_path, { parent: true });
+ old_dir = lookup.node;
+ lookup = FS.lookupPath(new_path, { parent: true });
+ new_dir = lookup.node;
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+ // need to be part of the same mount
+ if (old_dir.mount !== new_dir.mount) {
+ throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+ }
+ // source must exist
+ var old_node = FS.lookupNode(old_dir, old_name);
+ // old path should not be an ancestor of the new path
+ var relative = PATH.relative(old_path, new_dirname);
+ if (relative.charAt(0) !== '.') {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ // new path should not be an ancestor of the old path
+ relative = PATH.relative(new_path, old_dirname);
+ if (relative.charAt(0) !== '.') {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+ }
+ // see if the new path alreay exists
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {
+ // not fatal
+ }
+ // early out if nothing needs to changews
+ if (old_node === new_node) {
+ return;
+ }
+ // we'll need to delete the old entry
+ var isdir = FS.isDir(old_node.mode);
+ var err = FS.mayDelete(old_dir, old_name, isdir);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ // need delete permissions if we'll be overwriting.
+ // need create permissions if new doesn't already exist.
+ err = new_node ?
+ FS.mayDelete(new_dir, new_name, isdir) :
+ FS.mayCreate(new_dir, new_name);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ if (!old_dir.node_ops.rename) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+ // if we are going to change the parent, check write permissions
+ if (new_dir !== old_dir) {
+ err = FS.nodePermissions(old_dir, 'w');
+ if (err) {
+ throw new FS.ErrnoError(err);
}
+ }
+ // remove the node from the lookup hash
+ FS.hashRemoveNode(old_node);
+ // do the underlying fs rename
+ try {
+ old_node.node_ops.rename(old_node, new_dir, new_name);
+ } catch (e) {
+ throw e;
+ } finally {
+ // add the node back to the hash (in case node_ops.rename
+ // changed its name)
+ FS.hashAddNode(old_node);
+ }
+ },
+ rmdir: function (path) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var err = FS.mayDelete(parent, name, true);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ if (!parent.node_ops.rmdir) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+ parent.node_ops.rmdir(parent, name);
+ FS.destroyNode(node);
+ },
+ unlink: function (path) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var err = FS.mayDelete(parent, name, false);
+ if (err) {
+ // POSIX says unlink should set EPERM, not EISDIR
+ if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+ throw new FS.ErrnoError(err);
+ }
+ if (!parent.node_ops.unlink) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+ parent.node_ops.unlink(parent, name);
+ FS.destroyNode(node);
+ },
+ readlink: function (path) {
+ var lookup = FS.lookupPath(path, { follow: false });
+ var link = lookup.node;
+ if (!link.node_ops.readlink) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ return link.node_ops.readlink(link);
+ },
+ stat: function (path, dontFollow) {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ var node = lookup.node;
+ if (!node.node_ops.getattr) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ return node.node_ops.getattr(node);
+ },
+ lstat: function (path) {
+ return VFS.stat(path, true);
+ },
+ chmod: function (path, mode, dontFollow) {
+ var node;
+ if (typeof path === 'string') {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ node = lookup.node;
} else {
- throw new Error('Cannot load without read() or XMLHttpRequest.');
+ node = path;
}
- if (!success) ___setErrNo(ERRNO_CODES.EIO);
- return success;
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ node.node_ops.setattr(node, {
+ mode: (mode & {{{ cDefine('S_IALLUGO') }}}) | (node.mode & ~{{{ cDefine('S_IALLUGO') }}}),
+ timestamp: Date.now()
+ });
},
- ensureRoot: function() {
- if (FS.root) return;
- // The main file system tree. All the contents are inside this.
- FS.root = {
- read: true,
- write: true,
- isFolder: true,
- isDevice: false,
- timestamp: Date.now(),
- inodeNumber: 1,
- contents: {}
- };
+ lchmod: function (path, mode) {
+ VFS.chmod(path, mode, true);
},
- // Initializes the filesystems with stdin/stdout/stderr devices, given
- // optional handlers.
- init: function(input, output, error) {
- // Make sure we initialize only once.
- 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;
-
- FS.ensureRoot();
-
- // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
- input = input || Module['stdin'];
- output = output || Module['stdout'];
- error = error || Module['stderr'];
-
- // Default handlers.
- var stdinOverridden = true, stdoutOverridden = true, stderrOverridden = true;
- if (!input) {
- stdinOverridden = false;
- input = function() {
- if (!input.cache || !input.cache.length) {
- var result;
- if (typeof window != 'undefined' &&
- 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();
- }
- if (!result) result = '';
- input.cache = intArrayFromString(result + '\n', true);
- }
- return input.cache.shift();
- };
+ fchmod: function (fd, mode) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
}
- var utf8 = new Runtime.UTF8Processor();
- 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;
+ VFS.chmod(stream.node, mode);
+ },
+ chown: function (path, uid, gid, dontFollow) {
+ var node;
+ if (typeof path === 'string') {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ node = lookup.node;
+ } else {
+ node = path;
}
- if (!output) {
- stdoutOverridden = false;
- output = createSimpleOutput();
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
}
- if (!output.printer) output.printer = Module['print'];
- if (!output.buffer) output.buffer = [];
- if (!error) {
- stderrOverridden = false;
- error = createSimpleOutput();
+ node.node_ops.setattr(node, {
+ timestamp: Date.now()
+ // we ignore the uid / gid for now
+ });
+ },
+ lchown: function (path, uid, gid) {
+ VFS.chown(path, uid, gid, true);
+ },
+ fchown: function (fd, uid, gid) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
}
- if (!error.printer) error.printer = Module['printErr'];
- if (!error.buffer) error.buffer = [];
-
- // Create the temporary folder, if not already created
+ VFS.chown(stream.node, uid, gid);
+ },
+ truncate: function (path, len) {
+ if (len < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var node;
+ if (typeof path === 'string') {
+ var lookup = FS.lookupPath(path, { follow: true });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ if (FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+ }
+ if (!FS.isFile(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var err = FS.nodePermissions(node, 'w');
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ node.node_ops.setattr(node, {
+ size: len,
+ timestamp: Date.now()
+ });
+ },
+ ftruncate: function (fd, len) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ VFS.truncate(stream.node, len);
+ },
+ utime: function (path, atime, mtime) {
+ var lookup = FS.lookupPath(path, { follow: true });
+ var node = lookup.node;
+ node.node_ops.setattr(node, {
+ timestamp: Math.max(atime, mtime)
+ });
+ },
+ open: function (path, flags, mode, fd_start, fd_end) {
+ path = PATH.normalize(path);
+ flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+ if ((flags & {{{ cDefine('O_CREAT') }}})) {
+ mode = (mode & {{{ cDefine('S_IALLUGO') }}}) | {{{ cDefine('S_IFREG') }}};
+ } else {
+ mode = 0;
+ }
+ var node;
try {
- FS.createFolder('/', 'tmp', true, true);
- } catch(e) {}
-
- // Create the I/O devices.
- var devFolder = FS.createFolder('/', 'dev', true, true);
- var stdin = FS.createDevice(devFolder, 'stdin', input);
- stdin.isTerminal = !stdinOverridden;
- var stdout = FS.createDevice(devFolder, 'stdout', null, output);
- stdout.isTerminal = !stdoutOverridden;
- var stderr = FS.createDevice(devFolder, 'stderr', null, error);
- stderr.isTerminal = !stderrOverridden;
- FS.createDevice(devFolder, 'tty', input, output);
- FS.createDevice(devFolder, 'null', function(){}, function(){});
-
- // Create default streams.
- FS.streams[1] = {
- path: '/dev/stdin',
- object: stdin,
- position: 0,
- isRead: true,
- isWrite: false,
- isAppend: false,
- error: false,
- eof: false,
- ungotten: []
- };
- FS.streams[2] = {
- path: '/dev/stdout',
- object: stdout,
- position: 0,
- isRead: false,
- isWrite: true,
- isAppend: false,
- error: false,
- eof: false,
- ungotten: []
- };
- FS.streams[3] = {
- path: '/dev/stderr',
- object: stderr,
+ var lookup = FS.lookupPath(path, {
+ follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}})
+ });
+ node = lookup.node;
+ path = lookup.path;
+ } catch (e) {
+ // ignore
+ }
+ // perhaps we need to create the node
+ if ((flags & {{{ cDefine('O_CREAT') }}})) {
+ if (node) {
+ // if O_CREAT and O_EXCL are set, error out if the node already exists
+ if ((flags & {{{ cDefine('O_EXCL') }}})) {
+ throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+ }
+ } else {
+ // node doesn't exist, try to create it
+ node = VFS.mknod(path, mode, 0);
+ }
+ }
+ if (!node) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+ }
+ // can't truncate a device
+ if (FS.isChrdev(node.mode)) {
+ flags &= ~{{{ cDefine('O_TRUNC') }}};
+ }
+ // check permissions
+ var err = FS.mayOpen(node, flags);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ // do truncation if necessary
+ if ((flags & {{{ cDefine('O_TRUNC')}}})) {
+ VFS.truncate(node, 0);
+ }
+ // register the stream with the filesystem
+ var stream = FS.createStream({
+ path: path,
+ node: node,
+ flags: flags,
+ seekable: true,
position: 0,
- isRead: false,
- isWrite: true,
- isAppend: false,
- error: false,
- eof: false,
- ungotten: []
- };
- // TODO: put these low in memory like we used to assert on: assert(Math.max(_stdin, _stdout, _stderr) < 15000); // make sure these are low, we flatten arrays with these
- {{{ makeSetValue(makeGlobalUse('_stdin'), 0, 1, 'void*') }}};
- {{{ makeSetValue(makeGlobalUse('_stdout'), 0, 2, 'void*') }}};
- {{{ makeSetValue(makeGlobalUse('_stderr'), 0, 3, 'void*') }}};
-
- // Other system paths
- FS.createPath('/', 'dev/shm/tmp', true, true); // temp files
-
- // Newlib initialization
- for (var i = FS.streams.length; i < Math.max(_stdin, _stdout, _stderr) + {{{ QUANTUM_SIZE }}}; i++) {
- FS.streams[i] = null; // Make sure to keep FS.streams dense
+ stream_ops: node.stream_ops,
+ // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+ ungotten: [],
+ error: false
+ }, fd_start, fd_end);
+ // call the new stream's open function
+ if (stream.stream_ops.open) {
+ stream.stream_ops.open(stream);
}
- FS.streams[_stdin] = FS.streams[1];
- FS.streams[_stdout] = FS.streams[2];
- FS.streams[_stderr] = FS.streams[3];
-#if ASSERTIONS
- FS.checkStreams();
- // see previous TODO on stdin etc.: assert(FS.streams.length < 1024); // at this early stage, we should not have a large set of file descriptors - just a few
-#endif
- allocate([ allocate(
- {{{ Runtime.QUANTUM_SIZE === 4 ? '[0, 0, 0, 0, _stdin, 0, 0, 0, _stdout, 0, 0, 0, _stderr, 0, 0, 0]' : '[0, _stdin, _stdout, _stderr]' }}},
- 'void*', ALLOC_NORMAL) ], 'void*', ALLOC_NONE, {{{ makeGlobalUse('__impure_ptr') }}});
+ return stream;
},
-
- quit: function() {
- if (!FS.init.initialized) return;
- // Flush any partially-printed lines in stdout and stderr. Careful, they may have been closed
- if (FS.streams[2] && FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output({{{ charCode('\n') }}});
- if (FS.streams[3] && FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output({{{ charCode('\n') }}});
+ close: function (stream) {
+ try {
+ if (stream.stream_ops.close) {
+ stream.stream_ops.close(stream);
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ FS.closeStream(stream.fd);
+ }
+ },
+ llseek: function (stream, offset, whence) {
+ if (!stream.seekable || !stream.stream_ops.llseek) {
+ throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+ }
+ return stream.stream_ops.llseek(stream, offset, whence);
+ },
+ readdir: function (stream) {
+ if (!stream.stream_ops.readdir) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+ }
+ return stream.stream_ops.readdir(stream);
+ },
+ read: function (stream, buffer, offset, length, position) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+ }
+ if (!stream.stream_ops.read) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var seeking = true;
+ if (typeof position === 'undefined') {
+ position = stream.position;
+ seeking = false;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+ }
+ var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+ if (!seeking) stream.position += bytesRead;
+ return bytesRead;
+ },
+ write: function (stream, buffer, offset, length, position) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+ }
+ if (!stream.stream_ops.write) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var seeking = true;
+ if (typeof position === 'undefined') {
+ position = stream.position;
+ seeking = false;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+ }
+ if (stream.flags & {{{ cDefine('O_APPEND') }}}) {
+ // seek to the end before writing in append mode
+ VFS.llseek(stream, 0, {{{ cDefine('SEEK_END') }}});
+ }
+ var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position);
+ if (!seeking) stream.position += bytesWritten;
+ return bytesWritten;
},
+ allocate: function (stream, offset, length) {
+ if (offset < 0 || length <= 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+ }
+ if (!stream.stream_ops.allocate) {
+ throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+ }
+ stream.stream_ops.allocate(stream, offset, length);
+ },
+ mmap: function (stream, buffer, offset, length, position, prot, flags) {
+ // TODO if PROT is PROT_WRITE, make sure we have write acccess
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+ }
+ if (!stream.stream_ops.mmap) {
+ throw new FS.errnoError(ERRNO_CODES.ENODEV);
+ }
+ return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+ }
+ },
- // Standardizes a path. Useful for making comparisons of pathnames work in a consistent manner.
- // For example, ./file and file are really the same, so this function will remove ./
- standardizePath: function(path) {
- if (path.substr(0, 2) == './') path = path.substr(2);
- return path;
+ $MEMFS__deps: ['$FS'],
+ $MEMFS: {
+ mount: function (mount) {
+ return MEMFS.create_node(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
+ },
+ create_node: function (parent, name, mode, dev) {
+ if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+ // no supported
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ var node = FS.createNode(parent, name, mode, dev);
+ node.node_ops = MEMFS.node_ops;
+ if (FS.isDir(node.mode)) {
+ node.stream_ops = MEMFS.stream_ops;
+ node.contents = {};
+ } else if (FS.isFile(node.mode)) {
+ node.stream_ops = MEMFS.stream_ops;
+ node.contents = [];
+ } else if (FS.isLink(node.mode)) {
+ node.stream_ops = MEMFS.stream_ops;
+ } else if (FS.isChrdev(node.mode)) {
+ node.stream_ops = FS.chrdev_stream_ops;
+ }
+ node.timestamp = Date.now();
+ // add the new node to the parent
+ if (parent) {
+ parent.contents[name] = node;
+ }
+ return node;
},
+ node_ops: {
+ getattr: function (node) {
+ var attr = {};
+ // device numbers reuse inode numbers.
+ attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+ attr.ino = node.id;
+ attr.mode = node.mode;
+ attr.nlink = 1;
+ attr.uid = 0;
+ attr.gid = 0;
+ attr.rdev = node.rdev;
+ if (FS.isDir(node.mode)) {
+ attr.size = 4096;
+ } else if (FS.isFile(node.mode)) {
+ attr.size = node.contents.length;
+ } else if (FS.isLink(node.mode)) {
+ attr.size = node.link.length;
+ } else {
+ attr.size = 0;
+ }
+ attr.atime = new Date(node.timestamp);
+ attr.mtime = new Date(node.timestamp);
+ attr.ctime = new Date(node.timestamp);
+ // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+ // but this is not required by the standard.
+ attr.blksize = 4096;
+ attr.blocks = Math.ceil(attr.size / attr.blksize);
+ return attr;
+ },
+ setattr: function (node, attr) {
+ if (attr.mode !== undefined) {
+ node.mode = attr.mode;
+ }
+ if (attr.timestamp !== undefined) {
+ node.timestamp = attr.timestamp;
+ }
+ if (attr.size !== undefined) {
+ var contents = node.contents;
+ if (attr.size < contents.length) contents.length = attr.size;
+ else while (attr.size > contents.length) contents.push(0);
+ }
+ },
+ lookup: function (parent, name) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+ },
+ mknod: function (parent, name, mode, dev) {
+ return MEMFS.create_node(parent, name, mode, dev);
+ },
+ rename: function (old_node, new_dir, new_name) {
+ // if we're overwriting a directory at new_name, make sure it's empty.
+ if (FS.isDir(old_node.mode)) {
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {
+ }
+ if (new_node) {
+ for (var i in new_node.contents) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+ }
+ }
+ }
+ // do the internal rewiring
+ delete old_node.parent.contents[old_node.name];
+ old_node.name = new_name;
+ new_dir.contents[new_name] = old_node;
+ },
+ unlink: function (parent, name) {
+ delete parent.contents[name];
+ },
+ rmdir: function (parent, name) {
+ var node = FS.lookupNode(parent, name);
+ for (var i in node.contents) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+ }
+ delete parent.contents[name];
+ },
+ symlink: function (parent, newname, oldpath) {
+ var node = MEMFS.create_node(parent, newname, 0777 | {{{ cDefine('S_IFLNK') }}}, 0);
+ node.link = oldpath;
+ return node;
+ },
+ readlink: function (node) {
+ if (!FS.isLink(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ return node.link;
+ },
+ },
+ stream_ops: {
+ open: function (stream) {
+ if (FS.isDir(stream.node.mode)) {
+ // cache off the directory entries when open'd
+ var entries = ['.', '..']
+ for (var key in stream.node.contents) {
+ if (!stream.node.contents.hasOwnProperty(key)) {
+ continue;
+ }
+ entries.push(key);
+ }
+ stream.entries = entries;
+ }
+ },
+ read: function (stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ var size = Math.min(contents.length - position, length);
+#if USE_TYPED_ARRAYS == 2
+ if (contents.subarray) { // typed array
+ buffer.set(contents.subarray(position, position + size), offset);
+ } else
+#endif
+ {
+ for (var i = 0; i < size; i++) {
+ buffer[offset + i] = contents[position + i];
+ }
+ }
+ return size;
+ },
+ write: function (stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ while (contents.length < position) contents.push(0);
+ for (var i = 0; i < length; i++) {
+ contents[position + i] = buffer[offset + i];
+ }
+ stream.node.timestamp = Date.now();
+ return length;
+ },
+ llseek: function (stream, offset, whence) {
+ var position = offset;
+ if (whence === 1) { // SEEK_CUR.
+ position += stream.position;
+ } else if (whence === 2) { // SEEK_END.
+ if (FS.isFile(stream.node.mode)) {
+ position += stream.node.contents.length;
+ }
+ }
+ if (position < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ stream.ungotten = [];
+ stream.position = position;
+ return position;
+ },
+ readdir: function (stream) {
+ return stream.entries;
+ },
+ allocate: function (stream, offset, length) {
+ var contents = stream.node.contents;
+ var limit = offset + length;
+ while (limit > contents.length) contents.push(0);
+ },
+ mmap: function (stream, buffer, offset, length, position, prot, flags) {
+ if (!FS.isFile(stream.node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+ }
+ var ptr;
+ var allocated;
+ var contents = stream.node.contents;
+ // Only make a new copy when MAP_PRIVATE is specified.
+ if (!(flags & {{{ cDefine('MAP_PRIVATE') }}})) {
+ // We can't emulate MAP_SHARED when the file is not backed by the buffer
+ // we're mapping to (e.g. the HEAP buffer).
+ assert(contents.buffer === buffer || contents.buffer === buffer.buffer);
+ allocated = false;
+ ptr = contents.byteOffset;
+ } else {
+ // Try to avoid unnecessary slices.
+ if (position > 0 || position + length < contents.length) {
+ if (contents.subarray) {
+ contents = contents.subarray(position, position + length);
+ } else {
+ contents = Array.prototype.slice.call(contents, position, position + length);
+ }
+ }
+ allocated = true;
+ ptr = _malloc(length);
+ if (!ptr) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+ }
+ buffer.set(contents, ptr);
+ }
+ return { ptr: ptr, allocated: allocated };
+ },
+ }
+ },
+
+ $SOCKFS__postset: '__ATINIT__.push({ func: function() { SOCKFS.root = VFS.mount(SOCKFS, {}, null); } });',
+ $SOCKFS__deps: ['$FS'],
+ $SOCKFS: {
+ mount: function (mount) {
+ var node = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
+ node.node_ops = SOCKFS.node_ops;
+ node.stream_ops = SOCKFS.stream_ops;
+ return node;
+ },
+ node_ops: {
+ },
+ stream_ops: {
+ },
+ websocket_sock_ops: {
+ }
+ },
- deleteFile: function(path) {
- path = FS.analyzePath(path);
- if (!path.parentExists || !path.exists) {
- throw 'Invalid path ' + path;
+ $TTY__deps: ['$FS'],
+ $TTY: {
+ ttys: [],
+ register: function (dev, ops) {
+ TTY.ttys[dev] = { input: [], output: [], ops: ops };
+ FS.registerDevice(dev, TTY.stream_ops);
+ },
+ stream_ops: {
+ open: function (stream) {
+ // this wouldn't be required if the library wasn't eval'd at first...
+ if (!TTY.utf8) {
+ TTY.utf8 = new Runtime.UTF8Processor();
+ }
+ var tty = TTY.ttys[stream.node.rdev];
+ if (!tty) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+ }
+ stream.tty = tty;
+ stream.seekable = false;
+ },
+ close: function (stream) {
+ // flush any pending line data
+ if (stream.tty.output.length) {
+ stream.tty.ops.put_char(stream.tty, {{{ charCode('\n') }}});
+ }
+ },
+ read: function (stream, buffer, offset, length, pos /* ignored */) {
+ if (!stream.tty || !stream.tty.ops.get_char) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+ }
+ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = stream.tty.ops.get_char(stream.tty);
+ } 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) {
+ if (!stream.tty || !stream.tty.ops.put_char) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+ }
+ for (var i = 0; i < length; i++) {
+ try {
+ stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES.EIO);
+ }
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ }
+ },
+ // NOTE: This is weird to support stdout and stderr
+ // overrides in addition to print and printErr orverrides.
+ default_tty_ops: {
+ get_char: function (tty) {
+ if (!tty.input.length) {
+ var result = null;
+ if (ENVIRONMENT_IS_NODE) {
+ if (process.stdin.destroyed) {
+ return undefined;
+ }
+ result = process.stdin.read();
+ } else if (typeof window != 'undefined' &&
+ typeof window.prompt == 'function') {
+ // Browser.
+ result = window.prompt('Input: '); // returns null on cancel
+ if (result !== null) {
+ result += '\n';
+ }
+ } else if (typeof readline == 'function') {
+ // Command line.
+ result = readline();
+ if (result !== null) {
+ result += '\n';
+ }
+ }
+ if (!result) {
+ return null;
+ }
+ tty.input = intArrayFromString(result, true);
+ }
+ return tty.input.shift();
+ },
+ put_char: function (tty, val) {
+ if (val === null || val === {{{ charCode('\n') }}}) {
+ Module['print'](tty.output.join(''));
+ tty.output = [];
+ } else {
+ tty.output.push(TTY.utf8.processCChar(val));
+ }
+ }
+ },
+ default_tty1_ops: {
+ put_char: function (tty, val) {
+ if (val === null || val === {{{ charCode('\n') }}}) {
+ Module['printErr'](tty.output.join(''));
+ tty.output = [];
+ } else {
+ tty.output.push(TTY.utf8.processCChar(val));
+ }
}
- delete path.parentObject.contents[path.name];
}
},
+#endif
+
// ==========================================================================
// dirent.h
@@ -690,160 +1748,125 @@ LibraryManager.library = {
['i32', 'd_off'],
['i32', 'd_reclen'],
['i32', 'd_type']]),
- opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
+ opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout', 'open'],
opendir: function(dirname) {
// DIR *opendir(const char *dirname);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/opendir.html
// NOTE: Calculating absolute path redundantly since we need to associate it
// with the opened stream.
- var path = FS.absolutePath(Pointer_stringify(dirname));
- if (path === null) {
+ var path = Pointer_stringify(dirname);
+ if (!path) {
___setErrNo(ERRNO_CODES.ENOENT);
return 0;
}
- var target = FS.findObject(path);
- if (target === null) return 0;
- if (!target.isFolder) {
- ___setErrNo(ERRNO_CODES.ENOTDIR);
+ var node;
+ try {
+ var lookup = FS.lookupPath(path, { follow: true });
+ node = lookup.node;
+ } catch (e) {
+ FS.handleFSError(e);
return 0;
- } else if (!target.read) {
- ___setErrNo(ERRNO_CODES.EACCES);
+ }
+ if (!FS.isDir(node.mode)) {
+ ___setErrNo(ERRNO_CODES.ENOTDIR);
return 0;
}
- var contents = [];
- for (var key in target.contents) contents.push(key);
- var id = FS.createFileHandle({
- path: path,
- object: target,
- // An index into contents. Special values: -2 is ".", -1 is "..".
- position: -2,
- isRead: true,
- isWrite: false,
- isAppend: false,
- error: false,
- eof: false,
- ungotten: [],
- // Folder-specific properties:
- // Remember the contents at the time of opening in an array, so we can
- // seek between them relying on a single order.
- contents: contents,
- // Each stream has its own area for readdir() returns.
- currentEntry: _malloc(___dirent_struct_layout.__size__)
- });
-#if ASSERTIONS
- FS.checkStreams();
-#endif
- return id;
+ var err = _open(dirname, {{{ cDefine('O_RDONLY') }}}, allocate([0, 0, 0, 0], 'i32', ALLOC_STACK));
+ // open returns 0 on failure, not -1
+ return err === -1 ? 0 : err;
},
- closedir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
+ closedir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'close'],
closedir: function(dirp) {
// int closedir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/closedir.html
- if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
- ___setErrNo(ERRNO_CODES.EBADF);
- return -1;
- } else {
- _free(FS.streams[dirp].currentEntry);
- FS.streams[dirp] = null;
- return 0;
- }
+ return _close(dirp);
},
telldir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
telldir: function(dirp) {
// long int telldir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/telldir.html
- if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
+ var stream = FS.getStream(dirp);
+ if (!stream || !FS.isDir(stream.node.mode)) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else {
- return FS.streams[dirp].position;
}
+ return stream.position;
},
- seekdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
+ seekdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'lseek'],
seekdir: function(dirp, loc) {
// void seekdir(DIR *dirp, long int loc);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/seekdir.html
- if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
- ___setErrNo(ERRNO_CODES.EBADF);
- } else {
- var entries = 0;
- for (var key in FS.streams[dirp].contents) entries++;
- if (loc >= entries) {
- ___setErrNo(ERRNO_CODES.EINVAL);
- } else {
- FS.streams[dirp].position = loc;
- }
- }
+ _lseek(dirp, loc, {{{ cDefine('SEEK_SET') }}});
},
rewinddir__deps: ['seekdir'],
rewinddir: function(dirp) {
// void rewinddir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/rewinddir.html
- _seekdir(dirp, -2);
+ _seekdir(dirp, 0);
},
readdir_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
readdir_r: function(dirp, entry, result) {
// int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/readdir_r.html
- if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
+ var stream = FS.getStream(dirp);
+ if (!stream) {
return ___setErrNo(ERRNO_CODES.EBADF);
}
- var stream = FS.streams[dirp];
- var loc = stream.position;
- var entries = 0;
- for (var key in stream.contents) entries++;
- if (loc < -2 || loc >= entries) {
+ var entries;
+ try {
+ entries = VFS.readdir(stream);
+ } catch (e) {
+ return FS.handleFSError(e);
+ }
+ if (stream.position < 0 || stream.position >= entries.length) {
{{{ makeSetValue('result', '0', '0', 'i8*') }}}
- } else {
- var name, inode, type;
- if (loc === -2) {
- name = '.';
- inode = 1; // Really undefined.
- type = 4; //DT_DIR
- } else if (loc === -1) {
- name = '..';
- inode = 1; // Really undefined.
- type = 4; //DT_DIR
- } else {
- var object;
- name = stream.contents[loc];
- object = stream.object.contents[name];
- inode = object.inodeNumber;
- type = object.isDevice ? 2 // DT_CHR, character device.
- : object.isFolder ? 4 // DT_DIR, directory.
- : object.link !== undefined ? 10 // DT_LNK, symbolic link.
- : 8; // DT_REG, regular file.
- }
- stream.position++;
- var offsets = ___dirent_struct_layout;
- {{{ makeSetValue('entry', 'offsets.d_ino', 'inode', 'i32') }}}
- {{{ makeSetValue('entry', 'offsets.d_off', 'stream.position', 'i32') }}}
- {{{ makeSetValue('entry', 'offsets.d_reclen', 'name.length + 1', 'i32') }}}
- for (var i = 0; i < name.length; i++) {
- {{{ makeSetValue('entry + offsets.d_name', 'i', 'name.charCodeAt(i)', 'i8') }}}
- }
- {{{ makeSetValue('entry + offsets.d_name', 'i', '0', 'i8') }}}
- {{{ makeSetValue('entry', 'offsets.d_type', 'type', 'i8') }}}
- {{{ makeSetValue('result', '0', 'entry', 'i8*') }}}
+ return;
}
+ var id;
+ var type;
+ var name = entries[stream.position];
+ var offset = stream.position + 1;
+ if (!name.indexOf('.')) {
+ id = 1;
+ type = 4;
+ } else {
+ var child = FS.lookupNode(stream.node, name);
+ id = child.id;
+ type = FS.isChrdev(child.mode) ? 2 : // DT_CHR, character device.
+ FS.isDir(child.mode) ? 4 : // DT_DIR, directory.
+ FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link.
+ 8; // DT_REG, regular file.
+ }
+ {{{ makeSetValue('entry', '___dirent_struct_layout.d_ino', 'id', 'i32') }}}
+ {{{ makeSetValue('entry', '___dirent_struct_layout.d_off', 'offset', 'i32') }}}
+ {{{ makeSetValue('entry', '___dirent_struct_layout.d_reclen', 'name.length + 1', 'i32') }}}
+ for (var i = 0; i < name.length; i++) {
+ {{{ makeSetValue('entry + ___dirent_struct_layout.d_name', 'i', 'name.charCodeAt(i)', 'i8') }}}
+ }
+ {{{ makeSetValue('entry + ___dirent_struct_layout.d_name', 'i', '0', 'i8') }}}
+ {{{ makeSetValue('entry', '___dirent_struct_layout.d_type', 'type', 'i8') }}}
+ {{{ makeSetValue('result', '0', 'entry', 'i8*') }}}
+ stream.position++;
return 0;
},
readdir__deps: ['readdir_r', '__setErrNo', '$ERRNO_CODES'],
readdir: function(dirp) {
// struct dirent *readdir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/readdir_r.html
- if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
+ var stream = FS.getStream(dirp);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
- } else {
- if (!_readdir.result) _readdir.result = _malloc(4);
- _readdir_r(dirp, FS.streams[dirp].currentEntry, _readdir.result);
- if ({{{ makeGetValue(0, '_readdir.result', 'i8*') }}} === 0) {
- return 0;
- } else {
- return FS.streams[dirp].currentEntry;
- }
}
+ // TODO Is it supposed to be safe to execute multiple readdirs?
+ if (!_readdir.entry) _readdir.entry = _malloc(___dirent_struct_layout.__size__);
+ if (!_readdir.result) _readdir.result = _malloc(4);
+ var err = _readdir_r(dirp, _readdir.entry, _readdir.result);
+ if (err) {
+ ___setErrNo(err);
+ return 0;
+ }
+ return {{{ makeGetValue(0, '_readdir.result', 'i8*') }}};
},
__01readdir64_: 'readdir',
// TODO: Check if we need to link any other aliases.
@@ -868,10 +1891,14 @@ LibraryManager.library = {
} else {
time = Date.now();
}
- var file = FS.findObject(Pointer_stringify(path));
- if (file === null) return -1;
- file.timestamp = time;
- return 0;
+ path = Pointer_stringify(path);
+ try {
+ VFS.utime(path, time, time);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
+ }
},
utimes: function() { throw 'utimes not implemented' },
@@ -964,67 +1991,27 @@ LibraryManager.library = {
// int stat(const char *path, struct stat *buf);
// NOTE: dontResolveLastLink is a shortcut for lstat(). It should never be
// used in client code.
- var obj = FS.findObject(Pointer_stringify(path), dontResolveLastLink);
- if (obj === null || !FS.forceLoadFile(obj)) return -1;
-
- var offsets = ___stat_struct_layout;
-
- // Constants.
- {{{ makeSetValue('buf', 'offsets.st_nlink', '1', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.st_uid', '0', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.st_gid', '0', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.st_blksize', '4096', 'i32') }}}
-
- // Variables.
- {{{ makeSetValue('buf', 'offsets.st_ino', 'obj.inodeNumber', 'i32') }}}
- var time = Math.floor(obj.timestamp / 1000);
- if (offsets.st_atime === undefined) {
- offsets.st_atime = offsets.st_atim.tv_sec;
- offsets.st_mtime = offsets.st_mtim.tv_sec;
- offsets.st_ctime = offsets.st_ctim.tv_sec;
- var nanosec = (obj.timestamp % 1000) * 1000;
- {{{ makeSetValue('buf', 'offsets.st_atim.tv_nsec', 'nanosec', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.st_mtim.tv_nsec', 'nanosec', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.st_ctim.tv_nsec', 'nanosec', 'i32') }}}
- }
- {{{ makeSetValue('buf', 'offsets.st_atime', 'time', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.st_mtime', 'time', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.st_ctime', 'time', 'i32') }}}
- var mode = 0;
- var size = 0;
- var blocks = 0;
- var dev = 0;
- var rdev = 0;
- if (obj.isDevice) {
- // Device numbers reuse inode numbers.
- dev = rdev = obj.inodeNumber;
- size = blocks = 0;
- mode = 0x2000; // S_IFCHR.
- } else {
- dev = 1;
- rdev = 0;
- // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
- // but this is not required by the standard.
- if (obj.isFolder) {
- size = 4096;
- blocks = 1;
- mode = 0x4000; // S_IFDIR.
- } else {
- var data = obj.contents || obj.link;
- size = data.length;
- blocks = Math.ceil(data.length / 4096);
- mode = obj.link === undefined ? 0x8000 : 0xA000; // S_IFREG, S_IFLNK.
- }
+ path = typeof path !== 'string' ? Pointer_stringify(path) : path;
+ try {
+ var stat = dontResolveLastLink ? VFS.lstat(path) : VFS.stat(path);
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_dev', 'stat.dev', 'i32') }}};
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_ino', 'stat.ino', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_mode', 'stat.mode', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_nlink', 'stat.nlink', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_uid', 'stat.uid', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_gid', 'stat.gid', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_rdev', 'stat.rdev', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_size', 'stat.size', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_atime', 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_mtime', 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_ctime', 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_blksize', '4096', 'i32') }}}
+ {{{ makeSetValue('buf', '___stat_struct_layout.st_blocks', 'stat.blocks', 'i32') }}}
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
}
- {{{ makeSetValue('buf', 'offsets.st_dev', 'dev', 'i32') }}};
- {{{ makeSetValue('buf', 'offsets.st_rdev', 'rdev', 'i32') }}};
- {{{ makeSetValue('buf', 'offsets.st_size', 'size', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.st_blocks', 'blocks', 'i32') }}}
- if (obj.read) mode |= 0x16D; // S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH.
- if (obj.write) mode |= 0x92; // S_IWUSR | S_IWGRP | S_IWOTH.
- {{{ makeSetValue('buf', 'offsets.st_mode', 'mode', 'i32') }}}
-
- return 0;
},
lstat__deps: ['stat'],
lstat: function(path, buf) {
@@ -1036,40 +2023,30 @@ LibraryManager.library = {
fstat: function(fildes, buf) {
// int fstat(int fildes, struct stat *buf);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fstat.html
- if (!FS.streams[fildes]) {
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else {
- var pathArray = intArrayFromString(FS.streams[fildes].path);
- return _stat(allocate(pathArray, 'i8', ALLOC_STACK), buf);
}
+ return _stat(stream.path, buf);
},
mknod__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
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
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);
+ // we don't want this in the JS API as the JS API
+ // uses mknod to create all nodes.
+ var err = FS.mayMknod(mode);
+ if (err) {
+ ___setErrNo(err);
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.
+ VFS.mknod(path, mode, dev);
return 0;
} catch (e) {
+ FS.handleFSError(e);
return -1;
}
},
@@ -1078,13 +2055,11 @@ LibraryManager.library = {
// int mkdir(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkdir.html
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.
+ VFS.mkdir(path, mode, 0);
return 0;
} catch (e) {
+ FS.handleFSError(e);
return -1;
}
},
@@ -1099,33 +2074,43 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.EROFS);
return -1;
},
- chmod__deps: ['$FS'],
+ chmod__deps: ['$FS', '__setErrNo'],
chmod: function(path, mode, dontResolveLastLink) {
// int chmod(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/chmod.html
// 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.
- obj.timestamp = Date.now();
- return 0;
+ try {
+ VFS.chmod(path, mode);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
+ }
},
fchmod__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'chmod'],
fchmod: function(fildes, mode) {
// int fchmod(int fildes, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fchmod.html
- var stream = FS.streams[fildes];
- if (!stream) {
- ___setErrNo(ERRNO_CODES.EBADF);
+ try {
+ VFS.fchmod(fildes, mode);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
}
- return _chmod(stream.path, mode);
},
- lchmod: function(path, mode) {
- return _chmod(path, mode, true);
+ lchmod__deps: ['chmod'],
+ lchmod: function (path, mode) {
+ path = Pointer_stringify(path);
+ try {
+ VFS.lchmod(path, mode);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
+ }
},
umask__deps: ['$FS'],
@@ -1165,7 +2150,7 @@ LibraryManager.library = {
['i32', 'f_namemax']]),
statvfs__deps: ['$FS', '__statvfs_struct_layout'],
statvfs: function(path, buf) {
- // http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/statvfs.html
// int statvfs(const char *restrict path, struct statvfs *restrict buf);
var offsets = ___statvfs_struct_layout;
// NOTE: None of the constants here are true. We're just returning safe and
@@ -1209,108 +2194,15 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
// NOTE: This implementation tries to mimic glibc rather than strictly
// following the POSIX standard.
-
var mode = {{{ makeGetValue('varargs', 0, 'i32') }}};
-
- // Simplify flags.
- var accessMode = oflag & {{{ cDefine('O_ACCMODE') }}};
- var isWrite = accessMode != {{{ cDefine('O_RDONLY') }}};
- var isRead = accessMode != {{{ cDefine('O_WRONLY') }}};
- var isCreate = Boolean(oflag & {{{ cDefine('O_CREAT') }}});
- var isExistCheck = Boolean(oflag & {{{ cDefine('O_EXCL') }}});
- var isTruncate = Boolean(oflag & {{{ cDefine('O_TRUNC') }}});
- var isAppend = Boolean(oflag & {{{ cDefine('O_APPEND') }}});
-
- // Verify path.
- var origPath = path;
- path = FS.analyzePath(Pointer_stringify(path));
- if (!path.parentExists) {
- ___setErrNo(path.error);
+ path = Pointer_stringify(path);
+ try {
+ var stream = VFS.open(path, oflag, mode);
+ return stream.fd;
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
}
- var target = path.object || null;
- var finalPath;
-
- // Verify the file exists, create if needed and allowed.
- if (target) {
- if (isCreate && isExistCheck) {
- ___setErrNo(ERRNO_CODES.EEXIST);
- return -1;
- }
- if ((isWrite || isTruncate) && target.isFolder) {
- ___setErrNo(ERRNO_CODES.EISDIR);
- return -1;
- }
- if (isRead && !target.read || isWrite && !target.write) {
- ___setErrNo(ERRNO_CODES.EACCES);
- return -1;
- }
- if (isTruncate && !target.isDevice) {
- target.contents = [];
- } else {
- if (!FS.forceLoadFile(target)) {
- ___setErrNo(ERRNO_CODES.EIO);
- return -1;
- }
- }
- finalPath = path.path;
- } else {
- if (!isCreate) {
- ___setErrNo(ERRNO_CODES.ENOENT);
- return -1;
- }
- if (!path.parentObject.write) {
- ___setErrNo(ERRNO_CODES.EACCES);
- return -1;
- }
- target = FS.createDataFile(path.parentObject, path.name, [],
- mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
- finalPath = path.parentPath + '/' + path.name;
- }
- // Actually create an open stream.
- var id;
- if (target.isFolder) {
- var entryBuffer = 0;
- if (___dirent_struct_layout) {
- entryBuffer = _malloc(___dirent_struct_layout.__size__);
- }
- var contents = [];
- for (var key in target.contents) contents.push(key);
- id = FS.createFileHandle({
- path: finalPath,
- object: target,
- // An index into contents. Special values: -2 is ".", -1 is "..".
- position: -2,
- isRead: true,
- isWrite: false,
- isAppend: false,
- error: false,
- eof: false,
- ungotten: [],
- // Folder-specific properties:
- // Remember the contents at the time of opening in an array, so we can
- // seek between them relying on a single order.
- contents: contents,
- // Each stream has its own area for readdir() returns.
- currentEntry: entryBuffer
- });
- } else {
- id = FS.createFileHandle({
- path: finalPath,
- object: target,
- position: 0,
- isRead: isRead,
- isWrite: isWrite,
- isAppend: isAppend,
- error: false,
- eof: false,
- ungotten: []
- });
- }
-#if ASSERTIONS
- FS.checkStreams();
-#endif
- return id;
},
creat__deps: ['open'],
creat: function(path, mode) {
@@ -1331,11 +2223,11 @@ LibraryManager.library = {
fcntl: function(fildes, cmd, varargs, dup2) {
// int fcntl(int fildes, int cmd, ...);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/fcntl.html
- if (!FS.streams[fildes]) {
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
- var stream = FS.streams[fildes];
switch (cmd) {
case {{{ cDefine('F_DUPFD') }}}:
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
@@ -1343,31 +2235,22 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
- var newStream = {};
- for (var member in stream) {
- newStream[member] = stream[member];
+ var newStream;
+ try {
+ newStream = VFS.open(stream.path, stream.flags, 0, arg);
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
}
- arg = dup2 ? arg : Math.max(arg, FS.streams.length); // dup2 wants exactly arg; fcntl wants a free descriptor >= arg
- FS.createFileHandle(newStream, arg);
-#if ASSERTIONS
- FS.checkStreams();
-#endif
- return arg;
+ return newStream.fd;
case {{{ cDefine('F_GETFD') }}}:
case {{{ cDefine('F_SETFD') }}}:
return 0; // FD_CLOEXEC makes no sense for a single process.
case {{{ cDefine('F_GETFL') }}}:
- var flags = 0;
- if (stream.isRead && stream.isWrite) flags = {{{ cDefine('O_RDWR') }}};
- else if (!stream.isRead && stream.isWrite) flags = {{{ cDefine('O_WRONLY') }}};
- else if (stream.isRead && !stream.isWrite) flags = {{{ cDefine('O_RDONLY') }}};
- if (stream.isAppend) flags |= {{{ cDefine('O_APPEND') }}};
- // Synchronization and blocking flags are irrelevant to us.
- return flags;
+ return stream.flags;
case {{{ cDefine('F_SETFL') }}}:
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
- stream.isAppend = Boolean(arg | {{{ cDefine('O_APPEND') }}});
- // Synchronization and blocking flags are irrelevant to us.
+ stream.flags |= arg;
return 0;
case {{{ cDefine('F_GETLK') }}}:
case {{{ cDefine('F_GETLK64') }}}:
@@ -1405,14 +2288,27 @@ LibraryManager.library = {
posix_fallocate: function(fd, offset, len) {
// int posix_fallocate(int fd, off_t offset, off_t len);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate.html
- if (!FS.streams[fd] || !FS.streams[fd].isWrite || FS.streams[fd].link ||
- FS.streams[fd].isFolder || FS.streams[fd].isDevice) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
- var contents = FS.streams[fd].object.contents;
- var limit = offset + len;
- while (limit > contents.length) contents.push(0);
+ try {
+ VFS.allocate(stream, offset, len);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
+ }
+ },
+
+ // ==========================================================================
+ // sys/file.h
+ // ==========================================================================
+
+ flock: function(fd, operation) {
+ // int flock(int fd, int operation);
+ // Pretend to succeed
return 0;
},
@@ -1436,8 +2332,8 @@ LibraryManager.library = {
var fd = {{{ makeGetValue('pollfd', 'offsets.fd', 'i32') }}};
var events = {{{ makeGetValue('pollfd', 'offsets.events', 'i16') }}};
var revents = 0;
- if (FS.streams[fd]) {
- var stream = FS.streams[fd];
+ var stream = FS.getStream(fd);
+ if (stream) {
if (events & {{{ cDefine('POLLIN') }}}) revents |= {{{ cDefine('POLLIN') }}};
if (events & {{{ cDefine('POLLOUT') }}}) revents |= {{{ cDefine('POLLOUT') }}};
} else {
@@ -1458,15 +2354,28 @@ LibraryManager.library = {
// int access(const char *path, int amode);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/access.html
path = Pointer_stringify(path);
- var target = FS.findObject(path);
- if (target === null) return -1;
- if ((amode & 2 && !target.write) || // W_OK.
- ((amode & 1 || amode & 4) && !target.read)) { // X_OK, R_OK.
+ if (amode & ~{{{ cDefine('S_IRWXO') }}}) {
+ // need a valid mode
+ ___setErrNo(ERRNO_CODES.EINVAL);
+ return -1;
+ }
+ var node;
+ try {
+ var lookup = FS.lookupPath(path, { follow: true });
+ node = lookup.node;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
+ }
+ var perms = '';
+ if (amode & {{{ cDefine('R_OK') }}}) perms += 'r';
+ if (amode & {{{ cDefine('W_OK') }}}) perms += 'w';
+ if (amode & {{{ cDefine('X_OK') }}}) perms += 'x';
+ if (perms /* otherwise, they've just passed F_OK */ && FS.nodePermissions(node, perms)) {
___setErrNo(ERRNO_CODES.EACCES);
return -1;
- } else {
- return 0;
}
+ return 0;
},
chdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
chdir: function(path) {
@@ -1474,17 +2383,24 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/000095399/functions/chdir.html
// NOTE: The path argument may be a string, to simplify fchdir().
if (typeof path !== 'string') path = Pointer_stringify(path);
- path = FS.analyzePath(path);
- if (!path.exists) {
- ___setErrNo(path.error);
+ var lookup;
+ try {
+ lookup = FS.lookupPath(path, { follow: true });
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
- } else if (!path.object.isFolder) {
+ }
+ if (!FS.isDir(lookup.node.mode)) {
___setErrNo(ERRNO_CODES.ENOTDIR);
return -1;
- } else {
- FS.currentPath = path.path;
- return 0;
}
+ var err = FS.nodePermissions(lookup.node, 'x');
+ if (err) {
+ ___setErrNo(err);
+ return -1;
+ }
+ FS.currentPath = lookup.path;
+ return 0;
},
chown__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
chown: function(path, owner, group, dontResolveLastLink) {
@@ -1495,10 +2411,13 @@ LibraryManager.library = {
// NOTE: dontResolveLastLink is a shortcut for lchown(). It should never be
// used in client code.
if (typeof path !== 'string') path = Pointer_stringify(path);
- var target = FS.findObject(path, dontResolveLastLink);
- if (target === null) return -1;
- target.timestamp = Date.now();
- return 0;
+ try {
+ VFS.chown(path, owner, group);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
+ }
},
chroot__deps: ['__setErrNo', '$ERRNO_CODES'],
chroot: function(path) {
@@ -1511,16 +2430,18 @@ LibraryManager.library = {
close: function(fildes) {
// int close(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/close.html
- if (FS.streams[fildes]) {
- if (FS.streams[fildes].currentEntry) {
- _free(FS.streams[fildes].currentEntry);
- }
- FS.streams[fildes] = null;
- return 0;
- } else {
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
+ try {
+ VFS.close(stream);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);;
+ return -1;
+ }
},
dup__deps: ['fcntl'],
dup: function(fildes) {
@@ -1532,24 +2453,32 @@ LibraryManager.library = {
dup2: function(fildes, fildes2) {
// int dup2(int fildes, int fildes2);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/dup.html
+ var stream = FS.getStream(fildes);
if (fildes2 < 0) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else if (fildes === fildes2 && FS.streams[fildes]) {
+ } else if (fildes === fildes2 && stream) {
return fildes;
} else {
_close(fildes2);
- return _fcntl(fildes, 0, allocate([fildes2, 0, 0, 0], 'i32', ALLOC_STACK), true); // F_DUPFD.
+ try {
+ var stream2 = VFS.open(stream.path, stream.flags, 0, fildes2, fildes2);
+ return stream2.fd;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
+ }
}
},
fchown__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'chown'],
fchown: function(fildes, owner, group) {
// int fchown(int fildes, uid_t owner, gid_t group);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fchown.html
- if (FS.streams[fildes]) {
- return _chown(FS.streams[fildes].path, owner, group);
- } else {
- ___setErrNo(ERRNO_CODES.EBADF);
+ try {
+ VFS.fchown(fildes, owner, group);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
}
},
@@ -1557,8 +2486,9 @@ LibraryManager.library = {
fchdir: function(fildes) {
// int fchdir(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fchdir.html
- if (FS.streams[fildes]) {
- return _chdir(FS.streams[fildes].path);
+ var stream = FS.getStream(fildes);
+ if (stream) {
+ return _chdir(stream.path);
} else {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
@@ -1631,7 +2561,8 @@ LibraryManager.library = {
fsync: function(fildes) {
// int fsync(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fsync.html
- if (FS.streams[fildes]) {
+ var stream = FS.getStream(fildes);
+ if (stream) {
// We write directly to the file system, so there's nothing to do here.
return 0;
} else {
@@ -1645,42 +2576,24 @@ LibraryManager.library = {
// int truncate(const char *path, off_t length);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/truncate.html
// NOTE: The path argument may be a string, to simplify ftruncate().
- if (length < 0) {
- ___setErrNo(ERRNO_CODES.EINVAL);
+ if (typeof path !== 'string') path = Pointer_stringify(path);
+ try {
+ VFS.truncate(path, length);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
- } else {
- if (typeof path !== 'string') path = Pointer_stringify(path);
- var target = FS.findObject(path);
- if (target === null) return -1;
- if (target.isFolder) {
- ___setErrNo(ERRNO_CODES.EISDIR);
- return -1;
- } else if (target.isDevice) {
- ___setErrNo(ERRNO_CODES.EINVAL);
- return -1;
- } else if (!target.write) {
- ___setErrNo(ERRNO_CODES.EACCES);
- return -1;
- } else {
- var contents = target.contents;
- if (length < contents.length) contents.length = length;
- else while (length > contents.length) contents.push(0);
- target.timestamp = Date.now();
- return 0;
- }
}
},
ftruncate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'truncate'],
ftruncate: function(fildes, length) {
// int ftruncate(int fildes, off_t length);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ftruncate.html
- if (FS.streams[fildes] && FS.streams[fildes].isWrite) {
- return _truncate(FS.streams[fildes].path, length);
- } else if (FS.streams[fildes]) {
- ___setErrNo(ERRNO_CODES.EINVAL);
- return -1;
- } else {
- ___setErrNo(ERRNO_CODES.EBADF);
+ try {
+ VFS.ftruncate(fildes, length);
+ return 0;
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
}
},
@@ -1712,12 +2625,13 @@ LibraryManager.library = {
isatty: function(fildes) {
// int isatty(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/isatty.html
- var stream = FS.streams[fildes];
+ var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
}
- if (!stream.object.isTerminal) {
+ // HACK - implement tcgetattr
+ if (!stream.tty) {
___setErrNo(ERRNO_CODES.ENOTTY);
return 0;
}
@@ -1741,7 +2655,8 @@ LibraryManager.library = {
lockf: function(fildes, func, size) {
// int lockf(int fildes, int function, off_t size);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/lockf.html
- if (FS.streams[fildes]) {
+ var stream = FS.getStream(fildes);
+ if (stream) {
// Pretend whatever locking or unlocking operation succeeded. Locking does
// not make much sense, since we have a single process/thread.
return 0;
@@ -1754,26 +2669,17 @@ 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].object.isDevice) {
- var stream = FS.streams[fildes];
- var position = offset;
- if (whence === 1) { // SEEK_CUR.
- position += stream.position;
- } else if (whence === 2) { // SEEK_END.
- position += stream.object.contents.length;
- }
- if (position < 0) {
- ___setErrNo(ERRNO_CODES.EINVAL);
- return -1;
- } else {
- stream.ungotten = [];
- stream.position = position;
- return position;
- }
- } else {
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
+ try {
+ return VFS.llseek(stream, offset, whence);
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
+ }
},
pipe__deps: ['__setErrNo', '$ERRNO_CODES'],
pipe: function(fildes) {
@@ -1788,94 +2694,39 @@ LibraryManager.library = {
pread: function(fildes, buf, nbyte, offset) {
// ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
- var stream = FS.streams[fildes];
- if (!stream || stream.object.isDevice) {
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else if (!stream.isRead) {
- ___setErrNo(ERRNO_CODES.EACCES);
- return -1;
- } else if (stream.object.isFolder) {
- ___setErrNo(ERRNO_CODES.EISDIR);
- return -1;
- } else if (nbyte < 0 || offset < 0) {
- ___setErrNo(ERRNO_CODES.EINVAL);
+ }
+ try {
+ var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
+ return VFS.read(stream, slab, buf, nbyte, offset);
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
- } else if (offset >= stream.object.contents.length) {
- return 0;
- } else {
- var bytesRead = 0;
- 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);
- } else
-#endif
- if (contents.slice) { // normal array
- for (var i = 0; i < size; i++) {
- {{{ makeSetValue('buf', 'i', 'contents[offset + i]', 'i8') }}}
- }
- } else {
- for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
- {{{ makeSetValue('buf', 'i', 'contents.get(offset + i)', 'i8') }}}
- }
- }
- bytesRead += size;
- return bytesRead;
}
},
read__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'recv', 'pread'],
read: function(fildes, buf, nbyte) {
// ssize_t read(int fildes, void *buf, size_t nbyte);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
- var stream = FS.streams[fildes];
- if (stream && ('socket' in stream)) {
- return _recv(fildes, buf, nbyte, 0);
- } else if (!stream) {
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else if (!stream.isRead) {
- ___setErrNo(ERRNO_CODES.EACCES);
- return -1;
- } else if (nbyte < 0) {
- ___setErrNo(ERRNO_CODES.EINVAL);
+ }
+
+ if (stream && ('socket' in stream)) {
+ return _recv(fildes, buf, nbyte, 0);
+ }
+
+ try {
+ var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
+ return VFS.read(stream, slab, buf, nbyte);
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
- } else {
- var bytesRead;
- if (stream.object.isDevice) {
- if (stream.object.input) {
- bytesRead = 0;
- for (var i = 0; i < nbyte; i++) {
- try {
- var result = stream.object.input();
- } catch (e) {
- ___setErrNo(ERRNO_CODES.EIO);
- return -1;
- }
- if (result === undefined && bytesRead === 0) {
- ___setErrNo(ERRNO_CODES.EAGAIN);
- return -1;
- }
- if (result === null || result === undefined) break;
- bytesRead++;
- {{{ makeSetValue('buf', 'i', 'result', 'i8') }}}
- }
- return bytesRead;
- } else {
- ___setErrNo(ERRNO_CODES.ENXIO);
- return -1;
- }
- } else {
- bytesRead = _pread(fildes, buf, nbyte, stream.position);
- assert(bytesRead >= -1);
- if (bytesRead != -1) {
- stream.position += bytesRead;
- }
- return bytesRead;
- }
}
},
sync: function() {
@@ -1888,26 +2739,12 @@ LibraryManager.library = {
// int rmdir(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html
path = Pointer_stringify(path);
- path = FS.analyzePath(path, true);
- if (!path.parentExists || !path.exists) {
- ___setErrNo(path.error);
- return -1;
- } 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;
- }
- delete path.parentObject.contents[path.name];
+ try {
+ VFS.rmdir(path);
return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
}
},
unlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
@@ -1915,19 +2752,12 @@ LibraryManager.library = {
// int unlink(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html
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.EPERM);
- return -1;
- } else if (!path.parentObject.write) {
- ___setErrNo(ERRNO_CODES.EACCES);
- return -1;
- } else {
- delete path.parentObject.contents[path.name];
+ try {
+ VFS.unlink(path);
return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
}
},
ttyname__deps: ['ttyname_r'],
@@ -1941,7 +2771,7 @@ LibraryManager.library = {
ttyname_r: function(fildes, name, namesize) {
// int ttyname_r(int fildes, char *name, size_t namesize);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ttyname.html
- var stream = FS.streams[fildes];
+ var stream = FS.getStream(fildes);
var ttyname = '/dev/tty';
if (!stream) {
return ___setErrNo(ERRNO_CODES.EBADF);
@@ -1953,106 +2783,73 @@ LibraryManager.library = {
writeStringToMemory(ttyname, name);
return 0;
},
- symlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
+ symlink__deps: ['$FS', '$PATH', '__setErrNo', '$ERRNO_CODES'],
symlink: function(path1, path2) {
// int symlink(const char *path1, const char *path2);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/symlink.html
- var path = FS.analyzePath(Pointer_stringify(path2), true);
- if (!path.parentExists) {
- ___setErrNo(path.error);
- return -1;
- } else if (path.exists) {
- ___setErrNo(ERRNO_CODES.EEXIST);
- return -1;
- } else {
- FS.createLink(path.parentPath, path.name,
- Pointer_stringify(path1), true, true);
+ path1 = Pointer_stringify(path1);
+ path2 = Pointer_stringify(path2);
+ try {
+ VFS.symlink(path1, path2);
return 0;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
}
},
readlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
readlink: function(path, buf, bufsize) {
// ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/readlink.html
- var target = FS.findObject(Pointer_stringify(path), true);
- if (target === null) return -1;
- if (target.link !== undefined) {
- var length = Math.min(bufsize - 1, target.link.length);
- for (var i = 0; i < length; i++) {
- {{{ makeSetValue('buf', 'i', 'target.link.charCodeAt(i)', 'i8') }}}
- }
- if (bufsize - 1 > length) {{{ makeSetValue('buf', 'i', '0', 'i8') }}}
- return i;
- } else {
- ___setErrNo(ERRNO_CODES.EINVAL);
+ path = Pointer_stringify(path);
+ var str;
+ try {
+ str = VFS.readlink(path);
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
}
+ str = str.slice(0, Math.max(0, bufsize - 1));
+ writeStringToMemory(str, buf, true);
+ return str.length;
},
pwrite__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
pwrite: function(fildes, buf, nbyte, offset) {
// ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
- var stream = FS.streams[fildes];
- if (!stream || stream.object.isDevice) {
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else if (!stream.isWrite) {
- ___setErrNo(ERRNO_CODES.EACCES);
- return -1;
- } else if (stream.object.isFolder) {
- ___setErrNo(ERRNO_CODES.EISDIR);
- return -1;
- } else if (nbyte < 0 || offset < 0) {
- ___setErrNo(ERRNO_CODES.EINVAL);
+ }
+ try {
+ var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
+ return VFS.write(stream, slab, buf, nbyte, offset);
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
- } else {
- var contents = stream.object.contents;
- while (contents.length < offset) contents.push(0);
- for (var i = 0; i < nbyte; i++) {
- contents[offset + i] = {{{ makeGetValue('buf', 'i', 'i8', undefined, 1) }}};
- }
- stream.object.timestamp = Date.now();
- return i;
}
},
write__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'send', 'pwrite'],
write: function(fildes, buf, nbyte) {
// ssize_t write(int fildes, const void *buf, size_t nbyte);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
- var stream = FS.streams[fildes];
- if (stream && ('socket' in stream)) {
- return _send(fildes, buf, nbyte, 0);
- } else if (!stream) {
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else if (!stream.isWrite) {
- ___setErrNo(ERRNO_CODES.EACCES);
- return -1;
- } else if (nbyte < 0) {
- ___setErrNo(ERRNO_CODES.EINVAL);
+ }
+
+ if (stream && ('socket' in stream)) {
+ return _send(fildes, buf, nbyte, 0);
+ }
+
+ try {
+ var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
+ return VFS.write(stream, slab, buf, nbyte);
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
- } else {
- if (stream.object.isDevice) {
- if (stream.object.output) {
- for (var i = 0; i < nbyte; i++) {
- try {
- stream.object.output({{{ makeGetValue('buf', 'i', 'i8') }}});
- } catch (e) {
- ___setErrNo(ERRNO_CODES.EIO);
- return -1;
- }
- }
- stream.object.timestamp = Date.now();
- return i;
- } else {
- ___setErrNo(ERRNO_CODES.ENXIO);
- return -1;
- }
- } else {
- var bytesWritten = _pwrite(fildes, buf, nbyte, stream.position);
- if (bytesWritten != -1) stream.position += bytesWritten;
- return bytesWritten;
- }
}
},
alarm: function(seconds) {
@@ -2133,20 +2930,7 @@ LibraryManager.library = {
_exit: function(status) {
// void _exit(int status);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
-
- function ExitStatus() {
- this.name = "ExitStatus";
- this.message = "Program terminated with exit(" + status + ")";
- this.status = status;
- Module.print('Exit Status: ' + status);
- };
- ExitStatus.prototype = new Error();
- ExitStatus.prototype.constructor = ExitStatus;
-
- exitRuntime();
- ABORT = true;
-
- throw new ExitStatus();
+ Module['exit'](status);
},
fork__deps: ['__setErrNo', '$ERRNO_CODES'],
fork: function() {
@@ -3164,7 +3948,8 @@ LibraryManager.library = {
clearerr: function(stream) {
// void clearerr(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/clearerr.html
- if (FS.streams[stream]) FS.streams[stream].error = false;
+ stream = FS.getStream(stream);
+ if (stream) stream.error = false;
},
fclose__deps: ['close', 'fsync'],
fclose: function(stream) {
@@ -3177,68 +3962,51 @@ LibraryManager.library = {
fdopen: function(fildes, mode) {
// FILE *fdopen(int fildes, const char *mode);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fdopen.html
- if (FS.streams[fildes]) {
- var stream = FS.streams[fildes];
- mode = Pointer_stringify(mode);
- if ((mode.indexOf('w') != -1 && !stream.isWrite) ||
- (mode.indexOf('r') != -1 && !stream.isRead) ||
- (mode.indexOf('a') != -1 && !stream.isAppend) ||
- (mode.indexOf('+') != -1 && (!stream.isRead || !stream.isWrite))) {
- ___setErrNo(ERRNO_CODES.EINVAL);
- return 0;
- } else {
- stream.error = false;
- stream.eof = false;
- return fildes;
- }
- } else {
+ mode = Pointer_stringify(mode);
+ var stream = FS.getStream(fildes);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
}
+ if ((mode.indexOf('w') != -1 && !stream.isWrite) ||
+ (mode.indexOf('r') != -1 && !stream.isRead) ||
+ (mode.indexOf('a') != -1 && !stream.isAppend) ||
+ (mode.indexOf('+') != -1 && (!stream.isRead || !stream.isWrite))) {
+ ___setErrNo(ERRNO_CODES.EINVAL);
+ return 0;
+ } else {
+ stream.error = false;
+ stream.eof = false;
+ return fildes;
+ }
},
feof__deps: ['$FS'],
feof: function(stream) {
// int feof(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/feof.html
- return Number(FS.streams[stream] && FS.streams[stream].eof);
+ stream = FS.getStream(stream);
+ return Number(stream && stream.eof);
},
ferror__deps: ['$FS'],
ferror: function(stream) {
// int ferror(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ferror.html
- return Number(FS.streams[stream] && FS.streams[stream].error);
+ stream = FS.getStream(stream);
+ return Number(stream && stream.error);
},
fflush__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
fflush: function(stream) {
// int fflush(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
- var flush = function(filedes) {
- // Right now we write all data directly, except for output devices.
- if (FS.streams[filedes] && FS.streams[filedes].object.output) {
- if (!FS.streams[filedes].object.isTerminal) { // don't flush terminals, it would cause a \n to also appear
- FS.streams[filedes].object.output(null);
- }
- }
- };
- try {
- if (stream === 0) {
- for (var i = 0; i < FS.streams.length; i++) if (FS.streams[i]) flush(i);
- } else {
- flush(stream);
- }
- return 0;
- } catch (e) {
- ___setErrNo(ERRNO_CODES.EIO);
- return -1;
- }
+ // we don't currently perform any user-space buffering of data
},
fgetc__deps: ['$FS', 'fread'],
fgetc__postset: '_fgetc.ret = allocate([0], "i8", ALLOC_STATIC);',
fgetc: function(stream) {
// int fgetc(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetc.html
- if (!FS.streams[stream]) return -1;
- var streamObj = FS.streams[stream];
+ var streamObj = FS.getStream(stream);
+ if (!streamObj) return -1;
if (streamObj.eof || streamObj.error) return -1;
var ret = _fread(_fgetc.ret, 1, 1, stream);
if (ret == 0) {
@@ -3263,28 +4031,26 @@ LibraryManager.library = {
fgetpos: function(stream, pos) {
// int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetpos.html
- if (FS.streams[stream]) {
- stream = FS.streams[stream];
- if (stream.object.isDevice) {
- ___setErrNo(ERRNO_CODES.ESPIPE);
- return -1;
- } else {
- {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}}
- var state = (stream.eof ? 1 : 0) + (stream.error ? 2 : 0);
- {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}}
- return 0;
- }
- } else {
+ stream = FS.getStream(stream);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
+ if (FS.isChrdev(stream.node.mode)) {
+ ___setErrNo(ERRNO_CODES.ESPIPE);
+ return -1;
+ }
+ {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}}
+ var state = (stream.eof ? 1 : 0) + (stream.error ? 2 : 0);
+ {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}}
+ return 0;
},
fgets__deps: ['fgetc'],
fgets: function(s, n, stream) {
// char *fgets(char *restrict s, int n, FILE *restrict stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgets.html
- if (!FS.streams[stream]) return 0;
- var streamObj = FS.streams[stream];
+ var streamObj = FS.getStream(stream);
+ if (!streamObj) return 0;
if (streamObj.error || streamObj.eof) return 0;
var byte_;
for (var i = 0; i < n - 1 && byte_ != {{{ charCode('\n') }}}; i++) {
@@ -3362,7 +4128,8 @@ LibraryManager.library = {
{{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}}
var ret = _write(stream, _fputc.ret, 1);
if (ret == -1) {
- if (FS.streams[stream]) FS.streams[stream].error = true;
+ var streamObj = FS.getStream(stream);
+ if (streamObj) streamObj.error = true;
return -1;
} else {
return chr;
@@ -3406,7 +4173,7 @@ LibraryManager.library = {
return 0;
}
var bytesRead = 0;
- var streamObj = FS.streams[stream];
+ var streamObj = FS.getStream(stream);
while (streamObj.ungotten.length && bytesToRead > 0) {
{{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}}
bytesToRead--;
@@ -3426,12 +4193,13 @@ LibraryManager.library = {
// FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/freopen.html
if (!filename) {
- if (!FS.streams[stream]) {
+ var streamObj = FS.getStream(stream);
+ if (!streamObj) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
}
if (_freopen.buffer) _free(_freopen.buffer);
- filename = intArrayFromString(FS.streams[stream].path);
+ filename = intArrayFromString(streamObj.path);
filename = allocate(filename, 'i8', ALLOC_NORMAL);
}
_fclose(stream);
@@ -3444,10 +4212,10 @@ LibraryManager.library = {
var ret = _lseek(stream, offset, whence);
if (ret == -1) {
return -1;
- } else {
- FS.streams[stream].eof = false;
- return 0;
}
+ stream = FS.getStream(stream);
+ stream.eof = false;
+ return 0;
},
fseeko: 'fseek',
fseeko64: 'fseek',
@@ -3455,38 +4223,36 @@ LibraryManager.library = {
fsetpos: function(stream, pos) {
// int fsetpos(FILE *stream, const fpos_t *pos);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fsetpos.html
- if (FS.streams[stream]) {
- if (FS.streams[stream].object.isDevice) {
- ___setErrNo(ERRNO_CODES.EPIPE);
- return -1;
- } else {
- FS.streams[stream].position = {{{ makeGetValue('pos', '0', 'i32') }}};
- var state = {{{ makeGetValue('pos', Runtime.getNativeTypeSize('i32'), 'i32') }}};
- FS.streams[stream].eof = Boolean(state & 1);
- FS.streams[stream].error = Boolean(state & 2);
- return 0;
- }
- } else {
+ stream = FS.getStream(stream);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
+ if (FS.isChrdev(stream.node.mode)) {
+ ___setErrNo(ERRNO_CODES.EPIPE);
+ return -1;
+ }
+ stream.position = {{{ makeGetValue('pos', '0', 'i32') }}};
+ var state = {{{ makeGetValue('pos', Runtime.getNativeTypeSize('i32'), 'i32') }}};
+ stream.eof = Boolean(state & 1);
+ stream.error = Boolean(state & 2);
+ return 0;
},
ftell__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
ftell: function(stream) {
// long ftell(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ftell.html
- if (FS.streams[stream]) {
- stream = FS.streams[stream];
- if (stream.object.isDevice) {
- ___setErrNo(ERRNO_CODES.ESPIPE);
- return -1;
- } else {
- return stream.position;
- }
- } else {
+ stream = FS.getStream(stream);
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
+ if (FS.isChrdev(stream.node.mode)) {
+ ___setErrNo(ERRNO_CODES.ESPIPE);
+ return -1;
+ } else {
+ return stream.position;
+ }
},
ftello: 'ftell',
ftello64: 'ftell',
@@ -3498,7 +4264,8 @@ LibraryManager.library = {
if (bytesToWrite == 0) return 0;
var bytesWritten = _write(stream, ptr, bytesToWrite);
if (bytesWritten == -1) {
- if (FS.streams[stream]) FS.streams[stream].error = true;
+ var streamObj = FS.getStream(stream);
+ if (streamObj) streamObj.error = true;
return 0;
} else {
return Math.floor(bytesWritten / size);
@@ -3542,30 +4309,17 @@ LibraryManager.library = {
return ret;
},
rename__deps: ['__setErrNo', '$ERRNO_CODES'],
- rename: function(old, new_) {
+ rename: function(old_path, new_path) {
// int rename(const char *old, const char *new);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rename.html
- var oldObj = FS.analyzePath(Pointer_stringify(old));
- var newObj = FS.analyzePath(Pointer_stringify(new_));
- if (newObj.path == oldObj.path) {
+ old_path = Pointer_stringify(old_path);
+ new_path = Pointer_stringify(new_path);
+ try {
+ VFS.rename(old_path, new_path);
return 0;
- } else if (!oldObj.exists) {
- ___setErrNo(oldObj.error);
- return -1;
- } else if (oldObj.isRoot || oldObj.path == FS.currentPath) {
- ___setErrNo(ERRNO_CODES.EBUSY);
- return -1;
- } else if (newObj.parentPath &&
- newObj.parentPath.indexOf(oldObj.path) == 0) {
- ___setErrNo(ERRNO_CODES.EINVAL);
- return -1;
- } else if (newObj.exists && newObj.object.isFolder) {
- ___setErrNo(ERRNO_CODES.EISDIR);
+ } catch (e) {
+ FS.handleFSError(e);
return -1;
- } else {
- delete oldObj.parentObject.contents[oldObj.name];
- newObj.parentObject.contents[newObj.name] = oldObj.object;
- return 0;
}
},
rewind__deps: ['$FS', 'fseek'],
@@ -3573,7 +4327,8 @@ LibraryManager.library = {
// void rewind(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rewind.html
_fseek(stream, 0, 0); // SEEK_SET.
- if (FS.streams[stream]) FS.streams[stream].error = false;
+ var streamObj = FS.getStream(stream);
+ if (streamObj) streamObj.error = false;
},
setvbuf: function(stream, buf, type, size) {
// int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size);
@@ -3632,7 +4387,7 @@ LibraryManager.library = {
ungetc: function(c, stream) {
// int ungetc(int c, FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ungetc.html
- stream = FS.streams[stream];
+ stream = FS.getStream(stream);
if (!stream) {
return -1;
}
@@ -3653,34 +4408,24 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.EAGAIN);
return -1;
},
- fscanf__deps: ['$FS', '__setErrNo', '$ERRNO_CODES',
- '_scanString', 'fgetc', 'fseek', 'ftell'],
+ fscanf__deps: ['$FS', '_scanString', 'fgetc', 'ungetc'],
fscanf: function(stream, format, varargs) {
// int fscanf(FILE *restrict stream, const char *restrict format, ... );
// http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
- if (FS.streams[stream]) {
- var i = _ftell(stream), SEEK_SET = 0;
- // if the stream does not support seeking backwards (e.g. stdin), buffer it here
- var buffer = [], bufferIndex = 0;
- var get = function() {
- if (bufferIndex < buffer.length) {
- return buffer[bufferIndex++];
- }
- i++;
- bufferIndex++;
- var c = _fgetc(stream);
- buffer.push(c);
- return c;
- };
- var unget = function() {
- if (_fseek(stream, --i, SEEK_SET) !== 0) {
- bufferIndex--;
- }
- };
- return __scanString(format, get, unget, varargs);
- } else {
+ var streamObj = FS.getStream(stream);
+ if (!streamObj) {
return -1;
}
+ var buffer = [];
+ var get = function() {
+ var c = _fgetc(stream);
+ buffer.push(c);
+ return c;
+ };
+ var unget = function() {
+ _ungetc(buffer.pop(), stream);
+ };
+ return __scanString(format, get, unget, varargs);
},
scanf__deps: ['fscanf'],
scanf: function(format, varargs) {
@@ -3820,38 +4565,26 @@ LibraryManager.library = {
* mmap.
*/
var MAP_PRIVATE = 2;
+ var ptr;
var allocated = false;
if (!_mmap.mappings) _mmap.mappings = {};
if (stream == -1) {
- var ptr = _malloc(num);
+ ptr = _malloc(num);
if (!ptr) return -1;
_memset(ptr, 0, num);
allocated = true;
} else {
- var info = FS.streams[stream];
+ var info = FS.getStream(stream);
if (!info) return -1;
- var contents = info.object.contents;
- // Only make a new copy when MAP_PRIVATE is specified.
- if (flags & MAP_PRIVATE == 0) {
- // We can't emulate MAP_SHARED when the file is not backed by HEAP.
- assert(contents.buffer === HEAPU8.buffer);
- ptr = contents.byteOffset;
- allocated = false;
- } else {
- // Try to avoid unnecessary slices.
- if (offset > 0 || offset + num < contents.length) {
- if (contents.subarray) {
- contents = contents.subarray(offset, offset+num);
- } else {
- contents = Array.prototype.slice.call(contents, offset, offset+num);
- }
- }
- ptr = _malloc(num);
- if (!ptr) return -1;
- HEAPU8.set(contents, ptr);
- allocated = true;
+ try {
+ var res = VFS.mmap(info, HEAPU8, start, num, offset, prot, flags);
+ ptr = res.ptr;
+ allocated = res.allocated;
+ } catch (e) {
+ FS.handleFSError(e);
+ return -1;
}
}
@@ -3876,6 +4609,20 @@ LibraryManager.library = {
// TODO: Implement mremap.
+ mprotect: function(addr, len, prot) {
+ // int mprotect(void *addr, size_t len, int prot);
+ // http://pubs.opengroup.org/onlinepubs/7908799/xsh/mprotect.html
+ // Pretend to succeed
+ return 0;
+ },
+
+ msync: function(addr, len, flags) {
+ // int msync(void *addr, size_t len, int flags);
+ // http://pubs.opengroup.org/onlinepubs/009696799/functions/msync.html
+ // Pretend to succeed
+ return 0;
+ },
+
// ==========================================================================
// stdlib.h
// ==========================================================================
@@ -3939,13 +4686,16 @@ LibraryManager.library = {
__cxa_atexit: 'atexit',
abort: function() {
- ABORT = true;
- throw 'abort() at ' + (new Error().stack);
+ Module['abort']();
},
bsearch: function(key, base, num, size, compar) {
var cmp = function(x, y) {
- return Runtime.dynCall('iii', compar, [x, y])
+#if ASM_JS
+ return Module['dynCall_iii'](compar, x, y);
+#else
+ return FUNCTION_TABLE[compar](x, y);
+#endif
};
var left = 0;
var right = num;
@@ -3955,7 +4705,6 @@ LibraryManager.library = {
mid = (left + right) >>> 1;
addr = base + (mid * size);
test = cmp(key, addr);
-
if (test < 0) {
right = mid;
} else if (test > 0) {
@@ -4175,13 +4924,14 @@ LibraryManager.library = {
if (num == 0 || size == 0) return;
// forward calls to the JavaScript sort method
// first, sort the items logically
- var comparator = function(x, y) {
- return Runtime.dynCall('iii', cmp, [x, y]);
- }
var keys = [];
for (var i = 0; i < num; i++) keys.push(i);
keys.sort(function(a, b) {
- return comparator(base+a*size, base+b*size);
+#if ASM_JS
+ return Module['dynCall_iii'](cmp, base+a*size, base+b*size);
+#else
+ return FUNCTION_TABLE[cmp](base+a*size, base+b*size);
+#endif
});
// apply the sort
var temp = _malloc(num*size);
@@ -4459,6 +5209,13 @@ LibraryManager.library = {
llvm_memmove_p0i8_p0i8_i32: 'memmove',
llvm_memmove_p0i8_p0i8_i64: 'memmove',
+ bcopy__deps: ['memmove'],
+ bcopy: function(src, dest, num) {
+ // void bcopy(const void *s1, void *s2, size_t n);
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/bcopy.html
+ _memmove(dest, src, num);
+ },
+
memset__inline: function(ptr, value, num, align) {
return makeSetValues(ptr, 0, value, 'null', num, align);
},
@@ -6161,9 +6918,14 @@ LibraryManager.library = {
{{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'date.getUTCDay()', 'i32') }}}
{{{ makeSetValue('tmPtr', 'offsets.tm_gmtoff', '0', 'i32') }}}
{{{ makeSetValue('tmPtr', 'offsets.tm_isdst', '0', 'i32') }}}
-
- var start = new Date(date.getFullYear(), 0, 1);
- var yday = Math.round((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
+ var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC
+ start.setUTCDate(1);
+ start.setUTCMonth(0);
+ start.setUTCHours(0);
+ start.setUTCMinutes(0);
+ start.setUTCSeconds(0);
+ start.setUTCMilliseconds(0);
+ var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
{{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}}
var timezone = "GMT";
@@ -6174,7 +6936,6 @@ LibraryManager.library = {
return tmPtr;
},
-
timegm__deps: ['mktime'],
timegm: function(tmPtr) {
_tzset();
@@ -6966,8 +7727,6 @@ LibraryManager.library = {
// ==========================================================================
// sys/types.h
// ==========================================================================
-
- // NOTE: These are fake, since we don't support the C device creation API.
// http://www.kernel.org/doc/man-pages/online/pages/man3/minor.3.html
makedev: function(maj, min) {
return ((maj) << 8 | (min));
@@ -7814,42 +8573,53 @@ LibraryManager.library = {
ntohl: 'htonl',
ntohs: 'htons',
- inet_addr: function(ptr) {
- var b = Pointer_stringify(ptr).split(".");
- if (b.length !== 4) return -1; // we return -1 for error, and otherwise a uint32. this helps inet_pton differentiate
- return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0;
+ // http://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html
+ inet_ntop__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_ntop4', 'inet_ntop6'],
+ inet_ntop: function(af, src, dst, size) {
+ switch (af) {
+ case {{{ cDefine('AF_INET') }}}:
+ return _inet_ntop4(src, dst, size);
+ case {{{ cDefine('AF_INET6') }}}:
+ return _inet_ntop6(src, dst, size);
+ default:
+ ___setErrNo(ERRNO_CODES.EAFNOSUPPORT);
+ return 0;
+ }
},
-
- inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_addr'],
+ inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_pton4', 'inet_pton6'],
inet_pton: function(af, src, dst) {
- // int af, const char *src, void *dst
- if ((af ^ {{{ cDefine("AF_INET") }}}) !== 0) { ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); return -1; }
- var ret = _inet_addr(src);
- if (ret == -1 || isNaN(ret)) return 0;
- setValue(dst, ret, 'i32');
- return 1;
+ switch (af) {
+ case {{{ cDefine('AF_INET') }}}:
+ return _inet_pton4(src, dst);
+ case {{{ cDefine('AF_INET6') }}}:
+ return _inet_pton6(src, dst);
+ default:
+ ___setErrNo(ERRNO_CODES.EAFNOSUPPORT);
+ return -1;
+ }
},
-
- _inet_ntop_raw: function(addr) {
- return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff)
+ inet_addr: function(ptr) {
+ var b = Pointer_stringify(ptr).split(".");
+ if (b.length !== 4) return -1; // we return -1 for error, and otherwise a uint32. this helps inet_pton differentiate
+ return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0;
},
-
- inet_ntop__deps: ['_inet_ntop_raw'],
- inet_ntop: function(af, src, dst, size) {
- var addr = getValue(src, 'i32');
- var str = __inet_ntop_raw(addr);
- writeStringToMemory(str.substr(0, size), dst);
- return dst;
+ _inet_aton_raw: function(str) {
+ var b = str.split(".");
+ return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0;
},
-
- inet_ntoa__deps: ['inet_ntop'],
+ _inet_ntoa_raw: function(addr) {
+ return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff)
+ },
+ inet_ntoa__deps: ['_inet_ntoa_raw'],
inet_ntoa: function(in_addr) {
if (!_inet_ntoa.buffer) {
_inet_ntoa.buffer = _malloc(1024);
}
- return _inet_ntop(0, in_addr, _inet_ntoa.buffer, 1024);
+ var addr = getValue(in_addr, 'i32');
+ var str = __inet_ntoa_raw(addr);
+ writeStringToMemory(str.substr(0, 1024), _inet_ntoa.buffer);
+ return _inet_ntoa.buffer;
},
-
inet_aton__deps: ['inet_addr'],
inet_aton: function(cp, inp) {
var addr = _inet_addr(cp);
@@ -7858,6 +8628,182 @@ LibraryManager.library = {
return 1;
},
+ inet_ntop4__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntoa_raw'],
+ inet_ntop4: function(src, dst, size) {
+ var str = __inet_ntoa_raw(getValue(src, 'i32'));
+ if (str.length+1 > size) {
+ ___setErrNo(ERRNO_CODES.ENOSPC);
+ return 0;
+ }
+ writeStringToMemory(str, dst);
+ return dst;
+ },
+
+ inet_ntop6__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_ntop6_raw'],
+ inet_ntop6: function(src, dst, size) {
+ var str = _inet_ntop6_raw(src);
+ if (str.length+1 > size) {
+ ___setErrNo(ERRNO_CODES.ENOSPC);
+ return 0;
+ }
+ writeStringToMemory(str, dst);
+ return dst;
+ },
+ inet_ntop6_raw__deps: ['ntohs'],
+ inet_ntop6_raw: function(src) {
+
+ // ref: http://www.ietf.org/rfc/rfc2373.txt - section 2.5.4
+ // Format for IPv4 compatible and mapped 128-bit IPv6 Addresses
+ // 128-bits are split into eight 16-bit words
+ // stored in network byte order (big-endian)
+ // | 80 bits | 16 | 32 bits |
+ // +-----------------------------------------------------------------+
+ // | 10 bytes | 2 | 4 bytes |
+ // +--------------------------------------+--------------------------+
+ // + 5 words | 1 | 2 words |
+ // +--------------------------------------+--------------------------+
+ // |0000..............................0000|0000| IPv4 ADDRESS | (compatible)
+ // +--------------------------------------+----+---------------------+
+ // |0000..............................0000|FFFF| IPv4 ADDRESS | (mapped)
+ // +--------------------------------------+----+---------------------+
+
+ var str = "";
+ var word = 0;
+ var longest = 0;
+ var lastzero = 0;
+ var zstart = 0;
+ var len = 0;
+ var i = 0;
+
+ // Handle IPv4-compatible, IPv4-mapped, loopback and any/unspecified addresses
+
+ var hasipv4 = true;
+ var v4part = "";
+ // check if the 10 high-order bytes are all zeros (first 5 words)
+ for (i = 0; i < 10; i++) {
+ if ({{{ makeGetValue('src', 'i', 'i8') }}} !== 0) { hasipv4 = false; break; }
+ }
+
+ if (hasipv4) {
+ // low-order 32-bits store an IPv4 address (bytes 13 to 16) (last 2 words)
+ v4part = __inet_ntoa_raw({{{ makeGetValue('src', '12', 'i32') }}});
+ // IPv4-mapped IPv6 address if 16-bit value (bytes 11 and 12) == 0xFFFF (6th word)
+ if ({{{ makeGetValue('src', '10', 'i16') }}} === -1) {
+ str = "::ffff:";
+ str += v4part;
+ return str;
+ }
+ // IPv4-compatible IPv6 address if 16-bit value (bytes 11 and 12) == 0x0000 (6th word)
+ if ({{{ makeGetValue('src', '10', 'i16') }}} === 0) {
+ str = "::";
+ //special case IPv6 addresses
+ if(v4part === "0.0.0.0") v4part = ""; // any/unspecified address
+ if(v4part === "0.0.0.1") v4part = "1";// loopback address
+ str += v4part;
+ return str;
+ }
+ }
+
+ // Handle all other IPv6 addresses
+
+ // first run to find the longest contiguous zero words
+ for (word = 0; word < 8; word++) {
+ if ({{{ makeGetValue('src', 'word*2', 'i16') }}} === 0) {
+ if (word - lastzero > 1) {
+ len = 0;
+ }
+ lastzero = word;
+ len++;
+ }
+ if (len > longest) {
+ longest = len;
+ zstart = word - longest + 1;
+ }
+ }
+
+ for (word = 0; word < 8; word++) {
+ if (longest > 1) {
+ // compress contiguous zeros - to produce "::"
+ if ({{{ makeGetValue('src', 'word*2', 'i16') }}} === 0 && word >= zstart && word < (zstart + longest) ) {
+ if (word === zstart) {
+ str += ":";
+ if (zstart === 0) str += ":"; //leading zeros case
+ }
+ continue;
+ }
+ }
+ // converts 16-bit words from big-endian to little-endian before converting to hex string
+ str += Number(_ntohs({{{ makeGetValue('src', 'word*2', 'i16') }}} & 0xffff)).toString(16);
+ str += word < 7 ? ":" : "";
+ }
+ return str;
+ },
+
+ inet_pton4__deps: ['inet_addr'],
+ inet_pton4: function(src, dst) {
+ var ret = _inet_addr(src);
+ if (ret === -1 || isNaN(ret)) return 0;
+ setValue(dst, ret, 'i32');
+ return 1;
+ },
+
+ inet_pton6__deps: ['inet_pton6_raw'],
+ inet_pton6: function(src, dst) {
+ return _inet_pton6_raw(Pointer_stringify(src), dst);
+ },
+
+ inet_pton6_raw__deps: ['htons'],
+ inet_pton6_raw: function(addr, dst) {
+ var words;
+ var w, offset, z, i;
+ /* http://home.deds.nl/~aeron/regex/ */
+ var valid6regx = /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i
+ if (!valid6regx.test(addr)) {
+ return 0;
+ }
+ if (addr === "::") {
+ for (i=0; i < 4; i++) {{{ makeSetValue('dst', 'i*4', '0', 'i32') }}};
+ return 1;
+ }
+ // Z placeholder to keep track of zeros when splitting the string on ":"
+ if (addr.indexOf("::") === 0) {
+ addr = addr.replace("::", "Z:"); // leading zeros case
+ } else {
+ addr = addr.replace("::", ":Z:");
+ }
+
+ if (addr.indexOf(".") > 0) {
+ // parse IPv4 embedded address
+ addr = addr.replace(new RegExp('[.]', 'g'), ":");
+ words = addr.split(":");
+ words[words.length-4] = parseInt(words[words.length-4]) + parseInt(words[words.length-3])*256;
+ words[words.length-3] = parseInt(words[words.length-2]) + parseInt(words[words.length-1])*256;
+ words = words.slice(0, words.length-2);
+ } else {
+ words = addr.split(":");
+ }
+
+ offset = 0; z = 0;
+ for (w=0; w < words.length; w++) {
+ if (typeof words[w] === 'string') {
+ if (words[w] === 'Z') {
+ // compressed zeros - write appropriate number of zero words
+ for (z = 0; z < (8 - words.length+1); z++) {
+ {{{ makeSetValue('dst', '(w+z)*2', '0', 'i16') }}};
+ }
+ offset = z-1;
+ } else {
+ // parse hex to field to 16-bit value and write it in network byte-order
+ {{{ makeSetValue('dst', '(w+offset)*2', '_htons(parseInt(words[w],16))', 'i16') }}};
+ }
+ } else {
+ // parsed IPv4 words
+ {{{ makeSetValue('dst', '(w+offset)*2', 'words[w]', 'i16') }}};
+ }
+ }
+ return 1;
+ },
+
// netinet/in.h
_in6addr_any:
@@ -7911,7 +8857,7 @@ LibraryManager.library = {
var aliasesBuf = _malloc(4);
setValue(aliasesBuf, 0, 'i8*');
setValue(ret+___hostent_struct_layout.h_aliases, aliasesBuf, 'i8**');
- setValue(ret+___hostent_struct_layout.h_addrtype, {{{ cDefine("AF_INET") }}}, 'i32');
+ setValue(ret+___hostent_struct_layout.h_addrtype, {{{ cDefine('AF_INET') }}}, 'i32');
setValue(ret+___hostent_struct_layout.h_length, 4, 'i32');
var addrListBuf = _malloc(12);
setValue(addrListBuf, addrListBuf+8, 'i32*');
@@ -7989,15 +8935,16 @@ LibraryManager.library = {
socket__deps: ['$Sockets'],
socket: function(family, type, protocol) {
var INCOMING_QUEUE_LENGTH = 64;
- var fd = FS.createFileHandle({
+ var stream = FS.createStream({
addr: null,
port: null,
inQueue: new CircularBuffer(INCOMING_QUEUE_LENGTH),
header: new Uint16Array(2),
bound: false,
- socket: true
+ socket: true,
+ stream_ops: {}
});
- assert(fd < 64); // select() assumes socket fd values are in 0..63
+ assert(stream.fd < 64); // select() assumes socket fd values are in 0..63
var stream = type == {{{ cDefine('SOCK_STREAM') }}};
if (protocol) {
assert(stream == (protocol == {{{ cDefine('IPPROTO_TCP') }}})); // if stream, must be tcp
@@ -8111,7 +9058,7 @@ LibraryManager.library = {
};
};
- return fd;
+ return stream.fd;
},
mkport__deps: ['$Sockets'],
@@ -8130,9 +9077,9 @@ LibraryManager.library = {
// Stub: connection-oriented sockets are not supported yet.
},
- bind__deps: ['$Sockets', '_inet_ntop_raw', 'ntohs', 'mkport'],
+ bind__deps: ['$Sockets', '_inet_ntoa_raw', 'ntohs', 'mkport'],
bind: function(fd, addr, addrlen) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
if (addr) {
info.port = _ntohs(getValue(addr + Sockets.sockaddr_in_layout.sin_port, 'i16'));
@@ -8142,7 +9089,7 @@ LibraryManager.library = {
info.port = _mkport();
}
info.addr = Sockets.localAddr; // 10.0.0.254
- info.host = __inet_ntop_raw(info.addr);
+ info.host = __inet_ntoa_raw(info.addr);
info.close = function() {
Sockets.portmap[info.port] = undefined;
}
@@ -8151,9 +9098,9 @@ LibraryManager.library = {
info.bound = true;
},
- sendmsg__deps: ['$Sockets', 'bind', '_inet_ntop_raw', 'ntohs'],
+ sendmsg__deps: ['$Sockets', 'bind', '_inet_ntoa_raw', 'ntohs'],
sendmsg: function(fd, msg, flags) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
// if we are not connected, use the address info in the message
if (!info.bound) {
@@ -8165,7 +9112,7 @@ LibraryManager.library = {
var port = _ntohs(getValue(name + Sockets.sockaddr_in_layout.sin_port, 'i16'));
var addr = getValue(name + Sockets.sockaddr_in_layout.sin_addr, 'i32');
var connection = Sockets.connections[addr];
- // var host = __inet_ntop_raw(addr);
+ // var host = __inet_ntoa_raw(addr);
if (!(connection && connection.connected)) {
___setErrNo(ERRNO_CODES.EWOULDBLOCK);
@@ -8209,7 +9156,7 @@ LibraryManager.library = {
recvmsg__deps: ['$Sockets', 'bind', '__setErrNo', '$ERRNO_CODES', 'htons'],
recvmsg: function(fd, msg, flags) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
// if we are not connected, use the address info in the message
if (!info.port) {
@@ -8260,14 +9207,14 @@ LibraryManager.library = {
},
shutdown: function(fd, how) {
- var info = FS.streams[fd];
- if (!info) return -1;
- info.close();
- FS.removeFileHandle(fd);
+ var stream = FS.getStream(fd);
+ if (!stream) return -1;
+ stream.close();
+ FS.closeStream(stream);
},
ioctl: function(fd, request, varargs) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
var bytes = 0;
if (info.hasData()) {
@@ -8287,7 +9234,7 @@ LibraryManager.library = {
// TODO: webrtc queued incoming connections, etc.
// For now, the model is that bind does a connect, and we "accept" that one connection,
// which has host:port the same as ours. We also return the same socket fd.
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
if (addr) {
setValue(addr + Sockets.sockaddr_in_layout.sin_addr, info.addr, 'i32');
@@ -8328,7 +9275,7 @@ LibraryManager.library = {
var mask = 1 << (fd % 32), int_ = fd < 32 ? srcLow : srcHigh;
if (int_ & mask) {
// index is in the set, check if it is ready for read
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (info && can(info)) {
// set bit
fd < 32 ? (dstLow = dstLow | mask) : (dstHigh = dstHigh | mask);
@@ -8357,23 +9304,24 @@ LibraryManager.library = {
if (protocol) {
assert(stream == (protocol == {{{ cDefine('IPPROTO_TCP') }}})); // if SOCK_STREAM, must be tcp
}
- var fd = FS.createFileHandle({
+ var stream = FS.createStream({
connected: false,
stream: stream,
- socket: true
+ socket: true,
+ stream_ops: {}
});
- assert(fd < 64); // select() assumes socket fd values are in 0..63
- return fd;
+ assert(stream.fd < 64); // select() assumes socket fd values are in 0..63
+ return stream.fd;
},
- connect__deps: ['$FS', '$Sockets', '_inet_ntop_raw', 'ntohs', 'gethostbyname'],
+ connect__deps: ['$FS', '$Sockets', '_inet_ntoa_raw', 'ntohs', 'gethostbyname'],
connect: function(fd, addr, addrlen) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
info.connected = true;
info.addr = getValue(addr + Sockets.sockaddr_in_layout.sin_addr, 'i32');
info.port = _htons(getValue(addr + Sockets.sockaddr_in_layout.sin_port, 'i16'));
- info.host = __inet_ntop_raw(info.addr);
+ info.host = __inet_ntoa_raw(info.addr);
// Support 'fake' ips from gethostbyname
var parts = info.host.split('.');
if (parts[0] == '172' && parts[1] == '29') {
@@ -8486,7 +9434,7 @@ LibraryManager.library = {
recv__deps: ['$FS'],
recv: function(fd, buf, len, flags) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
if (!info.hasData()) {
___setErrNo(ERRNO_CODES.EAGAIN); // no data, and all sockets are nonblocking, so this is the right behavior
@@ -8512,7 +9460,7 @@ LibraryManager.library = {
send__deps: ['$FS'],
send: function(fd, buf, len, flags) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
info.sender(HEAPU8.subarray(buf, buf+len));
return len;
@@ -8520,7 +9468,7 @@ LibraryManager.library = {
sendmsg__deps: ['$FS', '$Sockets', 'connect'],
sendmsg: function(fd, msg, flags) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
// if we are not connected, use the address info in the message
if (!info.connected) {
@@ -8555,7 +9503,7 @@ LibraryManager.library = {
recvmsg__deps: ['$FS', '$Sockets', 'connect', 'recv', '__setErrNo', '$ERRNO_CODES', 'htons'],
recvmsg: function(fd, msg, flags) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
// if we are not connected, use the address info in the message
if (!info.connected) {
@@ -8613,7 +9561,7 @@ LibraryManager.library = {
recvfrom__deps: ['$FS', 'connect', 'recv'],
recvfrom: function(fd, buf, len, flags, addr, addrlen) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
// if we are not connected, use the address info in the message
if (!info.connected) {
@@ -8624,14 +9572,14 @@ LibraryManager.library = {
},
shutdown: function(fd, how) {
- var info = FS.streams[fd];
- if (!info) return -1;
- info.socket.close();
- FS.removeFileHandle(fd);
+ var stream = FS.getStream(fd);
+ if (!stream) return -1;
+ stream.socket.close();
+ FS.closeStream(stream);
},
ioctl: function(fd, request, varargs) {
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
var bytes = 0;
if (info.hasData()) {
@@ -8661,7 +9609,7 @@ LibraryManager.library = {
// TODO: webrtc queued incoming connections, etc.
// For now, the model is that bind does a connect, and we "accept" that one connection,
// which has host:port the same as ours. We also return the same socket fd.
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (!info) return -1;
if (addr) {
setValue(addr + Sockets.sockaddr_in_layout.sin_addr, info.addr, 'i32');
@@ -8717,7 +9665,7 @@ LibraryManager.library = {
var mask = 1 << (fd % 32), int_ = fd < 32 ? srcLow : srcHigh;
if (int_ & mask) {
// index is in the set, check if it is ready for read
- var info = FS.streams[fd];
+ var info = FS.getStream(fd);
if (info && can(info)) {
// set bit
fd < 32 ? (dstLow = dstLow | mask) : (dstHigh = dstHigh | mask);
diff --git a/src/library_gl.js b/src/library_gl.js
index d0f1a692..8c724245 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -636,6 +636,11 @@ var LibraryGL = {
for (var i = 0; i < n; i++) {
var id = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
var buffer = GL.buffers[id];
+
+ // From spec: "glDeleteBuffers silently ignores 0's and names that do not
+ // correspond to existing buffer objects."
+ if (!buffer) continue;
+
Module.ctx.deleteBuffer(buffer);
buffer.name = 0;
GL.buffers[id] = null;
@@ -1318,7 +1323,7 @@ var LibraryGL = {
GLEmulation.fogColor = new Float32Array(4);
// Add some emulation workarounds
- Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work');
+ Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work. (If you do not want this, build with -s DISABLE_GL_EMULATION=1)');
#if GL_UNSAFE_OPTS == 0
Module.printErr('WARNING: using emscripten GL emulation unsafe opts. If weirdness happens, try -s GL_UNSAFE_OPTS=0');
#endif
diff --git a/src/library_jansson.js b/src/library_jansson.js
index 93f239fc..da8c5aa8 100644
--- a/src/library_jansson.js
+++ b/src/library_jansson.js
@@ -79,7 +79,7 @@ var LibraryJansson = {
load: function(string, flags, error) {
// This is potentially a security problem.
// TODO: Make sure everything is properly escaped
- var json_obj = eval('(' + string + ')');
+ var json_obj = JSON.parse(string);
if (json_obj != null) {
// The context is an array storing all child nodes.
diff --git a/src/library_openal.js b/src/library_openal.js
index 6a97fce7..d2516559 100644
--- a/src/library_openal.js
+++ b/src/library_openal.js
@@ -5,6 +5,8 @@ var LibraryOpenAL = {
$AL: {
contexts: [],
currentContext: null,
+ QUEUE_INTERVAL: 25,
+ QUEUE_LOOKAHEAD: 100
},
alcProcessContext: function(context) {},
@@ -39,6 +41,7 @@ var LibraryOpenAL = {
alcDestroyContext: function(context) {
// Stop playback, etc
+ clearInterval(context.interval);
},
alcCloseDevice: function(device) {
@@ -54,6 +57,7 @@ var LibraryOpenAL = {
}
},
+ alcCreateContext__deps: ['updateSources'],
alcCreateContext: function(device, attrList) {
if (device != 1) {
return 0;
@@ -76,18 +80,152 @@ var LibraryOpenAL = {
}
if (ctx) {
- AL.contexts.push({ctx: ctx, err: 0, src: [], buf: []});
+ var context = {
+ ctx: ctx,
+ err: 0,
+ src: [],
+ buf: [],
+ interval: setInterval(function () { _updateSources(context); }, AL.QUEUE_INTERVAL)
+ };
+ AL.contexts.push(context);
return AL.contexts.length;
} else {
return 0;
}
},
+ updateSources__deps: ['updateSource'],
+ updateSources: function (context) {
+ for (var i = 0; i < context.src.length; i++) {
+ _updateSource(context.src[i]);
+ }
+ },
+
+ updateSource__deps: ['setSourceState'],
+ updateSource: function (src) {
+#if OPENAL_DEBUG
+ var idx = AL.currentContext.src.indexOf(src);
+#endif
+ if (src.state !== 0x1012 /* AL_PLAYING */) {
+ return;
+ }
+
+ var currentTime = AL.currentContext.ctx.currentTime;
+ var startTime = src.bufferPosition;
+
+ for (var i = src.buffersPlayed; i < src.queue.length; i++) {
+ var entry = src.queue[i];
+
+ var startOffset = startTime - currentTime;
+ var endTime = startTime + entry.buffer.duration;
+
+ // Clean up old buffers.
+ if (currentTime >= endTime) {
+ // Update our location in the queue.
+ src.bufferPosition = endTime;
+ src.buffersPlayed = i + 1;
+
+ // Stop / restart the source when we hit the end.
+ if (src.buffersPlayed >= src.queue.length) {
+ if (src.loop) {
+ _setSourceState(src, 0x1012 /* AL_PLAYING */);
+ } else {
+ _setSourceState(src, 0x1014 /* AL_STOPPED */);
+ }
+ }
+ }
+ // Process all buffers that'll be played before the next tick.
+ else if (startOffset < (AL.QUEUE_LOOKAHEAD / 1000) && !entry.src) {
+ // If the start offset is negative, we need to offset the actual buffer.
+ var offset = Math.abs(Math.min(startOffset, 0));
+
+ entry.src = AL.currentContext.ctx.createBufferSource();
+ entry.src.buffer = entry.buffer;
+ entry.src.connect(src.gain);
+ entry.src.start(startTime, offset);
+
+#if OPENAL_DEBUG
+ console.log('updateSource queuing buffer ' + i + ' for source ' + idx + ' at ' + startTime + ' (offset by ' + offset + ')');
+#endif
+ }
+
+ startTime = endTime;
+ }
+ },
+
+ setSourceState__deps: ['updateSource', 'stopSourceQueue'],
+ setSourceState: function (src, state) {
+#if OPENAL_DEBUG
+ var idx = AL.currentContext.src.indexOf(src);
+#endif
+ if (state === 0x1012 /* AL_PLAYING */) {
+ if (src.state !== 0x1013 /* AL_PAUSED */) {
+ src.state = 0x1012 /* AL_PLAYING */;
+ // Reset our position.
+ src.bufferPosition = AL.currentContext.ctx.currentTime;
+ src.buffersPlayed = 0;
+#if OPENAL_DEBUG
+ console.log('setSourceState resetting and playing source ' + idx);
+#endif
+ } else {
+ src.state = 0x1012 /* AL_PLAYING */;
+ // Use the current offset from src.bufferPosition to resume at the correct point.
+ src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition;
+#if OPENAL_DEBUG
+ console.log('setSourceState resuming source ' + idx + ' at ' + src.bufferPosition.toFixed(4));
+#endif
+ }
+ _stopSourceQueue(src);
+ _updateSource(src);
+ } else if (state === 0x1013 /* AL_PAUSED */) {
+ if (src.state === 0x1012 /* AL_PLAYING */) {
+ src.state = 0x1013 /* AL_PAUSED */;
+ // Store off the current offset to restore with on resume.
+ src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition;
+ _stopSourceQueue(src);
+#if OPENAL_DEBUG
+ console.log('setSourceState pausing source ' + idx + ' at ' + src.bufferPosition.toFixed(4));
+#endif
+ }
+ } else if (state === 0x1014 /* AL_STOPPED */) {
+ if (src.state !== 0x1011 /* AL_INITIAL */) {
+ src.state = 0x1014 /* AL_STOPPED */;
+ src.buffersPlayed = src.queue.length;
+ _stopSourceQueue(src);
+#if OPENAL_DEBUG
+ console.log('setSourceState stopping source ' + idx);
+#endif
+ }
+ } else if (state == 0x1011 /* AL_INITIAL */) {
+ if (src.state !== 0x1011 /* AL_INITIAL */) {
+ src.state = 0x1011 /* AL_INITIAL */;
+ src.bufferPosition = 0;
+ src.buffersPlayed = 0;
+#if OPENAL_DEBUG
+ console.log('setSourceState initializing source ' + idx);
+#endif
+ }
+ }
+ },
+
+ stopSourceQueue: function (src) {
+ for (var i = 0; i < src.queue.length; i++) {
+ var entry = src.queue[i];
+ if (entry.src) {
+ entry.src.stop(0);
+ entry.src = null;
+ }
+ }
+ },
+
alGetError: function() {
if (!AL.currentContext) {
return 0xA004 /* AL_INVALID_OPERATION */;
} else {
- return AL.currentContext.err;
+ // Reset error on get.
+ var err = AL.currentContext.err;
+ AL.currentContext.err = 0 /* AL_NO_ERROR */;
+ return err;
}
},
@@ -97,12 +235,12 @@ var LibraryOpenAL = {
return _alGetError();
},
- alDeleteSources: function(count, sources)
- {
+ alDeleteSources: function(count, sources) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alDeleteSources called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
@@ -116,57 +254,126 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alGenSources called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
var gain = AL.currentContext.ctx.createGain();
- var panner = AL.currentContext.ctx.createPanner();
- panner.panningModel = "equalpower";
- panner.distanceModel = "linear";
- panner.rolloffFactor = 0.3;
- gain.connect(panner);
- panner.connect(AL.currentContext.ctx.destination);
+ gain.connect(AL.currentContext.ctx.destination);
AL.currentContext.src.push({
+ state: 0x1011 /* AL_INITIAL */,
+ queue: [],
loop: false,
- buffer: null,
+ get refDistance() {
+ return this._refDistance || 1;
+ },
+ set refDistance(val) {
+ this._refDistance = val;
+ if (this.panner) this.panner.refDistance = val;
+ },
+ get maxDistance() {
+ return this._maxDistance || 10000;
+ },
+ set maxDistance(val) {
+ this._maxDistance = val;
+ if (this.panner) this.panner.maxDistance = val;
+ },
+ get rolloffFactor() {
+ return this._rolloffFactor || 1;
+ },
+ set rolloffFactor(val) {
+ this._rolloffFactor = val;
+ if (this.panner) this.panner.rolloffFactor = val;
+ },
+ get position() {
+ return this._position || [0, 0, 0];
+ },
+ set position(val) {
+ this._position = val;
+ if (this.panner) this.panner.setPosition(val[0], val[1], val[2]);
+ },
+ get velocity() {
+ return this._velocity || [0, 0, 0];
+ },
+ set velocity(val) {
+ this._velocity = val;
+ if (this.panner) this.panner.setVelocity(val[0], val[1], val[2]);
+ },
gain: gain,
- panner: panner,
- paused: false,
- playTime: -1,
- pausedTime: 0
+ panner: null,
+ buffersPlayed: 0,
+ bufferPosition: 0
});
{{{ makeSetValue('sources', 'i*4', 'AL.currentContext.src.length', 'i32') }}};
}
},
+ alSourcei__deps: ['updateSource'],
alSourcei: function(source, param, value) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourcei called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
console.error("alSourcei called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
switch (param) {
case 0x1007 /* AL_LOOPING */:
- AL.currentContext.src[source - 1].loop = (value != 0 /* AL_FALSE */);
+ src.loop = (value === 1 /* AL_TRUE */);
break;
case 0x1009 /* AL_BUFFER */:
+ var buffer = AL.currentContext.buf[value - 1];
if (value == 0) {
- AL.currentContext.src[source - 1].buffer = null;
+ src.queue = [];
+ } else {
+ src.queue = [{ buffer: buffer }];
+ }
+ _updateSource(src);
+ break;
+ case 0x202 /* AL_SOURCE_RELATIVE */:
+ if (value === 1 /* AL_TRUE */) {
+ if (src.panner) {
+ src.panner = null;
+
+ // Disconnect from the panner.
+ src.gain.disconnect();
+
+ src.gain.connect(AL.currentContext.ctx.destination);
+ }
+ } else if (value === 0 /* AL_FALSE */) {
+ if (!src.panner) {
+ var panner = src.panner = AL.currentContext.ctx.createPanner();
+ panner.panningModel = "equalpower";
+ panner.distanceModel = "linear";
+ panner.refDistance = src.refDistance;
+ panner.maxDistance = src.maxDistance;
+ panner.rolloffFactor = src.rolloffFactor;
+ panner.setPosition(src.position[0], src.position[1], src.position[2]);
+ panner.setVelocity(src.velocity[0], src.velocity[1], src.velocity[2]);
+ panner.connect(AL.currentContext.ctx.destination);
+
+ // Disconnect from the default source.
+ src.gain.disconnect();
+
+ src.gain.connect(panner);
+ }
} else {
- AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[value - 1].buf;
+ AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */;
}
break;
default:
#if OPENAL_DEBUG
console.log("alSourcei with param " + param + " not implemented yet");
#endif
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
@@ -176,130 +383,168 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alSourcef called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
console.error("alSourcef called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
switch (param) {
- case 0x100A /* AL_GAIN */:
- if (AL.currentContext.src[source - 1]) {
- AL.currentContext.src[source - 1].gain.gain.value = value;
- }
- break;
case 0x1003 /* AL_PITCH */:
#if OPENAL_DEBUG
- console.log("alSourcef was called with AL_PITCH, but Web Audio does not support static pitch changes");
+ console.log("alSourcef was called with 0x1003 /* AL_PITCH */, but Web Audio does not support static pitch changes");
#endif
break;
+ case 0x100A /* AL_GAIN */:
+ src.gain.gain.value = value;
+ break;
+ // case 0x100D /* AL_MIN_GAIN */:
+ // break;
+ // case 0x100E /* AL_MAX_GAIN */:
+ // break;
+ case 0x1023 /* AL_MAX_DISTANCE */:
+ src.maxDistance = value;
+ break;
+ case 0x1021 /* AL_ROLLOFF_FACTOR */:
+ src.rolloffFactor = value;
+ break;
+ // case 0x1022 /* AL_CONE_OUTER_GAIN */:
+ // break;
+ // case 0x1001 /* AL_CONE_INNER_ANGLE */:
+ // break;
+ // case 0x1002 /* AL_CONE_OUTER_ANGLE */:
+ // break;
+ case 0x1020 /* AL_REFERENCE_DISTANCE */:
+ src.refDistance = value;
+ break;
default:
#if OPENAL_DEBUG
console.log("alSourcef with param " + param + " not implemented yet");
#endif
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
- alSourcefv: function(source, param, value) {
+ alSource3f: function(source, param, v1, v2, v3) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
- console.error("alSourcefv called without a valid context");
+ console.error("alSource3f called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
- console.error("alSourcefv called with an invalid source");
+ console.error("alSource3f called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
switch (param) {
case 0x1004 /* AL_POSITION */:
- AL.currentContext.src[source - 1].panner.setPosition(
- {{{ makeGetValue('value', '0', 'float') }}},
- {{{ makeGetValue('value', '4', 'float') }}},
- {{{ makeGetValue('value', '8', 'float') }}}
- );
+ src.position = [v1, v2, v3];
break;
case 0x1006 /* AL_VELOCITY */:
- AL.currentContext.src[source - 1].panner.setVelocity(
- {{{ makeGetValue('value', '0', 'float') }}},
- {{{ makeGetValue('value', '4', 'float') }}},
- {{{ makeGetValue('value', '8', 'float') }}}
- );
+ src.velocity = [v1, v2, v3];
break;
default:
#if OPENAL_DEBUG
- console.log("alSourcefv with param " + param + " not implemented yet");
+ console.log("alSource3f with param " + param + " not implemented yet");
#endif
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
+ alSourcefv__deps: ['alSource3f'],
+ alSourcefv: function(source, param, value) {
+ _alSource3f(source, param,
+ {{{ makeGetValue('value', '0', 'float') }}},
+ {{{ makeGetValue('value', '4', 'float') }}},
+ {{{ makeGetValue('value', '8', 'float') }}});
+ },
+
+ alSourceQueueBuffers__deps: ["updateSource"],
alSourceQueueBuffers: function(source, count, buffers) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourceQueueBuffers called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
console.error("alSourceQueueBuffers called with an invalid source");
#endif
- return;
- }
- if (count != 1) {
-#if OPENAL_DEBUG
- console.error("Queuing multiple buffers using alSourceQueueBuffers is not supported yet");
-#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
for (var i = 0; i < count; ++i) {
- var buffer = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
- if (buffer > AL.currentContext.buf.length) {
+ var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
+ if (bufferIdx > AL.currentContext.buf.length) {
#if OPENAL_DEBUG
console.error("alSourceQueueBuffers called with an invalid buffer");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[buffer - 1].buf;
}
+
+ for (var i = 0; i < count; ++i) {
+ var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
+ var buffer = AL.currentContext.buf[bufferIdx - 1];
+ src.queue.push({ buffer: buffer, src: null });
+ }
+
+ _updateSource(src);
},
- alSourceUnqueueBuffers: function(source, count, buffers)
- {
+ alSourceUnqueueBuffers__deps: ["updateSource"],
+ alSourceUnqueueBuffers: function(source, count, buffers) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourceUnqueueBuffers called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
console.error("alSourceUnqueueBuffers called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- if (count != 1) {
-#if OPENAL_DEBUG
- console.error("Queuing multiple buffers using alSourceUnqueueBuffers is not supported yet");
-#endif
+
+ if (count > src.buffersPlayed) {
+ AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */;
return;
}
- for (var i = 0; i < count; ++i) {
- var buffer = AL.currentContext.src[source - 1].buffer;
- for (var j = 0; j < AL.currentContext.buf.length; ++j) {
- if (buffer == AL.currentContext.buf[j].buf) {
+
+ for (var i = 0; i < count; i++) {
+ var entry = src.queue.shift();
+ // Write the buffers index out to the return list.
+ for (var j = 0; j < AL.currentContext.buf.length; j++) {
+ var b = AL.currentContext.buf[j];
+ if (b && b == entry.buffer) {
{{{ makeSetValue('buffers', 'i*4', 'j+1', 'i32') }}};
- AL.currentContext.src[source - 1].buffer = null;
break;
}
}
+ src.buffersPlayed--;
}
+
+ _updateSource(src);
},
alDeleteBuffers: function(count, buffers)
@@ -308,21 +553,43 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alDeleteBuffers called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
+ return;
+ }
+ if (count > AL.currentContext.buf.length) {
+ AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */;
return;
}
+
for (var i = 0; i < count; ++i) {
var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1;
- if (bufferIdx < AL.currentContext.buf.length && AL.currentContext.buf[bufferIdx]) {
- var buffer = AL.currentContext.buf[bufferIdx].buf;
- for (var j = 0; j < AL.currentContext.src.length; ++j) {
- if (buffer == AL.currentContext.src[j].buffer) {
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
+
+ // Make sure the buffer index is valid.
+ if (bufferIdx >= AL.currentContext.buf.length || !AL.currentContext.buf[bufferIdx]) {
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
+ return;
+ }
+
+ // Make sure the buffer is no longer in use.
+ var buffer = AL.currentContext.buf[bufferIdx];
+ for (var j = 0; j < AL.currentContext.src.length; ++j) {
+ var src = AL.currentContext.src[j];
+ if (!src) {
+ continue;
+ }
+ for (var k = 0; k < src.queue.length; k++) {
+ if (buffer === src.queue[k].buffer) {
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
}
- delete AL.currentContext.buf[bufferIdx];
}
}
+
+ for (var i = 0; i < count; ++i) {
+ var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1;
+ delete AL.currentContext.buf[bufferIdx];
+ }
},
alGenBuffers: function(count, buffers) {
@@ -330,10 +597,11 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alGenBuffers called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
- AL.currentContext.buf.push({buf: null});
+ AL.currentContext.buf.push(null);
{{{ makeSetValue('buffers', 'i*4', 'AL.currentContext.buf.length', 'i32') }}};
}
},
@@ -343,6 +611,7 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alBufferData called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
if (buffer > AL.currentContext.buf.length) {
@@ -375,16 +644,21 @@ var LibraryOpenAL = {
#endif
return;
}
- AL.currentContext.buf[buffer - 1].buf = AL.currentContext.ctx.createBuffer(channels, size / (bytes * channels), freq);
+ try {
+ AL.currentContext.buf[buffer - 1] = AL.currentContext.ctx.createBuffer(channels, size / (bytes * channels), freq);
+ } catch (e) {
+ AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */;
+ return;
+ }
var buf = new Array(channels);
for (var i = 0; i < channels; ++i) {
- buf[i] = AL.currentContext.buf[buffer - 1].buf.getChannelData(i);
+ buf[i] = AL.currentContext.buf[buffer - 1].getChannelData(i);
}
for (var i = 0; i < size / (bytes * channels); ++i) {
for (var j = 0; j < channels; ++j) {
switch (bytes) {
case 1:
- var val = {{{ makeGetValue('data', 'i*channels+j', 'i8') }}};
+ var val = {{{ makeGetValue('data', 'i*channels+j', 'i8') }}} & 0xff; // unsigned
buf[j][i] = -1.0 + val * (2/256);
break;
case 2:
@@ -396,110 +670,105 @@ var LibraryOpenAL = {
}
},
- alSourcePlay__deps: ["alSourceStop"],
+ alSourcePlay__deps: ['setSourceState'],
alSourcePlay: function(source) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourcePlay called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
console.error("alSourcePlay called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- var offset = 0;
- if ("src" in AL.currentContext.src[source - 1] &&
- AL.currentContext.src[source - 1]["src"].buffer ==
- AL.currentContext.src[source - 1].buffer) {
- if (AL.currentContext.src[source - 1].paused) {
- // So now we have to resume playback, remember the offset here.
- offset = AL.currentContext.src[source - 1].pausedTime -
- AL.currentContext.src[source - 1].playTime;
- } else {
- // If the source is already playing, we need to resume from beginning.
- // We do that by stopping the current source and replaying it.
- _alSourceStop(source);
- }
- }
- var src = AL.currentContext.ctx.createBufferSource();
- src.loop = AL.currentContext.src[source - 1].loop;
- src.buffer = AL.currentContext.src[source - 1].buffer;
- src.connect(AL.currentContext.src[source - 1].gain);
- src.start(0, offset);
- AL.currentContext.src[source - 1].playTime = AL.currentContext.ctx.currentTime;
- AL.currentContext.src[source - 1].paused = false;
- AL.currentContext.src[source - 1]['src'] = src;
+ _setSourceState(src, 0x1012 /* AL_PLAYING */);
},
+ alSourceStop__deps: ['setSourceState'],
alSourceStop: function(source) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourceStop called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
console.error("alSourceStop called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- if (AL.currentContext.src[source - 1] && "src" in AL.currentContext.src[source - 1]) {
- AL.currentContext.src[source - 1]["src"].stop(0);
- delete AL.currentContext.src[source - 1]["src"];
- }
+ _setSourceState(src, 0x1014 /* AL_STOPPED */);
},
+ alSourcePause__deps: ['setSourceState'],
alSourcePause: function(source) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourcePause called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
console.error("alSourcePause called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- if ("src" in AL.currentContext.src[source - 1] &&
- !AL.currentContext.src[source - 1].paused) {
- AL.currentContext.src[source - 1].paused = true;
- AL.currentContext.src[source - 1].pausedTime = AL.currentContext.ctx.currentTime;
- AL.currentContext.src[source - 1]["src"].stop(0);
- delete AL.currentContext.src[source - 1].src;
- }
+ _setSourceState(src, 0x1013 /* AL_PAUSED */);
},
+ alGetSourcei__deps: ['updateSource'],
alGetSourcei: function(source, param, value) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alGetSourcei called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
#if OPENAL_DEBUG
console.error("alGetSourcei called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
+
+ // Being that we have no way to receive end events from buffer nodes,
+ // we currently proccess and update a source's buffer queue every
+ // ~QUEUE_INTERVAL milliseconds. However, this interval is not precise,
+ // so we also forcefully update the source when alGetSourcei is queried
+ // to aid in the common scenario of application calling alGetSourcei(AL_BUFFERS_PROCESSED)
+ // to recycle buffers.
+ _updateSource(src);
+
switch (param) {
case 0x202 /* AL_SOURCE_RELATIVE */:
- // Always return 1
- {{{ makeSetValue('value', '0', '1', 'i32') }}};
+ {{{ makeSetValue('value', '0', 'src.panner ? 1 : 0', 'i32') }}};
break;
case 0x1009 /* AL_BUFFER */:
- if (AL.currentContext.src[source - 1].buffer == null) {
+ if (!src.queue.length) {
{{{ makeSetValue('value', '0', '0', 'i32') }}};
} else {
- var buf = AL.currentContext.src[source - 1].buffer;
+ // Find the first unprocessed buffer.
+ var buffer = src.queue[src.buffersPlayed].buffer;
+ // Return its index.
for (var i = 0; i < AL.currentContext.buf.length; ++i) {
- if (buf == AL.currentContext.buf[i].buf) {
+ if (buffer == AL.currentContext.buf[i]) {
{{{ makeSetValue('value', '0', 'i+1', 'i32') }}};
return;
}
@@ -508,32 +777,79 @@ var LibraryOpenAL = {
}
break;
case 0x1010 /* AL_SOURCE_STATE */:
- if ("src" in AL.currentContext.src[source - 1]) {
- {{{ makeSetValue('value', '0', '0x1012', 'i32') }}} /* AL_PLAYING */;
- } else if (AL.currentContext.src[source - 1].paused) {
- {{{ makeSetValue('value', '0', '0x1013', 'i32') }}} /* AL_PAUSED */;
- } else if (AL.currentContext.src[source - 1].playTime == -1) {
- {{{ makeSetValue('value', '0', '0x1011', 'i32') }}} /* AL_INITIAL */;
- } else {
- {{{ makeSetValue('value', '0', '0x1014', 'i32') }}} /* AL_STOPPED */;
- }
+ {{{ makeSetValue('value', '0', 'src.state', 'i32') }}};
break;
case 0x1015 /* AL_BUFFERS_QUEUED */:
- if (AL.currentContext.src[source - 1].buffer) {
- {{{ makeSetValue('value', '0', '1', 'i32') }}}
- } else {
+ {{{ makeSetValue('value', '0', 'src.queue.length', 'i32') }}}
+ break;
+ case 0x1016 /* AL_BUFFERS_PROCESSED */:
+ if (src.loop) {
{{{ makeSetValue('value', '0', '0', 'i32') }}}
+ } else {
+ {{{ makeSetValue('value', '0', 'src.buffersPlayed', 'i32') }}}
}
break;
- case 0x1016 /* AL_BUFFERS_PROCESSED */:
- // Always return 1
- {{{ makeSetValue('value', '0', '1', 'i32') }}}
+ default:
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
+ break;
+ }
+ },
+
+ alGetSourcef: function(source, param, value) {
+ if (!AL.currentContext) {
+#if OPENAL_DEBUG
+ console.error("alGetSourcef called without a valid context");
+#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
+ return;
+ }
+ var src = AL.currentContext.src[source - 1];
+ if (!src) {
+#if OPENAL_DEBUG
+ console.error("alGetSourcef called with an invalid source");
+#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
+ return;
+ }
+ switch (param) {
+ // case 0x1003 /* AL_PITCH */:
+ // break;
+ case 0x100A /* AL_GAIN */:
+ {{{ makeSetValue('value', '0', 'src.gain.gain.value', 'float') }}}
+ break;
+ // case 0x100D /* AL_MIN_GAIN */:
+ // break;
+ // case 0x100E /* AL_MAX_GAIN */:
+ // break;
+ case 0x1023 /* AL_MAX_DISTANCE */:
+ {{{ makeSetValue('value', '0', 'src.maxDistance', 'float') }}}
+ break;
+ case 0x1021 /* AL_ROLLOFF_FACTOR */:
+ {{{ makeSetValue('value', '0', 'src.rolloffFactor', 'float') }}}
+ break;
+ // case 0x1022 /* AL_CONE_OUTER_GAIN */:
+ // break;
+ // case 0x1001 /* AL_CONE_INNER_ANGLE */:
+ // break;
+ // case 0x1002 /* AL_CONE_OUTER_ANGLE */:
+ // break;
+ case 0x1020 /* AL_REFERENCE_DISTANCE */:
+ {{{ makeSetValue('value', '0', 'src.refDistance', 'float') }}}
+ break;
+ // case 0x1024 /* AL_SEC_OFFSET */:
+ // break;
+ // case 0x1025 /* AL_SAMPLE_OFFSET */:
+ // break;
+ // case 0x1026 /* AL_BYTE_OFFSET */:
+ // break;
+ default:
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
alDistanceModel: function(model) {
- if (model != 0 /* AL_NONE */) {
+ if (model !== 0 /* AL_NONE */) {
#if OPENAL_DEBUG
console.log("Only alDistanceModel(AL_NONE) is currently supported");
#endif
@@ -545,6 +861,7 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alListenerfv called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
switch (param) {
@@ -576,6 +893,7 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.log("alListenerfv with param " + param + " not implemented yet");
#endif
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
@@ -588,13 +906,27 @@ var LibraryOpenAL = {
return 0;
},
+ alGetString: function (param) {
+ return allocate(intArrayFromString('NA'), 'i8', ALLOC_NORMAL);
+ },
+
alGetProcAddress: function(fname) {
return 0;
},
+ alcGetString: function (param) {
+ return allocate(intArrayFromString('NA'), 'i8', ALLOC_NORMAL);
+ },
+
alcGetProcAddress: function(device, fname) {
return 0;
},
+
+ alDopplerFactor: function(value) {
+ },
+
+ alDopplerVelocity: function(value) {
+ }
};
autoAddDeps(LibraryOpenAL, '$AL');
diff --git a/src/library_path.js b/src/library_path.js
new file mode 100644
index 00000000..feec1e68
--- /dev/null
+++ b/src/library_path.js
@@ -0,0 +1,134 @@
+mergeInto(LibraryManager.library, {
+ $PATH__deps: ['$FS'],
+ $PATH: {
+ // split a filename into [root, dir, basename, ext], unix version
+ // 'root' is just a slash, or nothing.
+ splitPath: function (filename) {
+ var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+ return splitPathRe.exec(filename).slice(1);
+ },
+ normalizeArray: function (parts, allowAboveRoot) {
+ // if the path tries to go above the root, `up` ends up > 0
+ var up = 0;
+ for (var i = parts.length - 1; i >= 0; i--) {
+ var last = parts[i];
+ if (last === '.') {
+ parts.splice(i, 1);
+ } else if (last === '..') {
+ parts.splice(i, 1);
+ up++;
+ } else if (up) {
+ parts.splice(i, 1);
+ up--;
+ }
+ }
+ // if the path is allowed to go above the root, restore leading ..s
+ if (allowAboveRoot) {
+ for (; up--; up) {
+ parts.unshift('..');
+ }
+ }
+ return parts;
+ },
+ normalize: function (path) {
+ var isAbsolute = path.charAt(0) === '/',
+ trailingSlash = path.substr(-1) === '/';
+ // Normalize the path
+ path = PATH.normalizeArray(path.split('/').filter(function(p) {
+ return !!p;
+ }), !isAbsolute).join('/');
+ if (!path && !isAbsolute) {
+ path = '.';
+ }
+ if (path && trailingSlash) {
+ path += '/';
+ }
+ return (isAbsolute ? '/' : '') + path;
+ },
+ dirname: function (path) {
+ var result = PATH.splitPath(path),
+ root = result[0],
+ dir = result[1];
+ if (!root && !dir) {
+ // No dirname whatsoever
+ return '.';
+ }
+ if (dir) {
+ // It has a dirname, strip trailing slash
+ dir = dir.substr(0, dir.length - 1);
+ }
+ return root + dir;
+ },
+ basename: function (path, ext) {
+ // EMSCRIPTEN return '/'' for '/', not an empty string
+ if (path === '/') return '/';
+ var f = PATH.splitPath(path)[2];
+ if (ext && f.substr(-1 * ext.length) === ext) {
+ f = f.substr(0, f.length - ext.length);
+ }
+ return f;
+ },
+ join: function () {
+ var paths = Array.prototype.slice.call(arguments, 0);
+ return PATH.normalize(paths.filter(function(p, index) {
+ if (typeof p !== 'string') {
+ throw new TypeError('Arguments to path.join must be strings');
+ }
+ return p;
+ }).join('/'));
+ },
+ resolve: function () {
+ var resolvedPath = '',
+ resolvedAbsolute = false;
+ for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+ var path = (i >= 0) ? arguments[i] : FS.cwd();
+ // Skip empty and invalid entries
+ if (typeof path !== 'string') {
+ throw new TypeError('Arguments to path.resolve must be strings');
+ } else if (!path) {
+ continue;
+ }
+ resolvedPath = path + '/' + resolvedPath;
+ resolvedAbsolute = path.charAt(0) === '/';
+ }
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when process.cwd() fails)
+ resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+ return !!p;
+ }), !resolvedAbsolute).join('/');
+ return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+ },
+ relative: function(from, to) {
+ from = PATH.resolve(from).substr(1);
+ to = PATH.resolve(to).substr(1);
+ function trim(arr) {
+ var start = 0;
+ for (; start < arr.length; start++) {
+ if (arr[start] !== '') break;
+ }
+ var end = arr.length - 1;
+ for (; end >= 0; end--) {
+ if (arr[end] !== '') break;
+ }
+ if (start > end) return [];
+ return arr.slice(start, end - start + 1);
+ }
+ var fromParts = trim(from.split('/'));
+ var toParts = trim(to.split('/'));
+ var length = Math.min(fromParts.length, toParts.length);
+ var samePartsLength = length;
+ for (var i = 0; i < length; i++) {
+ if (fromParts[i] !== toParts[i]) {
+ samePartsLength = i;
+ break;
+ }
+ }
+ var outputParts = [];
+ for (var i = samePartsLength; i < fromParts.length; i++) {
+ outputParts.push('..');
+ }
+ outputParts = outputParts.concat(toParts.slice(samePartsLength));
+ return outputParts.join('/');
+ }
+ }
+}); \ No newline at end of file
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 4477e457..80c7ac07 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -1238,61 +1238,133 @@ var LibrarySDL = {
return flags; // We support JPG, PNG, TIF because browsers do
},
- IMG_Load_RW__deps: ['SDL_LockSurface'],
- IMG_Load_RW: function(rwopsID, freesrc) {
- var rwops = SDL.rwops[rwopsID];
+ IMG_Load_RW__deps: ['SDL_LockSurface', 'SDL_FreeRW'],
+ IMG_Load_RW: function(rwopsID, freeSrc) {
+ try {
+ // stb_image integration support
+ var cleanup = function() {
+ if (rwops && freeSrc) _SDL_FreeRW(rwopsID);
+ };
+ function addCleanup(func) {
+ var old = cleanup;
+ cleanup = function() {
+ old();
+ func();
+ }
+ }
+ function callStbImage(func, params) {
+ var x = Module['_malloc']({{{ QUANTUM_SIZE }}});
+ var y = Module['_malloc']({{{ QUANTUM_SIZE }}});
+ var comp = Module['_malloc']({{{ QUANTUM_SIZE }}});
+ addCleanup(function() {
+ Module['_free'](x);
+ Module['_free'](y);
+ Module['_free'](comp);
+ if (data) Module['_stbi_image_free'](data);
+ });
+ var data = Module['_' + func].apply(null, params.concat([x, y, comp, 0]));
+ if (!data) return null;
+ return {
+ rawData: true,
+ data: data,
+ width: {{{ makeGetValue('x', 0, 'i32') }}},
+ height: {{{ makeGetValue('y', 0, 'i32') }}},
+ size: {{{ makeGetValue('x', 0, 'i32') }}} * {{{ makeGetValue('y', 0, 'i32') }}} * {{{ makeGetValue('comp', 0, 'i32') }}},
+ bpp: {{{ makeGetValue('comp', 0, 'i32') }}}
+ };
+ }
- if (rwops === undefined) {
- return 0;
- }
+ var rwops = SDL.rwops[rwopsID];
+ if (rwops === undefined) {
+ return 0;
+ }
- var filename = rwops.filename;
-
- if (filename === undefined) {
- Runtime.warnOnce('Only file names that have been preloaded are supported for IMG_Load_RW.');
- // TODO. Support loading image data from embedded files, similarly to Mix_LoadWAV_RW
- // TODO. Support loading image data from byte arrays, similarly to Mix_LoadWAV_RW
- return 0;
- }
-
- filename = FS.standardizePath(filename);
- if (filename[0] == '/') {
- // Convert the path to relative
- filename = filename.substr(1);
- }
- var raw = Module["preloadedImages"][filename];
- if (!raw) {
- if (raw === null) Module.printErr('Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!');
- Runtime.warnOnce('Cannot find preloaded image ' + filename);
- return 0;
- }
- if (Module['freePreloadedMediaOnUse']) {
- Module["preloadedImages"][filename] = null;
- }
- var surf = SDL.makeSurface(raw.width, raw.height, 0, false, 'load:' + filename);
- var surfData = SDL.surfaces[surf];
- surfData.ctx.globalCompositeOperation = "copy";
- surfData.ctx.drawImage(raw, 0, 0, raw.width, raw.height, 0, 0, raw.width, raw.height);
- surfData.ctx.globalCompositeOperation = "source-over";
- // XXX SDL does not specify that loaded images must have available pixel data, in fact
- // there are cases where you just want to blit them, so you just need the hardware
- // accelerated version. However, code everywhere seems to assume that the pixels
- // are in fact available, so we retrieve it here. This does add overhead though.
- _SDL_LockSurface(surf);
- surfData.locked--; // The surface is not actually locked in this hack
- if (SDL.GL) {
- // After getting the pixel data, we can free the canvas and context if we do not need to do 2D canvas blitting
- surfData.canvas = surfData.ctx = null;
+ var filename = rwops.filename;
+ if (filename === undefined) {
+#if STB_IMAGE
+ var raw = callStbImage('stbi_load_from_memory', [rwops.bytes, rwops.count]);
+ if (!raw) return 0;
+#else
+ Runtime.warnOnce('Only file names that have been preloaded are supported for IMG_Load_RW. Consider using STB_IMAGE=1 if you want synchronous image decoding (see settings.js)');
+ return 0;
+#endif
+ }
+
+ if (!raw) {
+ filename = FS.standardizePath(filename);
+ if (filename[0] == '/') {
+ // Convert the path to relative
+ filename = filename.substr(1);
+ }
+ var raw = Module["preloadedImages"][filename];
+ if (!raw) {
+ if (raw === null) Module.printErr('Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!');
+#if STB_IMAGE
+ var name = Module['_malloc'](filename.length+1);
+ writeStringToMemory(filename, name);
+ addCleanup(function() {
+ Module['_free'](name);
+ });
+ var raw = callStbImage('stbi_load', [name]);
+ if (!raw) return 0;
+#else
+ Runtime.warnOnce('Cannot find preloaded image ' + filename);
+ Runtime.warnOnce('Cannot find preloaded image ' + filename + '. Consider using STB_IMAGE=1 if you want synchronous image decoding (see settings.js)');
+ return 0;
+#endif
+ } else if (Module['freePreloadedMediaOnUse']) {
+ Module["preloadedImages"][filename] = null;
+ }
+ }
+
+ var surf = SDL.makeSurface(raw.width, raw.height, 0, false, 'load:' + filename);
+ var surfData = SDL.surfaces[surf];
+ surfData.ctx.globalCompositeOperation = "copy";
+ if (!raw.rawData) {
+ surfData.ctx.drawImage(raw, 0, 0, raw.width, raw.height, 0, 0, raw.width, raw.height);
+ } else {
+ var imageData = surfData.ctx.getImageData(0, 0, surfData.width, surfData.height);
+ if (raw.bpp == 4) {
+ imageData.data.set({{{ makeHEAPView('U8', 'raw.data', 'raw.data+raw.size') }}});
+ } else if (raw.bpp == 3) {
+ var pixels = raw.size/3;
+ var data = imageData.data;
+ var sourcePtr = raw.data;
+ var destPtr = 0;
+ for (var i = 0; i < pixels; i++) {
+ data[destPtr++] = {{{ makeGetValue('sourcePtr++', 0, 'i8', null, 1) }}};
+ data[destPtr++] = {{{ makeGetValue('sourcePtr++', 0, 'i8', null, 1) }}};
+ data[destPtr++] = {{{ makeGetValue('sourcePtr++', 0, 'i8', null, 1) }}};
+ data[destPtr++] = 255;
+ }
+ } else {
+ Module.printErr('cannot handle bpp ' + raw.bpp);
+ return 0;
+ }
+ surfData.ctx.putImageData(imageData, 0, 0);
+ }
+ surfData.ctx.globalCompositeOperation = "source-over";
+ // XXX SDL does not specify that loaded images must have available pixel data, in fact
+ // there are cases where you just want to blit them, so you just need the hardware
+ // accelerated version. However, code everywhere seems to assume that the pixels
+ // are in fact available, so we retrieve it here. This does add overhead though.
+ _SDL_LockSurface(surf);
+ surfData.locked--; // The surface is not actually locked in this hack
+ if (SDL.GL) {
+ // After getting the pixel data, we can free the canvas and context if we do not need to do 2D canvas blitting
+ surfData.canvas = surfData.ctx = null;
+ }
+ return surf;
+ } finally {
+ cleanup();
}
- return surf;
},
SDL_LoadBMP: 'IMG_Load',
SDL_LoadBMP_RW: 'IMG_Load_RW',
- IMG_Load__deps: ['IMG_Load_RW', 'SDL_RWFromFile', 'SDL_FreeRW'],
+ IMG_Load__deps: ['IMG_Load_RW', 'SDL_RWFromFile'],
IMG_Load: function(filename){
var rwops = _SDL_RWFromFile(filename);
- var result = _IMG_Load_RW(rwops);
- _SDL_FreeRW(rwops);
+ var result = _IMG_Load_RW(rwops, 1);
return result;
},
@@ -2055,11 +2127,13 @@ var LibrarySDL = {
// Misc
SDL_InitSubSystem: function(flags) { return 0 },
+
SDL_RWFromConstMem: function(mem, size) {
var id = SDL.rwops.length; // TODO: recycle ids when they are null
SDL.rwops.push({ bytes: mem, count: size });
return id;
},
+ SDL_RWFromMem: 'SDL_RWFromConstMem',
SDL_RWFromFile: function(_name, mode) {
var id = SDL.rwops.length; // TODO: recycle ids when they are null
diff --git a/src/modules.js b/src/modules.js
index 9f419234..f85e7d0e 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -422,7 +422,7 @@ var LibraryManager = {
load: function() {
if (this.library) return;
- var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries);
+ var libraries = ['library.js', 'library_path.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries);
for (var i = 0; i < libraries.length; i++) {
eval(processMacros(preprocess(read(libraries[i]))));
}
diff --git a/src/postamble.js b/src/postamble.js
index 49fd9b3e..25a50bfc 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -1,9 +1,12 @@
// === Auto-generated postamble setup entry stuff ===
-Module['callMain'] = function callMain(args) {
+var initialStackTop;
+var inMain;
+
+Module['callMain'] = Module.callMain = function callMain(args) {
assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
- assert(!Module['preRun'] || Module['preRun'].length == 0, 'cannot call main when preRun functions remain to be called');
+ assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
args = args || [];
@@ -28,29 +31,37 @@ Module['callMain'] = function callMain(args) {
var start = Date.now();
#endif
- var ret;
+ initialStackTop = STACKTOP;
+ inMain = true;
- var initialStackTop = STACKTOP;
+ var ret;
try {
ret = Module['_main'](argc, argv, 0);
}
catch(e) {
- if (e.name == 'ExitStatus') {
- return e.status;
+ if (e && typeof e == 'object' && e.type == 'ExitStatus') {
+ // exit() throws this once it's done to make sure execution
+ // has been stopped completely
+ Module.print('Exit Status: ' + e.value);
+ return e.value;
} else if (e == 'SimulateInfiniteLoop') {
+ // running an evented main loop, don't immediately exit
Module['noExitRuntime'] = true;
} else {
throw e;
}
} finally {
- STACKTOP = initialStackTop;
+ inMain = false;
}
#if BENCHMARK
Module.realPrint('main() took ' + (Date.now() - start) + ' milliseconds');
#endif
- return ret;
+ // if we're not running an evented main loop, it's time to exit
+ if (!Module['noExitRuntime']) {
+ exit(ret);
+ }
}
{{GLOBAL_VARS}}
@@ -60,20 +71,14 @@ function run(args) {
if (runDependencies > 0) {
Module.printErr('run() called, but dependencies remain, so not running');
- return 0;
+ return;
}
- if (Module['preRun']) {
- if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
- var toRun = Module['preRun'];
- Module['preRun'] = [];
- for (var i = toRun.length-1; i >= 0; i--) {
- toRun[i]();
- }
- if (runDependencies > 0) {
- // a preRun added a dependency, run will be called later
- return 0;
- }
+ preRun();
+
+ if (runDependencies > 0) {
+ // a preRun added a dependency, run will be called later
+ return;
}
function doRun() {
@@ -81,21 +86,12 @@ function run(args) {
preMain();
- var ret = 0;
calledRun = true;
if (Module['_main'] && shouldRunNow) {
- ret = Module['callMain'](args);
- if (!Module['noExitRuntime']) {
- exitRuntime();
- }
- }
- if (Module['postRun']) {
- if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
- while (Module['postRun'].length > 0) {
- Module['postRun'].pop()();
- }
+ Module['callMain'](args);
}
- return ret;
+
+ postRun();
}
if (Module['setStatus']) {
@@ -106,13 +102,43 @@ function run(args) {
}, 1);
if (!ABORT) doRun();
}, 1);
- return 0;
} else {
- return doRun();
+ doRun();
}
}
Module['run'] = Module.run = run;
+function exit(status) {
+ ABORT = true;
+ STACKTOP = initialStackTop;
+
+ // TODO call externally added 'exit' callbacks with the status code.
+ // It'd be nice to provide the same interface for all Module events (e.g.
+ // prerun, premain, postmain). Perhaps an EventEmitter so we can do:
+ // Module.on('exit', function (status) {});
+
+ // exit the runtime
+ exitRuntime();
+
+ if (inMain) {
+ // if we're still inside the callMain's try/catch, we need to throw an
+ // exception in order to immediately terminate execution.
+ throw { type: 'ExitStatus', value: status };
+ }
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+ if (text) {
+ Module.print(text);
+ }
+
+ ABORT = true;
+
+ throw 'abort() at ' + (new Error().stack);
+}
+Module['abort'] = Module.abort = abort;
+
// {{PRE_RUN_ADDITIONS}}
if (Module['preInit']) {
diff --git a/src/preamble.js b/src/preamble.js
index 218e0388..2955c885 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -242,12 +242,6 @@ var tempI64, tempI64b;
var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
#endif
-function abort(text) {
- Module.print(text + ':\n' + (new Error).stack);
- ABORT = true;
- throw "Assertion: " + text;
-}
-
function assert(condition, text) {
if (!condition) {
abort('Assertion failed: ' + text);
@@ -711,24 +705,75 @@ function callRuntimeCallbacks(callbacks) {
}
}
-var __ATINIT__ = []; // functions called during startup
-var __ATMAIN__ = []; // functions called when main() is to be run
-var __ATEXIT__ = []; // functions called during shutdown
+var __ATPRERUN__ = []; // functions called before the runtime is initialized
+var __ATINIT__ = []; // functions called during startup
+var __ATMAIN__ = []; // functions called when main() is to be run
+var __ATEXIT__ = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
var runtimeInitialized = false;
+function preRun() {
+ // compatibility - merge in anything from Module['preRun'] at this time
+ if (Module['preRun']) {
+ if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+ while (Module['preRun'].length) {
+ addOnPreRun(Module['preRun'].shift());
+ }
+ }
+ callRuntimeCallbacks(__ATPRERUN__);
+}
+
function ensureInitRuntime() {
if (runtimeInitialized) return;
runtimeInitialized = true;
callRuntimeCallbacks(__ATINIT__);
}
+
function preMain() {
callRuntimeCallbacks(__ATMAIN__);
}
+
function exitRuntime() {
callRuntimeCallbacks(__ATEXIT__);
}
+function postRun() {
+ // compatibility - merge in anything from Module['postRun'] at this time
+ if (Module['postRun']) {
+ if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+ while (Module['postRun'].length) {
+ addOnPostRun(Module['postRun'].shift());
+ }
+ }
+ callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+ __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+ __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+ __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+ __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+ __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
// Tools
// This processes a JS string into a C-line array of numbers, 0-terminated.
@@ -865,12 +910,6 @@ Module['removeRunDependency'] = removeRunDependency;
Module["preloadedImages"] = {}; // maps url to image data
Module["preloadedAudios"] = {}; // maps url to audio data
-function addPreRun(func) {
- if (!Module['preRun']) Module['preRun'] = [];
- else if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
- Module['preRun'].push(func);
-}
-
#if PGO
var PGOMonitor = {
called: {},
@@ -885,7 +924,7 @@ var PGOMonitor = {
};
Module['PGOMonitor'] = PGOMonitor;
__ATEXIT__.push({ func: function() { PGOMonitor.dump() } });
-addPreRun(function() { addRunDependency('pgo') });
+addOnPreRun(function() { addRunDependency('pgo') });
#endif
function loadMemoryInitializer(filename) {
@@ -898,7 +937,7 @@ function loadMemoryInitializer(filename) {
}
// always do this asynchronously, to keep shell and web as similar as possible
- addPreRun(function() {
+ addOnPreRun(function() {
if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
applyData(Module['readBinary'](filename));
} else {
diff --git a/src/settings.js b/src/settings.js
index 52e4eeb0..19108f3b 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -194,6 +194,12 @@ var FORCE_GL_EMULATION = 0; // Forces inclusion of full GL emulation code.
var DISABLE_GL_EMULATION = 0; // Disable inclusion of full GL emulation code. Useful when you don't want emulation
// but do need INCLUDE_FULL_LIBRARY or MAIN_MODULE.
+var STB_IMAGE = 0; // Enables building of stb-image, a tiny public-domain library for decoding images, allowing
+ // decoding of images without using the browser's built-in decoders. The benefit is that this
+ // can be done synchronously, however, it will not be as fast as the browser itself.
+ // When enabled, stb-image will be used automatically from IMG_Load and IMG_Load_RW. You
+ // can also call the stbi_* functions directly yourself.
+
var DISABLE_EXCEPTION_CATCHING = 0; // Disables generating code to actually catch exceptions. If the code you
// are compiling does not actually rely on catching exceptions (but the
// compiler generates code for it, maybe because of stdlibc++ stuff),
@@ -243,8 +249,6 @@ var FS_LOG = 0; // Log all FS operations. This is especially helpful when you'r
// a new project and want to see a list of file system operations happening
// so that you can create a virtual file system with all of the required files.
-var USE_OLD_FS = 1; // Switch to toggle the new / old FS code. Currently only used for testing purposes.
-
var USE_BSS = 1; // https://en.wikipedia.org/wiki/.bss
// When enabled, 0-initialized globals are sorted to the end of the globals list,
// enabling us to not explicitly store the initialization value for each 0 byte.
@@ -416,880 +420,908 @@ var DEBUG_TAGS_SHOWING = [];
// A cached set of defines, generated from the header files. This
// lets the emscripten libc (library.js) see the right values.
-// If you the headers or use different ones, you will need to override
-// this.
-var C_DEFINES = {'SI_MESGQ': '5',
- 'M_SQRTPI': '1.77245385091',
- '_NL_MESSAGES_CODESET': '86',
- 'SIGRTMIN': '27',
- 'math_errhandling': '1',
- 'M_LOG10E': '0.434294481903',
- '_S_IFMT': '0170000',
- '_CS_V7_ENV': '20',
- 'USHRT_MAX': '65535',
- '_SC_XOPEN_LEGACY': '98',
- 'HAVE_STDINT_H': '1',
- '_SC_XOPEN_VERSION': '106',
- 'F_UNLCK': '3',
- '_SC_BC_DIM_MAX': '58',
- 'SDL_LOADSO_DLOPEN': '1',
- 'S_IFDIR': '0040000',
- 'HAVE_ALLOCA': '1',
- '_SC_BARRIERS': '56',
- '_IFDIR': '0040000',
- 'SDL_JOYSTICK_DINPUT': '1',
- '_IFLNK': '0120000',
- '__long_double_t': "<type 'long'>",
- 'DEFFILEMODE': '0000400',
- 'HAVE_SSCANF': '1',
- '_FCREAT': '512',
- 'HAVE_STRTOLL': '1',
- 'SDL_VIDEO_OPENGL_ES': '1',
- 'O_CREAT': '512',
- 'SHRT_MAX': '32767',
- 'SDL_JOYSTICK_ANDROID': '1',
- '_SC_NPROCESSORS_CONF': '9',
- '_XOPEN_ENH_I18N': '1',
- 'F_DUPFD_CLOEXEC': '14',
- '_CS_POSIX_V6_LP64_OFF64_LIBS': '11',
- '_POSIX_SHARED_MEMORY_OBJECTS': '200112',
- 'ABDAY_7': '20',
- 'ABDAY_6': '19',
- 'ABDAY_5': '18',
- 'ABDAY_4': '17',
- 'ABDAY_3': '16',
- 'M_PI': '3.14159265359',
+// If you modify the headers or use different ones, you will need
+// to override this.
+var C_DEFINES = {
'ABDAY_1': '14',
- '_PC_REC_MIN_XFER_SIZE': '18',
- '_SC_V6_ILP32_OFFBIG': '93',
- 'SIGSTOP': '17',
- '_M_LN2': '0.69314718056',
- 'F_UNLKSYS': '4',
- 'PTHREAD_CREATE_JOINABLE': '1',
- 'SDL_VIDEO_OPENGL_GLX': '1',
- 'M_PI_2': '1.57079632679',
- '_SC_MEMLOCK': '24',
- 'M_PI_4': '0.785398163397',
+ 'ABDAY_2': '15',
+ 'ABDAY_3': '16',
+ 'ABDAY_4': '17',
+ 'ABDAY_5': '18',
+ 'ABDAY_6': '19',
+ 'ABDAY_7': '20',
+ 'ABMON_1': '33',
+ 'ABMON_10': '42',
+ 'ABMON_11': '43',
+ 'ABMON_12': '44',
+ 'ABMON_2': '34',
+ 'ABMON_3': '35',
+ 'ABMON_4': '36',
+ 'ABMON_5': '37',
+ 'ABMON_6': '38',
+ 'ABMON_7': '39',
+ 'ABMON_8': '40',
+ 'ABMON_9': '41',
+ 'ACCESSPERMS': '0000400',
+ 'AF_INET': '2',
+ 'AF_INET6': '6',
+ 'ALLPERMS': '0004000',
+ 'ALT_DIGITS': '49',
+ 'AM_STR': '5',
+ 'ARG_MAX': '4096',
+ 'AT_EACCESS': '1',
+ 'AT_FDCWD': '-2',
+ 'AT_REMOVEDIR': '8',
+ 'AT_SYMLINK_FOLLOW': '4',
+ 'AT_SYMLINK_NOFOLLOW': '2',
+ 'CHAR_BIT': '8',
+ 'CHAR_MAX': '127',
+ 'CHAR_MIN': '-128',
+ 'CLK_TCK': '1000',
+ 'CLOCKS_PER_SEC': '1000',
+ 'CLOCK_ALLOWED': '1',
+ 'CLOCK_DISABLED': '0',
+ 'CLOCK_DISALLOWED': '0',
+ 'CLOCK_ENABLED': '1',
+ 'CODESET': '0',
+ 'CRNCYSTR': '56',
+ 'DAY_1': '7',
+ 'DAY_2': '8',
+ 'DAY_3': '9',
+ 'DAY_4': '10',
+ 'DAY_5': '11',
+ 'DAY_6': '12',
+ 'DAY_7': '13',
+ 'DEFFILEMODE': '0000400',
+ 'DOMAIN': '1',
+ 'D_FMT': '2',
+ 'D_MD_ORDER': '57',
+ 'D_T_FMT': '1',
+ 'EOF': '-1',
+ 'ERA': '45',
+ 'ERA_D_FMT': '46',
+ 'ERA_D_T_FMT': '47',
+ 'ERA_T_FMT': '48',
+ 'FAPPEND': '8',
+ 'FASYNC': '64',
+ 'FCREAT': '512',
+ 'FDEFER': '32',
+ 'FD_CLOEXEC': '1',
+ 'FD_SETSIZE': '64',
+ 'FEXCL': '2048',
'FEXLOCK': '256',
- '_FNDELAY': '16384',
- 'SIGEV_NONE': '1',
- 'SIGWINCH': '28',
- 'UTIME_NOW': '-2',
- '_SC_THREADS': '42',
- '__INT_MAX__': '2147483647',
- '_XBS5_LP64_OFF64': '-1',
- '_CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS': '6',
- '___int_least32_t_defined': '1',
- '_POSIX_MAPPED_FILES': '200112',
- 'HAVE_FREE': '1',
- 'M_E': '2.71828182846',
- 'SIGTRAP': '5',
- '_SC_SS_REPL_MAX': '78',
- '_PC_SOCK_MAXBUF': '100',
- '_SC_THREAD_KEYS_MAX': '38',
- 'O_RDWR': '2',
- '__LARGE64_FILES': '1',
- '_POSIX_V6_LP64_OFF64': '-1',
- 'HAVE_COSF': '1',
- '_SC_2_PBS': '113',
+ 'FIONREAD': '1',
+ 'FLT_EVAL_METHOD': '0',
+ 'FMARK': '16',
+ 'FNBIO': '4096',
+ 'FNDELAY': '16384',
'FNOCTTY': '32768',
- '_SC_TRACE_INHERIT': '86',
- 'PTHREAD_PRIO_NONE': '0',
- '_SC_REGEXP': '72',
- '_CS_POSIX_V6_LP64_OFF64_CFLAGS': '9',
- '_SC_DELAYTIMER_MAX': '37',
- 'HAVE_SINF': '1',
- '_POSIX_RAW_SOCKETS': '200112',
- '___int64_t_defined': '1',
- 'S_IFREG': '0100000',
- 'SIGCLD': '20',
+ 'FNONBIO': '16384',
+ 'FOPEN': '-1',
+ 'FP_ILOGBNAN': '2147483647',
+ 'FP_INFINITE': '1',
+ 'FP_NAN': '0',
+ 'FP_NORMAL': '4',
+ 'FP_SUBNORMAL': '3',
+ 'FP_ZERO': '2',
+ 'FREAD': '1',
+ 'FSHLOCK': '128',
+ 'FSYNC': '8192',
+ 'FTRUNC': '1024',
+ 'FWRITE': '2',
+ 'F_CNVT': '12',
+ 'F_DUPFD': '0',
+ 'F_DUPFD_CLOEXEC': '14',
+ 'F_GETFD': '1',
+ 'F_GETFL': '3',
+ 'F_GETLK': '7',
'F_GETLK64': '20',
- '_IFCHR': '0020000',
- 'S_IRWXG': '0000040',
- 'SDL_VIDEO_DRIVER_ANDROID': '1',
- 'POLLHUP': '16',
- 'S_IFMT': '0170000',
- 'RADIXCHAR': '50',
- 'HAVE_UNSETENV': '1',
- '_S_IEXEC': '0000100',
- '_SC_XOPEN_CRYPT': '96',
- 'M_LN10': '2.30258509299',
- 'S_IRWXU': '0000400',
- 'OPTIONAL_ARG': '2',
- '_PC_CHOWN_RESTRICTED': '6',
- 'CRNCYSTR': '56',
- 'SIZEOF_VOIDP': '4',
- 'SCHAR_MAX': '127',
- 'S_BLKSIZE': '1024',
- 'SDL_JOYSTICK_NDS': '1',
- '_SC_CLK_TCK': '2',
- 'AM_STR': '5',
- '__BUFSIZ__': '16',
- 'ALT_DIGITS': '49',
- 'HAVE_SIGNAL_H': '1',
- 'HAVE_ATAN': '1',
- '_NL_CTYPE_MB_CUR_MAX': '85',
- '_REENT_SIGNAL_SIZE': '24',
- 'SDL_AUDIO_DRIVER_DSOUND': '1',
+ 'F_GETOWN': '5',
+ 'F_LOCK': '1',
+ 'F_OK': '0',
+ 'F_RDLCK': '1',
+ 'F_RGETLK': '10',
+ 'F_RSETLK': '11',
'F_RSETLKW': '13',
- 'HAVE_STRTOULL': '1',
- '___int16_t_defined': '1',
- 'SIGXCPU': '24',
- '_SC_MQ_PRIO_MAX': '14',
- '_FTRUNC': '1024',
- '__MACOSX__': '1',
- 'SDL_LOADSO_WINDOWS': '1',
- 'SDL_VIDEO_DRIVER_X11_XINERAMA': '1',
- 'MALLOC_ALIGNMENT': '16',
- 'PTHREAD_CREATE_DETACHED': '0',
- '_POSIX2_VERSION': '200112',
- '_O_CREAT': '512',
- 'PM_STR': '6',
- '_PC_POSIX_SECURITY': '91',
+ 'F_SETFD': '2',
+ 'F_SETFL': '4',
+ 'F_SETLK': '8',
+ 'F_SETLK64': '21',
+ 'F_SETLKW': '9',
+ 'F_SETLKW64': '22',
+ 'F_SETOWN': '6',
+ 'F_TEST': '3',
+ 'F_TLOCK': '2',
+ 'F_ULOCK': '0',
+ 'F_UNLCK': '3',
+ 'F_UNLKSYS': '4',
+ 'F_WRLCK': '2',
+ 'H8300': '1',
+ 'HAVE_ABS': '1',
+ 'HAVE_ALLOCA': '1',
+ 'HAVE_ALLOCA_H': '1',
+ 'HAVE_ATAN': '1',
+ 'HAVE_ATAN2': '1',
+ 'HAVE_ATOF': '1',
+ 'HAVE_ATOI': '1',
+ 'HAVE_BCOPY': '1',
+ 'HAVE_CALLOC': '1',
+ 'HAVE_CEIL': '1',
+ 'HAVE_COPYSIGN': '1',
+ 'HAVE_COS': '1',
+ 'HAVE_COSF': '1',
+ 'HAVE_CTYPE_H': '1',
+ 'HAVE_FABS': '1',
+ 'HAVE_FLOOR': '1',
+ 'HAVE_FREE': '1',
+ 'HAVE_GCC_ATOMICS': '1',
+ 'HAVE_GCC_SYNC_LOCK_TEST_AND_SET': '1',
+ 'HAVE_GETENV': '1',
+ 'HAVE_INDEX': '1',
'HAVE_INTTYPES_H': '1',
- '_SC_2_LOCALEDEF': '112',
- '_SC_STREAM_MAX': '100',
+ 'HAVE_ITOA': '1',
+ 'HAVE_LOG': '1',
+ 'HAVE_MALLOC': '1',
+ 'HAVE_MATH_H': '1',
'HAVE_MEMCMP': '1',
- '_CS_POSIX_V7_ILP32_OFF32_LIBS': '3',
- '_POSIX2_C_BIND': '200112',
- '_POSIX_VERSION': '200112',
- 'S_IFIFO': '0010000',
- 'SDL_VIDEO_DRIVER_X11_XSCRNSAVER': '1',
- 'SCHED_FIFO': '1',
- 'SDL_HAPTIC_DISABLED': '1',
- 'M_LN2LO': '1.90821492927e-10',
- 'MON_10': '30',
- '_CS_XBS5_ILP32_OFF32_LIBS': '3',
- 'O_SYNC': '8192',
- '_CS_POSIX_V6_ILP32_OFFBIG_LIBS': '7',
- 'YESEXPR': '52',
- '_PC_PATH_MAX': '4',
- '_SC_SPORADIC_SERVER': '77',
- 'SDL_POWER_UIKIT': '1',
- '_POSIX_SYNCHRONIZED_IO': '200112',
- 'SIGXFSZ': '25',
- '_SC_NPROCESSORS_ONLN': '10',
- '_CS_POSIX_V6_LPBIG_OFFBIG_LIBS': '15',
- '_PC_MAX_INPUT': '2',
- 'F_TLOCK': '2',
- 'REQUIRED_ARG': '1',
- '_SC_VERSION': '7',
+ 'HAVE_MEMCPY': '1',
+ 'HAVE_MEMMOVE': '1',
+ 'HAVE_MEMSET': '1',
+ 'HAVE_M_PI': '1',
+ 'HAVE_NANOSLEEP': '1',
+ 'HAVE_POW': '1',
+ 'HAVE_PUTENV': '1',
+ 'HAVE_QSORT': '1',
+ 'HAVE_REALLOC': '1',
+ 'HAVE_RINDEX': '1',
+ 'HAVE_SCALBN': '1',
+ 'HAVE_SETENV': '1',
+ 'HAVE_SETJMP': '1',
+ 'HAVE_SIGACTION': '1',
+ 'HAVE_SIGNAL_H': '1',
+ 'HAVE_SIN': '1',
+ 'HAVE_SINF': '1',
+ 'HAVE_SNPRINTF': '1',
+ 'HAVE_SQRT': '1',
+ 'HAVE_SSCANF': '1',
+ 'HAVE_STDARG_H': '1',
+ 'HAVE_STDDEF_H': '1',
+ 'HAVE_STDINT_H': '1',
+ 'HAVE_STDIO_H': '1',
+ 'HAVE_STRCASECMP': '1',
+ 'HAVE_STRCHR': '1',
+ 'HAVE_STRCMP': '1',
+ 'HAVE_STRDUP': '1',
+ 'HAVE_STRICMP': '1',
+ 'HAVE_STRING_H': '1',
+ 'HAVE_STRLCAT': '1',
+ 'HAVE_STRLCPY': '1',
+ 'HAVE_STRLEN': '1',
+ 'HAVE_STRNCASECMP': '1',
+ 'HAVE_STRNCMP': '1',
+ 'HAVE_STRRCHR': '1',
+ 'HAVE_STRSTR': '1',
+ 'HAVE_STRTOD': '1',
+ 'HAVE_STRTOL': '1',
+ 'HAVE_STRTOLL': '1',
+ 'HAVE_STRTOUL': '1',
+ 'HAVE_STRTOULL': '1',
+ 'HAVE_SYSCONF': '1',
+ 'HAVE_SYSCTLBYNAME': '1',
+ 'HAVE_SYS_TYPES_H': '1',
+ 'HAVE_UNSETENV': '1',
+ 'HAVE_VSNPRINTF': '1',
+ 'HAVE__LTOA': '1',
+ 'HAVE__STRICMP': '1',
+ 'HAVE__STRLWR': '1',
+ 'HAVE__STRNICMP': '1',
+ 'HAVE__STRREV': '1',
+ 'HAVE__STRUPR': '1',
+ 'HAVE__ULTOA': '1',
'HUGE_VAL': 'inf',
- 'AT_EACCESS': '1',
- 'ABMON_3': '35',
- 'ABMON_2': '34',
- 'ABMON_1': '33',
- '_SC_THREAD_ROBUST_PRIO_PROTECT': '123',
- 'ABMON_7': '39',
- 'ABMON_6': '38',
- 'ABMON_5': '37',
- 'ABMON_4': '36',
- 'S_IWUSR': '0000200',
- 'ABMON_9': '41',
- 'ABMON_8': '40',
- 'UNDERFLOW': '4',
- '_SC_AIO_MAX': '35',
- 'ERA': '45',
- '_CS_XBS5_ILP32_OFFBIG_LIBS': '7',
- 'S_IXUSR': '0000100',
- '_SC_THREAD_PRIO_INHERIT': '46',
- '__HPUX__': '1',
- 'M_2_PI': '0.636619772368',
- '_O_RDWR': '2',
- '_PC_2_SYMLINKS': '13',
- 'POSIX_FADV_DONTNEED': '135',
- 'SIG_BLOCK': '1',
- 'SDL_VIDEO_RENDER_NDS': '0',
- '_O_WRONLY': '1',
- '_CS_XBS5_LP64_OFF64_CFLAGS': '9',
- '__OS2__': '1',
+ 'INT_MAX': '2147483647',
+ 'IPPROTO_TCP': '1',
+ 'IPPROTO_UDP': '2',
+ 'ITIMER_PROF': '2',
+ 'ITIMER_REAL': '0',
+ 'ITIMER_VIRTUAL': '1',
+ 'LACKS_SYS_MMAN_H': '1',
+ 'LONG_MAX': '2147483647',
+ 'MAC_OS_X_VERSION_10_4': '1040',
+ 'MAC_OS_X_VERSION_10_5': '1050',
+ 'MAC_OS_X_VERSION_10_6': '1060',
+ 'MALLOC_ALIGNMENT': '16',
+ 'MATH_ERREXCEPT': '2',
+ 'math_errhandling': '1',
+ 'MATH_ERRNO': '1',
+ 'MAXPATHLEN': '1024',
+ 'MB_LEN_MAX': '1',
+ 'MON_1': '21',
+ 'MON_10': '30',
+ 'MON_11': '31',
+ 'MON_12': '32',
'MON_2': '22',
'MON_3': '23',
- '_POSIX_PRIORITY_SCHEDULING': '200112',
- 'MON_1': '21',
- 'MON_6': '26',
- 'MON_7': '27',
'MON_4': '24',
'MON_5': '25',
- '_SC_SPAWN': '75',
+ 'MON_6': '26',
+ 'MON_7': '27',
'MON_8': '28',
'MON_9': '29',
- '_CS_POSIX_V6_ILP32_OFF32_LDFLAGS': '2',
- '_SC_TRACE_EVENT_NAME_MAX': '85',
- 'SA_SIGINFO': '2',
- '_FBINARY': '65536',
- 'PTHREAD_PRIO_PROTECT': '2',
- 'POLLERR': '8',
- 'SIGVTALRM': '26',
- 'O_BINARY': '65536',
- '_REENT_EMERGENCY_SIZE': '25',
- 'S_IEXEC': '0000100',
- '_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS': '13',
- 'SIGEV_THREAD': '3',
- 'ITIMER_VIRTUAL': '1',
- 'HAVE_ATOI': '1',
- '_SC_TRACE_SYS_MAX': '89',
- '_POSIX_NO_TRUNC': '1',
- 'HAVE_ATOF': '1',
- '__RISCOS__': '1',
- '_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS': '17',
- 'HAVE_ATAN2': '1',
- 'HAVE_PUTENV': '1',
- 'SDL_AUDIO_DRIVER_ANDROID': '1',
- 'F_SETFL': '4',
- 'HAVE_GCC_ATOMICS': '1',
- '_CS_POSIX_V7_THREADS_CFLAGS': '18',
- '_SC_AIO_PRIO_DELTA_MAX': '36',
- '_POSIX2_C_DEV': '200112',
- '_SC_MONOTONIC_CLOCK': '69',
- '_POSIX_THREAD_SPORADIC_SERVER': '1',
- '_FNOINHERIT': '262144',
- 'SDL_HAPTIC_NDS': '1',
- '_SC_XOPEN_ENH_I18N': '97',
- 'SIGPROF': '27',
- 'F_SETLKW64': '22',
- 'HAVE__STRREV': '1',
- '_O_APPEND': '8',
- '_FDEFER': '32',
- 'SDL_VIDEO_DRIVER_X11_XINPUT': '1',
- 'CLOCK_DISALLOWED': '0',
- 'SDL_VIDEO_DRIVER_X11': '1',
- '_SC_MEMORY_PROTECTION': '26',
- 'HAVE_STDIO_H': '1',
- 'LONG_MAX': '2147483647',
- 'no_argument': '0',
- '__NINTENDODS__': '1',
- 'F_OK': '0',
- 'SDL_ASSEMBLY_ROUTINES': '1',
- 'FAPPEND': '8',
- 'SA_RESETHAND': '8',
- 'FREAD': '1',
- '_SC_SPIN_LOCKS': '76',
- 'SDL_VIDEO_DRIVER_COCOA': '1',
+ 'M_1_PI': '0.318309886184',
+ 'M_2_PI': '0.636619772368',
+ 'M_2_SQRTPI': '1.1283791671',
+ 'M_3PI_4': '2.35619449019',
+ 'M_E': '2.71828182846',
+ 'M_INVLN2': '1.44269504089',
+ 'M_IVLN10': '0.434294481903',
+ 'M_LN10': '2.30258509299',
+ 'M_LN2': '0.69314718056',
'M_LN2HI': '0.693147180369',
- '_LIBC_LIMITS_H_': '1',
- 'S_IFSOCK': '0140000',
- 'SDL_AUDIO_DRIVER_COREAUDIO': '1',
- 'HAVE_MALLOC': '1',
- '_POSIX_DEVCTL_DIRECTION': '1',
- 'ABDAY_2': '15',
- 'HAVE_STRTOL': '1',
- 'SDL_VIDEO_DRIVER_DUMMY': '1',
- '_PC_LINK_MAX': '0',
- '_POSIX_THREAD_PRIO_PROTECT': '1',
- 'HAVE_STRTOD': '1',
- '__DREAMCAST__': '1',
+ 'M_LN2LO': '1.90821492927e-10',
+ 'M_LOG10E': '0.434294481903',
+ 'M_LOG2E': '1.44269504089',
+ 'M_LOG2_E': '0.69314718056',
+ 'M_PI': '3.14159265359',
+ 'M_PI_2': '1.57079632679',
+ 'M_PI_4': '0.785398163397',
+ 'M_SQRT1_2': '0.707106781187',
+ 'M_SQRT2': '1.41421356237',
+ 'M_SQRT3': '1.73205080757',
+ 'M_SQRTPI': '1.77245385091',
+ 'M_TWOPI': '6.28318530718',
+ 'NBBY': '8',
+ 'NL_ARGMAX': '32',
'NOEXPR': '53',
- 'FEXCL': '2048',
- '_SC_FSYNC': '22',
- '_SC_GETGR_R_SIZE_MAX': '50',
- '_POSIX_THREAD_PROCESS_SHARED': '200112',
- 'HAVE_QSORT': '1',
- '_ATEXIT_SIZE': '32',
- '_SC_TRACE_NAME_MAX': '88',
- '_SC_BC_BASE_MAX': '57',
- '__WIN32__': '1',
- '_LIMITS_H': '1',
- 'PTHREAD_STACK_MIN': '200',
+ 'NOSTR': '55',
+ 'NO_ARG': '0',
+ 'no_argument': '0',
+ 'NSIG': '32',
+ 'NULL': '0',
+ 'OPTIONAL_ARG': '2',
+ 'optional_argument': '2',
+ 'OPT_ARG': '2',
+ 'OVERFLOW': '3',
+ 'O_ACCMODE': '3',
'O_APPEND': '8',
- '_CS_XBS5_LP64_OFF64_LINTFLAGS': '12',
- '_SC_XOPEN_STREAMS': '104',
- 'HAVE_CALLOC': '1',
- 'HAVE_CTYPE_H': '1',
- '_SC_GETPW_R_SIZE_MAX': '51',
- '_POSIX_ASYNCHRONOUS_IO': '1',
- 'UCHAR_MAX': '255',
- '__BSDI__': '1',
- '_SC_PAGE_SIZE': '8',
- 'SDL_THREADS_DISABLED': '1',
- '_SC_XBS5_ILP32_OFFBIG': '93',
- 'S_IFBLK': '0060000',
- '_S_IFIFO': '0010000',
- 'T_FMT_AMPM': '4',
- '_POSIX_SEMAPHORES': '200112',
- 'HAVE_SCALBN': '1',
- '__NETBSD__': '1',
- 'NBBY': '8',
- 'SDL_AUDIO_DRIVER_XAUDIO2': '1',
- 'SIGEMT': '7',
- '_POSIX_FSYNC': '200112',
- 'F_SETLKW': '9',
- '_MB_EXTENDED_CHARSETS_WINDOWS': '1',
- 'SIGALRM': '14',
- 'SDL_VIDEO_DRIVER_UIKIT': '1',
- '___int32_t_defined': '1',
+ 'O_BINARY': '65536',
+ 'O_CLOEXEC': '262144',
+ 'O_CREAT': '512',
+ 'O_EXCL': '2048',
+ 'O_NOCTTY': '32768',
+ 'O_NOINHERIT': '262144',
+ 'O_NONBLOCK': '16384',
+ 'O_RDONLY': '0',
+ 'O_RDWR': '2',
+ 'O_SYNC': '8192',
+ 'O_TEXT': '131072',
+ 'O_TRUNC': '1024',
+ 'O_WRONLY': '1',
+ 'PATH_MAX': '4096',
+ 'PF_INET': '2',
+ 'PF_INET6': '6',
+ 'PLOSS': '6',
+ 'PM_STR': '6',
+ 'POLLERR': '8',
+ 'POLLHUP': '16',
+ 'POLLIN': '1',
'POLLNVAL': '4',
- '_SC_OPEN_MAX': '4',
- 'CHAR_BIT': '8',
- '_N_LISTS': '30',
- '_SC_2_FORT_RUN': '111',
+ 'POLLOUT': '2',
+ 'POSIX_FADV_DONTNEED': '135',
+ 'PTHREAD_CREATE_DETACHED': '0',
+ 'PTHREAD_CREATE_JOINABLE': '1',
+ 'PTHREAD_EXPLICIT_SCHED': '2',
+ 'PTHREAD_INHERIT_SCHED': '1',
'PTHREAD_MUTEX_DEFAULT': '3',
- 'HAVE_STDARG_H': '1',
- '_POSIX_REGEXP': '1',
- '_SC_RE_DUP_MAX': '73',
+ 'PTHREAD_MUTEX_ERRORCHECK': '2',
+ 'PTHREAD_MUTEX_NORMAL': '0',
+ 'PTHREAD_MUTEX_RECURSIVE': '1',
+ 'PTHREAD_PRIO_INHERIT': '1',
+ 'PTHREAD_PRIO_NONE': '0',
+ 'PTHREAD_PRIO_PROTECT': '2',
'PTHREAD_PROCESS_PRIVATE': '0',
- '_S_IFREG': '0100000',
- '_SC_THREAD_THREADS_MAX': '40',
- '_SC_THREAD_PRIO_PROTECT': '47',
- 'SDL_THREAD_WINDOWS': '1',
- '_SC_2_PBS_CHECKPOINT': '115',
- 'M_1_PI': '0.318309886184',
- '_PC_POSIX_PERMISSIONS': '90',
- '_SC_TIMERS': '33',
- 'MON_11': '31',
- 'MON_12': '32',
- 'CLOCK_DISABLED': '0',
- '_SC_XBS5_LPBIG_OFFBIG': '95',
- '_POSIX_SPIN_LOCKS': '200112',
- '_FREAD': '1',
- 'HAVE_SYSCONF': '1',
- '_SC_SHARED_MEMORY_OBJECTS': '199',
- 'F_RDLCK': '1',
- 'F_GETFD': '1',
- 'MAC_OS_X_VERSION_10_4': '1040',
- 'AT_SYMLINK_NOFOLLOW': '2',
- '_PC_ALLOC_SIZE_MIN': '15',
- '_POSIX_C_SOURCE': '2',
- '_SC_READER_WRITER_LOCKS': '71',
- 'HAVE_STRING_H': '1',
- 'SI_USER': '1',
- '_SC_MEMLOCK_RANGE': '25',
- '_SC_PRIORITY_SCHEDULING': '101',
- 'optional_argument': '2',
- 'T_FMT': '3',
- 'LACKS_SYS_MMAN_H': '1',
- 'MAC_OS_X_VERSION_10_5': '1050',
- '_PC_VDISABLE': '8',
- 'SDL_VIDEO_DRIVER_X11_XSHAPE': '1',
- 'THOUSEP': '51',
- 'O_NOINHERIT': '262144',
'PTHREAD_PROCESS_SHARED': '1',
- '_SC_TRACE_EVENT_FILTER': '84',
- 'ERA_T_FMT': '48',
- '_SC_THREAD_ATTR_STACKADDR': '43',
- '_SC_LOGIN_NAME_MAX': '52',
- 'M_LOG2E': '1.44269504089',
- 'ITIMER_PROF': '2',
- 'HAVE_LOG': '1',
- '_SC_2_C_BIND': '108',
- 'FNONBIO': '16384',
- '_PC_NO_TRUNC': '7',
- 'F_RSETLK': '11',
- '_SC_V7_ILP32_OFF32': '92',
- '_FAPPEND': '8',
- 'PTHREAD_EXPLICIT_SCHED': '2',
- '_FNBIO': '4096',
- 'HAVE_SYSCTLBYNAME': '1',
- 'F_CNVT': '12',
- '_SC_SHELL': '74',
- '_SC_V6_LP64_OFF64': '94',
+ 'PTHREAD_SCOPE_PROCESS': '0',
+ 'PTHREAD_SCOPE_SYSTEM': '1',
+ 'PTHREAD_STACK_MIN': '200',
+ 'RADIXCHAR': '50',
+ 'REQUIRED_ARG': '1',
+ 'required_argument': '1',
+ 'REQ_ARG': '1',
+ 'R_OK': '4',
+ 'SA_NOCLDSTOP': '1',
+ 'SA_NODEFER': '4',
+ 'SA_RESETHAND': '8',
+ 'SA_SIGINFO': '2',
+ 'SCHAR_MAX': '127',
+ 'SCHAR_MIN': '-128',
+ 'SCHED_FIFO': '1',
'SCHED_OTHER': '0',
- '_CS_GNU_LIBC_VERSION': '42',
- '_SC_SEM_VALUE_MAX': '17',
- 'S_ENFMT': '0002000',
- '_SC_MQ_OPEN_MAX': '13',
+ 'SCHED_RR': '2',
+ 'SCHED_SPORADIC': '4',
+ 'SDL_ALTIVEC_BLITTERS': '1',
+ 'SDL_ASSEMBLY_ROUTINES': '1',
+ 'SDL_ASSERT_LEVEL': '1',
+ 'SDL_AUDIO_DRIVER_ANDROID': '1',
+ 'SDL_AUDIO_DRIVER_COREAUDIO': '1',
+ 'SDL_AUDIO_DRIVER_COREAUDIOIPHONE': '1',
+ 'SDL_AUDIO_DRIVER_DISK': '1',
+ 'SDL_AUDIO_DRIVER_DSOUND': '1',
+ 'SDL_AUDIO_DRIVER_DUMMY': '1',
+ 'SDL_AUDIO_DRIVER_NDS': '1',
+ 'SDL_AUDIO_DRIVER_WINMM': '1',
+ 'SDL_AUDIO_DRIVER_XAUDIO2': '1',
+ 'SDL_HAPTIC_DINPUT': '1',
+ 'SDL_HAPTIC_DISABLED': '1',
+ 'SDL_HAPTIC_DUMMY': '1',
+ 'SDL_HAPTIC_IOKIT': '1',
+ 'SDL_HAPTIC_NDS': '1',
+ 'SDL_IPHONE_KEYBOARD': '1',
+ 'SDL_IPHONE_MAX_GFORCE': '5.0',
+ 'SDL_JOYSTICK_ANDROID': '1',
+ 'SDL_JOYSTICK_DINPUT': '1',
'SDL_JOYSTICK_DISABLED': '1',
- '_POSIX_ADVISORY_INFO': '200112',
- 'SIGABRT': '6',
- '_CS_POSIX_V7_ILP32_OFF32_CFLAGS': '1',
- '_CS_XBS5_ILP32_OFF32_CFLAGS': '1',
- '_MB_EXTENDED_CHARSETS_ISO': '1',
- '_SC_HOST_NAME_MAX': '65',
- '_SC_THREAD_STACK_MIN': '39',
- '_SC_TIMEOUTS': '82',
- 'POLLOUT': '2',
- '_CS_XBS5_LPBIG_OFFBIG_LINTFLAGS': '16',
- '_SC_CHILD_MAX': '1',
- '__RAND_MAX': '2147483647',
+ 'SDL_JOYSTICK_IOKIT': '1',
+ 'SDL_JOYSTICK_NDS': '1',
+ 'SDL_LOADSO_DISABLED': '1',
+ 'SDL_LOADSO_DLOPEN': '1',
+ 'SDL_LOADSO_WINDOWS': '1',
+ 'SDL_POWER_MACOSX': '1',
+ 'SDL_POWER_NINTENDODS': '1',
+ 'SDL_POWER_UIKIT': '1',
+ 'SDL_POWER_WINDOWS': '1',
+ 'SDL_THREADS_DISABLED': '1',
+ 'SDL_THREAD_PTHREAD': '1',
+ 'SDL_THREAD_PTHREAD_RECURSIVE_MUTEX': '1',
+ 'SDL_THREAD_WINDOWS': '1',
+ 'SDL_TIMERS_DISABLED': '1',
+ 'SDL_TIMER_NDS': '1',
+ 'SDL_TIMER_UNIX': '1',
+ 'SDL_TIMER_WINCE': '1',
+ 'SDL_TIMER_WINDOWS': '1',
+ 'SDL_VIDEO_DRIVER_ANDROID': '1',
+ 'SDL_VIDEO_DRIVER_COCOA': '1',
+ 'SDL_VIDEO_DRIVER_DUMMY': '1',
'SDL_VIDEO_DRIVER_NDS': '1',
- '_POSIX_THREAD_ATTR_STACKADDR': '1',
+ 'SDL_VIDEO_DRIVER_UIKIT': '1',
+ 'SDL_VIDEO_DRIVER_WINDOWS': '1',
+ 'SDL_VIDEO_DRIVER_X11': '1',
+ 'SDL_VIDEO_DRIVER_X11_XINERAMA': '1',
+ 'SDL_VIDEO_DRIVER_X11_XINPUT': '1',
+ 'SDL_VIDEO_DRIVER_X11_XRANDR': '1',
+ 'SDL_VIDEO_DRIVER_X11_XSCRNSAVER': '1',
+ 'SDL_VIDEO_DRIVER_X11_XSHAPE': '1',
+ 'SDL_VIDEO_DRIVER_X11_XVIDMODE': '1',
+ 'SDL_VIDEO_OPENGL': '1',
+ 'SDL_VIDEO_OPENGL_CGL': '1',
+ 'SDL_VIDEO_OPENGL_ES': '1',
+ 'SDL_VIDEO_OPENGL_GLX': '1',
+ 'SDL_VIDEO_OPENGL_WGL': '1',
+ 'SDL_VIDEO_RENDER_D3D': '1',
+ 'SDL_VIDEO_RENDER_NDS': '0',
+ 'SDL_VIDEO_RENDER_OGL': '1',
+ 'SDL_VIDEO_RENDER_OGL_ES': '1',
+ 'SDL_VIDEO_RENDER_OGL_ES2': '1',
+ 'SEEK_CUR': '1',
+ 'SEEK_END': '2',
+ 'SEEK_SET': '0',
+ 'SHRT_MAX': '32767',
+ 'SHRT_MIN': '-32768',
+ 'SIGABRT': '6',
+ 'SIGALRM': '14',
+ 'SIGBUS': '10',
+ 'SIGCHLD': '20',
+ 'SIGCLD': '20',
+ 'SIGCONT': '19',
+ 'SIGEMT': '7',
+ 'SIGEV_NONE': '1',
+ 'SIGEV_SIGNAL': '2',
+ 'SIGEV_THREAD': '3',
'SIGFPE': '8',
- 'NL_ARGMAX': '32',
- '_SC_2_PBS_MESSAGE': '117',
- 'TIMER_ABSTIME': '4',
- '_NL_CTYPE_CODESET_NAME': '0',
- '_SC_2_C_DEV': '109',
- '_SC_TIMER_MAX': '19',
- 'S_IXOTH': '0000001',
- 'FP_ZERO': '2',
- 'SING': '2',
- 'M_INVLN2': '1.44269504089',
- 'SDL_TIMERS_DISABLED': '1',
- 'M_TWOPI': '6.28318530718',
- '_PC_REC_XFER_ALIGN': '19',
- '_NL_TIME_DATE_FMT': '84',
- '_SC_REALTIME_SIGNALS': '29',
- '_POSIX2_RE_DUP_MAX': '255',
- 'CLOCKS_PER_SEC': '1000',
- '_READ_WRITE_RETURN_TYPE': "<type 'int'>",
- 'ERA_D_T_FMT': '47',
+ 'SIGHUP': '1',
+ 'SIGILL': '4',
+ 'SIGINT': '2',
+ 'SIGIO': '23',
+ 'SIGIOT': '6',
+ 'SIGKILL': '9',
+ 'SIGLOST': '29',
+ 'SIGPIPE': '13',
+ 'SIGPOLL': '23',
+ 'SIGPROF': '27',
+ 'SIGPWR': '19',
+ 'SIGQUIT': '3',
+ 'SIGRTMAX': '31',
+ 'SIGRTMIN': '27',
+ 'SIGSEGV': '11',
+ 'SIGSTOP': '17',
+ 'SIGSYS': '12',
+ 'SIGTERM': '15',
+ 'SIGTRAP': '5',
+ 'SIGTSTP': '18',
+ 'SIGTTIN': '21',
+ 'SIGTTOU': '22',
+ 'SIGURG': '16',
+ 'SIGUSR1': '30',
+ 'SIGUSR2': '31',
+ 'SIGVTALRM': '26',
+ 'SIGWINCH': '28',
+ 'SIGXCPU': '24',
+ 'SIGXFSZ': '25',
+ 'SIG_BLOCK': '1',
+ 'SIG_SETMASK': '0',
'SIG_UNBLOCK': '2',
- '_CS_XBS5_ILP32_OFFBIG_LDFLAGS': '6',
- '_FSHLOCK': '128',
- 'CLK_TCK': '1000',
- 'D_FMT': '2',
- 'SDL_VIDEO_OPENGL_CGL': '1',
- '_POSIX_SPAWN': '1',
- '_XBS5_ILP32_OFF32': '-1',
- '_SC_THREAD_PRIO_CEILING': '47',
- 'SCHED_SPORADIC': '4',
- '_PC_ASYNC_IO': '9',
+ 'SING': '2',
+ 'SIZEOF_VOIDP': '4',
+ 'SI_ASYNCIO': '4',
+ 'SI_MESGQ': '5',
+ 'SI_QUEUE': '2',
'SI_TIMER': '3',
- 'DAY_2': '8',
- 'DAY_3': '9',
- 'DAY_1': '7',
- 'DAY_6': '12',
- 'DAY_7': '13',
- 'DAY_4': '10',
- 'DAY_5': '11',
- 'F_GETFL': '3',
- 'HAVE_STRNCMP': '1',
- 'AT_REMOVEDIR': '8',
- 'SDL_THREAD_PTHREAD_RECURSIVE_MUTEX': '1',
- 'PATH_MAX': '4096',
- '_POSIX_TIMEOUTS': '1',
- '_SC_MAPPED_FILES': '23',
- '__IRIX__': '1',
- 'HAVE_INDEX': '1',
- 'HAVE__LTOA': '1',
- '_SC_NGROUPS_MAX': '3',
- '__QNXNTO__': '1',
- '_FSYNC': '8192',
- 'MATH_ERRNO': '1',
- '_POSIX_SAVED_IDS': '1',
- 'SDL_POWER_MACOSX': '1',
- '_SC_SEMAPHORES': '30',
- '__FILENAME_MAX__': '255',
- 'SIGTSTP': '18',
- 'F_ULOCK': '0',
- 'HAVE_COS': '1',
- '__LONG_MAX__': '2147483647',
- 'F_WRLCK': '2',
- '_POSIX_JOB_CONTROL': '1',
- 'FLT_EVAL_METHOD': '0',
- '_XOPEN_SHM': '1',
- '_POSIX_CHOWN_RESTRICTED': '1',
- 'F_SETLK64': '21',
- '_SC_TRACE_LOG': '87',
- 'HAVE_ITOA': '1',
- 'SIGILL': '4',
- '_FNONBLOCK': '16384',
- '__OPENBSD__': '1',
- '_POSIX_TIMERS': '1',
- 'FNDELAY': '16384',
- 'FD_CLOEXEC': '1',
- 'POLLIN': '1',
+ 'SI_USER': '1',
+ 'SOCK_DGRAM': '20',
+ 'SOCK_STREAM': '200',
+ 'STDC_HEADERS': '1',
+ 'STDERR_FILENO': '2',
+ 'STDIN_FILENO': '0',
+ 'STDOUT_FILENO': '1',
+ 'S_BLKSIZE': '1024',
+ 'S_ENFMT': '0002000',
+ 'S_IEXEC': '0000100',
+ 'S_IFBLK': '0060000',
+ 'S_IFCHR': '0020000',
+ 'S_IFDIR': '0040000',
+ 'S_IFIFO': '0010000',
+ 'S_IFLNK': '0120000',
+ 'S_IFMT': '0170000',
+ 'S_IFREG': '0100000',
+ 'S_IFSOCK': '0140000',
+ 'S_IREAD': '0000400',
+ 'S_IRGRP': '0000040',
+ 'S_IROTH': '0000004',
+ 'S_IRUSR': '0000400',
+ 'S_IRWXG': '0000070',
+ 'S_IRWXO': '0000007',
+ 'S_IRWXU': '0000700',
+ 'S_ISGID': '0002000',
+ 'S_ISUID': '0004000',
+ 'S_ISVTX': '0001000',
+ 'S_IWGRP': '0000020',
+ 'S_IWOTH': '0000002',
+ 'S_IWRITE': '0000200',
+ 'S_IWUSR': '0000200',
+ 'S_IXGRP': '0000010',
+ 'S_IXOTH': '0000001',
+ 'S_IXUSR': '0000100',
+ 'THOUSEP': '51',
+ 'TIMER_ABSTIME': '4',
+ 'TLOSS': '5',
+ 'T_FMT': '3',
+ 'T_FMT_AMPM': '4',
+ 'UCHAR_MAX': '255',
+ 'UINT_MAX': '2147483647',
+ 'ULONG_MAX': '2147483647',
+ 'UNDERFLOW': '4',
+ 'USHRT_MAX': '65535',
+ 'UTIME_NOW': '-2',
+ 'UTIME_OMIT': '-1',
+ 'W_OK': '2',
+ 'X_OK': '1',
+ 'YESEXPR': '52',
+ 'YESSTR': '54',
+ '_ATEXIT_SIZE': '32',
+ '_CLOCKS_PER_SEC_': '1000',
+ '_CS_GNU_LIBC_VERSION': '42',
+ '_CS_GNU_LIBPTHREAD_VERSION': '43',
+ '_CS_PATH': '0',
+ '_CS_POSIX_V6_ILP32_OFF32_CFLAGS': '1',
+ '_CS_POSIX_V6_ILP32_OFF32_LDFLAGS': '2',
+ '_CS_POSIX_V6_ILP32_OFF32_LIBS': '3',
+ '_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS': '5',
+ '_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS': '6',
+ '_CS_POSIX_V6_ILP32_OFFBIG_LIBS': '7',
+ '_CS_POSIX_V6_LP64_OFF64_CFLAGS': '9',
+ '_CS_POSIX_V6_LP64_OFF64_LDFLAGS': '10',
+ '_CS_POSIX_V6_LP64_OFF64_LIBS': '11',
+ '_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS': '13',
'_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS': '14',
- '_POSIX_THREAD_CPUTIME': '1',
- 'F_LOCK': '1',
- '_FLOAT_ARG': "<type 'float'>",
- 'REQ_ARG': '1',
+ '_CS_POSIX_V6_LPBIG_OFFBIG_LIBS': '15',
+ '_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS': '17',
+ '_CS_POSIX_V7_ILP32_OFF32_CFLAGS': '1',
+ '_CS_POSIX_V7_ILP32_OFF32_LDFLAGS': '2',
+ '_CS_POSIX_V7_ILP32_OFF32_LIBS': '3',
+ '_CS_POSIX_V7_ILP32_OFFBIG_CFLAGS': '5',
+ '_CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS': '6',
+ '_CS_POSIX_V7_ILP32_OFFBIG_LIBS': '7',
+ '_CS_POSIX_V7_LP64_OFF64_CFLAGS': '9',
+ '_CS_POSIX_V7_LP64_OFF64_LDFLAGS': '10',
+ '_CS_POSIX_V7_LP64_OFF64_LIBS': '11',
+ '_CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS': '13',
+ '_CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS': '14',
+ '_CS_POSIX_V7_LPBIG_OFFBIG_LIBS': '15',
+ '_CS_POSIX_V7_THREADS_CFLAGS': '18',
+ '_CS_POSIX_V7_THREADS_LDFLAGS': '19',
+ '_CS_POSIX_V7_WIDTH_RESTRICTED_ENVS': '17',
+ '_CS_V7_ENV': '20',
+ '_CS_XBS5_ILP32_OFF32_CFLAGS': '1',
+ '_CS_XBS5_ILP32_OFF32_LDFLAGS': '2',
+ '_CS_XBS5_ILP32_OFF32_LIBS': '3',
'_CS_XBS5_ILP32_OFF32_LINTFLAGS': '4',
- '_SC_THREAD_DESTRUCTOR_ITERATIONS': '53',
- 'M_LN2': '0.69314718056',
- 'UINT_MAX': '2147483647',
- 'HAVE_STRDUP': '1',
- 'SIG_SETMASK': '0',
- '_SC_BC_STRING_MAX': '60',
+ '_CS_XBS5_ILP32_OFFBIG_CFLAGS': '5',
+ '_CS_XBS5_ILP32_OFFBIG_LDFLAGS': '6',
+ '_CS_XBS5_ILP32_OFFBIG_LIBS': '7',
+ '_CS_XBS5_ILP32_OFFBIG_LINTFLAGS': '8',
+ '_CS_XBS5_LP64_OFF64_CFLAGS': '9',
+ '_CS_XBS5_LP64_OFF64_LDFLAGS': '10',
+ '_CS_XBS5_LP64_OFF64_LIBS': '11',
+ '_CS_XBS5_LP64_OFF64_LINTFLAGS': '12',
+ '_CS_XBS5_LPBIG_OFFBIG_CFLAGS': '13',
+ '_CS_XBS5_LPBIG_OFFBIG_LDFLAGS': '14',
'_CS_XBS5_LPBIG_OFFBIG_LIBS': '15',
- '_SC_XOPEN_UUCP': '124',
- '_SC_2_SW_DEV': '119',
- 'FDEFER': '32',
- 'FP_NAN': '0',
- 'F_SETOWN': '6',
- 'SDL_LOADSO_DISABLED': '1',
- 'CHAR_MIN': '-128',
- 'PTHREAD_SCOPE_SYSTEM': '1',
- 'HAVE_SETENV': '1',
- 'HAVE_STRNCASECMP': '1',
- '_POSIX_V6_LPBIG_OFFBIG': '-1',
- '_S_IWRITE': '0000200',
- '_S_IFDIR': '0040000',
- '_SC_ARG_MAX': '0',
- '_SC_THREAD_PRIORITY_SCHEDULING': '45',
- 'F_GETLK': '7',
- 'SIGTTIN': '21',
- '_CS_POSIX_V7_WIDTH_RESTRICTED_ENVS': '17',
- '_POSIX_SPORADIC_SERVER': '1',
- '_SC_THREAD_CPUTIME': '80',
- '_POSIX_V6_ILP32_OFF32': '-1',
- '_CS_POSIX_V7_ILP32_OFFBIG_LIBS': '7',
- '_CS_POSIX_V6_ILP32_OFF32_LIBS': '3',
- '_SC_SYNCHRONIZED_IO': '32',
- '_UNIX98_THREAD_MUTEX_ATTRIBUTES': '1',
- '_POSIX_REALTIME_SIGNALS': '200112',
- '__SIGLASTNOTRT': '31',
- 'ERA_D_FMT': '46',
- 'HAVE_RINDEX': '1',
- 'OPT_ARG': '2',
- 'SDL_HAPTIC_IOKIT': '1',
+ '_CS_XBS5_LPBIG_OFFBIG_LINTFLAGS': '16',
+ '_DATE_FMT': '84',
+ '_FAPPEND': '8',
'_FASYNC': '64',
- '_CS_POSIX_V6_ILP32_OFF32_CFLAGS': '1',
- 'NOSTR': '55',
- '_POSIX_MONOTONIC_CLOCK': '200112',
- 'SIGPOLL': '23',
- 'S_ISGID': '0002000',
- 'FP_INFINITE': '1',
- 'ULONG_MAX': '2147483647',
- '__SIGFIRSTNOTRT': '1',
- 'AT_SYMLINK_FOLLOW': '4',
- 'FSYNC': '8192',
- '__USE_XOPEN2K': '1',
- 'SDL_VIDEO_RENDER_OGL_ES': '1',
- '_CS_XBS5_ILP32_OFFBIG_CFLAGS': '5',
- '_IFSOCK': '0140000',
+ '_FBINARY': '65536',
+ '_FCREAT': '512',
+ '_FDEFER': '32',
+ '_FEXCL': '2048',
+ '_FEXLOCK': '256',
+ '_FLOAT_ARG': "<type 'float'>",
+ '_FMARK': '16',
+ '_FNBIO': '4096',
+ '_FNDELAY': '16384',
+ '_FNOCTTY': '32768',
+ '_FNOINHERIT': '262144',
+ '_FNONBLOCK': '16384',
+ '_FOPEN': '-1',
+ '_FREAD': '1',
+ '_FSHLOCK': '128',
+ '_FSYNC': '8192',
+ '_FTEXT': '131072',
+ '_FTRUNC': '1024',
+ '_FWRITE': '2',
+ '_IFBLK': '0060000',
+ '_IFCHR': '0020000',
+ '_IFDIR': '0040000',
'_IFIFO': '0010000',
- 'ARG_MAX': '4096',
- 'SIGPIPE': '13',
- 'HAVE__ULTOA': '1',
+ '_IFLNK': '0120000',
+ '_IFMT': '0170000',
+ '_IFREG': '0100000',
+ '_IFSOCK': '0140000',
+ '_LARGEFILE64_SOURCE': '1',
+ '_LIBC_LIMITS_H_': '1',
+ '_LIMITS_H': '1',
+ '_LONG_LONG_TYPE': "<type 'long'>",
+ '_MB_EXTENDED_CHARSETS_ISO': '1',
+ '_MB_EXTENDED_CHARSETS_WINDOWS': '1',
+ '_M_LN2': '0.69314718056',
+ '_NL_CTYPE_CODESET_NAME': '0',
+ '_NL_CTYPE_MB_CUR_MAX': '85',
+ '_NL_MESSAGES_CODESET': '86',
+ '_NL_TIME_DATE_FMT': '84',
+ '_NULL': '0',
+ '_N_LISTS': '30',
+ '_O_APPEND': '8',
+ '_O_BINARY': '65536',
+ '_O_CREAT': '512',
'_O_EXCL': '2048',
- 'O_TRUNC': '1024',
- 'O_TEXT': '131072',
- '_POSIX_THREAD_PRIO_INHERIT': '1',
- '_XBS5_ILP32_OFFBIG': '1',
- 'HAVE_MEMMOVE': '1',
- 'STDERR_FILENO': '2',
- '_CS_XBS5_LPBIG_OFFBIG_CFLAGS': '13',
- '__LINUX__': '1',
- 'PLOSS': '6',
- 'S_IRWXO': '0000004',
- '_SC_V7_LP64_OFF64': '94',
'_O_NOINHERIT': '262144',
- 'D_MD_ORDER': '57',
- '_IFMT': '0170000',
- '_SC_SYMLOOP_MAX': '79',
- 'MB_LEN_MAX': '1',
- 'SDL_TIMER_WINDOWS': '1',
- '_SC_XOPEN_UNIX': '105',
- 'M_IVLN10': '0.434294481903',
- 'ALLPERMS': '0004000',
- 'HAVE_STRSTR': '1',
- '__BEOS__': '1',
- 'HAVE_GCC_SYNC_LOCK_TEST_AND_SET': '1',
- 'F_SETFD': '2',
- 'SIGUSR1': '30',
- 'HAVE_SIN': '1',
- 'SDL_VIDEO_DRIVER_X11_XRANDR': '1',
- 'MAC_OS_X_VERSION_10_6': '1060',
- '___int8_t_defined': '1',
- 'SIGKILL': '9',
- '_CS_POSIX_V7_ILP32_OFFBIG_CFLAGS': '5',
- 'PTHREAD_MUTEX_RECURSIVE': '1',
- 'SIGSEGV': '11',
- 'M_LOG2_E': '0.69314718056',
- 'FWRITE': '2',
- '_FEXCL': '2048',
- 'SIGINT': '2',
- 'HAVE_STRRCHR': '1',
- 'H8300': '1',
- '_POSIX_MEMORY_PROTECTION': '200112',
- 'FP_ILOGBNAN': '2147483647',
- '_SC_V7_LPBIG_OFFBIG': '95',
- '_SC_CLOCK_SELECTION': '61',
+ '_O_RAW': '65536',
+ '_O_RDONLY': '0',
+ '_O_RDWR': '2',
+ '_O_TEXT': '131072',
+ '_O_TRUNC': '1024',
+ '_O_WRONLY': '1',
+ '_PC_2_SYMLINKS': '13',
+ '_PC_ALLOC_SIZE_MIN': '15',
+ '_PC_ASYNC_IO': '9',
+ '_PC_CHOWN_RESTRICTED': '6',
+ '_PC_FILESIZEBITS': '12',
+ '_PC_LINK_MAX': '0',
+ '_PC_MAX_CANON': '1',
+ '_PC_MAX_INPUT': '2',
+ '_PC_NAME_MAX': '3',
+ '_PC_NO_TRUNC': '7',
+ '_PC_PATH_MAX': '4',
+ '_PC_PIPE_BUF': '5',
+ '_PC_POSIX_PERMISSIONS': '90',
+ '_PC_POSIX_SECURITY': '91',
'_PC_PRIO_IO': '10',
- 'M_2_SQRTPI': '1.1283791671',
- 'S_IROTH': '0000004',
- '_SC_MESSAGE_PASSING': '27',
- '_SC_V6_LPBIG_OFFBIG': '95',
- 'SDL_AUDIO_DRIVER_DUMMY': '1',
- 'HAVE_MEMCPY': '1',
- '_SC_EXPR_NEST_MAX': '64',
- 'SDL_TIMER_WINCE': '1',
- 'STDC_HEADERS': '1',
- '_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS': '5',
- 'S_ISVTX': '0001000',
- 'HAVE_STRLCPY': '1',
- 'UTIME_OMIT': '-1',
- '_CS_POSIX_V7_THREADS_LDFLAGS': '19',
- 'SDL_POWER_WINDOWS': '1',
- '_SC_PAGESIZE': '8',
+ '_PC_REC_INCR_XFER_SIZE': '16',
'_PC_REC_MAX_XFER_SIZE': '17',
- 'SIGIOT': '6',
- 'FASYNC': '64',
- '_SC_V7_ILP32_OFFBIG': '93',
- '_RAND48_MULT_0': '58989',
- '_RAND48_MULT_1': '57068',
- '_RAND48_MULT_2': '5',
- '_CS_POSIX_V6_LP64_OFF64_LDFLAGS': '10',
- 'HAVE_STRTOUL': '1',
- 'PTHREAD_MUTEX_NORMAL': '0',
- '_O_TRUNC': '1024',
- 'W_OK': '2',
- 'O_NONBLOCK': '16384',
- 'R_OK': '4',
- '_IFBLK': '0060000',
- 'FTRUNC': '1024',
- '__OSF__': '1',
- '_SC_XBS5_LP64_OFF64': '94',
- 'STDIN_FILENO': '0',
- 'HAVE_ABS': '1',
- 'SDL_TIMER_NDS': '1',
- '_CS_POSIX_V7_LPBIG_OFFBIG_LIBS': '15',
- 'SDL_AUDIO_DRIVER_DISK': '1',
- '_SC_SIGQUEUE_MAX': '18',
- 'M_3PI_4': '2.35619449019',
- 'HAVE_STRCMP': '1',
+ '_PC_REC_MIN_XFER_SIZE': '18',
+ '_PC_REC_XFER_ALIGN': '19',
+ '_PC_SOCK_MAXBUF': '100',
+ '_PC_SYMLINK_MAX': '14',
+ '_PC_SYNC_IO': '11',
+ '_PC_TIMESTAMP_RESOLUTION': '20',
+ '_PC_VDISABLE': '8',
+ '_POINTER_INT': "<type 'long'>",
+ '_POSIX2_CHAR_TERM': '200112',
+ '_POSIX2_C_BIND': '200112',
+ '_POSIX2_C_DEV': '200112',
+ '_POSIX2_RE_DUP_MAX': '255',
+ '_POSIX2_SW_DEV': '200112',
+ '_POSIX2_UPE': '200112',
+ '_POSIX2_VERSION': '200112',
+ '_POSIX_ADVISORY_INFO': '200112',
+ '_POSIX_ASYNCHRONOUS_IO': '1',
+ '_POSIX_BARRIERS': '200112',
+ '_POSIX_CHOWN_RESTRICTED': '1',
+ '_POSIX_CPUTIME': '1',
+ '_POSIX_C_SOURCE': '2',
+ '_POSIX_DEVCTL_DIRECTION': '1',
+ '_POSIX_DEVICE_CONTROL': '1',
+ '_POSIX_FSYNC': '200112',
+ '_POSIX_INTERRUPT_CONTROL': '1',
+ '_POSIX_IPV6': '200112',
+ '_POSIX_JOB_CONTROL': '1',
+ '_POSIX_MAPPED_FILES': '200112',
+ '_POSIX_MEMLOCK': '1',
+ '_POSIX_MEMLOCK_RANGE': '200112',
+ '_POSIX_MEMORY_PROTECTION': '200112',
'_POSIX_MESSAGE_PASSING': '200112',
- 'S_ISUID': '0004000',
- 'SIGLOST': '29',
+ '_POSIX_MONOTONIC_CLOCK': '200112',
+ '_POSIX_NO_TRUNC': '1',
+ '_POSIX_PRIORITIZED_IO': '1',
+ '_POSIX_PRIORITY_SCHEDULING': '200112',
+ '_POSIX_RAW_SOCKETS': '200112',
+ '_POSIX_READER_WRITER_LOCKS': '200112',
+ '_POSIX_REALTIME_SIGNALS': '200112',
+ '_POSIX_REGEXP': '1',
+ '_POSIX_SAVED_IDS': '1',
+ '_POSIX_SEMAPHORES': '200112',
+ '_POSIX_SHARED_MEMORY_OBJECTS': '200112',
+ '_POSIX_SHELL': '1',
+ '_POSIX_SPAWN': '1',
+ '_POSIX_SPIN_LOCKS': '200112',
+ '_POSIX_SPORADIC_SERVER': '1',
+ '_POSIX_SYNCHRONIZED_IO': '200112',
+ '_POSIX_THREADS': '200112',
+ '_POSIX_THREAD_ATTR_STACKADDR': '1',
+ '_POSIX_THREAD_ATTR_STACKSIZE': '200112',
+ '_POSIX_THREAD_CPUTIME': '1',
'_POSIX_THREAD_PRIORITY_SCHEDULING': '200112',
- 'SDL_VIDEO_RENDER_OGL_ES2': '1',
- '__FREEBSD__': '1',
- '_SC_TZNAME_MAX': '20',
- '_O_RAW': '65536',
- '_CS_PATH': '0',
- '_POSIX_BARRIERS': '200112',
- 'SDL_ALTIVEC_BLITTERS': '1',
- 'SEEK_SET': '0',
+ '_POSIX_THREAD_PRIO_INHERIT': '1',
+ '_POSIX_THREAD_PRIO_PROTECT': '1',
+ '_POSIX_THREAD_PROCESS_SHARED': '200112',
'_POSIX_THREAD_SAFE_FUNCTIONS': '200112',
- 'S_IREAD': '0000400',
- '_LONG_LONG_TYPE': "<type 'long'>",
- '___int_least8_t_defined': '1',
- 'INT_MAX': '2147483647',
+ '_POSIX_THREAD_SPORADIC_SERVER': '1',
+ '_POSIX_TIMEOUTS': '1',
+ '_POSIX_TIMERS': '1',
+ '_POSIX_V6_ILP32_OFF32': '-1',
'_POSIX_V6_ILP32_OFFBIG': '1',
- '_SC_PHYS_PAGES': '11',
- 'HAVE_BCOPY': '1',
- '_PC_MAX_CANON': '1',
- 'HAVE_STRICMP': '1',
- '_CS_XBS5_LPBIG_OFFBIG_LDFLAGS': '14',
- '_SC_THREAD_SAFE_FUNCTIONS': '49',
- 'SIGRTMAX': '31',
- 'S_IXGRP': '0000010',
- 'HAVE_GETENV': '1',
- '_XBS5_LPBIG_OFFBIG': '-1',
- '_PC_NAME_MAX': '3',
- 'O_EXCL': '2048',
- '_SC_XOPEN_SHM': '103',
- 'S_IWGRP': '0000020',
- '_SC_TRACE_USER_EVENT_MAX': '90',
- 'SDL_VIDEO_RENDER_D3D': '1',
- 'HAVE__STRNICMP': '1',
- 'M_SQRT1_2': '0.707106781187',
- '_SC_AVPHYS_PAGES': '12',
- '_SC_RAW_SOCKETS': '70',
- 'O_RDONLY': '0',
- '_DATE_FMT': '84',
- 'HAVE_STRCASECMP': '1',
- '__SOLARIS__': '1',
- '_SC_RTSIG_MAX': '15',
- '_POSIX_DEVICE_CONTROL': '1',
- 'CLOCK_ENABLED': '1',
- '_NULL': '0',
- '_SC_PRIORITIZED_IO': '28',
- '_O_TEXT': '131072',
- 'SDL_VIDEO_DRIVER_X11_XVIDMODE': '1',
- 'SIGBUS': '10',
- 'CODESET': '0',
- 'CHAR_MAX': '127',
- 'SDL_POWER_NINTENDODS': '1',
- 'SIGSYS': '12',
- '_PC_REC_INCR_XFER_SIZE': '16',
- 'S_IRUSR': '0000400',
- '_PC_FILESIZEBITS': '12',
- '_SC_XBS5_ILP32_OFF32': '92',
- 'HAVE_MATH_H': '1',
- 'HAVE_SQRT': '1',
- 'SIGURG': '16',
- '_POSIX_THREAD_ATTR_STACKSIZE': '200112',
- '_CS_POSIX_V7_LP64_OFF64_LIBS': '11',
- '_CS_GNU_LIBPTHREAD_VERSION': '43',
- 'HAVE_M_PI': '1',
+ '_POSIX_V6_LP64_OFF64': '-1',
+ '_POSIX_V6_LPBIG_OFFBIG': '-1',
+ '_POSIX_VERSION': '200112',
+ '_RAND48_ADD': '11',
+ '_RAND48_MULT_0': '58989',
+ '_RAND48_MULT_1': '57068',
+ '_RAND48_MULT_2': '5',
+ '_RAND48_SEED_0': '13070',
+ '_RAND48_SEED_1': '43981',
+ '_RAND48_SEED_2': '4660',
+ '_READ_WRITE_RETURN_TYPE': "<type 'int'>",
'_REENT_ASCTIME_SIZE': '26',
+ '_REENT_EMERGENCY_SIZE': '25',
+ '_REENT_SIGNAL_SIZE': '24',
+ '_SC_2_CHAR_TERM': '107',
+ '_SC_2_C_BIND': '108',
+ '_SC_2_C_DEV': '109',
+ '_SC_2_FORT_DEV': '110',
+ '_SC_2_FORT_RUN': '111',
+ '_SC_2_LOCALEDEF': '112',
+ '_SC_2_PBS': '113',
+ '_SC_2_PBS_ACCOUNTING': '114',
+ '_SC_2_PBS_CHECKPOINT': '115',
'_SC_2_PBS_LOCATE': '116',
- '_SC_V6_ILP32_OFF32': '92',
- 'SIGCHLD': '20',
- 'SHRT_MIN': '-32768',
- '__HAIKU__': '1',
- 'PTHREAD_MUTEX_ERRORCHECK': '2',
- '_PC_SYNC_IO': '11',
- 'SDL_VIDEO_OPENGL': '1',
- 'FP_NORMAL': '4',
+ '_SC_2_PBS_MESSAGE': '117',
+ '_SC_2_PBS_TRACK': '118',
+ '_SC_2_SW_DEV': '119',
'_SC_2_UPE': '120',
- 'HAVE_POW': '1',
- '_SC_SEM_NSEMS_MAX': '16',
- '__ANDROID__': '1',
+ '_SC_2_VERSION': '121',
+ '_SC_ADVISORY_INFO': '54',
+ '_SC_AIO_LISTIO_MAX': '34',
+ '_SC_AIO_MAX': '35',
+ '_SC_AIO_PRIO_DELTA_MAX': '36',
+ '_SC_ARG_MAX': '0',
+ '_SC_ASYNCHRONOUS_IO': '21',
+ '_SC_ATEXIT_MAX': '55',
+ '_SC_AVPHYS_PAGES': '12',
+ '_SC_BARRIERS': '56',
+ '_SC_BC_BASE_MAX': '57',
+ '_SC_BC_DIM_MAX': '58',
+ '_SC_BC_SCALE_MAX': '59',
+ '_SC_BC_STRING_MAX': '60',
+ '_SC_CHILD_MAX': '1',
+ '_SC_CLK_TCK': '2',
+ '_SC_CLOCK_SELECTION': '61',
+ '_SC_COLL_WEIGHTS_MAX': '62',
+ '_SC_CPUTIME': '63',
+ '_SC_DELAYTIMER_MAX': '37',
+ '_SC_EXPR_NEST_MAX': '64',
+ '_SC_FSYNC': '22',
+ '_SC_GETGR_R_SIZE_MAX': '50',
+ '_SC_GETPW_R_SIZE_MAX': '51',
+ '_SC_HOST_NAME_MAX': '65',
'_SC_IOV_MAX': '66',
- 'S_IRGRP': '0000040',
- 'YESSTR': '54',
- 'HAVE_ALLOCA_H': '1',
- 'S_IFCHR': '0020000',
- '_POSIX_MEMLOCK': '1',
- '_SC_TRACE': '83',
- '_POSIX_INTERRUPT_CONTROL': '1',
- '_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS': '6',
- 'PTHREAD_SCOPE_PROCESS': '0',
- '__GNUC_VA_LIST': '1',
- 'HAVE_FABS': '1',
- '_CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS': '14',
- 'TLOSS': '5',
- '_TIME_T_': "<type 'long'>",
- 'DOMAIN': '1',
- 'HAVE_REALLOC': '1',
- 'HAVE_STRLEN': '1',
- '__IPHONEOS__': '1',
- '_POINTER_INT': "<type 'long'>",
- 'O_NOCTTY': '32768',
- 'PTHREAD_PRIO_INHERIT': '1',
- '_SC_THREAD_SPORADIC_SERVER': '81',
- 'O_ACCMODE': '3',
+ '_SC_IPV6': '67',
+ '_SC_JOB_CONTROL': '5',
'_SC_LINE_MAX': '68',
- 'D_T_FMT': '1',
- '_RAND48_SEED_1': '43981',
- '_RAND48_SEED_0': '13070',
- '_RAND48_SEED_2': '4660',
- 'HAVE_STRLCAT': '1',
- 'HAVE_SETJMP': '1',
- 'SDL_AUDIO_DRIVER_COREAUDIOIPHONE': '1',
- 'FOPEN': '-1',
- 'F_RGETLK': '10',
- 'F_DUPFD': '0',
- '_S_IFCHR': '0020000',
- 'SDL_IPHONE_KEYBOARD': '1',
- '_POSIX_IPV6': '200112',
- '_XOPEN_VERSION': '600',
- 'HAVE_FLOOR': '1',
- '_CS_XBS5_LP64_OFF64_LDFLAGS': '10',
- '_FNOCTTY': '32768',
- '_IFREG': '0100000',
- 'FP_SUBNORMAL': '3',
- 'SA_NOCLDSTOP': '1',
- 'HAVE_STDDEF_H': '1',
- 'NSIG': '32',
- 'HAVE__STRUPR': '1',
- 'SDL_THREAD_PTHREAD': '1',
- 'S_IWOTH': '0000002',
- 'SEEK_END': '2',
- 'SDL_ASSERT_LEVEL': '1',
- 'SI_ASYNCIO': '4',
- 'required_argument': '1',
- '_FWRITE': '2',
- 'SCHED_RR': '2',
- '_SC_2_FORT_DEV': '110',
- 'SA_NODEFER': '4',
- '_POSIX2_CHAR_TERM': '200112',
- 'F_SETLK': '8',
- 'SIGQUIT': '3',
- '_SC_ATEXIT_MAX': '55',
- '_POSIX_MEMLOCK_RANGE': '200112',
+ '_SC_LOGIN_NAME_MAX': '52',
+ '_SC_MAPPED_FILES': '23',
+ '_SC_MEMLOCK': '24',
+ '_SC_MEMLOCK_RANGE': '25',
+ '_SC_MEMORY_PROTECTION': '26',
+ '_SC_MESSAGE_PASSING': '27',
+ '_SC_MONOTONIC_CLOCK': '69',
+ '_SC_MQ_OPEN_MAX': '13',
+ '_SC_MQ_PRIO_MAX': '14',
+ '_SC_NGROUPS_MAX': '3',
+ '_SC_NPROCESSORS_CONF': '9',
+ '_SC_NPROCESSORS_ONLN': '10',
+ '_SC_OPEN_MAX': '4',
+ '_SC_PAGESIZE': '8',
+ '_SC_PAGE_SIZE': '8',
+ '_SC_PHYS_PAGES': '11',
+ '_SC_PRIORITIZED_IO': '28',
+ '_SC_PRIORITY_SCHEDULING': '101',
+ '_SC_RAW_SOCKETS': '70',
+ '_SC_READER_WRITER_LOCKS': '71',
+ '_SC_REALTIME_SIGNALS': '29',
+ '_SC_REGEXP': '72',
+ '_SC_RE_DUP_MAX': '73',
+ '_SC_RTSIG_MAX': '15',
'_SC_SAVED_IDS': '6',
- 'PTHREAD_INHERIT_SCHED': '1',
- 'SEEK_CUR': '1',
- 'S_IFLNK': '0120000',
- '_S_IREAD': '0000400',
- '_FOPEN': '-1',
- 'OVERFLOW': '3',
- '_POSIX_SHELL': '1',
- 'FMARK': '16',
- '_POSIX2_UPE': '200112',
- 'SDL_VIDEO_RENDER_OGL': '1',
- '_SC_2_PBS_TRACK': '118',
- '_POSIX_CPUTIME': '1',
+ '_SC_SEMAPHORES': '30',
+ '_SC_SEM_NSEMS_MAX': '16',
+ '_SC_SEM_VALUE_MAX': '17',
+ '_SC_SHARED_MEMORY_OBJECTS': '199',
+ '_SC_SHELL': '74',
+ '_SC_SIGQUEUE_MAX': '18',
+ '_SC_SPAWN': '75',
+ '_SC_SPIN_LOCKS': '76',
+ '_SC_SPORADIC_SERVER': '77',
+ '_SC_SS_REPL_MAX': '78',
+ '_SC_STREAM_MAX': '100',
+ '_SC_SYMLOOP_MAX': '79',
+ '_SC_SYNCHRONIZED_IO': '32',
+ '_SC_THREADS': '42',
+ '_SC_THREAD_ATTR_STACKADDR': '43',
+ '_SC_THREAD_ATTR_STACKSIZE': '44',
+ '_SC_THREAD_CPUTIME': '80',
+ '_SC_THREAD_DESTRUCTOR_ITERATIONS': '53',
+ '_SC_THREAD_KEYS_MAX': '38',
+ '_SC_THREAD_PRIORITY_SCHEDULING': '45',
+ '_SC_THREAD_PRIO_CEILING': '47',
+ '_SC_THREAD_PRIO_INHERIT': '46',
+ '_SC_THREAD_PRIO_PROTECT': '47',
'_SC_THREAD_PROCESS_SHARED': '48',
- '_SC_JOB_CONTROL': '5',
- '_O_RDONLY': '0',
- 'FNBIO': '4096',
- 'O_CLOEXEC': '262144',
- '_CS_XBS5_LP64_OFF64_LIBS': '11',
- '_PC_TIMESTAMP_RESOLUTION': '20',
- '_POSIX_READER_WRITER_LOCKS': '200112',
- 'ACCESSPERMS': '0000400',
- '_POSIX_PRIORITIZED_IO': '1',
- '_SC_IPV6': '67',
- 'SDL_VIDEO_OPENGL_WGL': '1',
- '_CS_XBS5_ILP32_OFFBIG_LINTFLAGS': '8',
- 'HAVE__STRICMP': '1',
- '_SC_ADVISORY_INFO': '54',
- 'SCHAR_MIN': '-128',
- '_SC_XOPEN_REALTIME_THREADS': '102',
- 'SIGEV_SIGNAL': '2',
- 'HAVE_NANOSLEEP': '1',
- 'O_WRONLY': '1',
- '_PC_SYMLINK_MAX': '14',
'_SC_THREAD_ROBUST_PRIO_INHERIT': '122',
- 'X_OK': '1',
- '_CS_XBS5_ILP32_OFF32_LDFLAGS': '2',
- 'SIGTERM': '15',
- '_SC_COLL_WEIGHTS_MAX': '62',
- '_CS_POSIX_V7_ILP32_OFF32_LDFLAGS': '2',
- 'NO_ARG': '0',
- '_CS_POSIX_V7_LP64_OFF64_CFLAGS': '9',
- 'S_IWRITE': '0000200',
- '_FEXLOCK': '256',
+ '_SC_THREAD_ROBUST_PRIO_PROTECT': '123',
+ '_SC_THREAD_SAFE_FUNCTIONS': '49',
+ '_SC_THREAD_SPORADIC_SERVER': '81',
+ '_SC_THREAD_STACK_MIN': '39',
+ '_SC_THREAD_THREADS_MAX': '40',
+ '_SC_TIMEOUTS': '82',
+ '_SC_TIMERS': '33',
+ '_SC_TIMER_MAX': '19',
+ '_SC_TRACE': '83',
+ '_SC_TRACE_EVENT_FILTER': '84',
+ '_SC_TRACE_EVENT_NAME_MAX': '85',
+ '_SC_TRACE_INHERIT': '86',
+ '_SC_TRACE_LOG': '87',
+ '_SC_TRACE_NAME_MAX': '88',
+ '_SC_TRACE_SYS_MAX': '89',
+ '_SC_TRACE_USER_EVENT_MAX': '90',
+ '_SC_TTY_NAME_MAX': '41',
+ '_SC_TYPED_MEMORY_OBJECTS': '91',
+ '_SC_TZNAME_MAX': '20',
+ '_SC_V6_ILP32_OFF32': '92',
+ '_SC_V6_ILP32_OFFBIG': '93',
+ '_SC_V6_LP64_OFF64': '94',
+ '_SC_V6_LPBIG_OFFBIG': '95',
+ '_SC_V7_ILP32_OFF32': '92',
+ '_SC_V7_ILP32_OFFBIG': '93',
+ '_SC_V7_LP64_OFF64': '94',
+ '_SC_V7_LPBIG_OFFBIG': '95',
+ '_SC_VERSION': '7',
+ '_SC_XBS5_ILP32_OFF32': '92',
+ '_SC_XBS5_ILP32_OFFBIG': '93',
+ '_SC_XBS5_LP64_OFF64': '94',
+ '_SC_XBS5_LPBIG_OFFBIG': '95',
+ '_SC_XOPEN_CRYPT': '96',
+ '_SC_XOPEN_ENH_I18N': '97',
+ '_SC_XOPEN_LEGACY': '98',
'_SC_XOPEN_REALTIME': '99',
- 'SIGPWR': '19',
- 'SDL_AUDIO_DRIVER_WINMM': '1',
- 'HAVE_STRCHR': '1',
- '_PC_PIPE_BUF': '5',
- 'SDL_HAPTIC_DINPUT': '1',
- 'SIGHUP': '1',
- 'F_GETOWN': '5',
- 'CLOCK_ALLOWED': '1',
- 'HAVE_MEMSET': '1',
- 'SIGUSR2': '31',
- '_SC_2_PBS_ACCOUNTING': '114',
- 'F_TEST': '3',
- 'HAVE_VSNPRINTF': '1',
- 'ITIMER_REAL': '0',
- 'HAVE_SNPRINTF': '1',
- 'HAVE_SYS_TYPES_H': '1',
- 'HAVE_COPYSIGN': '1',
- '_CLOCKS_PER_SEC_': '1000',
- 'SDL_HAPTIC_DUMMY': '1',
- 'SIGCONT': '19',
- 'NULL': '0',
- 'FSHLOCK': '128',
- 'STDOUT_FILENO': '1',
+ '_SC_XOPEN_REALTIME_THREADS': '102',
+ '_SC_XOPEN_SHM': '103',
+ '_SC_XOPEN_STREAMS': '104',
+ '_SC_XOPEN_UNIX': '105',
+ '_SC_XOPEN_UUCP': '124',
+ '_SC_XOPEN_VERSION': '106',
+ '_S_IEXEC': '0000100',
+ '_S_IFCHR': '0020000',
+ '_S_IFDIR': '0040000',
+ '_S_IFIFO': '0010000',
+ '_S_IFMT': '0170000',
+ '_S_IFREG': '0100000',
+ '_S_IREAD': '0000400',
+ '_S_IWRITE': '0000200',
+ '_TIME_T_': "<type 'long'>",
+ '_UNIX98_THREAD_MUTEX_ATTRIBUTES': '1',
+ '_XBS5_ILP32_OFF32': '-1',
+ '_XBS5_ILP32_OFFBIG': '1',
+ '_XBS5_LP64_OFF64': '-1',
+ '_XBS5_LPBIG_OFFBIG': '-1',
+ '_XOPEN_CRYPT': '1',
+ '_XOPEN_ENH_I18N': '1',
+ '_XOPEN_SHM': '1',
+ '_XOPEN_VERSION': '600',
'__AIX__': '1',
- 'SDL_JOYSTICK_IOKIT': '1',
- '_SC_THREAD_ATTR_STACKSIZE': '44',
- 'SIGIO': '23',
- 'HAVE_CEIL': '1',
- 'HAVE__STRLWR': '1',
- 'HAVE_SIGACTION': '1',
- '_SC_CPUTIME': '63',
- '_SC_2_VERSION': '121',
- '_O_BINARY': '65536',
+ '__ANDROID__': '1',
+ '__BEOS__': '1',
+ '__BSDI__': '1',
+ '__BUFSIZ__': '16',
+ '__DREAMCAST__': '1',
+ '__FILENAME_MAX__': '255',
+ '__FREEBSD__': '1',
+ '__GNUC_VA_LIST': '1',
+ '__HAIKU__': '1',
+ '__HPUX__': '1',
+ '__INT_MAX__': '2147483647',
+ '__IPHONEOS__': '1',
+ '__IRIX__': '1',
+ '__LARGE64_FILES': '1',
+ '__LINUX__': '1',
+ '__long_double_t': "<type 'long'>",
+ '__LONG_MAX__': '2147483647',
+ '__MACOSX__': '1',
+ '__NETBSD__': '1',
+ '__NINTENDODS__': '1',
+ '__OPENBSD__': '1',
+ '__OS2__': '1',
+ '__OSF__': '1',
+ '__QNXNTO__': '1',
+ '__RAND_MAX': '2147483647',
+ '__RISCOS__': '1',
+ '__SIGFIRSTNOTRT': '1',
+ '__SIGLASTNOTRT': '31',
+ '__SOLARIS__': '1',
+ '__USE_XOPEN2K': '1',
+ '__WIN32__': '1',
+ '___int16_t_defined': '1',
+ '___int32_t_defined': '1',
+ '___int64_t_defined': '1',
+ '___int8_t_defined': '1',
'___int_least16_t_defined': '1',
- '_FTEXT': '131072',
- '_POSIX2_SW_DEV': '200112',
- '_LARGEFILE64_SOURCE': '1',
- '_XOPEN_CRYPT': '1',
- 'FD_SETSIZE': '64',
- 'SDL_AUDIO_DRIVER_NDS': '1',
- '_FMARK': '16',
- '_SC_TYPED_MEMORY_OBJECTS': '91',
- '_SC_ASYNCHRONOUS_IO': '21',
- '_SC_2_CHAR_TERM': '107',
- '_SC_AIO_LISTIO_MAX': '34',
- 'FCREAT': '512',
- '_RAND48_ADD': '11',
- 'MAXPATHLEN': '1024',
- '_SC_BC_SCALE_MAX': '59',
- 'SDL_IPHONE_MAX_GFORCE': '5.0',
- 'MATH_ERREXCEPT': '2',
- 'SDL_VIDEO_DRIVER_WINDOWS': '1',
- '_CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS': '13',
- 'M_SQRT3': '1.73205080757',
- 'M_SQRT2': '1.41421356237',
- '_POSIX_THREADS': '200112',
- 'ABMON_12': '44',
- 'ABMON_11': '43',
- 'ABMON_10': '42',
- 'SI_QUEUE': '2',
- 'SDL_TIMER_UNIX': '1',
- 'AT_FDCWD': '-2',
- 'SIGTTOU': '22',
- '_CS_POSIX_V7_LP64_OFF64_LDFLAGS': '10',
- '_SC_TTY_NAME_MAX': '41',
- 'AF_INET': '2',
- 'AF_INET6': '6',
- 'PF_INET': '2',
- 'PF_INET6': '6',
- 'FIONREAD': '1',
- 'SOCK_STREAM': '200',
- 'SOCK_DGRAM': '20',
- 'IPPROTO_TCP': '1',
- 'IPPROTO_UDP': '2',
- 'EOF': '-1'
+ '___int_least32_t_defined': '1',
+ '___int_least8_t_defined': '1',
+ 'FMODE_READ': '0x1',
+ 'FMODE_WRITE': '0x2',
+ 'FMODE_LSEEK': '0x4',
+ 'FMODE_PREAD': '0x8',
+ 'FMODE_PWRITE': '0x10',
+ 'FMODE_EXEC': '0x20',
+ 'FMODE_NDELAY': '0x40',
+ 'FMODE_EXCL': '0x80',
+ 'FMODE_NOCMTIME': '0x800',
+ 'FMODE_RANDOM': '0x1000',
+ 'FMODE_UNSIGNED_OFFSET': '0x2000',
+ 'FMODE_PATH': '0x4000',
+ 'FMODE_NONOTIFY': '0x1000000',
+ 'S_IRWXUGO': '511',
+ 'S_IALLUGO': '4095',
+ 'S_IRUGO': '292',
+ 'S_IWUGO': '146',
+ 'S_IXUGO': '73',
+ 'LOOKUP_FOLLOW': '0x0001',
+ 'LOOKUP_DIRECTORY': '0x0002',
+ 'LOOKUP_PARENT': '0x0010',
+ 'MAP_SHARED': '0x01',
+ 'MAP_PRIVATE': '0x02',
+ 'MAP_TYPE': '0x0f',
+ 'MAP_FIXED': '0x100',
+ 'MAP_ANONYMOUS': '0x10',
+ 'O_NOFOLLOW': '0200000'
};
diff --git a/src/utility.js b/src/utility.js
index 9cc8d3a3..7d122cef 100644
--- a/src/utility.js
+++ b/src/utility.js
@@ -312,6 +312,12 @@ function setUnion(x, y) {
return ret;
}
+function setSize(x) {
+ var ret = 0;
+ for (var xx in x) ret++;
+ return ret;
+}
+
function invertArray(x) {
var ret = {};
for (var i = 0; i < x.length; i++) {