Skip to content

Instantly share code, notes, and snippets.

@mlogan
Created June 24, 2015 21:29
Show Gist options
  • Save mlogan/a6ef2383807231b9a94a to your computer and use it in GitHub Desktop.
Save mlogan/a6ef2383807231b9a94a to your computer and use it in GitHub Desktop.
emscripten crash
error: failure to process js library "library.js": XXX missing C define _SC_PHYS_PAGES!,,
original source:
=============
//"use strict";
// An implementation of a libc for the web. Basically, implementations of
// the various standard C libraries, that can be called from compiled code,
// and work using the actual JavaScript environment.
//
// We search the Library object when there is an external function. If the
// entry in the Library is a function, we insert it. If it is a string, we
// do another lookup in the library (a simple way to write a function once,
// if it can be called by different names). We also allow dependencies,
// using __deps. Initialization code to be run after allocating all
// global constants can be defined by __postset.
//
// Note that the full function name will be '_' + the name in the Library
// object. For convenience, the short name appears here. Note that if you add a
// new function with an '_', it will not be found.
// Memory allocated during startup, in postsets, should only be ALLOC_STATIC
LibraryManager.library = {
// keep this low in memory, because we flatten arrays with them in them
#if USE_PTHREADS
stdin: '; if (ENVIRONMENT_IS_PTHREAD) _stdin = PthreadWorkerInit._stdin; else PthreadWorkerInit._stdin = _stdin = allocate(1, "i32*", ALLOC_STATIC)',
stdout: '; if (ENVIRONMENT_IS_PTHREAD) _stdout = PthreadWorkerInit._stdout; else PthreadWorkerInit._stdout = _stdout = allocate(1, "i32*", ALLOC_STATIC)',
stderr: '; if (ENVIRONMENT_IS_PTHREAD) _stderr = PthreadWorkerInit._stderr; else PthreadWorkerInit._stderr = _stderr = allocate(1, "i32*", ALLOC_STATIC)',
_impure_ptr: '; if (ENVIRONMENT_IS_PTHREAD) __impure_ptr = PthreadWorkerInit.__impure_ptr; else PthreadWorkerInit.__impure_ptr __impure_ptr = allocate(1, "i32*", ALLOC_STATIC)',
__dso_handle: '; if (ENVIRONMENT_IS_PTHREAD) ___dso_handle = PthreadWorkerInit.___dso_handle; else PthreadWorkerInit.___dso_handle = ___dso_handle = allocate(1, "i32*", ALLOC_STATIC)',
#else
stdin: 'allocate(1, "i32*", ALLOC_STATIC)',
stdout: 'allocate(1, "i32*", ALLOC_STATIC)',
stderr: 'allocate(1, "i32*", ALLOC_STATIC)',
_impure_ptr: 'allocate(1, "i32*", ALLOC_STATIC)',
__dso_handle: 'allocate(1, "i32*", ALLOC_STATIC)',
#endif
$PROCINFO: {
// permissions
/*
uid: 0,
gid: 0,
euid: 0,
egid: 0,
suid: 0,
sgid: 0,
fsuid: 0,
fsgid: 0,
*/
// process identification
ppid: 1,
pid: 42,
sid: 42,
pgid: 42
},
// ==========================================================================
// dirent.h
// ==========================================================================
opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'open'],
opendir: function(dirname) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_OPENDIR') }}}, dirname);
#endif
// 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 = Pointer_stringify(dirname);
if (!path) {
___setErrNo(ERRNO_CODES.ENOENT);
return 0;
}
var node;
try {
var lookup = FS.lookupPath(path, { follow: true });
node = lookup.node;
} catch (e) {
FS.handleFSError(e);
return 0;
}
if (!FS.isDir(node.mode)) {
___setErrNo(ERRNO_CODES.ENOTDIR);
return 0;
}
var fd = _open(dirname, {{{ cDefine('O_RDONLY') }}}, allocate([0, 0, 0, 0], 'i32', ALLOC_STACK));
return fd === -1 ? 0 : FS.getPtrForStream(FS.getStream(fd));
},
closedir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'close', 'fileno'],
closedir: function(dirp) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_CLOSEDIR') }}}, dirp);
#endif
// int closedir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/closedir.html
var fd = _fileno(dirp);
var stream = FS.getStream(fd);
if (stream.currReading) stream.currReading = null;
return _close(fd);
},
telldir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
telldir: function(dirp) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_TELLDIR') }}}, dirp);
#endif
// long int telldir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/telldir.html
var stream = FS.getStreamFromPtr(dirp);
if (!stream || !FS.isDir(stream.node.mode)) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
return stream.position;
},
seekdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'lseek', 'fileno'],
seekdir: function(dirp, loc) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_SEEKDIR') }}}, dirp, loc);
#endif
// void seekdir(DIR *dirp, long int loc);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/seekdir.html
var fd = _fileno(dirp);
_lseek(fd, loc, {{{ cDefine('SEEK_SET') }}});
},
rewinddir__deps: ['seekdir'],
rewinddir: function(dirp) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_REWINDDIR') }}}, dirp);
#endif
// void rewinddir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/rewinddir.html
_seekdir(dirp, 0);
var stream = FS.getStreamFromPtr(dirp);
if (stream.currReading) stream.currReading = null;
},
readdir_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
readdir_r: function(dirp, entry, result) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_READDIR_R') }}}, dirp, entry, result);
#endif
// int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/readdir_r.html
var stream = FS.getStreamFromPtr(dirp);
if (!stream) {
return ___setErrNo(ERRNO_CODES.EBADF);
}
if (!stream.currReading) {
try {
// load the list of entries now, then readdir will traverse that list, to ignore changes to files
stream.currReading = FS.readdir(stream.path);
} catch (e) {
return FS.handleFSError(e);
}
}
if (stream.position < 0 || stream.position >= stream.currReading.length) {
{{{ makeSetValue('result', '0', '0', 'i8*') }}};
return 0;
}
var id;
var type;
var name = stream.currReading[stream.position++];
if (!name.indexOf('.')) {
id = 1;
type = 4;
} else {
try {
// child may have been removed since we started to read this directory
var child = FS.lookupNode(stream.node, name);
} catch (e) {
// skip to the next entry (not infinite since position is incremented until currReading.length)
return _readdir_r(dirp, entry, result);
}
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', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}};
{{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'stream.position', 'i32') }}};
{{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, C_STRUCTS.dirent.__size__, 'i32') }}};
for (var i = 0; i < name.length; i++) {
{{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}};
}
{{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}};
{{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}};
{{{ makeSetValue('result', '0', 'entry', 'i8*') }}};
return 0;
},
readdir__deps: ['readdir_r', '__setErrNo', '$ERRNO_CODES'],
readdir: function(dirp) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_READDIR') }}}, dirp);
#endif
// struct dirent *readdir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/readdir_r.html
var stream = FS.getStreamFromPtr(dirp);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
}
// TODO Is it supposed to be safe to execute multiple readdirs?
if (!_readdir.entry) _readdir.entry = _malloc({{{ C_STRUCTS.dirent.__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*') }}};
},
// ==========================================================================
// utime.h
// ==========================================================================
utime__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
utime: function(path, times) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_UTIME') }}}, path, times);
#endif
// int utime(const char *path, const struct utimbuf *times);
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/utime.h.html
var time;
if (times) {
// NOTE: We don't keep track of access timestamps.
var offset = {{{ C_STRUCTS.utimbuf.modtime }}};
time = {{{ makeGetValue('times', 'offset', 'i32') }}};
time *= 1000;
} else {
time = Date.now();
}
path = Pointer_stringify(path);
try {
FS.utime(path, time, time);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
utimes__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
utimes: function(path, times) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_UTIMES') }}}, path, times);
#endif
var time;
if (times) {
var offset = {{{ C_STRUCTS.timeval.__size__ }}} + {{{ C_STRUCTS.timeval.tv_sec }}};
time = {{{ makeGetValue('times', 'offset', 'i32') }}} * 1000;
offset = {{{ C_STRUCTS.timeval.__size__ }}} + {{{ C_STRUCTS.timeval.tv_usec }}};
time += {{{ makeGetValue('times', 'offset', 'i32') }}} / 1000;
} else {
time = Date.now();
}
path = Pointer_stringify(path);
try {
FS.utime(path, time, time);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
// ==========================================================================
// libgen.h
// ==========================================================================
__libgenSplitName: function(path) {
if (path === 0 || {{{ makeGetValue('path', 0, 'i8') }}} === 0) {
// Null or empty results in '.'.
var me = ___libgenSplitName;
if (!me.ret) {
me.ret = allocate([{{{ charCode('.') }}}, 0], 'i8', ALLOC_NORMAL);
}
return [me.ret, -1];
} else {
var slash = {{{ charCode('/') }}};
var allSlashes = true;
var slashPositions = [];
for (var i = 0; {{{ makeGetValue('path', 'i', 'i8') }}} !== 0; i++) {
if ({{{ makeGetValue('path', 'i', 'i8') }}} === slash) {
slashPositions.push(i);
} else {
allSlashes = false;
}
}
var length = i;
if (allSlashes) {
// All slashes result in a single slash.
{{{ makeSetValue('path', '1', '0', 'i8') }}};
return [path, -1];
} else {
// Strip trailing slashes.
while (slashPositions.length &&
slashPositions[slashPositions.length - 1] == length - 1) {
{{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}};
length--;
}
return [path, slashPositions.pop()];
}
}
},
basename__deps: ['__libgenSplitName'],
basename: function(path) {
// char *basename(char *path);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/basename.html
var result = ___libgenSplitName(path);
return result[0] + result[1] + 1;
},
dirname__deps: ['__libgenSplitName'],
dirname: function(path) {
// char *dirname(char *path);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/dirname.html
var result = ___libgenSplitName(path);
if (result[1] == 0) {
{{{ makeSetValue('result[0]', 1, '0', 'i8') }}};
} else if (result[1] !== -1) {
{{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}};
}
return result[0];
},
// ==========================================================================
// sys/stat.h
// ==========================================================================
stat__deps: ['$FS'],
stat: function(path, buf, dontResolveLastLink) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_STAT') }}}, path, buf, dontResolveLastLink);
#endif
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
// int stat(const char *path, struct stat *buf);
// NOTE: dontResolveLastLink is a shortcut for lstat(). It should never be
// used in client code.
path = typeof path !== 'string' ? Pointer_stringify(path) : path;
try {
var stat = dontResolveLastLink ? FS.lstat(path) : FS.stat(path);
{{{ makeSetValue('buf', C_STRUCTS.stat.st_dev, 'stat.dev', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_dev_padding, '0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_ino_truncated, 'stat.ino', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_rdev_padding, '0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, '(stat.atime.getTime() / 1000)|0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, '(stat.mtime.getTime() / 1000)|0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, '(stat.ctime.getTime() / 1000)|0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}};
return 0;
} catch (e) {
if (e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) {
// an error occurred while trying to look up the path; we should just report ENOTDIR
e.setErrno(ERRNO_CODES.ENOTDIR);
}
FS.handleFSError(e);
return -1;
}
},
lstat__deps: ['stat'],
lstat: function(path, buf) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_LSTAT') }}}, path, buf);
#endif
// int lstat(const char *path, struct stat *buf);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/lstat.html
return _stat(path, buf, true);
},
fstat__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'stat'],
fstat: function(fildes, buf) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FSTAT') }}}, fildes, buf);
#endif
// int fstat(int fildes, struct stat *buf);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fstat.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
return _stat(stream.path, buf);
},
mknod__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
mknod: function(path, mode, dev) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_MKNOD') }}}, path, mode, dev);
#endif
// int mknod(const char *path, mode_t mode, dev_t dev);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mknod.html
path = Pointer_stringify(path);
// we don't want this in the JS API as the JS API
// uses mknod to create all nodes.
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') }}}:
break;
default:
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
try {
FS.mknod(path, mode, dev);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
mkdir__deps: ['mknod'],
mkdir: function(path, mode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_MKDIR') }}}, path, mode);
#endif
// int mkdir(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkdir.html
path = Pointer_stringify(path);
// remove a trailing slash, if one - /a/b/ has basename of '', but
// we want to create b in the context of this function
path = PATH.normalize(path);
if (path[path.length-1] === '/') path = path.substr(0, path.length-1);
try {
FS.mkdir(path, mode, 0);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
mkfifo__deps: ['__setErrNo', '$ERRNO_CODES'],
mkfifo: function(path, mode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_MKFIFO') }}}, path, mode);
#endif
// int mkfifo(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkfifo.html
// NOTE: We support running only a single process, and named pipes require
// blocking, which we can't provide. The error code is not very
// accurate, but it's the closest among those allowed in the standard
// and unlikely to result in retries.
___setErrNo(ERRNO_CODES.EROFS);
return -1;
},
chmod__deps: ['$FS', '__setErrNo'],
chmod: function(path, mode, dontResolveLastLink) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_CHMOD') }}}, path, mode, dontResolveLastLink);
#endif
// 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;
try {
FS.chmod(path, mode);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
fchmod__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'chmod'],
fchmod: function(fildes, mode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FCHMOD') }}}, fildes, mode);
#endif
// int fchmod(int fildes, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fchmod.html
try {
FS.fchmod(fildes, mode);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
lchmod__deps: ['chmod'],
lchmod: function(path, mode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_LCHMOD') }}}, path, mode);
#endif
path = Pointer_stringify(path);
try {
FS.lchmod(path, mode);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
umask__deps: ['$FS'],
umask: function(newMask) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_UMASK') }}}, newMask);
#endif
// mode_t umask(mode_t cmask);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/umask.html
// NOTE: This value isn't actually used for anything.
if (_umask.cmask === undefined) _umask.cmask = 0x1FF; // S_IRWXU | S_IRWXG | S_IRWXO.
var oldMask = _umask.cmask;
_umask.cmask = newMask;
return oldMask;
},
// ==========================================================================
// sys/statvfs.h
// ==========================================================================
statvfs__deps: ['$FS'],
statvfs: function(path, buf) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_STATVFS') }}}, path, buf);
#endif
// http://pubs.opengroup.org/onlinepubs/009695399/functions/statvfs.html
// int statvfs(const char *restrict path, struct statvfs *restrict buf);
// NOTE: None of the constants here are true. We're just returning safe and
// sane values.
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}}; // ST_NOSUID
{{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}};
return 0;
},
fstatvfs__deps: ['statvfs'],
fstatvfs: function(fildes, buf) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FSTATVFS') }}}, fildes, buf);
#endif
// int fstatvfs(int fildes, struct statvfs *buf);
// http://pubs.opengroup.org/onlinepubs/009604499/functions/statvfs.html
return _statvfs(0, buf);
},
// ==========================================================================
// fcntl.h
// ==========================================================================
open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
open: function(path, oflag, varargs) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_OPEN') }}}, path, oflag, varargs);
#endif
// int open(const char *path, int oflag, ...);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
var mode = {{{ makeGetValue('varargs', 0, 'i32') }}};
path = Pointer_stringify(path);
try {
var stream = FS.open(path, oflag, mode);
return stream.fd;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
creat__deps: ['open'],
creat: function(path, mode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_CREAT') }}}, path, mode);
#endif
// int creat(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/creat.html
return _open(path, {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_TRUNC') }}}, allocate([mode, 0, 0, 0], 'i32', ALLOC_STACK));
},
mktemp: function(template) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_MKTEMP') }}}, template);
#endif
if (!_mktemp.counter) _mktemp.counter = 0;
var c = (_mktemp.counter++).toString();
var rep = 'XXXXXX';
while (c.length < rep.length) c = '0' + c;
writeArrayToMemory(intArrayFromString(c), template + Pointer_stringify(template).indexOf(rep));
return template;
},
mkstemp__deps: ['creat', 'mktemp'],
mkstemp: function(template) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_MKSTEMP') }}}, template);
#endif
return _creat(_mktemp(template), 0600);
},
mkdtemp__deps: ['mktemp', 'mkdir'],
mkdtemp: function(template) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_MKDTEMP') }}}, template);
#endif
template = _mktemp(template);
return (_mkdir(template, 0700) === 0) ? template : 0;
},
fcntl__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
fcntl: function(fildes, cmd, varargs, dup2) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_FCNTL') }}}, fildes, cmd, varargs, dup2);
#endif
// int fcntl(int fildes, int cmd, ...);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/fcntl.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
switch (cmd) {
case {{{ cDefine('F_DUPFD') }}}:
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
if (arg < 0) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
var newStream;
try {
newStream = FS.open(stream.path, stream.flags, 0, arg);
} catch (e) {
FS.handleFSError(e);
return -1;
}
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') }}}:
return stream.flags;
case {{{ cDefine('F_SETFL') }}}:
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
stream.flags |= arg;
return 0;
case {{{ cDefine('F_GETLK') }}}:
case {{{ cDefine('F_GETLK64') }}}:
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
var offset = {{{ C_STRUCTS.flock.l_type }}};
// We're always unlocked.
{{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}};
return 0;
case {{{ cDefine('F_SETLK') }}}:
case {{{ cDefine('F_SETLKW') }}}:
case {{{ cDefine('F_SETLK64') }}}:
case {{{ cDefine('F_SETLKW64') }}}:
// Pretend that the locking is successful.
return 0;
case {{{ cDefine('F_SETOWN') }}}:
case {{{ cDefine('F_GETOWN') }}}:
// These are for sockets. We don't have them fully implemented yet.
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
default:
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
// Should never be reached. Only to silence strict warnings.
return -1;
},
posix_fadvise: function(fd, offset, len, advice) {
// int posix_fadvise(int fd, off_t offset, off_t len, int advice);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fadvise.html
// Advise as much as you wish. We don't care.
return 0;
},
posix_madvise: function(){ return 0 }, // ditto as fadvise
posix_fallocate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
posix_fallocate: function(fd, offset, len) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_POSIX_FALLOCATE') }}}, fd, offset, len);
#endif
// int posix_fallocate(int fd, off_t offset, off_t len);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate.html
var stream = FS.getStream(fd);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
FS.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;
},
// ==========================================================================
// nl_types.h
// ==========================================================================
catopen: function(name, oflag) {
// nl_catd catopen (const char *name, int oflag)
return -1;
},
catgets: function(catd, set_id, msg_id, s) {
// char *catgets (nl_catd catd, int set_id, int msg_id, const char *s)
return s;
},
catclose: function(catd) {
// int catclose (nl_catd catd)
return 0;
},
// ==========================================================================
// poll.h
// ==========================================================================
__DEFAULT_POLLMASK: {{{ cDefine('POLLIN') }}} | {{{ cDefine('POLLOUT') }}},
poll__deps: ['$FS', '__DEFAULT_POLLMASK'],
poll: function(fds, nfds, timeout) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_POLL') }}}, fds, nfds, timeout);
#endif
// int poll(struct pollfd fds[], nfds_t nfds, int timeout);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/poll.html
var nonzero = 0;
for (var i = 0; i < nfds; i++) {
var pollfd = fds + {{{ C_STRUCTS.pollfd.__size__ }}} * i;
var fd = {{{ makeGetValue('pollfd', C_STRUCTS.pollfd.fd, 'i32') }}};
var events = {{{ makeGetValue('pollfd', C_STRUCTS.pollfd.events, 'i16') }}};
var mask = {{{ cDefine('POLLNVAL') }}};
var stream = FS.getStream(fd);
if (stream) {
mask = ___DEFAULT_POLLMASK;
if (stream.stream_ops.poll) {
mask = stream.stream_ops.poll(stream);
}
}
mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}};
if (mask) nonzero++;
{{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}};
}
return nonzero;
},
// ==========================================================================
// unistd.h
// ==========================================================================
access__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
access: function(path, amode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_ACCESS') }}}, path, amode);
#endif
// int access(const char *path, int amode);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/access.html
path = Pointer_stringify(path);
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;
}
return 0;
},
chdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
chdir: function(path) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_CHDIR') }}}, path);
#endif
// int chdir(const char *path);
// 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);
try {
FS.chdir(path);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
chown__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
chown: function(path, owner, group, dontResolveLastLink) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_CHOWN') }}}, path, owner, group, dontResolveLastLink);
#endif
// int chown(const char *path, uid_t owner, gid_t group);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/chown.html
// We don't support multiple users, so changing ownership makes no sense.
// NOTE: The path argument may be a string, to simplify fchown().
// NOTE: dontResolveLastLink is a shortcut for lchown(). It should never be
// used in client code.
if (typeof path !== 'string') path = Pointer_stringify(path);
try {
FS.chown(path, owner, group);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
chroot__deps: ['__setErrNo', '$ERRNO_CODES'],
chroot: function(path) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_CHROOT') }}}, path);
#endif
// int chroot(const char *path);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/chroot.html
___setErrNo(ERRNO_CODES.EACCES);
return -1;
},
close__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
close: function(fildes) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_CLOSE') }}}, fildes);
#endif
// int close(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/close.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
FS.close(stream);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
dup__deps: ['fcntl'],
dup: function(fildes) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_DUP') }}}, fildes);
#endif
// int dup(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/dup.html
return _fcntl(fildes, 0, allocate([0, 0, 0, 0], 'i32', ALLOC_STACK)); // F_DUPFD.
},
dup2__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'fcntl', 'close'],
dup2: function(fildes, fildes2) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_DUP2') }}}, fildes, fildes2);
#endif
// 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 && stream) {
return fildes;
} else {
_close(fildes2);
try {
var stream2 = FS.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) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_FCHOWN') }}}, fildes, owner, group);
#endif
// int fchown(int fildes, uid_t owner, gid_t group);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fchown.html
try {
FS.fchown(fildes, owner, group);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
fchdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'chdir'],
fchdir: function(fildes) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FCHDIR') }}}, fildes);
#endif
// int fchdir(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fchdir.html
var stream = FS.getStream(fildes);
if (stream) {
return _chdir(stream.path);
} else {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
},
ctermid__deps: ['strcpy'],
ctermid: function(s) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_CTERMID') }}}, s);
#endif
// char *ctermid(char *s);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ctermid.html
if (!_ctermid.ret) {
var arr = intArrayFromString('/dev/tty');
_ctermid.ret = allocate(arr, 'i8', ALLOC_NORMAL);
}
return s ? _strcpy(s, _ctermid.ret) : _ctermid.ret;
},
crypt: function(key, salt) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_CRYPT') }}}, key, salt);
#endif
// char *(const char *, const char *);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/crypt.html
// TODO: Implement (probably compile from C).
___setErrNo(ERRNO_CODES.ENOSYS);
#if ASSERTIONS
Runtime.warnOnce('crypt() returning an error as we do not support it');
#endif
return 0;
},
encrypt: function(block, edflag) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_ENCRYPT') }}}, block, edflag);
#endif
// void encrypt(char block[64], int edflag);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/encrypt.html
// TODO: Implement (probably compile from C).
#if ASSERTIONS
Runtime.warnOnce('encrypt() returning an error as we do not support it');
#endif
___setErrNo(ERRNO_CODES.ENOSYS);
},
fpathconf__deps: ['__setErrNo', '$ERRNO_CODES'],
fpathconf: function(fildes, name) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FPATHCONF') }}}, fildes, name);
#endif
// long fpathconf(int fildes, int name);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/encrypt.html
// NOTE: The first parameter is ignored, so pathconf == fpathconf.
// The constants here aren't real values. Just mimicking glibc.
switch (name) {
case {{{ cDefine('_PC_LINK_MAX') }}}:
return 32000;
case {{{ cDefine('_PC_MAX_CANON') }}}:
case {{{ cDefine('_PC_MAX_INPUT') }}}:
case {{{ cDefine('_PC_NAME_MAX') }}}:
return 255;
case {{{ cDefine('_PC_PATH_MAX') }}}:
case {{{ cDefine('_PC_PIPE_BUF') }}}:
case {{{ cDefine('_PC_REC_MIN_XFER_SIZE') }}}:
case {{{ cDefine('_PC_REC_XFER_ALIGN') }}}:
case {{{ cDefine('_PC_ALLOC_SIZE_MIN') }}}:
return 4096;
case {{{ cDefine('_PC_CHOWN_RESTRICTED') }}}:
case {{{ cDefine('_PC_NO_TRUNC') }}}:
case {{{ cDefine('_PC_2_SYMLINKS') }}}:
return 1;
case {{{ cDefine('_PC_VDISABLE') }}}:
return 0;
case {{{ cDefine('_PC_SYNC_IO') }}}:
case {{{ cDefine('_PC_ASYNC_IO') }}}:
case {{{ cDefine('_PC_PRIO_IO') }}}:
case {{{ cDefine('_PC_SOCK_MAXBUF') }}}:
case {{{ cDefine('_PC_REC_INCR_XFER_SIZE') }}}:
case {{{ cDefine('_PC_REC_MAX_XFER_SIZE') }}}:
case {{{ cDefine('_PC_SYMLINK_MAX') }}}:
return -1;
case {{{ cDefine('_PC_FILESIZEBITS') }}}:
return 64;
}
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
},
pathconf: 'fpathconf',
#if EMTERPRETIFY_ASYNC
fsync__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '$EmterpreterAsync'],
fsync: function(fildes) {
return EmterpreterAsync.handle(function(resume) {
// int fsync(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fsync.html
var stream = FS.getStream(fildes);
if (stream) {
var mount = stream.node.mount;
if (!mount.type.syncfs) {
// We write directly to the file system, so there's nothing to do here.
resume(function() { return 0 });
return;
}
mount.type.syncfs(mount, false, function(err) {
if (err) {
___setErrNo(ERRNO_CODES.EIO);
resume(function() { return -1 });
return;
}
resume(function() { return 0 });
});
} else {
___setErrNo(ERRNO_CODES.EBADF);
resume(function() { return -1 });
}
});
},
#else
fsync__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
fsync: function(fildes) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FSYNC') }}}, fildes);
#endif
// int fsync(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fsync.html
var stream = FS.getStream(fildes);
if (stream) {
// We write directly to the file system, so there's nothing to do here.
return 0;
} else {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
},
#endif // EMTERPRETIFY_ASYNC
fdatasync: 'fsync',
truncate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
truncate: function(path, length) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_TRUNCATE') }}}, path, length);
#endif
// 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 (typeof path !== 'string') path = Pointer_stringify(path);
try {
FS.truncate(path, length);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
ftruncate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'truncate'],
ftruncate: function(fildes, length) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FTRUNCATE') }}}, fildes, length);
#endif
// int ftruncate(int fildes, off_t length);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ftruncate.html
try {
FS.ftruncate(fildes, length);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
getcwd__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
getcwd: function(buf, size) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_GETCWD') }}}, buf, size);
#endif
// char *getcwd(char *buf, size_t size);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getcwd.html
if (size == 0) {
___setErrNo(ERRNO_CODES.EINVAL);
return 0;
}
var cwd = FS.cwd();
if (size < cwd.length + 1) {
___setErrNo(ERRNO_CODES.ERANGE);
return 0;
} else {
writeAsciiToMemory(cwd, buf);
return buf;
}
},
isatty__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
isatty: function(fildes) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_ISATTY') }}}, fildes);
#endif
// int isatty(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/isatty.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
}
// HACK - implement tcgetattr
if (!stream.tty) {
___setErrNo(ERRNO_CODES.ENOTTY);
return 0;
}
return 1;
},
lchown__deps: ['chown'],
lchown: function(path, owner, group) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_LCHOWN') }}}, path, owner, group);
#endif
// int lchown(const char *path, uid_t owner, gid_t group);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/lchown.html
return _chown(path, owner, group, true);
},
link__deps: ['__setErrNo', '$ERRNO_CODES'],
link: function(path1, path2) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_LINK') }}}, path1, path2);
#endif
// int link(const char *path1, const char *path2);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/link.html
// We don't support hard links.
___setErrNo(ERRNO_CODES.EMLINK);
return -1;
},
lockf__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
lockf: function(fildes, func, size) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_LOCKF') }}}, fildes, func, size);
#endif
// int lockf(int fildes, int function, off_t size);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/lockf.html
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;
} else {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
},
lseek__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
lseek: function(fildes, offset, whence) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_LSEEK') }}}, fildes, offset, whence);
#endif
// off_t lseek(int fildes, off_t offset, int whence);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/lseek.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
return FS.llseek(stream, offset, whence);
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
pipe__deps: ['__setErrNo', '$ERRNO_CODES'],
pipe: function(fildes) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_PIPE') }}}, fildes);
#endif
// int pipe(int fildes[2]);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/pipe.html
// It is possible to implement this using two device streams, but pipes make
// little sense in a single-threaded environment, so we do not support them.
___setErrNo(ERRNO_CODES.ENOSYS);
#if ASSERTIONS
Runtime.warnOnce('pipe() returning an error as we do not support them');
#endif
return -1;
},
pread__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
pread: function(fildes, buf, nbyte, offset) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_PREAD') }}}, fildes, buf, nbyte, offset);
#endif
// 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.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
return FS.read(stream, slab, buf, nbyte, offset);
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
read__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'recv', 'pread'],
read: function(fildes, buf, nbyte) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_READ') }}}, fildes, buf, nbyte);
#endif
// ssize_t read(int fildes, void *buf, size_t nbyte);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
#if SOCKET_WEBRTC
if (stream && ('socket' in stream)) {
return _recv(fildes, buf, nbyte, 0);
}
#endif
try {
var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
return FS.read(stream, slab, buf, nbyte);
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
sync: function() {
// void sync(void);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/sync.html
// All our writing is already synchronized. This is a no-op.
},
rmdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
rmdir: function(path) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_RMDIR') }}}, path);
#endif
// int rmdir(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html
path = Pointer_stringify(path);
try {
FS.rmdir(path);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
unlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
unlink: function(path) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_UNLINK') }}}, path);
#endif
// int unlink(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html
path = Pointer_stringify(path);
try {
FS.unlink(path);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
ttyname__deps: ['ttyname_r'],
ttyname: function(fildes) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_TTYNAME') }}}, fildes);
#endif
// char *ttyname(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ttyname.html
if (!_ttyname.ret) _ttyname.ret = _malloc(256);
return _ttyname_r(fildes, _ttyname.ret, 256) ? 0 : _ttyname.ret;
},
ttyname_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'isatty'],
ttyname_r: function(fildes, name, namesize) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_TTYNAME_R') }}}, fildes, name, namesize);
#endif
// int ttyname_r(int fildes, char *name, size_t namesize);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ttyname.html
var stream = FS.getStream(fildes);
var ttyname = '/dev/tty';
if (!stream) {
return ___setErrNo(ERRNO_CODES.EBADF);
} else if (!_isatty(fildes)) {
return ___setErrNo(ERRNO_CODES.ENOTTY);
} else if (namesize < ttyname.length + 1) {
return ___setErrNo(ERRNO_CODES.ERANGE);
}
writeStringToMemory(ttyname, name);
return 0;
},
symlink__deps: ['$FS', '$PATH', '__setErrNo', '$ERRNO_CODES'],
symlink: function(path1, path2) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_SYMLINK') }}}, path1, path2);
#endif
// int symlink(const char *path1, const char *path2);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/symlink.html
path1 = Pointer_stringify(path1);
path2 = Pointer_stringify(path2);
try {
FS.symlink(path1, path2);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
readlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
readlink: function(path, buf, bufsize) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_READLINK') }}}, path, buf, bufsize);
#endif
// ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/readlink.html
path = Pointer_stringify(path);
var str;
try {
str = FS.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) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_PWRITE') }}}, fildes, buf, nbyte, offset);
#endif
// 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.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
return FS.write(stream, slab, buf, nbyte, offset);
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
write__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'send', 'pwrite'],
write: function(fildes, buf, nbyte) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_WRITE') }}}, fildes, buf, nbyte);
#endif
// ssize_t write(int fildes, const void *buf, size_t nbyte);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
#if SOCKET_WEBRTC
if (stream && ('socket' in stream)) {
return _send(fildes, buf, nbyte, 0);
}
#endif
try {
var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
return FS.write(stream, slab, buf, nbyte);
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
confstr__deps: ['__setErrNo', '$ERRNO_CODES', '$ENV'],
confstr: function(name, buf, len) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_CONFSTR') }}}, name, buf, len);
#endif
// size_t confstr(int name, char *buf, size_t len);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/confstr.html
var value;
switch (name) {
case {{{ cDefine('_CS_PATH') }}}:
value = ENV['PATH'] || '/';
break;
case {{{ cDefine('_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS') }}}:
// Mimicking glibc.
value = 'POSIX_V6_ILP32_OFF32\nPOSIX_V6_ILP32_OFFBIG';
break;
case {{{ cDefine('_CS_GNU_LIBC_VERSION') }}}:
// This JS implementation was tested against this glibc version.
value = 'glibc 2.14';
break;
case {{{ cDefine('_CS_GNU_LIBPTHREAD_VERSION') }}}:
// We don't support pthreads.
value = '';
break;
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFF32_LIBS') }}}:
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFFBIG_LIBS') }}}:
case {{{ cDefine('_CS_POSIX_V6_LP64_OFF64_CFLAGS') }}}:
case {{{ cDefine('_CS_POSIX_V6_LP64_OFF64_LDFLAGS') }}}:
case {{{ cDefine('_CS_POSIX_V6_LP64_OFF64_LIBS') }}}:
case {{{ cDefine('_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS') }}}:
case {{{ cDefine('_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS') }}}:
case {{{ cDefine('_CS_POSIX_V6_LPBIG_OFFBIG_LIBS') }}}:
value = '';
break;
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFF32_CFLAGS') }}}:
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFF32_LDFLAGS') }}}:
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS') }}}:
value = '-m32';
break;
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS') }}}:
value = '-m32 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64';
break;
default:
___setErrNo(ERRNO_CODES.EINVAL);
return 0;
}
if (len == 0 || buf == 0) {
return value.length + 1;
} else {
var length = Math.min(len, value.length);
for (var i = 0; i < length; i++) {
{{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}};
}
if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}};
return i;
}
},
execl__deps: ['__setErrNo', '$ERRNO_CODES'],
execl: function(/* ... */) {
// int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html
// We don't support executing external code.
___setErrNo(ERRNO_CODES.ENOEXEC);
return -1;
},
execle: 'execl',
execlp: 'execl',
execv: 'execl',
execve: 'execl',
execvp: 'execl',
_exit: function(status) {
// void _exit(int status);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
Module['exit'](status);
},
fork__deps: ['__setErrNo', '$ERRNO_CODES'],
fork: function() {
// pid_t fork(void);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fork.html
// We don't support multiple processes.
___setErrNo(ERRNO_CODES.EAGAIN);
return -1;
},
vfork: 'fork',
getpid__deps: ['$PROCINFO'],
getpid: function() { return PROCINFO.pid; },
getppid__deps: ['$PROCINFO'],
getppid: function() { return PROCINFO.ppid; },
getpgrp__deps: ['$PROCINFO'],
getpgrp: function() { return PROCINFO.pgid; },
setpgrp: function() { return 0; },
getsid__deps: ['__setErrNo', '$ERRNO_CODES', '$PROCINFO'],
getsid: function(pid) {
if (pid && pid != PROCINFO.pid) {
___setErrNo(ERRNO_CODES.ESRCH);
return -1;
}
return PROCINFO.sid;
},
setsid: function() { return 0; },
getpgid__deps: ['__setErrNo', '$ERRNO_CODES', '$PROCINFO'],
getpgid: function(pid) {
if (pid && pid != PROCINFO.pid) {
___setErrNo(ERRNO_CODES.ESRCH);
return -1;
}
return PROCINFO.pgid;
},
setpgid__deps: ['__setErrNo', '$ERRNO_CODES', '$PROCINFO'],
setpgid: function(pid, pgid) {
if (pid && pid != PROCINFO.pid) {
___setErrNo(ERRNO_CODES.ESRCH);
return -1;
}
if (pgid != PROCINFO.pgid) {
___setErrNo(ERRNO_CODES.EPERM);
return -1;
}
return 0; // TODO: call setpgrp()
},
tcgetpgrp__deps: ['$PROCINFO'],
tcgetpgrp: function(fildes) {
// TODO: check that filedes is terminal
return PROCINFO.pgid;
},
tcsetpgrp__deps: ['__setErrNo', '$ERRNO_CODES', '$PROCINFO'],
tcsetpgrp: function(fildes, pgid_id) {
// TODO: check that filedes is terminal
if (pgid_id != PROCINFO.pgid) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
return 0;
},
getuid: function() { return 0; },
setuid__deps: ['__setErrNo', '$ERRNO_CODES'],
setuid: function(uid) {
if (uid != 0) {
___setErrNo(ERRNO_CODES.EPERM);
return -1;
}
return 0;
},
getegid: 'getgid',
setegid: 'setgid',
getgid: 'getuid',
setgid: 'setuid',
geteuid: 'getuid',
seteuid: 'setuid',
// NOTE: These do not match the signatures, but they all use the same stub.
setregid: 'setgid',
setreuid: 'setuid',
getresuid: function(ruid, euid, suid) {
{{{ makeSetValue('ruid', '0', '0', 'i32') }}};
{{{ makeSetValue('euid', '0', '0', 'i32') }}};
{{{ makeSetValue('suid', '0', '0', 'i32') }}};
return 0;
},
getresgid: 'getresuid',
// NOTE: These do not match the signatures, but they all use the same stub.
setresuid: 'setuid',
setresgid: 'setgid',
getgroups__deps: ['__setErrNo', '$ERRNO_CODES'],
getgroups: function(gidsetsize, grouplist) {
// int getgroups(int gidsetsize, gid_t grouplist[]);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getgroups.html
if (gidsetsize < 1) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
} else {
{{{ makeSetValue('grouplist', '0', '0', 'i32') }}};
return 1;
}
},
// TODO: Implement initgroups (grp.h).
setgroups__deps: ['__setErrNo', '$ERRNO_CODES', 'sysconf'],
setgroups: function(ngroups, gidset) {
// int setgroups(int ngroups, const gid_t *gidset);
// https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/setgroups.2.html
if (ngroups < 1 || ngroups > _sysconf({{{ cDefine('_SC_NGROUPS_MAX') }}})) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
} else {
// We have just one process/user/group, so it makes no sense to set groups.
___setErrNo(ERRNO_CODES.EPERM);
return -1;
}
},
gethostid: function() {
// long gethostid(void);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/gethostid.html
return 42;
},
gethostname__deps: ['__setErrNo', '$ERRNO_CODES'],
gethostname: function(name, namelen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_GETHOSTNAME') }}}, name, namelen);
#endif
// int gethostname(char *name, size_t namelen);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/gethostname.html
var host = 'emscripten';
if (typeof window !== 'undefined' && window.location.host) {
host = window.location.host;
}
var length = Math.min(namelen, host.length);
for (var i = 0; i < length; i++) {
{{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}};
}
if (namelen > length) {
{{{ makeSetValue('name', 'i', '0', 'i8') }}};
return 0;
} else {
___setErrNo(ERRNO_CODES.ENAMETOOLONG);
return -1;
}
},
getlogin__deps: ['getlogin_r'],
getlogin: function() {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_0({{{ cDefine('EM_PROXIED_GETLOGIN') }}});
#endif
// char *getlogin(void);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getlogin.html
if (!_getlogin.ret) _getlogin.ret = _malloc(8);
return _getlogin_r(_getlogin.ret, 8) ? 0 : _getlogin.ret;
},
getlogin_r__deps: ['__setErrNo', '$ERRNO_CODES'],
getlogin_r: function(name, namesize) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_GETLOGIN_R') }}}, name, namesize);
#endif
// int getlogin_r(char *name, size_t namesize);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getlogin.html
var ret = 'root';
if (namesize < ret.length + 1) {
return ___setErrNo(ERRNO_CODES.ERANGE);
} else {
writeAsciiToMemory(ret, name);
return 0;
}
},
getpagesize: function() {
// int getpagesize(void);
return PAGE_SIZE;
},
getopt: function(argc, argv, optstring) {
// int getopt(int argc, char * const argv[], const char *optstring);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html
// TODO: Implement (probably compile from C).
return -1;
},
nice__deps: ['__setErrNo', '$ERRNO_CODES'],
nice: function(incr) {
// int nice(int incr);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/nice.html
// Niceness makes no sense in a single-process environment.
___setErrNo(ERRNO_CODES.EPERM);
return 0;
},
sleep__deps: ['usleep'],
sleep: function(seconds) {
// unsigned sleep(unsigned seconds);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/sleep.html
return _usleep(seconds * 1e6);
},
swab: function(src, dest, nbytes) {
// void swab(const void *restrict src, void *restrict dest, ssize_t nbytes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/swab.html
if (nbytes < 0) return;
nbytes -= nbytes % 2;
for (var i = 0; i < nbytes; i += 2) {
var first = {{{ makeGetValue('src', 'i', 'i8') }}};
var second = {{{ makeGetValue('src', 'i + 1', 'i8') }}};
{{{ makeSetValue('dest', 'i', 'second', 'i8') }}};
{{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}};
}
},
tcgetpgrp: function(fildes) {
// pid_t tcgetpgrp(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tcgetpgrp.html
// Our only process always runs with group ID 0.
return 0;
},
tcsetpgrp__deps: ['__setErrNo', '$ERRNO_CODES'],
tcsetpgrp: function(fildes, pgid_id) {
// int tcsetpgrp(int fildes, pid_t pgid_id);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tcsetpgrp.html
// We don't support multiple processes or groups with ID other than 0.
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
},
sysconf__deps: ['__setErrNo', '$ERRNO_CODES'],
sysconf: function(name) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_SYSCONF') }}}, name);
#endif
// long sysconf(int name);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
switch(name) {
case {{{ cDefine('_SC_PAGE_SIZE') }}}: return PAGE_SIZE;
case {{{ cDefine('_SC_PHYS_PAGES') }}}: return totalMemory / PAGE_SIZE;
case {{{ cDefine('_SC_ADVISORY_INFO') }}}:
case {{{ cDefine('_SC_BARRIERS') }}}:
case {{{ cDefine('_SC_ASYNCHRONOUS_IO') }}}:
case {{{ cDefine('_SC_CLOCK_SELECTION') }}}:
case {{{ cDefine('_SC_CPUTIME') }}}:
case {{{ cDefine('_SC_FSYNC') }}}:
case {{{ cDefine('_SC_IPV6') }}}:
case {{{ cDefine('_SC_MAPPED_FILES') }}}:
case {{{ cDefine('_SC_MEMLOCK') }}}:
case {{{ cDefine('_SC_MEMLOCK_RANGE') }}}:
case {{{ cDefine('_SC_MEMORY_PROTECTION') }}}:
case {{{ cDefine('_SC_MESSAGE_PASSING') }}}:
case {{{ cDefine('_SC_MONOTONIC_CLOCK') }}}:
case {{{ cDefine('_SC_PRIORITIZED_IO') }}}:
case {{{ cDefine('_SC_PRIORITY_SCHEDULING') }}}:
case {{{ cDefine('_SC_RAW_SOCKETS') }}}:
case {{{ cDefine('_SC_READER_WRITER_LOCKS') }}}:
case {{{ cDefine('_SC_REALTIME_SIGNALS') }}}:
case {{{ cDefine('_SC_SEMAPHORES') }}}:
case {{{ cDefine('_SC_SHARED_MEMORY_OBJECTS') }}}:
case {{{ cDefine('_SC_SPAWN') }}}:
case {{{ cDefine('_SC_SPIN_LOCKS') }}}:
case {{{ cDefine('_SC_SYNCHRONIZED_IO') }}}:
case {{{ cDefine('_SC_THREAD_ATTR_STACKADDR') }}}:
case {{{ cDefine('_SC_THREAD_ATTR_STACKSIZE') }}}:
case {{{ cDefine('_SC_THREAD_CPUTIME') }}}:
case {{{ cDefine('_SC_THREAD_PRIO_INHERIT') }}}:
case {{{ cDefine('_SC_THREAD_PRIO_PROTECT') }}}:
case {{{ cDefine('_SC_THREAD_PROCESS_SHARED') }}}:
case {{{ cDefine('_SC_THREAD_SAFE_FUNCTIONS') }}}:
case {{{ cDefine('_SC_THREADS') }}}:
case {{{ cDefine('_SC_TIMEOUTS') }}}:
case {{{ cDefine('_SC_TIMERS') }}}:
case {{{ cDefine('_SC_VERSION') }}}:
case {{{ cDefine('_SC_2_C_BIND') }}}:
case {{{ cDefine('_SC_2_C_DEV') }}}:
case {{{ cDefine('_SC_2_CHAR_TERM') }}}:
case {{{ cDefine('_SC_2_LOCALEDEF') }}}:
case {{{ cDefine('_SC_2_SW_DEV') }}}:
case {{{ cDefine('_SC_2_VERSION') }}}:
return 200809;
case {{{ cDefine('_SC_THREAD_PRIORITY_SCHEDULING') }}}:
return 0;
case {{{ cDefine('_SC_MQ_OPEN_MAX') }}}:
case {{{ cDefine('_SC_XOPEN_STREAMS') }}}:
case {{{ cDefine('_SC_XBS5_LP64_OFF64') }}}:
case {{{ cDefine('_SC_XBS5_LPBIG_OFFBIG') }}}:
case {{{ cDefine('_SC_AIO_LISTIO_MAX') }}}:
case {{{ cDefine('_SC_AIO_MAX') }}}:
case {{{ cDefine('_SC_SPORADIC_SERVER') }}}:
case {{{ cDefine('_SC_THREAD_SPORADIC_SERVER') }}}:
case {{{ cDefine('_SC_TRACE') }}}:
case {{{ cDefine('_SC_TRACE_EVENT_FILTER') }}}:
case {{{ cDefine('_SC_TRACE_EVENT_NAME_MAX') }}}:
case {{{ cDefine('_SC_TRACE_INHERIT') }}}:
case {{{ cDefine('_SC_TRACE_LOG') }}}:
case {{{ cDefine('_SC_TRACE_NAME_MAX') }}}:
case {{{ cDefine('_SC_TRACE_SYS_MAX') }}}:
case {{{ cDefine('_SC_TRACE_USER_EVENT_MAX') }}}:
case {{{ cDefine('_SC_TYPED_MEMORY_OBJECTS') }}}:
case {{{ cDefine('_SC_V6_LP64_OFF64') }}}:
case {{{ cDefine('_SC_V6_LPBIG_OFFBIG') }}}:
case {{{ cDefine('_SC_2_FORT_DEV') }}}:
case {{{ cDefine('_SC_2_FORT_RUN') }}}:
case {{{ cDefine('_SC_2_PBS') }}}:
case {{{ cDefine('_SC_2_PBS_ACCOUNTING') }}}:
case {{{ cDefine('_SC_2_PBS_CHECKPOINT') }}}:
case {{{ cDefine('_SC_2_PBS_LOCATE') }}}:
case {{{ cDefine('_SC_2_PBS_MESSAGE') }}}:
case {{{ cDefine('_SC_2_PBS_TRACK') }}}:
case {{{ cDefine('_SC_2_UPE') }}}:
case {{{ cDefine('_SC_THREAD_THREADS_MAX') }}}:
case {{{ cDefine('_SC_SEM_NSEMS_MAX') }}}:
case {{{ cDefine('_SC_SYMLOOP_MAX') }}}:
case {{{ cDefine('_SC_TIMER_MAX') }}}:
return -1;
case {{{ cDefine('_SC_V6_ILP32_OFF32') }}}:
case {{{ cDefine('_SC_V6_ILP32_OFFBIG') }}}:
case {{{ cDefine('_SC_JOB_CONTROL') }}}:
case {{{ cDefine('_SC_REGEXP') }}}:
case {{{ cDefine('_SC_SAVED_IDS') }}}:
case {{{ cDefine('_SC_SHELL') }}}:
case {{{ cDefine('_SC_XBS5_ILP32_OFF32') }}}:
case {{{ cDefine('_SC_XBS5_ILP32_OFFBIG') }}}:
case {{{ cDefine('_SC_XOPEN_CRYPT') }}}:
case {{{ cDefine('_SC_XOPEN_ENH_I18N') }}}:
case {{{ cDefine('_SC_XOPEN_LEGACY') }}}:
case {{{ cDefine('_SC_XOPEN_REALTIME') }}}:
case {{{ cDefine('_SC_XOPEN_REALTIME_THREADS') }}}:
case {{{ cDefine('_SC_XOPEN_SHM') }}}:
case {{{ cDefine('_SC_XOPEN_UNIX') }}}:
return 1;
case {{{ cDefine('_SC_THREAD_KEYS_MAX') }}}:
case {{{ cDefine('_SC_IOV_MAX') }}}:
case {{{ cDefine('_SC_GETGR_R_SIZE_MAX') }}}:
case {{{ cDefine('_SC_GETPW_R_SIZE_MAX') }}}:
case {{{ cDefine('_SC_OPEN_MAX') }}}:
return 1024;
case {{{ cDefine('_SC_RTSIG_MAX') }}}:
case {{{ cDefine('_SC_EXPR_NEST_MAX') }}}:
case {{{ cDefine('_SC_TTY_NAME_MAX') }}}:
return 32;
case {{{ cDefine('_SC_ATEXIT_MAX') }}}:
case {{{ cDefine('_SC_DELAYTIMER_MAX') }}}:
case {{{ cDefine('_SC_SEM_VALUE_MAX') }}}:
return 2147483647;
case {{{ cDefine('_SC_SIGQUEUE_MAX') }}}:
case {{{ cDefine('_SC_CHILD_MAX') }}}:
return 47839;
case {{{ cDefine('_SC_BC_SCALE_MAX') }}}:
case {{{ cDefine('_SC_BC_BASE_MAX') }}}:
return 99;
case {{{ cDefine('_SC_LINE_MAX') }}}:
case {{{ cDefine('_SC_BC_DIM_MAX') }}}:
return 2048;
case {{{ cDefine('_SC_ARG_MAX') }}}: return 2097152;
case {{{ cDefine('_SC_NGROUPS_MAX') }}}: return 65536;
case {{{ cDefine('_SC_MQ_PRIO_MAX') }}}: return 32768;
case {{{ cDefine('_SC_RE_DUP_MAX') }}}: return 32767;
case {{{ cDefine('_SC_THREAD_STACK_MIN') }}}: return 16384;
case {{{ cDefine('_SC_BC_STRING_MAX') }}}: return 1000;
case {{{ cDefine('_SC_XOPEN_VERSION') }}}: return 700;
case {{{ cDefine('_SC_LOGIN_NAME_MAX') }}}: return 256;
case {{{ cDefine('_SC_COLL_WEIGHTS_MAX') }}}: return 255;
case {{{ cDefine('_SC_CLK_TCK') }}}: return 100;
case {{{ cDefine('_SC_HOST_NAME_MAX') }}}: return 64;
case {{{ cDefine('_SC_AIO_PRIO_DELTA_MAX') }}}: return 20;
case {{{ cDefine('_SC_STREAM_MAX') }}}: return 16;
case {{{ cDefine('_SC_TZNAME_MAX') }}}: return 6;
case {{{ cDefine('_SC_THREAD_DESTRUCTOR_ITERATIONS') }}}: return 4;
case {{{ cDefine('_SC_NPROCESSORS_ONLN') }}}: {
if (typeof navigator === 'object') return navigator['hardwareConcurrency'] || 1;
return 1;
}
}
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
},
sbrk: function(bytes) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_SBRK') }}}, bytes);
#endif
// Implement a Linux-like 'memory area' for our 'process'.
// Changes the size of the memory area by |bytes|; returns the
// address of the previous top ('break') of the memory area
// We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
var self = _sbrk;
if (!self.called) {
DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
self.called = true;
assert(Runtime.dynamicAlloc);
self.alloc = Runtime.dynamicAlloc;
Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
}
var ret = DYNAMICTOP;
if (bytes != 0) {
var success = self.alloc(bytes);
if (!success) return -1 >>> 0; // sbrk failure code
}
return ret; // Previous break location.
},
// ==========================================================================
// stdio.h
// ==========================================================================
_getFloat: function(text) {
return /^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?/.exec(text);
},
_scanString__deps: ['_getFloat'],
_scanString: function(format, get, unget, varargs) {
if (!__scanString.whiteSpace) {
__scanString.whiteSpace = {};
__scanString.whiteSpace[{{{ charCode(' ') }}}] = 1;
__scanString.whiteSpace[{{{ charCode('\t') }}}] = 1;
__scanString.whiteSpace[{{{ charCode('\n') }}}] = 1;
__scanString.whiteSpace[{{{ charCode('\v') }}}] = 1;
__scanString.whiteSpace[{{{ charCode('\f') }}}] = 1;
__scanString.whiteSpace[{{{ charCode('\r') }}}] = 1;
}
// Supports %x, %4x, %d.%d, %lld, %s, %f, %lf.
// TODO: Support all format specifiers.
format = Pointer_stringify(format);
var soFar = 0;
if (format.indexOf('%n') >= 0) {
// need to track soFar
var _get = get;
get = function get() {
soFar++;
return _get();
}
var _unget = unget;
unget = function unget() {
soFar--;
return _unget();
}
}
var formatIndex = 0;
var argsi = 0;
var fields = 0;
var argIndex = 0;
var next;
mainLoop:
for (var formatIndex = 0; formatIndex < format.length;) {
if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') {
argIndex = Runtime.prepVararg(argIndex, '*');
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
argIndex += Runtime.getAlignSize('void*', null, true);
{{{ makeSetValue('argPtr', 0, 'soFar', 'i32') }}};
formatIndex += 2;
continue;
}
if (format[formatIndex] === '%') {
var nextC = format.indexOf('c', formatIndex+1);
if (nextC > 0) {
var maxx = 1;
if (nextC > formatIndex+1) {
var sub = format.substring(formatIndex+1, nextC);
maxx = parseInt(sub);
if (maxx != sub) maxx = 0;
}
if (maxx) {
argIndex = Runtime.prepVararg(argIndex, '*');
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
argIndex += Runtime.getAlignSize('void*', null, true);
fields++;
for (var i = 0; i < maxx; i++) {
next = get();
{{{ makeSetValue('argPtr++', 0, 'next', 'i8') }}};
if (next === 0) return i > 0 ? fields : fields-1; // we failed to read the full length of this field
}
formatIndex += nextC - formatIndex + 1;
continue;
}
}
}
// handle %[...]
if (format[formatIndex] === '%' && format.indexOf('[', formatIndex+1) > 0) {
var match = /\%([0-9]*)\[(\^)?(\]?[^\]]*)\]/.exec(format.substring(formatIndex));
if (match) {
var maxNumCharacters = parseInt(match[1]) || Infinity;
var negateScanList = (match[2] === '^');
var scanList = match[3];
// expand "middle" dashs into character sets
var middleDashMatch;
while ((middleDashMatch = /([^\-])\-([^\-])/.exec(scanList))) {
var rangeStartCharCode = middleDashMatch[1].charCodeAt(0);
var rangeEndCharCode = middleDashMatch[2].charCodeAt(0);
for (var expanded = ''; rangeStartCharCode <= rangeEndCharCode; expanded += String.fromCharCode(rangeStartCharCode++));
scanList = scanList.replace(middleDashMatch[1] + '-' + middleDashMatch[2], expanded);
}
argIndex = Runtime.prepVararg(argIndex, '*');
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
argIndex += Runtime.getAlignSize('void*', null, true);
fields++;
for (var i = 0; i < maxNumCharacters; i++) {
next = get();
if (negateScanList) {
if (scanList.indexOf(String.fromCharCode(next)) < 0) {
{{{ makeSetValue('argPtr++', 0, 'next', 'i8') }}};
} else {
unget();
break;
}
} else {
if (scanList.indexOf(String.fromCharCode(next)) >= 0) {
{{{ makeSetValue('argPtr++', 0, 'next', 'i8') }}};
} else {
unget();
break;
}
}
}
// write out null-terminating character
{{{ makeSetValue('argPtr++', 0, '0', 'i8') }}};
formatIndex += match[0].length;
continue;
}
}
// remove whitespace
while (1) {
next = get();
if (next == 0) return fields;
if (!(next in __scanString.whiteSpace)) break;
}
unget();
if (format[formatIndex] === '%') {
formatIndex++;
var suppressAssignment = false;
if (format[formatIndex] == '*') {
suppressAssignment = true;
formatIndex++;
}
var maxSpecifierStart = formatIndex;
while (format[formatIndex].charCodeAt(0) >= {{{ charCode('0') }}} &&
format[formatIndex].charCodeAt(0) <= {{{ charCode('9') }}}) {
formatIndex++;
}
var max_;
if (formatIndex != maxSpecifierStart) {
max_ = parseInt(format.slice(maxSpecifierStart, formatIndex), 10);
}
var long_ = false;
var half = false;
var quarter = false;
var longLong = false;
if (format[formatIndex] == 'l') {
long_ = true;
formatIndex++;
if (format[formatIndex] == 'l') {
longLong = true;
formatIndex++;
}
} else if (format[formatIndex] == 'h') {
half = true;
formatIndex++;
if (format[formatIndex] == 'h') {
quarter = true;
formatIndex++;
}
}
var type = format[formatIndex];
formatIndex++;
var curr = 0;
var buffer = [];
// Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later
if (type == 'f' || type == 'e' || type == 'g' ||
type == 'F' || type == 'E' || type == 'G') {
next = get();
while (next > 0 && (!(next in __scanString.whiteSpace))) {
buffer.push(String.fromCharCode(next));
next = get();
}
var m = __getFloat(buffer.join(''));
var last = m ? m[0].length : 0;
for (var i = 0; i < buffer.length - last + 1; i++) {
unget();
}
buffer.length = last;
} else {
next = get();
var first = true;
// Strip the optional 0x prefix for %x.
if ((type == 'x' || type == 'X') && (next == {{{ charCode('0') }}})) {
var peek = get();
if (peek == {{{ charCode('x') }}} || peek == {{{ charCode('X') }}}) {
next = get();
} else {
unget();
}
}
while ((curr < max_ || isNaN(max_)) && next > 0) {
if (!(next in __scanString.whiteSpace) && // stop on whitespace
(type == 's' ||
((type === 'd' || type == 'u' || type == 'i') && ((next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) ||
(first && next == {{{ charCode('-') }}}))) ||
((type === 'x' || type === 'X') && (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}} ||
next >= {{{ charCode('a') }}} && next <= {{{ charCode('f') }}} ||
next >= {{{ charCode('A') }}} && next <= {{{ charCode('F') }}}))) &&
(formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up
buffer.push(String.fromCharCode(next));
next = get();
curr++;
first = false;
} else {
break;
}
}
unget();
}
if (buffer.length === 0) return fields; // Stop here.
if (suppressAssignment) continue;
var text = buffer.join('');
argIndex = Runtime.prepVararg(argIndex, '*');
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
argIndex += Runtime.getAlignSize('void*', null, true);
var base = 10;
switch (type) {
case 'X': case 'x':
base = 16;
case 'd': case 'u': case 'i':
if (quarter) {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, base)', 'i8') }}};
} else if (half) {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, base)', 'i16') }}};
} else if (longLong) {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, base)', 'i64') }}};
} else {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, base)', 'i32') }}};
}
break;
case 'F':
case 'f':
case 'E':
case 'e':
case 'G':
case 'g':
case 'E':
// fallthrough intended
if (long_) {
{{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}};
} else {
{{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}};
}
break;
case 's':
var array = intArrayFromString(text);
for (var j = 0; j < array.length; j++) {
{{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}};
}
break;
}
fields++;
} else if (format[formatIndex].charCodeAt(0) in __scanString.whiteSpace) {
next = get();
while (next in __scanString.whiteSpace) {
if (next <= 0) break mainLoop; // End of input.
next = get();
}
unget(next);
formatIndex++;
} else {
// Not a specifier.
next = get();
if (format[formatIndex].charCodeAt(0) !== next) {
unget(next);
break mainLoop;
}
formatIndex++;
}
}
return fields;
},
// NOTE: Invalid stream pointers passed to these functions would cause a crash
// in native code. We, on the other hand, just ignore them, since it's
// easier.
clearerr__deps: ['$FS'],
clearerr: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_CLEARERR') }}}, stream);
#endif
// void clearerr(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/clearerr.html
stream = FS.getStreamFromPtr(stream);
if (!stream) {
return;
}
stream.eof = false;
stream.error = false;
},
fclose__deps: ['close', 'fileno'],
fclose: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FCLOSE') }}}, stream);
#endif
// int fclose(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fclose.html
var fd = _fileno(stream);
return _close(fd);
},
fdopen__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
fdopen: function(fildes, mode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FDOPEN') }}}, fildes, mode);
#endif
// FILE *fdopen(int fildes, const char *mode);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fdopen.html
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 FS.getPtrForStream(stream);
}
},
feof__deps: ['$FS'],
feof: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FEOF') }}}, stream);
#endif
// int feof(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/feof.html
stream = FS.getStreamFromPtr(stream);
return Number(stream && stream.eof);
},
ferror__deps: ['$FS'],
ferror: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FERROR') }}}, stream);
#endif
// int ferror(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ferror.html
stream = FS.getStreamFromPtr(stream);
return Number(stream && stream.error);
},
fflush__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
fflush: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FFLUSH') }}}, stream);
#endif
// int fflush(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
/*
// Disabled, see https://github.com/kripken/emscripten/issues/2770
stream = FS.getStreamFromPtr(stream);
if (stream.stream_ops.flush) {
stream.stream_ops.flush(stream);
}
*/
},
fgetc__deps: ['$FS', 'fread'],
#if USE_PTHREADS
fgetc__postset: 'if (ENVIRONMENT_IS_PTHREAD) _fgetc.ret = PthreadWorkerInit._fgetc_ret; else PthreadWorkerInit._fgetc_ret = _fgetc.ret = allocate([0], "i8", ALLOC_STATIC);',
#else
fgetc__postset: '_fgetc.ret = allocate([0], "i8", ALLOC_STATIC);',
#endif
fgetc: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FGETC') }}}, stream);
#endif
// int fgetc(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetc.html
var streamObj = FS.getStreamFromPtr(stream);
if (!streamObj) return -1;
if (streamObj.eof || streamObj.error) return -1;
var ret = _fread(_fgetc.ret, 1, 1, stream);
if (ret == 0) {
return -1;
} else if (ret == -1) {
streamObj.error = true;
return -1;
} else {
return {{{ makeGetValue('_fgetc.ret', '0', 'i8', null, 1) }}};
}
},
getc: 'fgetc',
getc_unlocked: 'fgetc',
getchar__deps: ['fgetc', 'stdin'],
getchar: function() {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_0({{{ cDefine('EM_PROXIED_GETCHAR') }}});
#endif
// int getchar(void);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getchar.html
return _fgetc({{{ makeGetValue(makeGlobalUse('_stdin'), '0', 'void*') }}});
},
fgetpos__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
fgetpos: function(stream, pos) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FGETPOS') }}}, stream, pos);
#endif
// int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetpos.html
stream = FS.getStreamFromPtr(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) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_FGETS') }}}, s, n, stream);
#endif
// char *fgets(char *restrict s, int n, FILE *restrict stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgets.html
var streamObj = FS.getStreamFromPtr(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++) {
byte_ = _fgetc(stream);
if (byte_ == -1) {
if (streamObj.error || (streamObj.eof && i == 0)) return 0;
else if (streamObj.eof) break;
}
{{{ makeSetValue('s', 'i', 'byte_', 'i8') }}};
}
{{{ makeSetValue('s', 'i', '0', 'i8') }}};
return s;
},
gets__deps: ['fgets'],
gets: function(s) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_GETS') }}}, s);
#endif
// char *gets(char *s);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/gets.html
return _fgets(s, 1e6, {{{ makeGetValue(makeGlobalUse('_stdin'), '0', 'void*') }}});
},
fileno: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FILENO') }}}, stream);
#endif
// int fileno(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
stream = FS.getStreamFromPtr(stream);
if (!stream) return -1;
return stream.fd;
},
ftrylockfile: function() {
// int ftrylockfile(FILE *file);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/flockfile.html
// Locking is useless in a single-threaded environment. Pretend to succeed.
return 0;
},
flockfile: 'ftrylockfile',
funlockfile: 'ftrylockfile',
fopen__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'open'],
fopen: function(filename, mode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FOPEN') }}}, filename, mode);
#endif
// FILE *fopen(const char *restrict filename, const char *restrict mode);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fopen.html
var flags;
mode = Pointer_stringify(mode);
if (mode[0] == 'r') {
if (mode.indexOf('+') != -1) {
flags = {{{ cDefine('O_RDWR') }}};
} else {
flags = {{{ cDefine('O_RDONLY') }}};
}
} else if (mode[0] == 'w') {
if (mode.indexOf('+') != -1) {
flags = {{{ cDefine('O_RDWR') }}};
} else {
flags = {{{ cDefine('O_WRONLY') }}};
}
flags |= {{{ cDefine('O_CREAT') }}};
flags |= {{{ cDefine('O_TRUNC') }}};
} else if (mode[0] == 'a') {
if (mode.indexOf('+') != -1) {
flags = {{{ cDefine('O_RDWR') }}};
} else {
flags = {{{ cDefine('O_WRONLY') }}};
}
flags |= {{{ cDefine('O_CREAT') }}};
flags |= {{{ cDefine('O_APPEND') }}};
} else {
___setErrNo(ERRNO_CODES.EINVAL);
return 0;
}
var fd = _open(filename, flags, allocate([0x1FF, 0, 0, 0], 'i32', ALLOC_STACK)); // All creation permissions.
return fd === -1 ? 0 : FS.getPtrForStream(FS.getStream(fd));
},
fputc__deps: ['$FS', 'write', 'fileno'],
#if USE_PTHREADS
fputc__postset: 'if (ENVIRONMENT_IS_PTHREAD) _fputc.ret = PthreadWorkerInit._fputc_ret; else PthreadWorkerInit._fputc_ret = _fputc.ret = allocate([0], "i8", ALLOC_STATIC);',
#else
fputc__postset: '_fputc.ret = allocate([0], "i8", ALLOC_STATIC);',
#endif
fputc: function(c, stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FPUTC') }}}, c, stream);
#endif
// int fputc(int c, FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
var chr = unSign(c & 0xFF);
{{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}};
var fd = _fileno(stream);
var ret = _write(fd, _fputc.ret, 1);
if (ret == -1) {
var streamObj = FS.getStreamFromPtr(stream);
if (streamObj) streamObj.error = true;
return -1;
} else {
return chr;
}
},
putc: 'fputc',
putc_unlocked: 'fputc',
putchar__deps: ['fputc', 'stdout'],
putchar: function(c) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_PUTCHAR') }}}, c);
#endif
// int putchar(int c);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/putchar.html
return _fputc(c, {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}});
},
putchar_unlocked: 'putchar',
fputs__deps: ['write', 'strlen', 'fileno'],
fputs: function(s, stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FPUTS') }}}, s, stream);
#endif
// int fputs(const char *restrict s, FILE *restrict stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
var fd = _fileno(stream);
return _write(fd, s, _strlen(s));
},
puts__deps: ['fputs', 'fputc', 'stdout'],
puts: function(s) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_PUTS') }}}, s);
#endif
#if NO_FILESYSTEM == 0
// int puts(const char *s);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html
// NOTE: puts() always writes an extra newline.
var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}};
var ret = _fputs(s, stdout);
if (ret < 0) {
return ret;
} else {
var newlineRet = _fputc({{{ charCode('\n') }}}, stdout);
return (newlineRet < 0) ? -1 : ret + 1;
}
#else
// extra effort to support puts, even without a filesystem. very partial, very hackish
var result = Pointer_stringify(s);
var string = result.substr(0);
if (string[string.length-1] === '\n') string = string.substr(0, string.length-1); // remove a final \n, as Module.print will do that
Module.print(string);
return result.length;
#endif
},
fread__deps: ['$FS', 'read'],
fread: function(ptr, size, nitems, stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_FREAD') }}}, ptr, size, nitems, stream);
#endif
// size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fread.html
var bytesToRead = nitems * size;
if (bytesToRead == 0) {
return 0;
}
var bytesRead = 0;
var streamObj = FS.getStreamFromPtr(stream);
if (!streamObj) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
}
while (streamObj.ungotten.length && bytesToRead > 0) {
{{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}};
bytesToRead--;
bytesRead++;
}
var err = _read(streamObj.fd, ptr, bytesToRead);
if (err == -1) {
if (streamObj) streamObj.error = true;
return 0;
}
bytesRead += err;
if (bytesRead < bytesToRead) streamObj.eof = true;
return (bytesRead / size)|0;
},
freopen__deps: ['$FS', 'fclose', 'fopen', '__setErrNo', '$ERRNO_CODES'],
freopen: function(filename, mode, stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_FREOPEN') }}}, filename, mode, stream);
#endif
// FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/freopen.html
if (!filename) {
var streamObj = FS.getStreamFromPtr(stream);
if (!streamObj) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
}
if (_freopen.buffer) _free(_freopen.buffer);
filename = intArrayFromString(streamObj.path);
filename = allocate(filename, 'i8', ALLOC_NORMAL);
}
_fclose(stream);
return _fopen(filename, mode);
},
fseek__deps: ['$FS', 'lseek', 'fileno'],
fseek: function(stream, offset, whence) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_FSEEK') }}}, stream, offset, whence);
#endif
// int fseek(FILE *stream, long offset, int whence);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fseek.html
var fd = _fileno(stream);
var ret = _lseek(fd, offset, whence);
if (ret == -1) {
return -1;
}
stream = FS.getStreamFromPtr(stream);
stream.eof = false;
return 0;
},
fseeko: 'fseek',
fsetpos__deps: ['$FS', 'lseek', '__setErrNo', '$ERRNO_CODES'],
fsetpos: function(stream, pos) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_FSETPOS') }}}, stream, pos);
#endif
// int fsetpos(FILE *stream, const fpos_t *pos);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fsetpos.html
stream = FS.getStreamFromPtr(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) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_FTELL') }}}, stream);
#endif
// long ftell(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ftell.html
stream = FS.getStreamFromPtr(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',
fwrite__deps: ['$FS', 'write', 'fileno'],
fwrite: function(ptr, size, nitems, stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_FWRITE') }}}, ptr, size, nitems, stream);
#endif
// size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
var bytesToWrite = nitems * size;
if (bytesToWrite == 0) return 0;
var fd = _fileno(stream);
var bytesWritten = _write(fd, ptr, bytesToWrite);
if (bytesWritten == -1) {
var streamObj = FS.getStreamFromPtr(stream);
if (streamObj) streamObj.error = true;
return 0;
} else {
return (bytesWritten / size)|0;
}
},
popen__deps: ['__setErrNo', '$ERRNO_CODES'],
popen: function(command, mode) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_POPEN') }}}, command, mode);
#endif
// FILE *popen(const char *command, const char *mode);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/popen.html
// We allow only one process, so no pipes.
___setErrNo(ERRNO_CODES.EMFILE);
return 0;
},
pclose__deps: ['__setErrNo', '$ERRNO_CODES'],
pclose: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_PCLOSE') }}}, stream);
#endif
// int pclose(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/pclose.html
// We allow only one process, so no pipes.
___setErrNo(ERRNO_CODES.ECHILD);
return -1;
},
perror__deps: ['puts', 'fputs', 'fputc', 'strerror', '__errno_location'],
perror: function(s) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_PERROR') }}}, s);
#endif
// void perror(const char *s);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/perror.html
var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}};
if (s) {
_fputs(s, stdout);
_fputc({{{ charCode(':') }}}, stdout);
_fputc({{{ charCode(' ') }}}, stdout);
}
var errnum = {{{ makeGetValue('___errno_location()', '0', 'i32') }}};
_puts(_strerror(errnum));
},
remove__deps: ['unlink', 'rmdir'],
remove: function(path) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_REMOVE') }}}, path);
#endif
// int remove(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/remove.html
var ret = _unlink(path);
if (ret == -1) ret = _rmdir(path);
return ret;
},
rename__deps: ['__setErrNo', '$ERRNO_CODES'],
rename: function(old_path, new_path) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_RENAME') }}}, old_path, new_path);
#endif
// int rename(const char *old, const char *new);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rename.html
old_path = Pointer_stringify(old_path);
new_path = Pointer_stringify(new_path);
try {
FS.rename(old_path, new_path);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
rewind__deps: ['$FS', 'fseek'],
rewind: function(stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_REWIND') }}}, stream);
#endif
// void rewind(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rewind.html
_fseek(stream, 0, 0); // SEEK_SET.
var streamObj = FS.getStreamFromPtr(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);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/setvbuf.html
// TODO: Implement custom buffering.
return 0;
},
setbuf__deps: ['setvbuf'],
setbuf: function(stream, buf) {
// void setbuf(FILE *restrict stream, char *restrict buf);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/setbuf.html
if (buf) _setvbuf(stream, buf, 0, 8192); // _IOFBF, BUFSIZ.
else _setvbuf(stream, buf, 2, 8192); // _IONBF, BUFSIZ.
},
tmpnam__deps: ['$FS'],
tmpnam: function(s, dir, prefix) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_TMPNAM') }}}, s, dir, prefix);
#endif
// char *tmpnam(char *s);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpnam.html
// NOTE: The dir and prefix arguments are for internal use only.
dir = dir || '/tmp';
var folder = FS.findObject(dir);
if (!folder || !folder.isFolder) {
dir = '/tmp';
folder = FS.findObject(dir);
if (!folder || !folder.isFolder) return 0;
}
var name = prefix || 'file';
do {
name += String.fromCharCode(65 + (Math.random() * 25)|0);
} while (name in folder.contents);
var result = dir + '/' + name;
if (!_tmpnam.buffer) _tmpnam.buffer = _malloc(256);
if (!s) s = _tmpnam.buffer;
assert(result.length <= 255);
writeAsciiToMemory(result, s);
return s;
},
tempnam__deps: ['tmpnam'],
tempnam: function(dir, pfx) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_TEMPNAM') }}}, dir, pfx);
#endif
// char *tempnam(const char *dir, const char *pfx);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tempnam.html
return _tmpnam(0, Pointer_stringify(dir), Pointer_stringify(pfx));
},
tmpfile__deps: ['tmpnam', 'fopen'],
tmpfile: function() {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_0({{{ cDefine('EM_PROXIED_TMPFILE') }}});
#endif
// FILE *tmpfile(void);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpfile.html
// TODO: Delete the created file on closing.
if (!_tmpfile.mode) {
_tmpfile.mode = allocate(intArrayFromString('w+'), 'i8', ALLOC_NORMAL);
}
return _fopen(_tmpnam(0), _tmpfile.mode);
},
ungetc__deps: ['$FS'],
ungetc: function(c, stream) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_UNGETC') }}}, c, stream);
#endif
// int ungetc(int c, FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ungetc.html
stream = FS.getStreamFromPtr(stream);
if (!stream) {
return -1;
}
if (c === {{{ cDefine('EOF') }}}) {
// do nothing for EOF character
return c;
}
c = unSign(c & 0xFF);
stream.ungotten.push(c);
stream.eof = false;
return c;
},
system__deps: ['__setErrNo', '$ERRNO_CODES'],
system: function(command) {
// int system(const char *command);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/system.html
// Can't call external programs.
___setErrNo(ERRNO_CODES.EAGAIN);
return -1;
},
fscanf__deps: ['$FS', '_scanString', 'fgetc', 'ungetc'],
fscanf: function(stream, format, varargs) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_FSCANF') }}}, stream, format, varargs);
#endif
// int fscanf(FILE *restrict stream, const char *restrict format, ... );
// http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
var streamObj = FS.getStreamFromPtr(stream);
if (!streamObj) {
return -1;
}
var buffer = [];
function get() {
var c = _fgetc(stream);
buffer.push(c);
return c;
};
function unget() {
_ungetc(buffer.pop(), stream);
};
return __scanString(format, get, unget, varargs);
},
scanf__deps: ['fscanf'],
scanf: function(format, varargs) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_SCANF') }}}, format, varargs);
#endif
// int scanf(const char *restrict format, ... );
// http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
var stdin = {{{ makeGetValue(makeGlobalUse('_stdin'), '0', 'void*') }}};
return _fscanf(stdin, format, varargs);
},
fprintf__deps: ['fwrite', '_formatString'],
fprintf: function(stream, format, varargs) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_xprintf_varargs({{{ cDefine('EM_PROXIED_FPRINTF') }}}, stream, format, varargs);
#endif
// int fprintf(FILE *restrict stream, const char *restrict format, ...);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
var result = __formatString(format, varargs);
var stack = Runtime.stackSave();
var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
Runtime.stackRestore(stack);
return ret;
},
printf__deps: ['fprintf'],
printf: function(format, varargs) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_xprintf_varargs({{{ cDefine('EM_PROXIED_PRINTF') }}}, 0, format, varargs);
#endif
// int printf(const char *restrict format, ...);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
#if NO_FILESYSTEM == 0
var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}};
return _fprintf(stdout, format, varargs);
#else
// extra effort to support printf, even without a filesystem. very partial, very hackish
var result = __formatString(format, varargs);
var string = intArrayToString(result);
if (string[string.length-1] === '\n') string = string.substr(0, string.length-1); // remove a final \n, as Module.print will do that
Module.print(string);
return result.length;
#endif
},
dprintf__deps: ['_formatString', 'write'],
dprintf: function(fd, format, varargs) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_xprintf_varargs({{{ cDefine('EM_PROXIED_DPRINTF') }}}, fd, format, varargs);
#endif
var result = __formatString(format, varargs);
var stack = Runtime.stackSave();
var ret = _write(fd, allocate(result, 'i8', ALLOC_STACK), result.length);
Runtime.stackRestore(stack);
},
// convert va_arg into varargs
vfprintf__deps: ['fprintf'],
vfprintf: function(s, f, va_arg) {
return _fprintf(s, f, {{{ makeGetValue('va_arg', 0, '*') }}});
},
vprintf__deps: ['printf'],
vprintf: function(format, va_arg) {
return _printf(format, {{{ makeGetValue('va_arg', 0, '*') }}});
},
vdprintf__deps: ['dprintf'],
vdprintf: function (fd, format, va_arg) {
return _dprintf(fd, format, {{{ makeGetValue('va_arg', 0, '*') }}});
},
vscanf__deps: ['scanf'],
vscanf: function(format, va_arg) {
return _scanf(format, {{{ makeGetValue('va_arg', 0, '*') }}});
},
vfscanf__deps: ['fscanf'],
vfscanf: function(s, format, va_arg) {
return _fscanf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
},
// ==========================================================================
// sys/mman.h
// ==========================================================================
mmap__deps: ['$FS', 'memset'],
mmap: function(start, num, prot, flags, fd, offset) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_6({{{ cDefine('EM_PROXIED_MMAP') }}}, start, num, prot, flags, fd, offset);
#endif
/* FIXME: Since mmap is normally implemented at the kernel level,
* this implementation simply uses malloc underneath the call to
* mmap.
*/
var MAP_PRIVATE = 2;
var ptr;
var allocated = false;
if (!_mmap.mappings) _mmap.mappings = {};
if (fd == -1) {
ptr = _malloc(num);
if (!ptr) return -1;
_memset(ptr, 0, num);
allocated = true;
} else {
var info = FS.getStream(fd);
if (!info) return -1;
try {
var res = FS.mmap(info, HEAPU8, start, num, offset, prot, flags);
ptr = res.ptr;
allocated = res.allocated;
} catch (e) {
FS.handleFSError(e);
return -1;
}
}
_mmap.mappings[ptr] = { malloc: ptr, num: num, allocated: allocated, fd: fd, flags: flags };
return ptr;
},
munmap__deps: ['msync'],
munmap: function(start, num) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_MUNMAP') }}}, start, num);
#endif
if (!_mmap.mappings) _mmap.mappings = {};
// TODO: support unmmap'ing parts of allocations
var info = _mmap.mappings[start];
if (!info) return 0;
if (num == info.num) {
// At the Linux man page, it says:
// "The file may not actually be updated until msync(2) or munmap(2) are called."
// I guess that means we need to call msync when doing munmap
_msync(start, num); // todo: which flags?
FS.munmap(FS.getStream(info.fd));
_mmap.mappings[start] = null;
if (info.allocated) {
_free(info.malloc);
}
}
return 0;
},
// 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
// TODO: support sync'ing parts of allocations
var info = _mmap.mappings[addr];
if (!info) return 0;
if (len == info.num) {
var buffer = new Uint8Array(HEAPU8.buffer, addr, len);
return FS.msync(FS.getStream(info.fd), buffer, 0, len, info.flags);
}
return 0;
},
// ==========================================================================
// stdlib.h
// ==========================================================================
// tiny, fake malloc/free implementation. If the program actually uses malloc,
// a compiled version will be used; this will only be used if the runtime
// needs to allocate something, for which this is good enough if otherwise
// no malloc is needed.
malloc: function(bytes) {
/* Over-allocate to make sure it is byte-aligned by 8.
* This will leak memory, but this is only the dummy
* implementation (replaced by dlmalloc normally) so
* not an issue.
*/
#if ASSERTIONS == 2
Runtime.warnOnce('using stub malloc (reference it from C to have the real one included)');
#endif
var ptr = Runtime.dynamicAlloc(bytes + 8);
return (ptr+8) & 0xFFFFFFF8;
},
free: function() {
#if ASSERTIONS == 2
Runtime.warnOnce('using stub free (reference it from C to have the real one included)');
#endif
},
calloc: function(n, s) {
var ret = _malloc(n*s);
_memset(ret, 0, n*s);
return ret;
},
abs: 'Math_abs',
labs: 'Math_abs',
llabs__deps: [function() { Types.preciseI64MathUsed = 1 }],
llabs: function(lo, hi) {
i64Math.abs(lo, hi);
{{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]) }}};
},
exit__deps: ['_exit'],
exit: function(status) {
__exit(status);
},
_ZSt9terminatev__deps: ['exit'],
_ZSt9terminatev: function() {
_exit(-1234);
},
atexit: function(func, arg) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_ATEXIT') }}}, func, arg);
#endif
__ATEXIT__.unshift({ func: func, arg: arg });
},
__cxa_atexit: 'atexit',
abort: function() {
Module['abort']();
},
realloc__deps: ['memcpy'],
realloc: function(ptr, size) {
// Very simple, inefficient implementation - if you use a real malloc, best to use
// a real realloc with it
if (!size) {
if (ptr) _free(ptr);
return 0;
}
var ret = _malloc(size);
if (ptr) {
_memcpy(ret, ptr, size); // might be some invalid reads
_free(ptr);
}
return ret;
},
_parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'],
_parseInt: function(str, endptr, base, min, max, bits, unsign) {
// Skip space.
while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
// Check for a plus/minus sign.
var multiplier = 1;
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('-') }}}) {
multiplier = -1;
str++;
} else if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('+') }}}) {
str++;
}
// Find base.
var finalBase = base;
if (!finalBase) {
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('0') }}}) {
if ({{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('x') }}} ||
{{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('X') }}}) {
finalBase = 16;
str += 2;
} else {
finalBase = 8;
str++;
}
}
} else if (finalBase==16) {
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('0') }}}) {
if ({{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('x') }}} ||
{{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('X') }}}) {
str += 2;
}
}
}
if (!finalBase) finalBase = 10;
// Get digits.
var chr;
var ret = 0;
while ((chr = {{{ makeGetValue('str', 0, 'i8') }}}) != 0) {
var digit = parseInt(String.fromCharCode(chr), finalBase);
if (isNaN(digit)) {
break;
} else {
ret = ret * finalBase + digit;
str++;
}
}
// Apply sign.
ret *= multiplier;
// Set end pointer.
if (endptr) {
{{{ makeSetValue('endptr', 0, 'str', '*') }}};
}
// Unsign if needed.
if (unsign) {
if (Math.abs(ret) > max) {
ret = max;
___setErrNo(ERRNO_CODES.ERANGE);
} else {
ret = unSign(ret, bits);
}
}
// Validate range.
if (ret > max || ret < min) {
ret = ret > max ? max : min;
___setErrNo(ERRNO_CODES.ERANGE);
}
if (bits == 64) {
{{{ makeStructuralReturn(splitI64('ret')) }}};
}
return ret;
},
_parseInt64__deps: ['isspace', '__setErrNo', '$ERRNO_CODES', function() { Types.preciseI64MathUsed = 1 }],
_parseInt64: function(str, endptr, base, min, max, unsign) {
var isNegative = false;
// Skip space.
while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
// Check for a plus/minus sign.
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('-') }}}) {
str++;
isNegative = true;
} else if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('+') }}}) {
str++;
}
// Find base.
var ok = false;
var finalBase = base;
if (!finalBase) {
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('0') }}}) {
if ({{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('x') }}} ||
{{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('X') }}}) {
finalBase = 16;
str += 2;
} else {
finalBase = 8;
ok = true; // we saw an initial zero, perhaps the entire thing is just "0"
}
}
} else if (finalBase==16) {
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('0') }}}) {
if ({{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('x') }}} ||
{{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('X') }}}) {
str += 2;
}
}
}
if (!finalBase) finalBase = 10;
var start = str;
// Get digits.
var chr;
while ((chr = {{{ makeGetValue('str', 0, 'i8') }}}) != 0) {
var digit = parseInt(String.fromCharCode(chr), finalBase);
if (isNaN(digit)) {
break;
} else {
str++;
ok = true;
}
}
if (!ok) {
___setErrNo(ERRNO_CODES.EINVAL);
{{{ makeStructuralReturn(['0', '0']) }}};
}
// Set end pointer.
if (endptr) {
{{{ makeSetValue('endptr', 0, 'str', '*') }}};
}
try {
var numberString = isNegative ? '-'+Pointer_stringify(start, str - start) : Pointer_stringify(start, str - start);
i64Math.fromString(numberString, finalBase, min, max, unsign);
} catch(e) {
___setErrNo(ERRNO_CODES.ERANGE); // not quite correct
}
{{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]) }}};
},
environ__deps: ['$ENV'],
#if USE_PTHREADS
environ: '; if (ENVIRONMENT_IS_PTHREAD) _environ = PthreadWorkerInit._environ; else PthreadWorkerInit._environ = _environ = allocate(1, "i32*", ALLOC_STATIC)',
#else
environ: 'allocate(1, "i32*", ALLOC_STATIC)',
#endif
__environ__deps: ['environ'],
__environ: 'environ',
__buildEnvironment__deps: ['__environ'],
__buildEnvironment: function(env) {
// WARNING: Arbitrary limit!
var MAX_ENV_VALUES = 64;
var TOTAL_ENV_SIZE = 1024;
// Statically allocate memory for the environment.
var poolPtr;
var envPtr;
if (!___buildEnvironment.called) {
___buildEnvironment.called = true;
// Set default values. Use string keys for Closure Compiler compatibility.
ENV['USER'] = 'web_user';
ENV['PATH'] = '/';
ENV['PWD'] = '/';
ENV['HOME'] = '/home/web_user';
ENV['LANG'] = 'C';
ENV['_'] = Module['thisProgram'];
// Allocate memory.
poolPtr = allocate(TOTAL_ENV_SIZE, 'i8', ALLOC_STATIC);
envPtr = allocate(MAX_ENV_VALUES * {{{ Runtime.QUANTUM_SIZE }}},
'i8*', ALLOC_STATIC);
{{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}};
{{{ makeSetValue(makeGlobalUse('_environ'), 0, 'envPtr', 'i8*') }}};
} else {
envPtr = {{{ makeGetValue(makeGlobalUse('_environ'), '0', 'i8**') }}};
poolPtr = {{{ makeGetValue('envPtr', '0', 'i8*') }}};
}
// Collect key=value lines.
var strings = [];
var totalSize = 0;
for (var key in env) {
if (typeof env[key] === 'string') {
var line = key + '=' + env[key];
strings.push(line);
totalSize += line.length;
}
}
if (totalSize > TOTAL_ENV_SIZE) {
throw new Error('Environment size exceeded TOTAL_ENV_SIZE!');
}
// Make new.
var ptrSize = {{{ Runtime.getNativeTypeSize('i8*') }}};
for (var i = 0; i < strings.length; i++) {
var line = strings[i];
writeAsciiToMemory(line, poolPtr);
{{{ makeSetValue('envPtr', 'i * ptrSize', 'poolPtr', 'i8*') }}};
poolPtr += line.length + 1;
}
{{{ makeSetValue('envPtr', 'strings.length * ptrSize', '0', 'i8*') }}};
},
$ENV__deps: ['__buildEnvironment'],
#if USE_PTHREADS
$ENV__postset: 'if (!ENVIRONMENT_IS_PTHREAD) ___buildEnvironment(ENV);',
#else
$ENV__postset: '___buildEnvironment(ENV);',
#endif
$ENV: {},
getenv__deps: ['$ENV'],
getenv: function(name) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_GETENV') }}}, name);
#endif
// char *getenv(const char *name);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/getenv.html
if (name === 0) return 0;
name = Pointer_stringify(name);
if (!ENV.hasOwnProperty(name)) return 0;
if (_getenv.ret) _free(_getenv.ret);
_getenv.ret = allocate(intArrayFromString(ENV[name]), 'i8', ALLOC_NORMAL);
return _getenv.ret;
},
clearenv__deps: ['$ENV', '__buildEnvironment'],
clearenv: function(name) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_CLEARENV') }}}, name);
#endif
// int clearenv (void);
// http://www.gnu.org/s/hello/manual/libc/Environment-Access.html#index-clearenv-3107
ENV = {};
___buildEnvironment(ENV);
return 0;
},
setenv__deps: ['$ENV', '__buildEnvironment', '$ERRNO_CODES', '__setErrNo'],
setenv: function(envname, envval, overwrite) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_SETENV') }}}, envname, envval, overwrite);
#endif
// int setenv(const char *envname, const char *envval, int overwrite);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/setenv.html
if (envname === 0) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
var name = Pointer_stringify(envname);
var val = Pointer_stringify(envval);
if (name === '' || name.indexOf('=') !== -1) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
if (ENV.hasOwnProperty(name) && !overwrite) return 0;
ENV[name] = val;
___buildEnvironment(ENV);
return 0;
},
unsetenv__deps: ['$ENV', '__buildEnvironment', '$ERRNO_CODES', '__setErrNo'],
unsetenv: function(name) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_UNSETENV') }}}, name);
#endif
// int unsetenv(const char *name);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/unsetenv.html
if (name === 0) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
name = Pointer_stringify(name);
if (name === '' || name.indexOf('=') !== -1) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
if (ENV.hasOwnProperty(name)) {
delete ENV[name];
___buildEnvironment(ENV);
}
return 0;
},
putenv__deps: ['$ENV', '__buildEnvironment', '$ERRNO_CODES', '__setErrNo'],
putenv: function(string) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_1({{{ cDefine('EM_PROXIED_PUTENV') }}}, string);
#endif
// int putenv(char *string);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html
// WARNING: According to the standard (and the glibc implementation), the
// string is taken by reference so future changes are reflected.
// We copy it instead, possibly breaking some uses.
if (string === 0) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
string = Pointer_stringify(string);
var splitPoint = string.indexOf('=')
if (string === '' || string.indexOf('=') === -1) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
var name = string.slice(0, splitPoint);
var value = string.slice(splitPoint + 1);
if (!(name in ENV) || ENV[name] !== value) {
ENV[name] = value;
___buildEnvironment(ENV);
}
return 0;
},
getloadavg: function(loadavg, nelem) {
// int getloadavg(double loadavg[], int nelem);
// http://linux.die.net/man/3/getloadavg
var limit = Math.min(nelem, 3);
var doubleSize = {{{ Runtime.getNativeTypeSize('double') }}};
for (var i = 0; i < limit; i++) {
{{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}};
}
return limit;
},
realpath__deps: ['$FS', '__setErrNo'],
realpath: function(file_name, resolved_name) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_REALPATH') }}}, file_name, resolved_name);
#endif
// char *realpath(const char *restrict file_name, char *restrict resolved_name);
// http://pubs.opengroup.org/onlinepubs/009604499/functions/realpath.html
var absolute = FS.analyzePath(Pointer_stringify(file_name));
if (absolute.error) {
___setErrNo(absolute.error);
return 0;
} else {
var size = Math.min(4095, absolute.path.length); // PATH_MAX - 1.
if (resolved_name === 0) resolved_name = _malloc(size+1);
for (var i = 0; i < size; i++) {
{{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}};
}
{{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}};
return resolved_name;
}
},
// For compatibility, call to rand() when code requests arc4random(), although this is *not* at all
// as strong as rc4 is. See https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/arc4random.3.html
arc4random: 'rand',
// ==========================================================================
// string.h
// ==========================================================================
memcpy__inline: function(dest, src, num, align) {
var ret = '';
ret += makeCopyValues(dest, src, num, 'null', null, align);
return ret;
},
emscripten_memcpy_big: function(dest, src, num) {
HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
return dest;
},
memcpy__asm: true,
memcpy__sig: 'iiii',
memcpy__deps: ['emscripten_memcpy_big'],
memcpy: function(dest, src, num) {
dest = dest|0; src = src|0; num = num|0;
var ret = 0;
if ((num|0) >= 4096) return _emscripten_memcpy_big(dest|0, src|0, num|0)|0;
ret = dest|0;
if ((dest&3) == (src&3)) {
while (dest & 3) {
if ((num|0) == 0) return ret|0;
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
dest = (dest+1)|0;
src = (src+1)|0;
num = (num-1)|0;
}
while ((num|0) >= 4) {
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i32'), 'i32') }}};
dest = (dest+4)|0;
src = (src+4)|0;
num = (num-4)|0;
}
}
while ((num|0) > 0) {
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
dest = (dest+1)|0;
src = (src+1)|0;
num = (num-1)|0;
}
return ret|0;
},
llvm_memcpy_i32: 'memcpy',
llvm_memcpy_i64: 'memcpy',
llvm_memcpy_p0i8_p0i8_i32: 'memcpy',
llvm_memcpy_p0i8_p0i8_i64: 'memcpy',
memmove__sig: 'iiii',
memmove__asm: true,
memmove__deps: ['memcpy'],
memmove: function(dest, src, num) {
dest = dest|0; src = src|0; num = num|0;
var ret = 0;
if (((src|0) < (dest|0)) & ((dest|0) < ((src + num)|0))) {
// Unlikely case: Copy backwards in a safe manner
ret = dest;
src = (src + num)|0;
dest = (dest + num)|0;
while ((num|0) > 0) {
dest = (dest - 1)|0;
src = (src - 1)|0;
num = (num - 1)|0;
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
}
dest = ret;
} else {
_memcpy(dest, src, num) | 0;
}
return dest | 0;
},
llvm_memmove_i32: 'memmove',
llvm_memmove_i64: 'memmove',
llvm_memmove_p0i8_p0i8_i32: 'memmove',
llvm_memmove_p0i8_p0i8_i64: 'memmove',
memset__inline: function(ptr, value, num, align) {
return makeSetValues(ptr, 0, value, 'null', num, align);
},
memset__sig: 'iiii',
memset__asm: true,
memset: function(ptr, value, num) {
ptr = ptr|0; value = value|0; num = num|0;
var stop = 0, value4 = 0, stop4 = 0, unaligned = 0;
stop = (ptr + num)|0;
if ((num|0) >= {{{ Math.round(2.5*UNROLL_LOOP_MAX) }}}) {
// This is unaligned, but quite large, so work hard to get to aligned settings
value = value & 0xff;
unaligned = ptr & 3;
value4 = value | (value << 8) | (value << 16) | (value << 24);
stop4 = stop & ~3;
if (unaligned) {
unaligned = (ptr + 4 - unaligned)|0;
while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num
{{{ makeSetValueAsm('ptr', 0, 'value', 'i8') }}};
ptr = (ptr+1)|0;
}
}
while ((ptr|0) < (stop4|0)) {
{{{ makeSetValueAsm('ptr', 0, 'value4', 'i32') }}};
ptr = (ptr+4)|0;
}
}
while ((ptr|0) < (stop|0)) {
{{{ makeSetValueAsm('ptr', 0, 'value', 'i8') }}};
ptr = (ptr+1)|0;
}
return (ptr-num)|0;
},
llvm_memset_i32: 'memset',
llvm_memset_p0i8_i32: 'memset',
llvm_memset_p0i8_i64: 'memset',
strlen__sig: 'ii',
strlen__asm: true,
strlen: function(ptr) {
ptr = ptr|0;
var curr = 0;
curr = ptr;
while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}) {
curr = (curr + 1)|0;
}
return (curr - ptr)|0;
},
strcpy__asm: true,
strcpy__sig: 'iii',
strcpy: function(pdest, psrc) {
pdest = pdest|0; psrc = psrc|0;
var i = 0;
do {
{{{ makeCopyValues('(pdest+i)|0', '(psrc+i)|0', 1, 'i8', null, 1) }}};
i = (i+1)|0;
} while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}});
return pdest|0;
},
strncpy__asm: true,
strncpy__sig: 'iiii',
strncpy: function(pdest, psrc, num) {
pdest = pdest|0; psrc = psrc|0; num = num|0;
var padding = 0, curr = 0, i = 0;
while ((i|0) < (num|0)) {
curr = padding ? 0 : {{{ makeGetValueAsm('psrc', 'i', 'i8') }}};
{{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}};
padding = padding ? 1 : ({{{ makeGetValueAsm('psrc', 'i', 'i8') }}} == 0);
i = (i+1)|0;
}
return pdest|0;
},
strcat__asm: true,
strcat__sig: 'iii',
strcat__deps: ['strlen'],
strcat: function(pdest, psrc) {
pdest = pdest|0; psrc = psrc|0;
var i = 0;
var pdestEnd = 0;
pdestEnd = (pdest + (_strlen(pdest)|0))|0;
do {
{{{ makeCopyValues('pdestEnd+i', 'psrc+i', 1, 'i8', null, 1) }}};
i = (i+1)|0;
} while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}});
return pdest|0;
},
strerror_r__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo'],
strerror_r: function(errnum, strerrbuf, buflen) {
if (errnum in ERRNO_MESSAGES) {
if (ERRNO_MESSAGES[errnum].length > buflen - 1) {
return ___setErrNo(ERRNO_CODES.ERANGE);
} else {
var msg = ERRNO_MESSAGES[errnum];
writeAsciiToMemory(msg, strerrbuf);
return 0;
}
} else {
return ___setErrNo(ERRNO_CODES.EINVAL);
}
},
strerror__deps: ['strerror_r'],
strerror: function(errnum) {
if (!_strerror.buffer) _strerror.buffer = _malloc(256);
_strerror_r(errnum, _strerror.buffer, 256);
return _strerror.buffer;
},
// ==========================================================================
// ctype.h
// ==========================================================================
// Lookup tables for glibc ctype implementation.
__ctype_b_loc: function() {
// http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---ctype-b-loc.html
var me = ___ctype_b_loc;
if (!me.ret) {
var values = [
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,8195,8194,8194,8194,8194,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,24577,49156,49156,49156,
49156,49156,49156,49156,49156,49156,49156,49156,49156,49156,49156,49156,55304,55304,55304,55304,55304,55304,55304,55304,
55304,55304,49156,49156,49156,49156,49156,49156,49156,54536,54536,54536,54536,54536,54536,50440,50440,50440,50440,50440,
50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,49156,49156,49156,49156,49156,
49156,54792,54792,54792,54792,54792,54792,50696,50696,50696,50696,50696,50696,50696,50696,50696,50696,50696,50696,50696,
50696,50696,50696,50696,50696,50696,50696,49156,49156,49156,49156,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
];
var i16size = {{{ Runtime.getNativeTypeSize('i16') }}};
var arr = _malloc(values.length * i16size);
for (var i = 0; i < values.length; i++) {
{{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}};
}
me.ret = allocate([arr + 128 * i16size], 'i16*', ALLOC_NORMAL);
}
return me.ret;
},
__ctype_tolower_loc: function() {
// http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/libutil---ctype-tolower-loc.html
var me = ___ctype_tolower_loc;
if (!me.ret) {
var values = [
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,
158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,
188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,
218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
248,249,250,251,252,253,254,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,97,98,99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95,96,97,98,99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,
134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,
164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,
194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,
254,255
];
var i32size = {{{ Runtime.getNativeTypeSize('i32') }}};
var arr = _malloc(values.length * i32size);
for (var i = 0; i < values.length; i++) {
{{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}};
}
me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
}
return me.ret;
},
__ctype_toupper_loc: function() {
// http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/libutil---ctype-toupper-loc.html
var me = ___ctype_toupper_loc;
if (!me.ret) {
var values = [
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,
158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,
188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,
218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
248,249,250,251,252,253,254,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,
73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,
145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,
175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,
205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,
235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
];
var i32size = {{{ Runtime.getNativeTypeSize('i32') }}};
var arr = _malloc(values.length * i32size);
for (var i = 0; i < values.length; i++) {
{{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}};
}
me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
}
return me.ret;
},
// ==========================================================================
// GCC/LLVM specifics
// ==========================================================================
__builtin_prefetch: function(){},
// ==========================================================================
// LLVM specifics
// ==========================================================================
llvm_va_start__inline: function(ptr) {
// varargs - we received a pointer to the varargs as a final 'extra' parameter called 'varrp'
// 2-word structure: struct { void* start; void* currentOffset; }
return makeSetValue(ptr, 0, 'varrp', 'void*') + ';' + makeSetValue(ptr, Runtime.QUANTUM_SIZE, 0, 'void*');
},
llvm_va_end: function() {},
llvm_va_copy: function(ppdest, ppsrc) {
// copy the list start
{{{ makeCopyValues('ppdest', 'ppsrc', Runtime.QUANTUM_SIZE, 'null', null, 1) }}};
// copy the list's current offset (will be advanced with each call to va_arg)
{{{ makeCopyValues('(ppdest+'+Runtime.QUANTUM_SIZE+')', '(ppsrc+'+Runtime.QUANTUM_SIZE+')', Runtime.QUANTUM_SIZE, 'null', null, 1) }}};
},
llvm_bswap_i16__asm: true,
llvm_bswap_i16__sig: 'ii',
llvm_bswap_i16: function(x) {
x = x|0;
return (((x&0xff)<<8) | ((x>>8)&0xff))|0;
},
llvm_bswap_i32__asm: true,
llvm_bswap_i32__sig: 'ii',
llvm_bswap_i32: function(x) {
x = x|0;
return (((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24))|0;
},
llvm_bswap_i64__deps: ['llvm_bswap_i32'],
llvm_bswap_i64: function(l, h) {
var retl = _llvm_bswap_i32(h)>>>0;
var reth = _llvm_bswap_i32(l)>>>0;
{{{ makeStructuralReturn(['retl', 'reth']) }}};
},
llvm_ctlz_i64__asm: true,
llvm_ctlz_i64__sig: 'iii',
llvm_ctlz_i64: function(l, h, isZeroUndef) {
l = l | 0;
h = h | 0;
isZeroUndef = isZeroUndef | 0;
var ret = 0;
ret = Math_clz32(h) | 0;
if ((ret | 0) == 32) ret = ret + (Math_clz32(l) | 0) | 0;
{{{ makeSetTempRet0('0') }}};
return ret | 0;
},
llvm_cttz_i32__deps: [function() {
function cttz(x) {
for (var i = 0; i < 8; i++) {
if (x & (1 << i)) {
return i;
}
}
return 8;
}
if (SIDE_MODULE) return ''; // uses it from the parent
#if USE_PTHREADS
return 'var cttz_i8; if (ENVIRONMENT_IS_PTHREAD) cttz_i8 = PthreadWorkerInit.cttz_i8; else PthreadWorkerInit.cttz_i8 = cttz_i8 = allocate([' + range(256).map(function(x) { return cttz(x) }).join(',') + '], "i8", ALLOC_STATIC);';
#else
return 'var cttz_i8 = allocate([' + range(256).map(function(x) { return cttz(x) }).join(',') + '], "i8", ALLOC_STATIC);';
#endif
}],
llvm_cttz_i32__asm: true,
llvm_cttz_i32__sig: 'ii',
llvm_cttz_i32: function(x) {
x = x|0;
var ret = 0;
ret = {{{ makeGetValueAsm('cttz_i8', 'x & 0xff', 'i8') }}};
if ((ret|0) < 8) return ret|0;
ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 8)&0xff', 'i8') }}};
if ((ret|0) < 8) return (ret + 8)|0;
ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 16)&0xff', 'i8') }}};
if ((ret|0) < 8) return (ret + 16)|0;
return ({{{ makeGetValueAsm('cttz_i8', 'x >>> 24', 'i8') }}} + 24)|0;
},
llvm_cttz_i64__deps: ['llvm_cttz_i32'],
llvm_cttz_i64: function(l, h) {
var ret = _llvm_cttz_i32(l);
if (ret == 32) ret += _llvm_cttz_i32(h);
{{{ makeStructuralReturn(['ret', '0']) }}};
},
llvm_ctpop_i32: function(x) {
var ret = 0;
while (x) {
if (x&1) ret++;
x >>>= 1;
}
return ret;
},
llvm_ctpop_i64__deps: ['llvm_ctpop_i32'],
llvm_ctpop_i64: function(l, h) {
return _llvm_ctpop_i32(l) + _llvm_ctpop_i32(h);
},
llvm_trap: function() {
abort('trap!');
},
llvm_prefetch: function(){},
__assert_fail: function(condition, filename, line, func) {
ABORT = true;
throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace();
},
__assert_func: function(filename, line, func, condition) {
throw 'Assertion failed: ' + (condition ? Pointer_stringify(condition) : 'unknown condition') + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace();
},
__cxa_guard_acquire: function(variable) {
if (!{{{ makeGetValue(0, 'variable', 'i8', null, null, 1) }}}) { // ignore SAFE_HEAP stuff because llvm mixes i64 and i8 here
{{{ makeSetValue(0, 'variable', '1', 'i8') }}};
return 1;
}
return 0;
},
__cxa_guard_release: function() {},
__cxa_guard_abort: function() {},
$EXCEPTIONS: {
last: 0,
caught: [],
infos: {},
deAdjust: function(adjusted) {
if (!adjusted || EXCEPTIONS.infos[adjusted]) return adjusted;
for (var ptr in EXCEPTIONS.infos) {
var info = EXCEPTIONS.infos[ptr];
if (info.adjusted === adjusted) {
#if EXCEPTION_DEBUG
Module.printErr('de-adjusted exception ptr ' + adjusted + ' to ' + ptr);
#endif
return ptr;
}
}
#if EXCEPTION_DEBUG
Module.printErr('no de-adjustment for unknown exception ptr ' + adjusted);
#endif
return adjusted;
},
addRef: function(ptr) {
#if EXCEPTION_DEBUG
Module.printErr('addref ' + ptr);
#endif
if (!ptr) return;
var info = EXCEPTIONS.infos[ptr];
info.refcount++;
},
decRef: function(ptr) {
#if EXCEPTION_DEBUG
Module.printErr('decref ' + ptr);
#endif
if (!ptr) return;
var info = EXCEPTIONS.infos[ptr];
assert(info.refcount > 0);
info.refcount--;
if (info.refcount === 0) {
if (info.destructor) {
Runtime.dynCall('vi', info.destructor, [ptr]);
}
delete EXCEPTIONS.infos[ptr];
___cxa_free_exception(ptr);
#if EXCEPTION_DEBUG
Module.printErr('decref freeing exception ' + [ptr, EXCEPTIONS.last, 'stack', EXCEPTIONS.caught]);
#endif
}
},
clearRef: function(ptr) {
if (!ptr) return;
var info = EXCEPTIONS.infos[ptr];
info.refcount = 0;
},
},
// Exceptions
__cxa_allocate_exception__deps: ['malloc'],
__cxa_allocate_exception: function(size) {
return _malloc(size);
},
__cxa_free_exception__deps: ['free'],
__cxa_free_exception: function(ptr) {
try {
return _free(ptr);
} catch(e) { // XXX FIXME
#if ASSERTIONS
Module.printErr('exception during cxa_free_exception: ' + e);
#endif
}
},
__cxa_increment_exception_refcount__deps: ['$EXCEPTIONS'],
__cxa_increment_exception_refcount: function(ptr) {
EXCEPTIONS.addRef(EXCEPTIONS.deAdjust(ptr));
},
__cxa_decrement_exception_refcount__deps: ['$EXCEPTIONS'],
__cxa_decrement_exception_refcount: function(ptr) {
EXCEPTIONS.decRef(EXCEPTIONS.deAdjust(ptr));
},
// Here, we throw an exception after recording a couple of values that we need to remember
// We also remember that it was the last exception thrown as we need to know that later.
__cxa_throw__sig: 'viii',
__cxa_throw__deps: ['_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch', '$EXCEPTIONS'],
__cxa_throw: function(ptr, type, destructor) {
#if EXCEPTION_DEBUG
Module.printErr('Compiled code throwing an exception, ' + [ptr,type,destructor]);
#endif
EXCEPTIONS.infos[ptr] = {
ptr: ptr,
adjusted: ptr,
type: type,
destructor: destructor,
refcount: 0
};
EXCEPTIONS.last = ptr;
if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
__ZSt18uncaught_exceptionv.uncaught_exception = 1;
} else {
__ZSt18uncaught_exceptionv.uncaught_exception++;
}
{{{ makeThrow('ptr') }}}
},
// This exception will be caught twice, but while begin_catch runs twice,
// we early-exit from end_catch when the exception has been rethrown, so
// pop that here from the caught exceptions.
__cxa_rethrow__deps: ['__cxa_end_catch', '$EXCEPTIONS'],
__cxa_rethrow: function() {
___cxa_end_catch.rethrown = true;
var ptr = EXCEPTIONS.caught.pop();
#if EXCEPTION_DEBUG
Module.printErr('Compiled code RE-throwing an exception, popped ' + [ptr, EXCEPTIONS.last, 'stack', EXCEPTIONS.caught]);
#endif
EXCEPTIONS.last = ptr;
{{{ makeThrow('ptr') }}}
},
llvm_eh_exception__deps: ['$EXCEPTIONS'],
llvm_eh_exception: function() {
return EXCEPTIONS.last;
},
llvm_eh_selector__jsargs: true,
llvm_eh_selector__deps: ['$EXCEPTIONS'],
llvm_eh_selector: function(unused_exception_value, personality/*, varargs*/) {
var type = EXCEPTIONS.last;
for (var i = 2; i < arguments.length; i++) {
if (arguments[i] == type) return type;
}
return 0;
},
llvm_eh_typeid_for: function(type) {
return type;
},
__cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv', '$EXCEPTIONS'],
__cxa_begin_catch: function(ptr) {
__ZSt18uncaught_exceptionv.uncaught_exception--;
EXCEPTIONS.caught.push(ptr);
#if EXCEPTION_DEBUG
Module.printErr('cxa_begin_catch ' + [ptr, 'stack', EXCEPTIONS.caught]);
#endif
EXCEPTIONS.addRef(EXCEPTIONS.deAdjust(ptr));
return ptr;
},
// We're done with a catch. Now, we can run the destructor if there is one
// and free the exception. Note that if the dynCall on the destructor fails
// due to calling apply on undefined, that means that the destructor is
// an invalid index into the FUNCTION_TABLE, so something has gone wrong.
__cxa_end_catch__deps: ['__cxa_free_exception', '$EXCEPTIONS'],
__cxa_end_catch: function() {
if (___cxa_end_catch.rethrown) {
___cxa_end_catch.rethrown = false;
return;
}
// Clear state flag.
asm['setThrew'](0);
// Call destructor if one is registered then clear it.
var ptr = EXCEPTIONS.caught.pop();
#if EXCEPTION_DEBUG
Module.printErr('cxa_end_catch popped ' + [ptr, EXCEPTIONS.last, 'stack', EXCEPTIONS.caught]);
#endif
if (ptr) {
EXCEPTIONS.decRef(EXCEPTIONS.deAdjust(ptr));
EXCEPTIONS.last = 0; // XXX in decRef?
}
},
__cxa_get_exception_ptr: function(ptr) {
#if EXCEPTION_DEBUG
Module.printErr('cxa_get_exception_ptr ' + ptr);
#endif
// TODO: use info.adjusted?
return ptr;
},
_ZSt18uncaught_exceptionv: function() { // std::uncaught_exception()
return !!__ZSt18uncaught_exceptionv.uncaught_exception;
},
__cxa_uncaught_exception__deps: ['_ZSt18uncaught_exceptionv'],
__cxa_uncaught_exception: function() {
return !!__ZSt18uncaught_exceptionv.uncaught_exception;
},
__cxa_call_unexpected: function(exception) {
Module.printErr('Unexpected exception thrown, this is not properly supported - aborting');
ABORT = true;
throw exception;
},
__cxa_current_primary_exception: function() {
var ret = EXCEPTIONS.caught[EXCEPTIONS.caught.length-1] || 0;
if (ret) EXCEPTIONS.addRef(EXCEPTIONS.deAdjust(ret));
return ret;
},
__cxa_rethrow_primary_exception__deps: ['__cxa_rethrow'],
__cxa_rethrow_primary_exception: function(ptr) {
if (!ptr) return;
EXCEPTIONS.caught.push(ptr);
___cxa_rethrow();
},
terminate: '__cxa_call_unexpected',
__gxx_personality_v0__deps: ['_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'],
__gxx_personality_v0: function() {
},
// Finds a suitable catch clause for when an exception is thrown.
// In normal compilers, this functionality is handled by the C++
// 'personality' routine. This is passed a fairly complex structure
// relating to the context of the exception and makes judgements
// about how to handle it. Some of it is about matching a suitable
// catch clause, and some of it is about unwinding. We already handle
// unwinding using 'if' blocks around each function, so the remaining
// functionality boils down to picking a suitable 'catch' block.
// We'll do that here, instead, to keep things simpler.
__cxa_find_matching_catch__deps: ['__resumeException', '$EXCEPTIONS'],
__cxa_find_matching_catch: function() {
var thrown = EXCEPTIONS.last;
if (!thrown) {
// just pass through the null ptr
{{{ makeStructuralReturn([0, 0]) }}};
}
var info = EXCEPTIONS.infos[thrown];
var throwntype = info.type;
if (!throwntype) {
// just pass through the thrown ptr
{{{ makeStructuralReturn(['thrown', 0]) }}};
}
var typeArray = Array.prototype.slice.call(arguments);
var pointer = Module['___cxa_is_pointer_type'](throwntype);
// can_catch receives a **, add indirection
if (!___cxa_find_matching_catch.buffer) ___cxa_find_matching_catch.buffer = _malloc(4);
#if EXCEPTION_DEBUG
Module.print("can_catch on " + [thrown]);
#endif
{{{ makeSetValue('___cxa_find_matching_catch.buffer', '0', 'thrown', '*') }}};
thrown = ___cxa_find_matching_catch.buffer;
// The different catch blocks are denoted by different types.
// Due to inheritance, those types may not precisely match the
// type of the thrown object. Find one which matches, and
// return the type of the catch block which should be called.
for (var i = 0; i < typeArray.length; i++) {
if (typeArray[i] && Module['___cxa_can_catch'](typeArray[i], throwntype, thrown)) {
thrown = {{{ makeGetValue('thrown', '0', '*') }}}; // undo indirection
info.adjusted = thrown;
#if EXCEPTION_DEBUG
Module.print(" can_catch found " + [thrown, typeArray[i]]);
#endif
{{{ makeStructuralReturn(['thrown', 'typeArray[i]']) }}};
}
}
// Shouldn't happen unless we have bogus data in typeArray
// or encounter a type for which emscripten doesn't have suitable
// typeinfo defined. Best-efforts match just in case.
thrown = {{{ makeGetValue('thrown', '0', '*') }}}; // undo indirection
{{{ makeStructuralReturn(['thrown', 'throwntype']) }}};
},
__resumeException__deps: ['$EXCEPTIONS', function() { Functions.libraryFunctions['___resumeException'] = 1 }], // will be called directly from compiled code
__resumeException: function(ptr) {
#if EXCEPTION_DEBUG
Module.print("Resuming exception " + [ptr, EXCEPTIONS.last]);
#endif
if (!EXCEPTIONS.last) { EXCEPTIONS.last = ptr; }
EXCEPTIONS.clearRef(EXCEPTIONS.deAdjust(ptr)); // exception refcount should be cleared, but don't free it
{{{ makeThrow('ptr') }}}
},
llvm_uadd_with_overflow_i8: function(x, y) {
x = x & 0xff;
y = y & 0xff;
{{{ makeStructuralReturn(['(x+y) & 0xff', 'x+y > 255']) }}};
},
llvm_umul_with_overflow_i8: function(x, y) {
x = x & 0xff;
y = y & 0xff;
{{{ makeStructuralReturn(['(x*y) & 0xff', 'x*y > 255']) }}};
},
llvm_uadd_with_overflow_i16: function(x, y) {
x = x & 0xffff;
y = y & 0xffff;
{{{ makeStructuralReturn(['(x+y) & 0xffff', 'x+y > 65535']) }}};
},
llvm_umul_with_overflow_i16: function(x, y) {
x = x & 0xffff;
y = y & 0xffff;
{{{ makeStructuralReturn(['(x*y) & 0xffff', 'x*y > 65535']) }}};
},
llvm_uadd_with_overflow_i32: function(x, y) {
x = x>>>0;
y = y>>>0;
{{{ makeStructuralReturn(['(x+y)>>>0', 'x+y > 4294967295']) }}};
},
llvm_umul_with_overflow_i32: function(x, y) {
x = x>>>0;
y = y>>>0;
{{{ makeStructuralReturn(['(x*y)>>>0', 'x*y > 4294967295']) }}};
},
llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }],
llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) {
#if ASSERTIONS
Runtime.warnOnce('no overflow support in llvm_umul_with_overflow_i64');
#endif
var low = ___muldi3(xl, xh, yl, yh);
{{{ makeStructuralReturn(['low', makeGetTempRet0(), '0']) }}};
},
llvm_stacksave: function() {
var self = _llvm_stacksave;
if (!self.LLVM_SAVEDSTACKS) {
self.LLVM_SAVEDSTACKS = [];
}
self.LLVM_SAVEDSTACKS.push(Runtime.stackSave());
return self.LLVM_SAVEDSTACKS.length-1;
},
llvm_stackrestore: function(p) {
var self = _llvm_stacksave;
var ret = self.LLVM_SAVEDSTACKS[p];
self.LLVM_SAVEDSTACKS.splice(p, 1);
Runtime.stackRestore(ret);
},
__cxa_pure_virtual: function() {
ABORT = true;
throw 'Pure virtual function called!';
},
llvm_flt_rounds: function() {
return -1; // 'indeterminable' for FLT_ROUNDS
},
llvm_memory_barrier: function(){},
llvm_atomic_load_add_i32_p0i32: function(ptr, delta) {
var ret = {{{ makeGetValue('ptr', '0', 'i32') }}};
{{{ makeSetValue('ptr', '0', 'ret+delta', 'i32') }}};
return ret;
},
llvm_expect_i32__inline: function(val, expected) {
return '(' + val + ')';
},
llvm_lifetime_start: function() {},
llvm_lifetime_end: function() {},
llvm_invariant_start: function() {},
llvm_invariant_end: function() {},
llvm_objectsize_i32: function() { return -1 }, // TODO: support this
llvm_dbg_declare__inline: function() { throw 'llvm_debug_declare' }, // avoid warning
// llvm-nacl
llvm_nacl_atomic_store_i32__inline: true,
llvm_nacl_atomic_cmpxchg_i8__inline: true,
llvm_nacl_atomic_cmpxchg_i16__inline: true,
llvm_nacl_atomic_cmpxchg_i32__inline: true,
// gnu atomics
__atomic_is_lock_free: function(size, ptr) {
return size <= 4 && (ptr&(size-1)) == 0;
},
__atomic_load_8: function(ptr, memmodel) {
{{{ makeStructuralReturn([makeGetValue('ptr', 0, 'i32'), makeGetValue('ptr', 4, 'i32')]) }}};
},
__atomic_store_8: function(ptr, vall, valh, memmodel) {
{{{ makeSetValue('ptr', 0, 'vall', 'i32') }}};
{{{ makeSetValue('ptr', 4, 'valh', 'i32') }}};
},
__atomic_exchange_8: function(ptr, vall, valh, memmodel) {
var l = {{{ makeGetValue('ptr', 0, 'i32') }}};
var h = {{{ makeGetValue('ptr', 4, 'i32') }}};
{{{ makeSetValue('ptr', 0, 'vall', 'i32') }}};
{{{ makeSetValue('ptr', 4, 'valh', 'i32') }}};
{{{ makeStructuralReturn(['l', 'h']) }}};
},
__atomic_compare_exchange_8: function(ptr, expected, desiredl, desiredh, weak, success_memmodel, failure_memmodel) {
var pl = {{{ makeGetValue('ptr', 0, 'i32') }}};
var ph = {{{ makeGetValue('ptr', 4, 'i32') }}};
var el = {{{ makeGetValue('expected', 0, 'i32') }}};
var eh = {{{ makeGetValue('expected', 4, 'i32') }}};
if (pl === el && ph === eh) {
{{{ makeSetValue('ptr', 0, 'desiredl', 'i32') }}};
{{{ makeSetValue('ptr', 4, 'desiredh', 'i32') }}};
return 1;
} else {
{{{ makeSetValue('expected', 0, 'pl', 'i32') }}};
{{{ makeSetValue('expected', 4, 'ph', 'i32') }}};
return 0;
}
},
__atomic_fetch_add_8__deps: ['llvm_uadd_with_overflow_i64'],
__atomic_fetch_add_8: function(ptr, vall, valh, memmodel) {
var l = {{{ makeGetValue('ptr', 0, 'i32') }}};
var h = {{{ makeGetValue('ptr', 4, 'i32') }}};
{{{ makeSetValue('ptr', 0, '_llvm_uadd_with_overflow_i64(l, h, vall, valh)', 'i32') }}};
{{{ makeSetValue('ptr', 4, makeGetTempRet0(), 'i32') }}};
{{{ makeStructuralReturn(['l', 'h']) }}};
},
__atomic_fetch_sub_8__deps: ['i64Subtract'],
__atomic_fetch_sub_8: function(ptr, vall, valh, memmodel) {
var l = {{{ makeGetValue('ptr', 0, 'i32') }}};
var h = {{{ makeGetValue('ptr', 4, 'i32') }}};
{{{ makeSetValue('ptr', 0, '_i64Subtract(l, h, vall, valh)', 'i32') }}};
{{{ makeSetValue('ptr', 4, makeGetTempRet0(), 'i32') }}};
{{{ makeStructuralReturn(['l', 'h']) }}};
},
__atomic_fetch_and_8__deps: ['i64Subtract'],
__atomic_fetch_and_8: function(ptr, vall, valh, memmodel) {
var l = {{{ makeGetValue('ptr', 0, 'i32') }}};
var h = {{{ makeGetValue('ptr', 4, 'i32') }}};
{{{ makeSetValue('ptr', 0, 'l&vall', 'i32') }}};
{{{ makeSetValue('ptr', 4, 'h&valh', 'i32') }}};
{{{ makeStructuralReturn(['l', 'h']) }}};
},
__atomic_fetch_or_8: function(ptr, vall, valh, memmodel) {
var l = {{{ makeGetValue('ptr', 0, 'i32') }}};
var h = {{{ makeGetValue('ptr', 4, 'i32') }}};
{{{ makeSetValue('ptr', 0, 'l|vall', 'i32') }}};
{{{ makeSetValue('ptr', 4, 'h|valh', 'i32') }}};
{{{ makeStructuralReturn(['l', 'h']) }}};
},
__atomic_fetch_xor_8: function(ptr, vall, valh, memmodel) {
var l = {{{ makeGetValue('ptr', 0, 'i32') }}};
var h = {{{ makeGetValue('ptr', 4, 'i32') }}};
{{{ makeSetValue('ptr', 0, 'l^vall', 'i32') }}};
{{{ makeSetValue('ptr', 4, 'h^valh', 'i32') }}};
{{{ makeStructuralReturn(['l', 'h']) }}};
},
// ==========================================================================
// llvm-mono integration
// ==========================================================================
llvm_mono_load_i8_p0i8: function(ptr) {
return {{{ makeGetValue('ptr', 0, 'i8') }}};
},
llvm_mono_store_i8_p0i8: function(value, ptr) {
{{{ makeSetValue('ptr', 0, 'value', 'i8') }}};
},
llvm_mono_load_i16_p0i16: function(ptr) {
return {{{ makeGetValue('ptr', 0, 'i16') }}};
},
llvm_mono_store_i16_p0i16: function(value, ptr) {
{{{ makeSetValue('ptr', 0, 'value', 'i16') }}};
},
llvm_mono_load_i32_p0i32: function(ptr) {
return {{{ makeGetValue('ptr', 0, 'i32') }}};
},
llvm_mono_store_i32_p0i32: function(value, ptr) {
{{{ makeSetValue('ptr', 0, 'value', 'i32') }}};
},
// ==========================================================================
// math.h
// ==========================================================================
cos: 'Math_cos',
cosf: 'Math_cos',
cosl: 'Math_cos',
sin: 'Math_sin',
sinf: 'Math_sin',
sinl: 'Math_sin',
tan: 'Math_tan',
tanf: 'Math_tan',
tanl: 'Math_tan',
acos: 'Math_acos',
acosf: 'Math_acos',
acosl: 'Math_acos',
asin: 'Math_asin',
asinf: 'Math_asin',
asinl: 'Math_asin',
atan: 'Math_atan',
atanf: 'Math_atan',
atanl: 'Math_atan',
atan2: 'Math_atan2',
atan2f: 'Math_atan2',
atan2l: 'Math_atan2',
exp: 'Math_exp',
expf: 'Math_exp',
expl: 'Math_exp',
// The erf and erfc functions are inspired from
// http://www.digitalmars.com/archives/cplusplus/3634.html
// and mruby source code at
// https://github.com/mruby/mruby/blob/master/src/math.c
erfc: function(x) {
var MATH_TOLERANCE = 1E-12;
var ONE_SQRTPI = 0.564189583547756287;
var a = 1;
var b = x;
var c = x;
var d = x * x + 0.5;
var n = 1.0;
var q2 = b / d;
var q1, t;
if (Math.abs(x) < 2.2) {
return 1.0 - _erf(x);
}
if (x < 0) {
return 2.0 - _erfc(-x);
}
do {
t = a * n + b * x;
a = b;
b = t;
t = c * n + d * x;
c = d;
d = t;
n += 0.5;
q1 = q2;
q2 = b / d;
} while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE);
return (ONE_SQRTPI * Math.exp(- x * x) * q2);
},
erfcf: 'erfc',
erfcl: 'erfc',
erf__deps: ['erfc'],
erf: function(x) {
var MATH_TOLERANCE = 1E-12;
var TWO_SQRTPI = 1.128379167095512574;
var sum = x;
var term = x;
var xsqr = x*x;
var j = 1;
if (Math.abs(x) > 2.2) {
return 1.0 - _erfc(x);
}
do {
term *= xsqr / j;
sum -= term / (2 * j + 1);
++j;
term *= xsqr / j;
sum += term / (2 * j + 1);
++j;
} while (Math.abs(term / sum) > MATH_TOLERANCE);
return (TWO_SQRTPI * sum);
},
erff: 'erf',
erfl: 'erf',
log: 'Math_log',
logf: 'Math_log',
logl: 'Math_log',
sqrt: 'Math_sqrt',
sqrtf: 'Math_sqrt',
sqrtl: 'Math_sqrt',
fabs: 'Math_abs',
fabsf: 'Math_abs',
fabsl: 'Math_abs',
llvm_fabs_f32: 'Math_abs',
llvm_fabs_f64: 'Math_abs',
ceil: 'Math_ceil',
ceilf: 'Math_ceil',
ceill: 'Math_ceil',
floor: 'Math_floor',
floorf: 'Math_floor',
floorl: 'Math_floor',
pow: 'Math_pow',
powf: 'Math_pow',
powl: 'Math_pow',
llvm_sqrt_f32: 'Math_sqrt',
llvm_sqrt_f64: 'Math_sqrt',
llvm_pow_f32: 'Math_pow',
llvm_pow_f64: 'Math_pow',
llvm_log_f32: 'Math_log',
llvm_log_f64: 'Math_log',
llvm_exp_f32: 'Math_exp',
llvm_exp_f64: 'Math_exp',
_reallyNegative: function(x) {
return x < 0 || (x === 0 && (1/x) === -Infinity);
},
div: function(divt, numer, denom) {
var quot = (numer / denom) | 0;
var rem = numer - quot * denom;
{{{ makeSetValue('divt', C_STRUCTS.div_t.quot, 'quot', 'i32') }}};
{{{ makeSetValue('divt', C_STRUCTS.div_t.rem, 'rem', 'i32') }}};
return divt;
},
// ==========================================================================
// sys/utsname.h
// ==========================================================================
uname: function(name) {
// int uname(struct utsname *name);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/uname.html
var layout = {{{ JSON.stringify(C_STRUCTS.utsname) }}};
function copyString(element, value) {
var offset = layout[element];
writeAsciiToMemory(value, name + offset);
}
if (name === 0) {
return -1;
} else {
copyString('sysname', 'Emscripten');
copyString('nodename', 'emscripten');
copyString('release', '1.0');
copyString('version', '#1');
copyString('machine', 'x86-JS');
return 0;
}
},
// ==========================================================================
// dlfcn.h - Dynamic library loading
//
// Some limitations:
//
// * Minification on each file separately may not work, as they will
// have different shortened names. You can in theory combine them, then
// minify, then split... perhaps.
//
// * LLVM optimizations may fail. If the child wants to access a function
// in the parent, LLVM opts may remove it from the parent when it is
// being compiled. Not sure how to tell LLVM to not do so.
// ==========================================================================
$DLFCN: {
error: null,
errorMsg: null,
loadedLibs: {}, // handle -> [refcount, name, lib_object]
loadedLibNames: {}, // name -> handle
},
// void* dlopen(const char* filename, int flag);
dlopen__deps: ['$DLFCN', '$FS', '$ENV'],
dlopen: function(filename, flag) {
// void *dlopen(const char *file, int mode);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
filename = filename === 0 ? '__self__' : (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename);
if (DLFCN.loadedLibNames[filename]) {
// Already loaded; increment ref count and return.
var handle = DLFCN.loadedLibNames[filename];
DLFCN.loadedLibs[handle].refcount++;
return handle;
}
if (filename === '__self__') {
var handle = -1;
var lib_module = Module;
var cached_functions = {};
} else {
var target = FS.findObject(filename);
if (!target || target.isFolder || target.isDevice) {
DLFCN.errorMsg = 'Could not find dynamic lib: ' + filename;
return 0;
} else {
FS.forceLoadFile(target);
var lib_data = FS.readFile(filename, { encoding: 'utf8' });
}
try {
var lib_module = eval(lib_data)(
Runtime.alignFunctionTables(),
Module
);
} catch (e) {
#if ASSERTIONS
Module.printErr('Error in loading dynamic library: ' + e);
#endif
DLFCN.errorMsg = 'Could not evaluate dynamic lib: ' + filename;
return 0;
}
// Not all browsers support Object.keys().
var handle = 1;
for (var key in DLFCN.loadedLibs) {
if (DLFCN.loadedLibs.hasOwnProperty(key)) handle++;
}
// We don't care about RTLD_NOW and RTLD_LAZY.
if (flag & 256) { // RTLD_GLOBAL
for (var ident in lib_module) {
if (lib_module.hasOwnProperty(ident)) {
Module[ident] = lib_module[ident];
}
}
}
var cached_functions = {};
}
DLFCN.loadedLibs[handle] = {
refcount: 1,
name: filename,
module: lib_module,
cached_functions: cached_functions
};
DLFCN.loadedLibNames[filename] = handle;
return handle;
},
// int dlclose(void* handle);
dlclose__deps: ['$DLFCN'],
dlclose: function(handle) {
// int dlclose(void *handle);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlclose.html
if (!DLFCN.loadedLibs[handle]) {
DLFCN.errorMsg = 'Tried to dlclose() unopened handle: ' + handle;
return 1;
} else {
var lib_record = DLFCN.loadedLibs[handle];
if (--lib_record.refcount == 0) {
if (lib_record.module.cleanups) {
lib_record.module.cleanups.forEach(function(cleanup) { cleanup() });
}
delete DLFCN.loadedLibNames[lib_record.name];
delete DLFCN.loadedLibs[handle];
}
return 0;
}
},
// void* dlsym(void* handle, const char* symbol);
dlsym__deps: ['$DLFCN'],
dlsym: function(handle, symbol) {
// void *dlsym(void *restrict handle, const char *restrict name);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
symbol = Pointer_stringify(symbol);
if (!DLFCN.loadedLibs[handle]) {
DLFCN.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle;
return 0;
} else {
var lib = DLFCN.loadedLibs[handle];
symbol = '_' + symbol;
if (lib.cached_functions.hasOwnProperty(symbol)) {
return lib.cached_functions[symbol];
}
if (!lib.module.hasOwnProperty(symbol)) {
DLFCN.errorMsg = ('Tried to lookup unknown symbol "' + symbol +
'" in dynamic lib: ' + lib.name);
return 0;
} else {
var result = lib.module[symbol];
if (typeof result == 'function') {
result = Runtime.addFunction(result);
lib.cached_functions = result;
}
return result;
}
}
},
// char* dlerror(void);
dlerror__deps: ['$DLFCN'],
dlerror: function() {
// char *dlerror(void);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlerror.html
if (DLFCN.errorMsg === null) {
return 0;
} else {
if (DLFCN.error) _free(DLFCN.error);
var msgArr = intArrayFromString(DLFCN.errorMsg);
DLFCN.error = allocate(msgArr, 'i8', ALLOC_NORMAL);
DLFCN.errorMsg = null;
return DLFCN.error;
}
},
dladdr: function(addr, info) {
// report all function pointers as coming from this program itself XXX not really correct in any way
var fname = allocate(intArrayFromString(Module['thisProgram'] || './this.program'), 'i8', ALLOC_NORMAL); // XXX leak
{{{ makeSetValue('addr', 0, 'fname', 'i32') }}};
{{{ makeSetValue('addr', QUANTUM_SIZE, '0', 'i32') }}};
{{{ makeSetValue('addr', QUANTUM_SIZE*2, '0', 'i32') }}};
{{{ makeSetValue('addr', QUANTUM_SIZE*3, '0', 'i32') }}};
return 1;
},
// ==========================================================================
// pwd.h
// ==========================================================================
// TODO: Implement.
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/pwd.h.html
getpwuid: function(uid) {
return 0; // NULL
},
// ==========================================================================
// termios.h
// ==========================================================================
tcgetattr: function(fildes, termios_p) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_TCGETATTR') }}}, fildes, termios_p);
#endif
// http://pubs.opengroup.org/onlinepubs/009695399/functions/tcgetattr.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
if (!stream.tty) {
___setErrNo(ERRNO_CODES.ENOTTY);
return -1;
}
return 0;
},
tcsetattr: function(fildes, optional_actions, termios_p) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_TCSETATTR') }}}, fildes, optional_actions, termios_p);
#endif
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/tcsetattr.html
var stream = FS.getStream(fildes);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
if (!stream.tty) {
___setErrNo(ERRNO_CODES.ENOTTY);
return -1;
}
return 0;
},
cfgetospeed: function(termios_p) {
#if ASSERTIONS
Runtime.warnOnce('cfgetospeed() returning a fake value');
#endif
return 15;
},
// ==========================================================================
// time.h
// ==========================================================================
clock: function() {
if (_clock.start === undefined) _clock.start = Date.now();
return ((Date.now() - _clock.start) * ({{{ cDefine('CLOCKS_PER_SEC') }}} / 1000))|0;
},
time: function(ptr) {
var ret = (Date.now()/1000)|0;
if (ptr) {
{{{ makeSetValue('ptr', 0, 'ret', 'i32') }}};
}
return ret;
},
difftime: function(time1, time0) {
return time1 - time0;
},
// Statically allocated time struct.
#if USE_PTHREADS
__tm_current: '; if (ENVIRONMENT_IS_PTHREAD) ___tm_current = PthreadWorkerInit.___tm_current; else PthreadWorkerInit.___tm_current = ___tm_current = allocate({{{ C_STRUCTS.tm.__size__ }}}, "i8", ALLOC_STATIC)',
__tm_timezone: '; if (ENVIRONMENT_IS_PTHREAD) ___tm_timezone = PthreadWorkerInit.___tm_timezone; else PthreadWorkerInit.___tm_timezone = ___tm_timezone = allocate(intArrayFromString("GMT"), "i8", ALLOC_STATIC)',
__tm_formatted: '; if (ENVIRONMENT_IS_PTHREAD) ___tm_formatted = PthreadWorkerInit.___tm_formatted; else PthreadWorkerInit.___tm_formatted = ___tm_formatted = allocate({{{ C_STRUCTS.tm.__size__ }}}, "i8", ALLOC_STATIC)',
#else
__tm_current: 'allocate({{{ C_STRUCTS.tm.__size__ }}}, "i8", ALLOC_STATIC)',
// Statically allocated copy of the string "GMT" for gmtime() to point to
__tm_timezone: 'allocate(intArrayFromString("GMT"), "i8", ALLOC_STATIC)',
// Statically allocated time strings.
__tm_formatted: 'allocate({{{ C_STRUCTS.tm.__size__ }}}, "i8", ALLOC_STATIC)',
#endif
mktime__deps: ['tzset'],
mktime: function(tmPtr) {
_tzset();
var date = new Date({{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}} + 1900,
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}},
0);
// There's an ambiguous hour when the time goes back; the tm_isdst field is
// used to disambiguate it. Date() basically guesses, so we fix it up if it
// guessed wrong, or fill in tm_isdst with the guess if it's -1.
var dst = {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'i32') }}};
var guessedOffset = date.getTimezoneOffset();
var start = new Date(date.getFullYear(), 0, 1);
var summerOffset = new Date(2000, 6, 1).getTimezoneOffset();
var winterOffset = start.getTimezoneOffset();
var dstOffset = Math.min(winterOffset, summerOffset); // DST is in December in South
if (dst < 0) {
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'Number(winterOffset != guessedOffset)', 'i32') }}};
} else if ((dst > 0) != (winterOffset != guessedOffset)) {
var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset();
var trueOffset = dst > 0 ? summerOffset : winterOffset;
// Don't try setMinutes(date.getMinutes() + ...) -- it's messed up.
date.setTime(date.getTime() + (trueOffset - guessedOffset)*60000);
}
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}};
var yday = ((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24))|0;
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
return (date.getTime() / 1000)|0;
},
timelocal: 'mktime',
gmtime__deps: ['__tm_current', 'gmtime_r'],
gmtime: function(time) {
return _gmtime_r(time, ___tm_current);
},
gmtime_r__deps: ['__tm_timezone'],
gmtime_r: function(time, tmPtr) {
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}};
var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0);
var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24))|0;
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}};
return tmPtr;
},
timegm__deps: ['tzset'],
timegm: function(tmPtr) {
_tzset();
var time = Date.UTC({{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}} + 1900,
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}},
0);
var date = new Date(time);
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}};
var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0);
var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24))|0;
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
return (date.getTime() / 1000)|0;
},
localtime__deps: ['__tm_current', 'localtime_r'],
localtime: function(time) {
return _localtime_r(time, ___tm_current);
},
localtime_r__deps: ['__tm_timezone', 'tzset'],
localtime_r: function(time, tmPtr) {
_tzset();
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}};
var start = new Date(date.getFullYear(), 0, 1);
var yday = ((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24))|0;
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '-(date.getTimezoneOffset() * 60)', 'i32') }}};
// DST is in December in South
var summerOffset = new Date(2000, 6, 1).getTimezoneOffset();
var winterOffset = start.getTimezoneOffset();
var dst = (date.getTimezoneOffset() == Math.min(winterOffset, summerOffset))|0;
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}};
var zonePtr = {{{ makeGetValue(makeGlobalUse('_tzname'), 'dst ? Runtime.QUANTUM_SIZE : 0', 'i32') }}};
{{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, 'zonePtr', 'i32') }}};
return tmPtr;
},
asctime__deps: ['__tm_formatted', 'asctime_r'],
asctime: function(tmPtr) {
return _asctime_r(tmPtr, ___tm_formatted);
},
asctime_r__deps: ['__tm_formatted', 'mktime'],
asctime_r: function(tmPtr, buf) {
var date = {
tm_sec: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}},
tm_min: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}},
tm_hour: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'i32') }}},
tm_mday: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'i32') }}},
tm_mon: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}},
tm_year: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}},
tm_wday: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'i32') }}}
};
var days = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];
var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
var s = days[date.tm_wday] + ' ' + months[date.tm_mon] +
(date.tm_mday < 10 ? ' ' : ' ') + date.tm_mday +
(date.tm_hour < 10 ? ' 0' : ' ') + date.tm_hour +
(date.tm_min < 10 ? ':0' : ':') + date.tm_min +
(date.tm_sec < 10 ? ':0' : ':') + date.tm_sec +
' ' + (1900 + date.tm_year) + "\n";
writeStringToMemory(s, buf);
return buf;
},
ctime__deps: ['__tm_current', 'ctime_r'],
ctime: function(timer) {
return _ctime_r(timer, ___tm_current);
},
ctime_r__deps: ['localtime_r', 'asctime_r'],
ctime_r: function(time, buf) {
var stack = Runtime.stackSave();
var rv = _asctime_r(_localtime_r(time, Runtime.stackAlloc({{{ C_STRUCTS.tm.__size__ }}})), buf);
Runtime.stackRestore(stack);
return rv;
},
dysize: function(year) {
var leap = ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)));
return leap ? 366 : 365;
},
// TODO: Initialize these to defaults on startup from system settings.
// Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm)
#if USE_PTHREADS
tzname: '; if (ENVIRONMENT_IS_PTHREAD) _tzname = PthreadWorkerInit._tzname; else PthreadWorkerInit._tzname = _tzname = allocate({{{ 2*Runtime.QUANTUM_SIZE }}}, "i32*", ALLOC_STATIC)',
daylight: '; if (ENVIRONMENT_IS_PTHREAD) _daylight = PthreadWorkerInit._daylight; else PthreadWorkerInit._daylight = _daylight = allocate(1, "i32*", ALLOC_STATIC)',
timezone: '; if (ENVIRONMENT_IS_PTHREAD) _timezone = PthreadWorkerInit._timezone; else PthreadWorkerInit._timezone = _timezone = allocate(1, "i32*", ALLOC_STATIC)',
#else
tzname: 'allocate({{{ 2*Runtime.QUANTUM_SIZE }}}, "i32*", ALLOC_STATIC)',
daylight: 'allocate(1, "i32*", ALLOC_STATIC)',
timezone: 'allocate(1, "i32*", ALLOC_STATIC)',
#endif
tzset__deps: ['tzname', 'daylight', 'timezone'],
tzset: function() {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_0({{{ cDefine('EM_PROXIED_TZSET') }}});
#endif
// TODO: Use (malleable) environment variables instead of system settings.
if (_tzset.called) return;
_tzset.called = true;
{{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}};
var winter = new Date(2000, 0, 1);
var summer = new Date(2000, 6, 1);
{{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}};
function extractZone(date) {
var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/);
return match ? match[1] : "GMT";
};
var winterName = extractZone(winter);
var summerName = extractZone(summer);
var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
if (summer.getTimezoneOffset() < winter.getTimezoneOffset()) {
// Northern hemisphere
{{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}};
{{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}};
} else {
{{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'summerNamePtr', 'i32') }}};
{{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'winterNamePtr', 'i32') }}};
}
},
stime__deps: ['$ERRNO_CODES', '__setErrNo'],
stime: function(when) {
___setErrNo(ERRNO_CODES.EPERM);
return -1;
},
_MONTH_DAYS_REGULAR: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
_MONTH_DAYS_LEAP: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
_isLeapYear: function(year) {
return year%4 === 0 && (year%100 !== 0 || year%400 === 0);
},
_arraySum: function(array, index) {
var sum = 0;
for (var i = 0; i <= index; sum += array[i++]);
return sum;
},
_addDays__deps: ['_isLeapYear', '_MONTH_DAYS_LEAP', '_MONTH_DAYS_REGULAR'],
_addDays: function(date, days) {
var newDate = new Date(date.getTime());
while(days > 0) {
var leap = __isLeapYear(newDate.getFullYear());
var currentMonth = newDate.getMonth();
var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth];
if (days > daysInCurrentMonth-newDate.getDate()) {
// we spill over to next month
days -= (daysInCurrentMonth-newDate.getDate()+1);
newDate.setDate(1);
if (currentMonth < 11) {
newDate.setMonth(currentMonth+1)
} else {
newDate.setMonth(0);
newDate.setFullYear(newDate.getFullYear()+1);
}
} else {
// we stay in current month
newDate.setDate(newDate.getDate()+days);
return newDate;
}
}
return newDate;
},
strftime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'],
strftime: function(s, maxsize, format, tm) {
// size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html
var tm_zone = {{{ makeGetValue('tm', C_STRUCTS.tm.tm_zone, 'i32') }}};
var date = {
tm_sec: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_sec, 'i32') }}},
tm_min: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_min, 'i32') }}},
tm_hour: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_hour, 'i32') }}},
tm_mday: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_mday, 'i32') }}},
tm_mon: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_mon, 'i32') }}},
tm_year: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_year, 'i32') }}},
tm_wday: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_wday, 'i32') }}},
tm_yday: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_yday, 'i32') }}},
tm_isdst: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_isdst, 'i32') }}},
tm_gmtoff: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_gmtoff, 'i32') }}},
tm_zone: tm_zone ? Pointer_stringify(tm_zone) : ''
};
var pattern = Pointer_stringify(format);
// expand format
var EXPANSION_RULES_1 = {
'%c': '%a %b %d %H:%M:%S %Y', // Replaced by the locale's appropriate date and time representation - e.g., Mon Aug 3 14:02:01 2013
'%D': '%m/%d/%y', // Equivalent to %m / %d / %y
'%F': '%Y-%m-%d', // Equivalent to %Y - %m - %d
'%h': '%b', // Equivalent to %b
'%r': '%I:%M:%S %p', // Replaced by the time in a.m. and p.m. notation
'%R': '%H:%M', // Replaced by the time in 24-hour notation
'%T': '%H:%M:%S', // Replaced by the time
'%x': '%m/%d/%y', // Replaced by the locale's appropriate date representation
'%X': '%H:%M:%S' // Replaced by the locale's appropriate date representation
};
for (var rule in EXPANSION_RULES_1) {
pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_1[rule]);
}
var WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
function leadingSomething(value, digits, character) {
var str = typeof value === 'number' ? value.toString() : (value || '');
while (str.length < digits) {
str = character[0]+str;
}
return str;
};
function leadingNulls(value, digits) {
return leadingSomething(value, digits, '0');
};
function compareByDay(date1, date2) {
function sgn(value) {
return value < 0 ? -1 : (value > 0 ? 1 : 0);
};
var compare;
if ((compare = sgn(date1.getFullYear()-date2.getFullYear())) === 0) {
if ((compare = sgn(date1.getMonth()-date2.getMonth())) === 0) {
compare = sgn(date1.getDate()-date2.getDate());
}
}
return compare;
};
function getFirstWeekStartDate(janFourth) {
switch (janFourth.getDay()) {
case 0: // Sunday
return new Date(janFourth.getFullYear()-1, 11, 29);
case 1: // Monday
return janFourth;
case 2: // Tuesday
return new Date(janFourth.getFullYear(), 0, 3);
case 3: // Wednesday
return new Date(janFourth.getFullYear(), 0, 2);
case 4: // Thursday
return new Date(janFourth.getFullYear(), 0, 1);
case 5: // Friday
return new Date(janFourth.getFullYear()-1, 11, 31);
case 6: // Saturday
return new Date(janFourth.getFullYear()-1, 11, 30);
}
};
function getWeekBasedYear(date) {
var thisDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4);
var janFourthNextYear = new Date(thisDate.getFullYear()+1, 0, 4);
var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {
// this date is after the start of the first week of this year
if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {
return thisDate.getFullYear()+1;
} else {
return thisDate.getFullYear();
}
} else {
return thisDate.getFullYear()-1;
}
};
var EXPANSION_RULES_2 = {
'%a': function(date) {
return WEEKDAYS[date.tm_wday].substring(0,3);
},
'%A': function(date) {
return WEEKDAYS[date.tm_wday];
},
'%b': function(date) {
return MONTHS[date.tm_mon].substring(0,3);
},
'%B': function(date) {
return MONTHS[date.tm_mon];
},
'%C': function(date) {
var year = date.tm_year+1900;
return leadingNulls((year/100)|0,2);
},
'%d': function(date) {
return leadingNulls(date.tm_mday, 2);
},
'%e': function(date) {
return leadingSomething(date.tm_mday, 2, ' ');
},
'%g': function(date) {
// %g, %G, and %V give values according to the ISO 8601:2000 standard week-based year.
// In this system, weeks begin on a Monday and week 1 of the year is the week that includes
// January 4th, which is also the week that includes the first Thursday of the year, and
// is also the first week that contains at least four days in the year.
// If the first Monday of January is the 2nd, 3rd, or 4th, the preceding days are part of
// the last week of the preceding year; thus, for Saturday 2nd January 1999,
// %G is replaced by 1998 and %V is replaced by 53. If December 29th, 30th,
// or 31st is a Monday, it and any following days are part of week 1 of the following year.
// Thus, for Tuesday 30th December 1997, %G is replaced by 1998 and %V is replaced by 01.
return getWeekBasedYear(date).toString().substring(2);
},
'%G': function(date) {
return getWeekBasedYear(date);
},
'%H': function(date) {
return leadingNulls(date.tm_hour, 2);
},
'%I': function(date) {
return leadingNulls(date.tm_hour < 13 ? date.tm_hour : date.tm_hour-12, 2);
},
'%j': function(date) {
// Day of the year (001-366)
return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date.tm_mon-1), 3);
},
'%m': function(date) {
return leadingNulls(date.tm_mon+1, 2);
},
'%M': function(date) {
return leadingNulls(date.tm_min, 2);
},
'%n': function() {
return '\n';
},
'%p': function(date) {
if (date.tm_hour > 0 && date.tm_hour < 13) {
return 'AM';
} else {
return 'PM';
}
},
'%S': function(date) {
return leadingNulls(date.tm_sec, 2);
},
'%t': function() {
return '\t';
},
'%u': function(date) {
var day = new Date(date.tm_year+1900, date.tm_mon+1, date.tm_mday, 0, 0, 0, 0);
return day.getDay() || 7;
},
'%U': function(date) {
// Replaced by the week number of the year as a decimal number [00,53].
// The first Sunday of January is the first day of week 1;
// days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
var janFirst = new Date(date.tm_year+1900, 0, 1);
var firstSunday = janFirst.getDay() === 0 ? janFirst : __addDays(janFirst, 7-janFirst.getDay());
var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
// is target date after the first Sunday?
if (compareByDay(firstSunday, endDate) < 0) {
// calculate difference in days between first Sunday and endDate
var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
var firstSundayUntilEndJanuary = 31-firstSunday.getDate();
var days = firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
return leadingNulls(Math.ceil(days/7), 2);
}
return compareByDay(firstSunday, janFirst) === 0 ? '01': '00';
},
'%V': function(date) {
// Replaced by the week number of the year (Monday as the first day of the week)
// as a decimal number [01,53]. If the week containing 1 January has four
// or more days in the new year, then it is considered week 1.
// Otherwise, it is the last week of the previous year, and the next week is week 1.
// Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
var janFourthThisYear = new Date(date.tm_year+1900, 0, 4);
var janFourthNextYear = new Date(date.tm_year+1901, 0, 4);
var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
var endDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
if (compareByDay(endDate, firstWeekStartThisYear) < 0) {
// if given date is before this years first week, then it belongs to the 53rd week of last year
return '53';
}
if (compareByDay(firstWeekStartNextYear, endDate) <= 0) {
// if given date is after next years first week, then it belongs to the 01th week of next year
return '01';
}
// given date is in between CW 01..53 of this calendar year
var daysDifference;
if (firstWeekStartThisYear.getFullYear() < date.tm_year+1900) {
// first CW of this year starts last year
daysDifference = date.tm_yday+32-firstWeekStartThisYear.getDate()
} else {
// first CW of this year starts this year
daysDifference = date.tm_yday+1-firstWeekStartThisYear.getDate();
}
return leadingNulls(Math.ceil(daysDifference/7), 2);
},
'%w': function(date) {
var day = new Date(date.tm_year+1900, date.tm_mon+1, date.tm_mday, 0, 0, 0, 0);
return day.getDay();
},
'%W': function(date) {
// Replaced by the week number of the year as a decimal number [00,53].
// The first Monday of January is the first day of week 1;
// days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
var janFirst = new Date(date.tm_year, 0, 1);
var firstMonday = janFirst.getDay() === 1 ? janFirst : __addDays(janFirst, janFirst.getDay() === 0 ? 1 : 7-janFirst.getDay()+1);
var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
// is target date after the first Monday?
if (compareByDay(firstMonday, endDate) < 0) {
var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
var firstMondayUntilEndJanuary = 31-firstMonday.getDate();
var days = firstMondayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
return leadingNulls(Math.ceil(days/7), 2);
}
return compareByDay(firstMonday, janFirst) === 0 ? '01': '00';
},
'%y': function(date) {
// Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
return (date.tm_year+1900).toString().substring(2);
},
'%Y': function(date) {
// Replaced by the year as a decimal number (for example, 1997). [ tm_year]
return date.tm_year+1900;
},
'%z': function(date) {
// Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ).
// For example, "-0430" means 4 hours 30 minutes behind UTC (west of Greenwich).
var off = date.tm_gmtoff;
var ahead = off >= 0;
off = Math.abs(off) / 60;
// convert from minutes into hhmm format (which means 60 minutes = 100 units)
off = (off / 60)*100 + (off % 60);
return (ahead ? '+' : '-') + String("0000" + off).slice(-4);
},
'%Z': function(date) {
return date.tm_zone;
},
'%%': function() {
return '%';
}
};
for (var rule in EXPANSION_RULES_2) {
if (pattern.indexOf(rule) >= 0) {
pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_2[rule](date));
}
}
var bytes = intArrayFromString(pattern, false);
if (bytes.length > maxsize) {
return 0;
}
writeArrayToMemory(bytes, s);
return bytes.length-1;
},
strftime_l__deps: ['strftime'],
strftime_l: function(s, maxsize, format, tm) {
return _strftime(s, maxsize, format, tm); // no locale support yet
},
strptime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'],
strptime: function(buf, format, tm) {
// char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html
var pattern = Pointer_stringify(format);
// escape special characters
// TODO: not sure we really need to escape all of these in JS regexps
var SPECIAL_CHARS = '\\!@#$^&*()+=-[]/{}|:<>?,.';
for (var i=0, ii=SPECIAL_CHARS.length; i<ii; ++i) {
pattern = pattern.replace(new RegExp('\\'+SPECIAL_CHARS[i], 'g'), '\\'+SPECIAL_CHARS[i]);
}
// reduce number of matchers
var EQUIVALENT_MATCHERS = {
'%A': '%a',
'%B': '%b',
'%c': '%x\\s+%X',
'%D': '%m\\/%d\\/%y',
'%e': '%d',
'%h': '%b',
'%R': '%H\\:%M',
'%r': '%I\\:%M\\:%S\\s%p',
'%T': '%H\\:%M\\:%S',
'%x': '%m\\/%d\\/(?:%y|%Y)',
'%X': '%H\\:%M\\:%S'
};
for (var matcher in EQUIVALENT_MATCHERS) {
pattern = pattern.replace(matcher, EQUIVALENT_MATCHERS[matcher]);
}
// TODO: take care of locale
var DATE_PATTERNS = {
/* weeday name */ '%a': '(?:Sun(?:day)?)|(?:Mon(?:day)?)|(?:Tue(?:sday)?)|(?:Wed(?:nesday)?)|(?:Thu(?:rsday)?)|(?:Fri(?:day)?)|(?:Sat(?:urday)?)',
/* month name */ '%b': '(?:Jan(?:uary)?)|(?:Feb(?:ruary)?)|(?:Mar(?:ch)?)|(?:Apr(?:il)?)|May|(?:Jun(?:e)?)|(?:Jul(?:y)?)|(?:Aug(?:ust)?)|(?:Sep(?:tember)?)|(?:Oct(?:ober)?)|(?:Nov(?:ember)?)|(?:Dec(?:ember)?)',
/* century */ '%C': '\\d\\d',
/* day of month */ '%d': '0[1-9]|[1-9](?!\\d)|1\\d|2\\d|30|31',
/* hour (24hr) */ '%H': '\\d(?!\\d)|[0,1]\\d|20|21|22|23',
/* hour (12hr) */ '%I': '\\d(?!\\d)|0\\d|10|11|12',
/* day of year */ '%j': '00[1-9]|0?[1-9](?!\\d)|0?[1-9]\\d(?!\\d)|[1,2]\\d\\d|3[0-6]\\d',
/* month */ '%m': '0[1-9]|[1-9](?!\\d)|10|11|12',
/* minutes */ '%M': '0\\d|\\d(?!\\d)|[1-5]\\d',
/* whitespace */ '%n': '\\s',
/* AM/PM */ '%p': 'AM|am|PM|pm|A\\.M\\.|a\\.m\\.|P\\.M\\.|p\\.m\\.',
/* seconds */ '%S': '0\\d|\\d(?!\\d)|[1-5]\\d|60',
/* week number */ '%U': '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53',
/* week number */ '%W': '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53',
/* weekday number */ '%w': '[0-6]',
/* 2-digit year */ '%y': '\\d\\d',
/* 4-digit year */ '%Y': '\\d\\d\\d\\d',
/* % */ '%%': '%',
/* whitespace */ '%t': '\\s',
};
var MONTH_NUMBERS = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11};
var DAY_NUMBERS_SUN_FIRST = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6};
var DAY_NUMBERS_MON_FIRST = {MON: 0, TUE: 1, WED: 2, THU: 3, FRI: 4, SAT: 5, SUN: 6};
for (var datePattern in DATE_PATTERNS) {
pattern = pattern.replace(datePattern, '('+datePattern+DATE_PATTERNS[datePattern]+')');
}
// take care of capturing groups
var capture = [];
for (var i=pattern.indexOf('%'); i>=0; i=pattern.indexOf('%')) {
capture.push(pattern[i+1]);
pattern = pattern.replace(new RegExp('\\%'+pattern[i+1], 'g'), '');
}
var matches = new RegExp('^'+pattern, "i").exec(Pointer_stringify(buf))
// Module['print'](Pointer_stringify(buf)+ ' is matched by '+((new RegExp('^'+pattern)).source)+' into: '+JSON.stringify(matches));
function initDate() {
function fixup(value, min, max) {
return (typeof value !== 'number' || isNaN(value)) ? min : (value>=min ? (value<=max ? value: max): min);
};
return {
year: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_year, 'i32', 0, 0, 1) }}} + 1900 , 1970, 9999),
month: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_mon, 'i32', 0, 0, 1) }}}, 0, 11),
day: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_mday, 'i32', 0, 0, 1) }}}, 1, 31),
hour: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_hour, 'i32', 0, 0, 1) }}}, 0, 23),
min: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_min, 'i32', 0, 0, 1) }}}, 0, 59),
sec: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_sec, 'i32', 0, 0, 1) }}}, 0, 59)
};
};
if (matches) {
var date = initDate();
var value;
function getMatch(symbol) {
var pos = capture.indexOf(symbol);
// check if symbol appears in regexp
if (pos >= 0) {
// return matched value or null (falsy!) for non-matches
return matches[pos+1];
}
return;
}
// seconds
if ((value=getMatch('S'))) {
date.sec = parseInt(value);
}
// minutes
if ((value=getMatch('M'))) {
date.min = parseInt(value);
}
// hours
if ((value=getMatch('H'))) {
// 24h clock
date.hour = parseInt(value);
} else if ((value = getMatch('I'))) {
// AM/PM clock
var hour = parseInt(value);
if ((value=getMatch('p'))) {
hour += value.toUpperCase()[0] === 'P' ? 12 : 0;
}
date.hour = hour;
}
// year
if ((value=getMatch('Y'))) {
// parse from four-digit year
date.year = parseInt(value);
} else if ((value=getMatch('y'))) {
// parse from two-digit year...
var year = parseInt(value);
if ((value=getMatch('C'))) {
// ...and century
year += parseInt(value)*100;
} else {
// ...and rule-of-thumb
year += year<69 ? 2000 : 1900;
}
date.year = year;
}
// month
if ((value=getMatch('m'))) {
// parse from month number
date.month = parseInt(value)-1;
} else if ((value=getMatch('b'))) {
// parse from month name
date.month = MONTH_NUMBERS[value.substring(0,3).toUpperCase()] || 0;
// TODO: derive month from day in year+year, week number+day of week+year
}
// day
if ((value=getMatch('d'))) {
// get day of month directly
date.day = parseInt(value);
} else if ((value=getMatch('j'))) {
// get day of month from day of year ...
var day = parseInt(value);
var leapYear = __isLeapYear(date.year);
for (var month=0; month<12; ++month) {
var daysUntilMonth = __arraySum(leapYear ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, month-1);
if (day<=daysUntilMonth+(leapYear ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[month]) {
date.day = day-daysUntilMonth;
}
}
} else if ((value=getMatch('a'))) {
// get day of month from weekday ...
var weekDay = value.substring(0,3).toUpperCase();
if ((value=getMatch('U'))) {
// ... and week number (Sunday being first day of week)
// Week number of the year (Sunday as the first day of the week) as a decimal number [00,53].
// All days in a new year preceding the first Sunday are considered to be in week 0.
var weekDayNumber = DAY_NUMBERS_SUN_FIRST[weekDay];
var weekNumber = parseInt(value);
// January 1st
var janFirst = new Date(date.year, 0, 1);
var endDate;
if (janFirst.getDay() === 0) {
// Jan 1st is a Sunday, and, hence in the 1st CW
endDate = __addDays(janFirst, weekDayNumber+7*(weekNumber-1));
} else {
// Jan 1st is not a Sunday, and, hence still in the 0th CW
endDate = __addDays(janFirst, 7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1));
}
date.day = endDate.getDate();
date.month = endDate.getMonth();
} else if ((value=getMatch('W'))) {
// ... and week number (Monday being first day of week)
// Week number of the year (Monday as the first day of the week) as a decimal number [00,53].
// All days in a new year preceding the first Monday are considered to be in week 0.
var weekDayNumber = DAY_NUMBERS_MON_FIRST[weekDay];
var weekNumber = parseInt(value);
// January 1st
var janFirst = new Date(date.year, 0, 1);
var endDate;
if (janFirst.getDay()===1) {
// Jan 1st is a Monday, and, hence in the 1st CW
endDate = __addDays(janFirst, weekDayNumber+7*(weekNumber-1));
} else {
// Jan 1st is not a Monday, and, hence still in the 0th CW
endDate = __addDays(janFirst, 7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1));
}
date.day = endDate.getDate();
date.month = endDate.getMonth();
}
}
/*
tm_sec int seconds after the minute 0-61*
tm_min int minutes after the hour 0-59
tm_hour int hours since midnight 0-23
tm_mday int day of the month 1-31
tm_mon int months since January 0-11
tm_year int years since 1900
tm_wday int days since Sunday 0-6
tm_yday int days since January 1 0-365
tm_isdst int Daylight Saving Time flag
*/
var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0);
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}};
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}};
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}};
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}};
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}};
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}};
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}};
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}};
{{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}};
// we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F
// TODO: not sure that intArrayFromString handles all unicode characters correctly
return buf+intArrayFromString(matches[0]).length-1;
}
return 0;
},
strptime_l__deps: ['strptime'],
strptime_l: function(buf, format, tm) {
return _strptime(buf, format, tm); // no locale support yet
},
getdate: function(string) {
// struct tm *getdate(const char *string);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/getdate.html
// TODO: Implement.
return 0;
},
// ==========================================================================
// sys/time.h
// ==========================================================================
nanosleep__deps: ['usleep'],
nanosleep: function(rqtp, rmtp) {
// int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
var seconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_sec, 'i32') }}};
var nanoseconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
if (rmtp !== 0) {
{{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}};
{{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}};
}
return _usleep((seconds * 1e6) + (nanoseconds / 1000));
},
clock_gettime__deps: ['emscripten_get_now', 'emscripten_get_now_is_monotonic', '$ERRNO_CODES', '__setErrNo'],
clock_gettime: function(clk_id, tp) {
// int clock_gettime(clockid_t clk_id, struct timespec *tp);
var now;
if (clk_id === {{{ cDefine('CLOCK_REALTIME') }}}) {
now = Date.now();
} else if (clk_id === {{{ cDefine('CLOCK_MONOTONIC') }}} && _emscripten_get_now_is_monotonic()) {
now = _emscripten_get_now();
} else {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
{{{ makeSetValue('tp', C_STRUCTS.timespec.tv_sec, '(now/1000)|0', 'i32') }}}; // seconds
{{{ makeSetValue('tp', C_STRUCTS.timespec.tv_nsec, '((now % 1000)*1000*1000)|0', 'i32') }}}; // nanoseconds
return 0;
},
clock_settime__deps: ['$ERRNO_CODES', '__setErrNo'],
clock_settime: function(clk_id, tp) {
// int clock_settime(clockid_t clk_id, const struct timespec *tp);
// Nothing.
___setErrNo(clk_id === {{{ cDefine('CLOCK_REALTIME') }}} ? ERRNO_CODES.EPERM
: ERRNO_CODES.EINVAL);
return -1;
},
clock_getres__deps: ['emscripten_get_now_res', 'emscripten_get_now_is_monotonic', '$ERRNO_CODES', '__setErrNo'],
clock_getres: function(clk_id, res) {
// int clock_getres(clockid_t clk_id, struct timespec *res);
var nsec;
if (clk_id === {{{ cDefine('CLOCK_REALTIME') }}}) {
nsec = 1000 * 1000; // educated guess that it's milliseconds
} else if (clk_id === {{{ cDefine('CLOCK_MONOTONIC') }}} && _emscripten_get_now_is_monotonic()) {
nsec = _emscripten_get_now_res();
} else {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
}
{{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '(nsec/1000000000)|0', 'i32') }}};
{{{ makeSetValue('res', C_STRUCTS.timespec.tv_nsec, 'nsec', 'i32') }}} // resolution is nanoseconds
return 0;
},
clock_getcpuclockid__deps: ['$PROCINFO'],
clock_getcpuclockid: function(pid, clk_id) {
if (pid < 0) return ERRNO_CODES.ESRCH;
if (pid !== 0 && pid !== PROCINFO.pid) return ERRNO_CODES.ENOSYS;
if (clk_id) {{{ makeSetValue('clk_id', 0, 2/*CLOCK_PROCESS_CPUTIME_ID*/, 'i32') }}};
return 0;
},
// http://pubs.opengroup.org/onlinepubs/000095399/basedefs/sys/time.h.html
gettimeofday: function(ptr) {
var now = Date.now();
{{{ makeSetValue('ptr', C_STRUCTS.timeval.tv_sec, '(now/1000)|0', 'i32') }}}; // seconds
{{{ makeSetValue('ptr', C_STRUCTS.timeval.tv_usec, '((now % 1000)*1000)|0', 'i32') }}}; // microseconds
return 0;
},
// ==========================================================================
// sys/timeb.h
// ==========================================================================
ftime: function(p) {
var millis = Date.now();
{{{ makeSetValue('p', C_STRUCTS.timeb.time, '(millis/1000)|0', 'i32') }}};
{{{ makeSetValue('p', C_STRUCTS.timeb.millitm, 'millis % 1000', 'i16') }}};
{{{ makeSetValue('p', C_STRUCTS.timeb.timezone, '0', 'i16') }}}; // Obsolete field
{{{ makeSetValue('p', C_STRUCTS.timeb.dstflag, '0', 'i16') }}}; // Obsolete field
return 0;
},
// ==========================================================================
// sys/times.h
// ==========================================================================
times__deps: ['memset'],
times: function(buffer) {
// clock_t times(struct tms *buffer);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/times.html
// NOTE: This is fake, since we can't calculate real CPU time usage in JS.
if (buffer !== 0) {
_memset(buffer, 0, {{{ C_STRUCTS.tms.__size__ }}});
}
return 0;
},
// ==========================================================================
// sys/types.h
// ==========================================================================
// http://www.kernel.org/doc/man-pages/online/pages/man3/minor.3.html
makedev: function(maj, min) {
return ((maj) << 8 | (min));
},
gnu_dev_makedev: 'makedev',
major: function(dev) {
return ((dev) >> 8);
},
gnu_dev_major: 'major',
minor: function(dev) {
return ((dev) & 0xff);
},
gnu_dev_minor: 'minor',
// ==========================================================================
// setjmp.h
// ==========================================================================
saveSetjmp__asm: true,
saveSetjmp__sig: 'iii',
saveSetjmp__deps: ['realloc'],
saveSetjmp: function(env, label, table, size) {
// Not particularly fast: slow table lookup of setjmpId to label. But setjmp
// prevents relooping anyhow, so slowness is to be expected. And typical case
// is 1 setjmp per invocation, or less.
env = env|0;
label = label|0;
table = table|0;
size = size|0;
var i = 0;
setjmpId = (setjmpId+1)|0;
{{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}};
while ((i|0) < (size|0)) {
if ({{{ makeGetValueAsm('table', '(i<<3)', 'i32') }}} == 0) {
{{{ makeSetValueAsm('table', '(i<<3)', 'setjmpId', 'i32') }}};
{{{ makeSetValueAsm('table', '(i<<3)+4', 'label', 'i32') }}};
// prepare next slot
{{{ makeSetValueAsm('table', '(i<<3)+8', '0', 'i32') }}};
{{{ makeSetTempRet0('size') }}};
return table | 0;
}
i = i+1|0;
}
// grow the table
size = (size*2)|0;
table = _realloc(table|0, 8*(size+1|0)|0) | 0;
table = _saveSetjmp(env|0, label|0, table|0, size|0) | 0;
{{{ makeSetTempRet0('size') }}};
return table | 0;
},
testSetjmp__asm: true,
testSetjmp__sig: 'iii',
testSetjmp: function(id, table, size) {
id = id|0;
table = table|0;
size = size|0;
var i = 0, curr = 0;
while ((i|0) < (size|0)) {
curr = {{{ makeGetValueAsm('table', '(i<<3)', 'i32') }}};
if ((curr|0) == 0) break;
if ((curr|0) == (id|0)) {
return {{{ makeGetValueAsm('table', '(i<<3)+4', 'i32') }}};
}
i = i+1|0;
}
return 0;
},
setjmp__deps: ['saveSetjmp', 'testSetjmp'],
setjmp__inline: function(env) {
// Save the label
return '_saveSetjmp(' + env + ', label, setjmpTable)|0';
},
longjmp__deps: ['saveSetjmp', 'testSetjmp'],
longjmp: function(env, value) {
asm['setThrew'](env, value || 1);
throw 'longjmp';
},
emscripten_longjmp__deps: ['longjmp'],
emscripten_longjmp: function(env, value) {
_longjmp(env, value);
},
// ==========================================================================
// sys/wait.h
// ==========================================================================
wait__deps: ['$ERRNO_CODES', '__setErrNo'],
wait: function(stat_loc) {
// pid_t wait(int *stat_loc);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/wait.html
// Makes no sense in a single-process environment.
___setErrNo(ERRNO_CODES.ECHILD);
return -1;
},
// NOTE: These aren't really the same, but we use the same stub for them all.
waitid: 'wait',
waitpid: 'wait',
wait3: 'wait',
wait4: 'wait',
// ==========================================================================
// locale.h
// ==========================================================================
$LOCALE: {
curr: 0,
check: function(locale) {
if (locale) locale = Pointer_stringify(locale);
return locale === 'C' || locale === 'POSIX' || !locale;
},
},
newlocale__deps: ['$LOCALE', 'calloc'],
newlocale: function(mask, locale, base) {
if (!LOCALE.check(locale)) {
___setErrNo(ERRNO_CODES.ENOENT);
return 0;
}
if (!base) base = _calloc(1, 4);
return base;
},
freelocale__deps: ['$LOCALE', 'free'],
freelocale: function(locale) {
_free(locale);
},
uselocale__deps: ['$LOCALE'],
uselocale: function(locale) {
var old = LOCALE.curr;
if (locale) LOCALE.curr = locale;
return old;
},
setlocale__deps: ['$LOCALE'],
setlocale: function(category, locale) {
if (LOCALE.check(locale)) {
if (!_setlocale.ret) _setlocale.ret = allocate(intArrayFromString('C'), 'i8', ALLOC_NORMAL);
return _setlocale.ret;
}
return 0;
},
localeconv: function() {
// %struct.timeval = type { char* decimal point, other stuff... }
// var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] });
var me = _localeconv;
if (!me.ret) {
// These are defaults from the "C" locale
me.ret = allocate([
allocate(intArrayFromString('.'), 'i8', ALLOC_NORMAL),0,0,0, // decimal_point
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // thousands_sep
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // grouping
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // int_curr_symbol
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // currency_symbol
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_decimal_point
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_thousands_sep
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_grouping
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // positive_sign
allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0 // negative_sign
], 'i8*', ALLOC_NORMAL); // Allocate strings in lconv, still don't allocate chars
}
return me.ret;
},
__locale_mb_cur_max: function() { throw '__locale_mb_cur_max not implemented' },
// ==========================================================================
// langinfo.h
// ==========================================================================
nl_langinfo: function(item) {
// char *nl_langinfo(nl_item item);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/nl_langinfo.html
var result;
switch (item) {
case {{{ cDefine('CODESET') }}}:
result = 'ANSI_X3.4-1968';
break;
case {{{ cDefine('D_T_FMT') }}}:
result = '%a %b %e %H:%M:%S %Y';
break;
case {{{ cDefine('D_FMT') }}}:
result = '%m/%d/%y';
break;
case {{{ cDefine('T_FMT') }}}:
result = '%H:%M:%S';
break;
case {{{ cDefine('T_FMT_AMPM') }}}:
result = '%I:%M:%S %p';
break;
case {{{ cDefine('AM_STR') }}}:
result = 'AM';
break;
case {{{ cDefine('PM_STR') }}}:
result = 'PM';
break;
case {{{ cDefine('DAY_1') }}}:
result = 'Sunday';
break;
case {{{ cDefine('DAY_2') }}}:
result = 'Monday';
break;
case {{{ cDefine('DAY_3') }}}:
result = 'Tuesday';
break;
case {{{ cDefine('DAY_4') }}}:
result = 'Wednesday';
break;
case {{{ cDefine('DAY_5') }}}:
result = 'Thursday';
break;
case {{{ cDefine('DAY_6') }}}:
result = 'Friday';
break;
case {{{ cDefine('DAY_7') }}}:
result = 'Saturday';
break;
case {{{ cDefine('ABDAY_1') }}}:
result = 'Sun';
break;
case {{{ cDefine('ABDAY_2') }}}:
result = 'Mon';
break;
case {{{ cDefine('ABDAY_3') }}}:
result = 'Tue';
break;
case {{{ cDefine('ABDAY_4') }}}:
result = 'Wed';
break;
case {{{ cDefine('ABDAY_5') }}}:
result = 'Thu';
break;
case {{{ cDefine('ABDAY_6') }}}:
result = 'Fri';
break;
case {{{ cDefine('ABDAY_7') }}}:
result = 'Sat';
break;
case {{{ cDefine('MON_1') }}}:
result = 'January';
break;
case {{{ cDefine('MON_2') }}}:
result = 'February';
break;
case {{{ cDefine('MON_3') }}}:
result = 'March';
break;
case {{{ cDefine('MON_4') }}}:
result = 'April';
break;
case {{{ cDefine('MON_5') }}}:
result = 'May';
break;
case {{{ cDefine('MON_6') }}}:
result = 'June';
break;
case {{{ cDefine('MON_7') }}}:
result = 'July';
break;
case {{{ cDefine('MON_8') }}}:
result = 'August';
break;
case {{{ cDefine('MON_9') }}}:
result = 'September';
break;
case {{{ cDefine('MON_10') }}}:
result = 'October';
break;
case {{{ cDefine('MON_11') }}}:
result = 'November';
break;
case {{{ cDefine('MON_12') }}}:
result = 'December';
break;
case {{{ cDefine('ABMON_1') }}}:
result = 'Jan';
break;
case {{{ cDefine('ABMON_2') }}}:
result = 'Feb';
break;
case {{{ cDefine('ABMON_3') }}}:
result = 'Mar';
break;
case {{{ cDefine('ABMON_4') }}}:
result = 'Apr';
break;
case {{{ cDefine('ABMON_5') }}}:
result = 'May';
break;
case {{{ cDefine('ABMON_6') }}}:
result = 'Jun';
break;
case {{{ cDefine('ABMON_7') }}}:
result = 'Jul';
break;
case {{{ cDefine('ABMON_8') }}}:
result = 'Aug';
break;
case {{{ cDefine('ABMON_9') }}}:
result = 'Sep';
break;
case {{{ cDefine('ABMON_10') }}}:
result = 'Oct';
break;
case {{{ cDefine('ABMON_11') }}}:
result = 'Nov';
break;
case {{{ cDefine('ABMON_12') }}}:
result = 'Dec';
break;
case {{{ cDefine('ALT_DIGITS') }}}:
result = '';
break;
case {{{ cDefine('RADIXCHAR') }}}:
result = '.';
break;
case {{{ cDefine('THOUSEP') }}}:
result = '';
break;
case {{{ cDefine('YESEXPR') }}}:
result = '^[yY]';
break;
case {{{ cDefine('NOEXPR') }}}:
result = '^[nN]';
break;
case {{{ cDefine('CRNCYSTR') }}}:
result = '-';
break;
case {{{ cDefine('ERA') }}}:
case {{{ cDefine('ERA_D_FMT') }}}:
case {{{ cDefine('ERA_D_T_FMT') }}}:
case {{{ cDefine('ERA_T_FMT') }}}:
default:
result = '';
break;
}
var me = _nl_langinfo;
if (!me.ret) me.ret = _malloc(32);
writeAsciiToMemory(result, me.ret);
return me.ret;
},
// ==========================================================================
// errno.h
// ==========================================================================
$ERRNO_CODES: {
EPERM: {{{ cDefine('EPERM') }}},
ENOENT: {{{ cDefine('ENOENT') }}},
ESRCH: {{{ cDefine('ESRCH') }}},
EINTR: {{{ cDefine('EINTR') }}},
EIO: {{{ cDefine('EIO') }}},
ENXIO: {{{ cDefine('ENXIO') }}},
E2BIG: {{{ cDefine('E2BIG') }}},
ENOEXEC: {{{ cDefine('ENOEXEC') }}},
EBADF: {{{ cDefine('EBADF') }}},
ECHILD: {{{ cDefine('ECHILD') }}},
EAGAIN: {{{ cDefine('EAGAIN') }}},
EWOULDBLOCK: {{{ cDefine('EWOULDBLOCK') }}},
ENOMEM: {{{ cDefine('ENOMEM') }}},
EACCES: {{{ cDefine('EACCES') }}},
EFAULT: {{{ cDefine('EFAULT') }}},
ENOTBLK: {{{ cDefine('ENOTBLK') }}},
EBUSY: {{{ cDefine('EBUSY') }}},
EEXIST: {{{ cDefine('EEXIST') }}},
EXDEV: {{{ cDefine('EXDEV') }}},
ENODEV: {{{ cDefine('ENODEV') }}},
ENOTDIR: {{{ cDefine('ENOTDIR') }}},
EISDIR: {{{ cDefine('EISDIR') }}},
EINVAL: {{{ cDefine('EINVAL') }}},
ENFILE: {{{ cDefine('ENFILE') }}},
EMFILE: {{{ cDefine('EMFILE') }}},
ENOTTY: {{{ cDefine('ENOTTY') }}},
ETXTBSY: {{{ cDefine('ETXTBSY') }}},
EFBIG: {{{ cDefine('EFBIG') }}},
ENOSPC: {{{ cDefine('ENOSPC') }}},
ESPIPE: {{{ cDefine('ESPIPE') }}},
EROFS: {{{ cDefine('EROFS') }}},
EMLINK: {{{ cDefine('EMLINK') }}},
EPIPE: {{{ cDefine('EPIPE') }}},
EDOM: {{{ cDefine('EDOM') }}},
ERANGE: {{{ cDefine('ERANGE') }}},
ENOMSG: {{{ cDefine('ENOMSG') }}},
EIDRM: {{{ cDefine('EIDRM') }}},
ECHRNG: {{{ cDefine('ECHRNG') }}},
EL2NSYNC: {{{ cDefine('EL2NSYNC') }}},
EL3HLT: {{{ cDefine('EL3HLT') }}},
EL3RST: {{{ cDefine('EL3RST') }}},
ELNRNG: {{{ cDefine('ELNRNG') }}},
EUNATCH: {{{ cDefine('EUNATCH') }}},
ENOCSI: {{{ cDefine('ENOCSI') }}},
EL2HLT: {{{ cDefine('EL2HLT') }}},
EDEADLK: {{{ cDefine('EDEADLK') }}},
ENOLCK: {{{ cDefine('ENOLCK') }}},
EBADE: {{{ cDefine('EBADE') }}},
EBADR: {{{ cDefine('EBADR') }}},
EXFULL: {{{ cDefine('EXFULL') }}},
ENOANO: {{{ cDefine('ENOANO') }}},
EBADRQC: {{{ cDefine('EBADRQC') }}},
EBADSLT: {{{ cDefine('EBADSLT') }}},
EDEADLOCK: {{{ cDefine('EDEADLOCK') }}},
EBFONT: {{{ cDefine('EBFONT') }}},
ENOSTR: {{{ cDefine('ENOSTR') }}},
ENODATA: {{{ cDefine('ENODATA') }}},
ETIME: {{{ cDefine('ETIME') }}},
ENOSR: {{{ cDefine('ENOSR') }}},
ENONET: {{{ cDefine('ENONET') }}},
ENOPKG: {{{ cDefine('ENOPKG') }}},
EREMOTE: {{{ cDefine('EREMOTE') }}},
ENOLINK: {{{ cDefine('ENOLINK') }}},
EADV: {{{ cDefine('EADV') }}},
ESRMNT: {{{ cDefine('ESRMNT') }}},
ECOMM: {{{ cDefine('ECOMM') }}},
EPROTO: {{{ cDefine('EPROTO') }}},
EMULTIHOP: {{{ cDefine('EMULTIHOP') }}},
EDOTDOT: {{{ cDefine('EDOTDOT') }}},
EBADMSG: {{{ cDefine('EBADMSG') }}},
ENOTUNIQ: {{{ cDefine('ENOTUNIQ') }}},
EBADFD: {{{ cDefine('EBADFD') }}},
EREMCHG: {{{ cDefine('EREMCHG') }}},
ELIBACC: {{{ cDefine('ELIBACC') }}},
ELIBBAD: {{{ cDefine('ELIBBAD') }}},
ELIBSCN: {{{ cDefine('ELIBSCN') }}},
ELIBMAX: {{{ cDefine('ELIBMAX') }}},
ELIBEXEC: {{{ cDefine('ELIBEXEC') }}},
ENOSYS: {{{ cDefine('ENOSYS') }}},
ENOTEMPTY: {{{ cDefine('ENOTEMPTY') }}},
ENAMETOOLONG: {{{ cDefine('ENAMETOOLONG') }}},
ELOOP: {{{ cDefine('ELOOP') }}},
EOPNOTSUPP: {{{ cDefine('EOPNOTSUPP') }}},
EPFNOSUPPORT: {{{ cDefine('EPFNOSUPPORT') }}},
ECONNRESET: {{{ cDefine('ECONNRESET') }}},
ENOBUFS: {{{ cDefine('ENOBUFS') }}},
EAFNOSUPPORT: {{{ cDefine('EAFNOSUPPORT') }}},
EPROTOTYPE: {{{ cDefine('EPROTOTYPE') }}},
ENOTSOCK: {{{ cDefine('ENOTSOCK') }}},
ENOPROTOOPT: {{{ cDefine('ENOPROTOOPT') }}},
ESHUTDOWN: {{{ cDefine('ESHUTDOWN') }}},
ECONNREFUSED: {{{ cDefine('ECONNREFUSED') }}},
EADDRINUSE: {{{ cDefine('EADDRINUSE') }}},
ECONNABORTED: {{{ cDefine('ECONNABORTED') }}},
ENETUNREACH: {{{ cDefine('ENETUNREACH') }}},
ENETDOWN: {{{ cDefine('ENETDOWN') }}},
ETIMEDOUT: {{{ cDefine('ETIMEDOUT') }}},
EHOSTDOWN: {{{ cDefine('EHOSTDOWN') }}},
EHOSTUNREACH: {{{ cDefine('EHOSTUNREACH') }}},
EINPROGRESS: {{{ cDefine('EINPROGRESS') }}},
EALREADY: {{{ cDefine('EALREADY') }}},
EDESTADDRREQ: {{{ cDefine('EDESTADDRREQ') }}},
EMSGSIZE: {{{ cDefine('EMSGSIZE') }}},
EPROTONOSUPPORT: {{{ cDefine('EPROTONOSUPPORT') }}},
ESOCKTNOSUPPORT: {{{ cDefine('ESOCKTNOSUPPORT') }}},
EADDRNOTAVAIL: {{{ cDefine('EADDRNOTAVAIL') }}},
ENETRESET: {{{ cDefine('ENETRESET') }}},
EISCONN: {{{ cDefine('EISCONN') }}},
ENOTCONN: {{{ cDefine('ENOTCONN') }}},
ETOOMANYREFS: {{{ cDefine('ETOOMANYREFS') }}},
EUSERS: {{{ cDefine('EUSERS') }}},
EDQUOT: {{{ cDefine('EDQUOT') }}},
ESTALE: {{{ cDefine('ESTALE') }}},
ENOTSUP: {{{ cDefine('ENOTSUP') }}},
ENOMEDIUM: {{{ cDefine('ENOMEDIUM') }}},
EILSEQ: {{{ cDefine('EILSEQ') }}},
EOVERFLOW: {{{ cDefine('EOVERFLOW') }}},
ECANCELED: {{{ cDefine('ECANCELED') }}},
ENOTRECOVERABLE: {{{ cDefine('ENOTRECOVERABLE') }}},
EOWNERDEAD: {{{ cDefine('EOWNERDEAD') }}},
ESTRPIPE: {{{ cDefine('ESTRPIPE') }}},
},
$ERRNO_MESSAGES: {
0: 'Success',
{{{ cDefine('EPERM') }}}: 'Not super-user',
{{{ cDefine('ENOENT') }}}: 'No such file or directory',
{{{ cDefine('ESRCH') }}}: 'No such process',
{{{ cDefine('EINTR') }}}: 'Interrupted system call',
{{{ cDefine('EIO') }}}: 'I/O error',
{{{ cDefine('ENXIO') }}}: 'No such device or address',
{{{ cDefine('E2BIG') }}}: 'Arg list too long',
{{{ cDefine('ENOEXEC') }}}: 'Exec format error',
{{{ cDefine('EBADF') }}}: 'Bad file number',
{{{ cDefine('ECHILD') }}}: 'No children',
{{{ cDefine('EWOULDBLOCK') }}}: 'No more processes',
{{{ cDefine('ENOMEM') }}}: 'Not enough core',
{{{ cDefine('EACCES') }}}: 'Permission denied',
{{{ cDefine('EFAULT') }}}: 'Bad address',
{{{ cDefine('ENOTBLK') }}}: 'Block device required',
{{{ cDefine('EBUSY') }}}: 'Mount device busy',
{{{ cDefine('EEXIST') }}}: 'File exists',
{{{ cDefine('EXDEV') }}}: 'Cross-device link',
{{{ cDefine('ENODEV') }}}: 'No such device',
{{{ cDefine('ENOTDIR') }}}: 'Not a directory',
{{{ cDefine('EISDIR') }}}: 'Is a directory',
{{{ cDefine('EINVAL') }}}: 'Invalid argument',
{{{ cDefine('ENFILE') }}}: 'Too many open files in system',
{{{ cDefine('EMFILE') }}}: 'Too many open files',
{{{ cDefine('ENOTTY') }}}: 'Not a typewriter',
{{{ cDefine('ETXTBSY') }}}: 'Text file busy',
{{{ cDefine('EFBIG') }}}: 'File too large',
{{{ cDefine('ENOSPC') }}}: 'No space left on device',
{{{ cDefine('ESPIPE') }}}: 'Illegal seek',
{{{ cDefine('EROFS') }}}: 'Read only file system',
{{{ cDefine('EMLINK') }}}: 'Too many links',
{{{ cDefine('EPIPE') }}}: 'Broken pipe',
{{{ cDefine('EDOM') }}}: 'Math arg out of domain of func',
{{{ cDefine('ERANGE') }}}: 'Math result not representable',
{{{ cDefine('ENOMSG') }}}: 'No message of desired type',
{{{ cDefine('EIDRM') }}}: 'Identifier removed',
{{{ cDefine('ECHRNG') }}}: 'Channel number out of range',
{{{ cDefine('EL2NSYNC') }}}: 'Level 2 not synchronized',
{{{ cDefine('EL3HLT') }}}: 'Level 3 halted',
{{{ cDefine('EL3RST') }}}: 'Level 3 reset',
{{{ cDefine('ELNRNG') }}}: 'Link number out of range',
{{{ cDefine('EUNATCH') }}}: 'Protocol driver not attached',
{{{ cDefine('ENOCSI') }}}: 'No CSI structure available',
{{{ cDefine('EL2HLT') }}}: 'Level 2 halted',
{{{ cDefine('EDEADLK') }}}: 'Deadlock condition',
{{{ cDefine('ENOLCK') }}}: 'No record locks available',
{{{ cDefine('EBADE') }}}: 'Invalid exchange',
{{{ cDefine('EBADR') }}}: 'Invalid request descriptor',
{{{ cDefine('EXFULL') }}}: 'Exchange full',
{{{ cDefine('ENOANO') }}}: 'No anode',
{{{ cDefine('EBADRQC') }}}: 'Invalid request code',
{{{ cDefine('EBADSLT') }}}: 'Invalid slot',
{{{ cDefine('EDEADLOCK') }}}: 'File locking deadlock error',
{{{ cDefine('EBFONT') }}}: 'Bad font file fmt',
{{{ cDefine('ENOSTR') }}}: 'Device not a stream',
{{{ cDefine('ENODATA') }}}: 'No data (for no delay io)',
{{{ cDefine('ETIME') }}}: 'Timer expired',
{{{ cDefine('ENOSR') }}}: 'Out of streams resources',
{{{ cDefine('ENONET') }}}: 'Machine is not on the network',
{{{ cDefine('ENOPKG') }}}: 'Package not installed',
{{{ cDefine('EREMOTE') }}}: 'The object is remote',
{{{ cDefine('ENOLINK') }}}: 'The link has been severed',
{{{ cDefine('EADV') }}}: 'Advertise error',
{{{ cDefine('ESRMNT') }}}: 'Srmount error',
{{{ cDefine('ECOMM') }}}: 'Communication error on send',
{{{ cDefine('EPROTO') }}}: 'Protocol error',
{{{ cDefine('EMULTIHOP') }}}: 'Multihop attempted',
{{{ cDefine('EDOTDOT') }}}: 'Cross mount point (not really error)',
{{{ cDefine('EBADMSG') }}}: 'Trying to read unreadable message',
{{{ cDefine('ENOTUNIQ') }}}: 'Given log. name not unique',
{{{ cDefine('EBADFD') }}}: 'f.d. invalid for this operation',
{{{ cDefine('EREMCHG') }}}: 'Remote address changed',
{{{ cDefine('ELIBACC') }}}: 'Can access a needed shared lib',
{{{ cDefine('ELIBBAD') }}}: 'Accessing a corrupted shared lib',
{{{ cDefine('ELIBSCN') }}}: '.lib section in a.out corrupted',
{{{ cDefine('ELIBMAX') }}}: 'Attempting to link in too many libs',
{{{ cDefine('ELIBEXEC') }}}: 'Attempting to exec a shared library',
{{{ cDefine('ENOSYS') }}}: 'Function not implemented',
{{{ cDefine('ENOTEMPTY') }}}: 'Directory not empty',
{{{ cDefine('ENAMETOOLONG') }}}: 'File or path name too long',
{{{ cDefine('ELOOP') }}}: 'Too many symbolic links',
{{{ cDefine('EOPNOTSUPP') }}}: 'Operation not supported on transport endpoint',
{{{ cDefine('EPFNOSUPPORT') }}}: 'Protocol family not supported',
{{{ cDefine('ECONNRESET') }}}: 'Connection reset by peer',
{{{ cDefine('ENOBUFS') }}}: 'No buffer space available',
{{{ cDefine('EAFNOSUPPORT') }}}: 'Address family not supported by protocol family',
{{{ cDefine('EPROTOTYPE') }}}: 'Protocol wrong type for socket',
{{{ cDefine('ENOTSOCK') }}}: 'Socket operation on non-socket',
{{{ cDefine('ENOPROTOOPT') }}}: 'Protocol not available',
{{{ cDefine('ESHUTDOWN') }}}: 'Can\'t send after socket shutdown',
{{{ cDefine('ECONNREFUSED') }}}: 'Connection refused',
{{{ cDefine('EADDRINUSE') }}}: 'Address already in use',
{{{ cDefine('ECONNABORTED') }}}: 'Connection aborted',
{{{ cDefine('ENETUNREACH') }}}: 'Network is unreachable',
{{{ cDefine('ENETDOWN') }}}: 'Network interface is not configured',
{{{ cDefine('ETIMEDOUT') }}}: 'Connection timed out',
{{{ cDefine('EHOSTDOWN') }}}: 'Host is down',
{{{ cDefine('EHOSTUNREACH') }}}: 'Host is unreachable',
{{{ cDefine('EINPROGRESS') }}}: 'Connection already in progress',
{{{ cDefine('EALREADY') }}}: 'Socket already connected',
{{{ cDefine('EDESTADDRREQ') }}}: 'Destination address required',
{{{ cDefine('EMSGSIZE') }}}: 'Message too long',
{{{ cDefine('EPROTONOSUPPORT') }}}: 'Unknown protocol',
{{{ cDefine('ESOCKTNOSUPPORT') }}}: 'Socket type not supported',
{{{ cDefine('EADDRNOTAVAIL') }}}: 'Address not available',
{{{ cDefine('ENETRESET') }}}: 'Connection reset by network',
{{{ cDefine('EISCONN') }}}: 'Socket is already connected',
{{{ cDefine('ENOTCONN') }}}: 'Socket is not connected',
{{{ cDefine('ETOOMANYREFS') }}}: 'Too many references',
{{{ cDefine('EUSERS') }}}: 'Too many users',
{{{ cDefine('EDQUOT') }}}: 'Quota exceeded',
{{{ cDefine('ESTALE') }}}: 'Stale file handle',
{{{ cDefine('ENOTSUP') }}}: 'Not supported',
{{{ cDefine('ENOMEDIUM') }}}: 'No medium (in tape drive)',
{{{ cDefine('EILSEQ') }}}: 'Illegal byte sequence',
{{{ cDefine('EOVERFLOW') }}}: 'Value too large for defined data type',
{{{ cDefine('ECANCELED') }}}: 'Operation canceled',
{{{ cDefine('ENOTRECOVERABLE') }}}: 'State not recoverable',
{{{ cDefine('EOWNERDEAD') }}}: 'Previous owner died',
{{{ cDefine('ESTRPIPE') }}}: 'Streams pipe error',
},
__errno_state: 0,
__setErrNo__deps: ['__errno_state'],
#if USE_PTHREADS
__setErrNo__postset: 'if (ENVIRONMENT_IS_PTHREAD) ___errno_state = PthreadWorkerInit.___errno_state; else { PthreadWorkerInit.___errno_state = ___errno_state = Runtime.staticAlloc(4); {{{ makeSetValue("___errno_state", 0, 0, "i32") }}}; }',
#else
__setErrNo__postset: '___errno_state = Runtime.staticAlloc(4); {{{ makeSetValue("___errno_state", 0, 0, "i32") }}};',
#endif
__setErrNo: function(value) {
// For convenient setting and returning of errno.
{{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}};
return value;
},
__errno_location__deps: ['__setErrNo'],
__errno_location: function() {
return ___errno_state;
},
__errno: '__errno_location',
// ==========================================================================
// sys/resource.h
// ==========================================================================
// TODO: Implement for real.
getrlimit: function(resource, rlp) {
// int getrlimit(int resource, struct rlimit *rlp);
{{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_cur, '-1', 'i32') }}}; // RLIM_INFINITY
{{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_cur + 4, '-1', 'i32') }}}; // RLIM_INFINITY
{{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_max, '-1', 'i32') }}}; // RLIM_INFINITY
{{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_max + 4, '-1', 'i32') }}}; // RLIM_INFINITY
return 0;
},
setrlimit: function(resource, rlp) {
// int setrlimit(int resource, const struct rlimit *rlp)
return 0;
},
// TODO: Implement for real. We just do time used, and no useful data
getrusage: function(resource, rlp) {
// int getrusage(int resource, struct rusage *rlp);
{{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}};
{{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}};
{{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}};
{{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}};
return 0;
},
// ==========================================================================
// sched.h (stubs only - no thread support yet!)
// ==========================================================================
sched_yield: function() {
return 0;
},
// ==========================================================================
// malloc.h
// ==========================================================================
memalign: function(boundary, size) {
// leaks, and even returns an invalid pointer. Horrible hack... but then, this is a deprecated function...
var ret = Runtime.staticAlloc(size + boundary);
return ret + boundary - (ret % boundary);
},
posix_memalign__deps: ['memalign'],
posix_memalign: function(memptr, alignment, size) {
var ptr = _memalign(alignment, size);
{{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}};
return 0;
},
// ==========================================================================
// arpa/inet.h
// ==========================================================================
htonl: function(value) {
return ((value & 0xff) << 24) + ((value & 0xff00) << 8) +
((value & 0xff0000) >>> 8) + ((value & 0xff000000) >>> 24);
},
htons: function(value) {
return ((value & 0xff) << 8) + ((value & 0xff00) >> 8);
},
ntohl: 'htonl',
ntohs: 'htons',
// old ipv4 only functions
inet_addr__deps: ['_inet_pton4_raw'],
inet_addr: function(ptr) {
var addr = __inet_pton4_raw(Pointer_stringify(ptr));
if (addr === null) {
return -1;
}
return addr;
},
inet_ntoa__deps: ['_inet_ntop4_raw'],
inet_ntoa: function(in_addr) {
if (!_inet_ntoa.buffer) {
_inet_ntoa.buffer = _malloc(1024);
}
var addr = {{{ makeGetValue('in_addr', '0', 'i32') }}};
var str = __inet_ntop4_raw(addr);
writeStringToMemory(str.substr(0, 1024), _inet_ntoa.buffer);
return _inet_ntoa.buffer;
},
inet_aton__deps: ['_inet_pton4_raw'],
inet_aton: function(cp, inp) {
var addr = __inet_pton4_raw(Pointer_stringify(cp));
if (addr === null) {
return 0;
}
{{{ makeSetValue('inp', '0', 'addr', 'i32') }}};
return 1;
},
// new ipv4 / ipv6 functions
_inet_ntop4_raw: function(addr) {
return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff)
},
_inet_ntop4__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntop4_raw'],
_inet_ntop4: function(src, dst, size) {
var addr = {{{ makeGetValue('src', '0', 'i32') }}};
var str = __inet_ntop4_raw(addr);
if (str.length+1 > size) {
___setErrNo(ERRNO_CODES.ENOSPC);
return 0;
}
writeStringToMemory(str, dst);
return dst;
},
_inet_ntop6_raw__deps: ['ntohs', '_inet_ntop4_raw'],
_inet_ntop6_raw: function(ints) {
// 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;
var parts = [
ints[0] & 0xffff,
(ints[0] >> 16),
ints[1] & 0xffff,
(ints[1] >> 16),
ints[2] & 0xffff,
(ints[2] >> 16),
ints[3] & 0xffff,
(ints[3] >> 16)
];
// 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 < 5; i++) {
if (parts[i] !== 0) { hasipv4 = false; break; }
}
if (hasipv4) {
// low-order 32-bits store an IPv4 address (bytes 13 to 16) (last 2 words)
v4part = __inet_ntop4_raw(parts[6] | (parts[7] << 16));
// IPv4-mapped IPv6 address if 16-bit value (bytes 11 and 12) == 0xFFFF (6th word)
if (parts[5] === -1) {
str = "::ffff:";
str += v4part;
return str;
}
// IPv4-compatible IPv6 address if 16-bit value (bytes 11 and 12) == 0x0000 (6th word)
if (parts[5] === 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 (parts[word] === 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 (parts[word] === 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(parts[word] & 0xffff)).toString(16);
str += word < 7 ? ":" : "";
}
return str;
},
_inet_ntop6__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntop6_raw'],
_inet_ntop6: function(src, dst, size) {
var addr = [
{{{ makeGetValue('src', '0', 'i32') }}}, {{{ makeGetValue('src', '4', 'i32') }}},
{{{ makeGetValue('src', '8', 'i32') }}}, {{{ makeGetValue('src', '12', 'i32') }}}
];
var str = __inet_ntop6_raw(addr);
if (str.length+1 > size) {
___setErrNo(ERRNO_CODES.ENOSPC);
return 0;
}
writeStringToMemory(str, dst);
return dst;
},
inet_ntop__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntop4', '_inet_ntop6'],
inet_ntop: function(af, src, dst, size) {
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html
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_pton4_raw: function(str) {
var b = str.split('.');
for (var i = 0; i < 4; i++) {
var tmp = Number(b[i]);
if (isNaN(tmp)) return null;
b[i] = tmp;
}
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
},
_inet_pton4__deps: ['_inet_pton4_raw'],
_inet_pton4: function(src, dst) {
var ret = __inet_pton4_raw(Pointer_stringify(src));
if (ret === null) {
return 0;
}
{{{ makeSetValue('dst', '0', 'ret', 'i32') }}};
return 1;
},
_inet_pton6_raw__deps: ['htons'],
_inet_pton6_raw: function(str) {
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
var parts = [];
if (!valid6regx.test(str)) {
return null;
}
if (str === "::") {
return [0, 0, 0, 0, 0, 0, 0, 0];
}
// Z placeholder to keep track of zeros when splitting the string on ":"
if (str.indexOf("::") === 0) {
str = str.replace("::", "Z:"); // leading zeros case
} else {
str = str.replace("::", ":Z:");
}
if (str.indexOf(".") > 0) {
// parse IPv4 embedded stress
str = str.replace(new RegExp('[.]', 'g'), ":");
words = str.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 = str.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++) {
parts[w+z] = 0;
}
offset = z-1;
} else {
// parse hex to field to 16-bit value and write it in network byte-order
parts[w+offset] = _htons(parseInt(words[w],16));
}
} else {
// parsed IPv4 words
parts[w+offset] = words[w];
}
}
return [
(parts[1] << 16) | parts[0],
(parts[3] << 16) | parts[2],
(parts[5] << 16) | parts[4],
(parts[7] << 16) | parts[6]
];
},
_inet_pton6__deps: ['_inet_pton6_raw'],
_inet_pton6: function(src, dst) {
var ints = __inet_pton6_raw(Pointer_stringify(src));
if (ints === null) {
return 0;
}
for (var i = 0; i < 4; i++) {
{{{ makeSetValue('dst', 'i*4', 'ints[i]', 'i32') }}};
}
return 1;
},
inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_pton4', '_inet_pton6'],
inet_pton: function(af, src, dst) {
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_pton.html
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;
}
},
// ==========================================================================
// net/if.h
// ==========================================================================
if_nametoindex: function(a) {
return 0;
},
if_indextoname: function(a, b) {
return 0;
},
if_nameindex: function() {
return 0;
},
if_freenameindex: function(a) {
},
// ==========================================================================
// netinet/in.h
// ==========================================================================
#if USE_PTHREADS
in6addr_any: '; if (ENVIRONMENT_IS_PTHREAD) _in6addr_any = PthreadWorkerInit._in6addr_any; else PthreadWorkerInit._in6addr_any = _in6addr_any = allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_STATIC)',
in6addr_loopback: '; if (ENVIRONMENT_IS_PTHREAD) _in6addr_loopback = PthreadWorkerInit._in6addr_loopback; else PthreadWorkerInit._in6addr_loopback = _in6addr_loopback = allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], "i8", ALLOC_STATIC)',
#else
in6addr_any:
'allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_STATIC)',
in6addr_loopback:
'allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], "i8", ALLOC_STATIC)',
#endif
// ==========================================================================
// netdb.h
// ==========================================================================
#if USE_PTHREADS
__h_errno_state: '; if (ENVIRONMENT_IS_PTHREAD) ___h_errno_state = PthreadWorkerInit.___h_errno_state; else PthreadWorkerInit.___h_errno_state = ___h_errno_state = allocate(1, "i32", ALLOC_STATIC)',
#else
__h_errno_state: 'allocate(1, "i32", ALLOC_STATIC)',
#endif
__h_errno_location__deps: ['__h_errno_state'],
__h_errno_location: function() {
return ___h_errno_state;
},
// We can't actually resolve hostnames in the browser, so instead
// we're generating fake IP addresses with lookup_name that we can
// resolve later on with lookup_addr.
// We do the aliasing in 172.29.*.*, giving us 65536 possibilities.
$DNS__deps: ['_inet_pton4_raw', '_inet_pton6_raw'],
$DNS: {
address_map: {
id: 1,
addrs: {},
names: {}
},
lookup_name: function (name) {
// If the name is already a valid ipv4 / ipv6 address, don't generate a fake one.
var res = __inet_pton4_raw(name);
if (res) {
return name;
}
res = __inet_pton6_raw(name);
if (res) {
return name;
}
// See if this name is already mapped.
var addr;
if (DNS.address_map.addrs[name]) {
addr = DNS.address_map.addrs[name];
} else {
var id = DNS.address_map.id++;
assert(id < 65535, 'exceeded max address mappings of 65535');
addr = '172.29.' + (id & 0xff) + '.' + (id & 0xff00);
DNS.address_map.names[addr] = name;
DNS.address_map.addrs[name] = addr;
}
return addr;
},
lookup_addr: function (addr) {
if (DNS.address_map.names[addr]) {
return DNS.address_map.names[addr];
}
return null;
}
},
// note: lots of leaking here!
gethostbyaddr__deps: ['$DNS', 'gethostbyname', '_inet_ntop4_raw'],
gethostbyaddr: function (addr, addrlen, type) {
if (type !== {{{ cDefine('AF_INET') }}}) {
___setErrNo(ERRNO_CODES.EAFNOSUPPORT);
// TODO: set h_errno
return null;
}
addr = {{{ makeGetValue('addr', '0', 'i32') }}}; // addr is in_addr
var host = __inet_ntop4_raw(addr);
var lookup = DNS.lookup_addr(host);
if (lookup) {
host = lookup;
}
var hostp = allocate(intArrayFromString(host), 'i8', ALLOC_STACK);
return _gethostbyname(hostp);
},
gethostbyname__deps: ['$DNS', '_inet_pton4_raw'],
gethostbyname: function(name) {
name = Pointer_stringify(name);
// generate hostent
var ret = _malloc({{{ C_STRUCTS.hostent.__size__ }}}); // XXX possibly leaked, as are others here
var nameBuf = _malloc(name.length+1);
writeStringToMemory(name, nameBuf);
{{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}};
var aliasesBuf = _malloc(4);
{{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}};
{{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}};
var afinet = {{{ cDefine('AF_INET') }}};
{{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}};
{{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}};
var addrListBuf = _malloc(12);
{{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}};
{{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}};
{{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}};
{{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}};
return ret;
},
gethostbyname_r__deps: ['gethostbyname'],
gethostbyname_r: function(name, ret, buf, buflen, out, err) {
var data = _gethostbyname(name);
_memcpy(ret, data, {{{ C_STRUCTS.hostent.__size__ }}});
_free(data);
{{{ makeSetValue('err', '0', '0', 'i32') }}};
{{{ makeSetValue('out', '0', 'ret', '*') }}};
return 0;
},
getaddrinfo__deps: ['$Sockets', '$DNS', '_inet_pton4_raw', '_inet_ntop4_raw', '_inet_pton6_raw', '_inet_ntop6_raw', '_write_sockaddr', 'htonl'],
getaddrinfo: function(node, service, hint, out) {
// Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL
// hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we
// really should provide a linked list of suitable addrinfo values.
var addrs = [];
var canon = null;
var addr = 0;
var port = 0;
var flags = 0;
var family = {{{ cDefine('AF_UNSPEC') }}};
var type = 0;
var proto = 0;
var ai, last;
function allocaddrinfo(family, type, proto, canon, addr, port) {
var sa, salen, ai;
var res;
salen = family === {{{ cDefine('AF_INET6') }}} ?
{{{ C_STRUCTS.sockaddr_in6.__size__ }}} :
{{{ C_STRUCTS.sockaddr_in.__size__ }}};
addr = family === {{{ cDefine('AF_INET6') }}} ?
__inet_ntop6_raw(addr) :
__inet_ntop4_raw(addr);
sa = _malloc(salen);
res = __write_sockaddr(sa, family, addr, port);
assert(!res.errno);
ai = _malloc({{{ C_STRUCTS.addrinfo.__size__ }}});
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_family, 'family', 'i32') }}};
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_socktype, 'type', 'i32') }}};
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_protocol, 'proto', 'i32') }}};
if (canon) {
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_canonname, 'canon', 'i32') }}};
}
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addr, 'sa', '*') }}};
if (family === {{{ cDefine('AF_INET6') }}}) {
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in6.__size__, 'i32') }}};
} else {
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in.__size__, 'i32') }}};
}
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_next, '0', 'i32') }}};
return ai;
}
if (hint) {
flags = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}};
family = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_family, 'i32') }}};
type = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_socktype, 'i32') }}};
proto = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_protocol, 'i32') }}};
}
if (type && !proto) {
proto = type === {{{ cDefine('SOCK_DGRAM') }}} ? {{{ cDefine('IPPROTO_UDP') }}} : {{{ cDefine('IPPROTO_TCP') }}};
}
if (!type && proto) {
type = proto === {{{ cDefine('IPPROTO_UDP') }}} ? {{{ cDefine('SOCK_DGRAM') }}} : {{{ cDefine('SOCK_STREAM') }}};
}
// If type or proto are set to zero in hints we should really be returning multiple addrinfo values, but for
// now default to a TCP STREAM socket so we can at least return a sensible addrinfo given NULL hints.
if (proto === 0) {
proto = {{{ cDefine('IPPROTO_TCP') }}};
}
if (type === 0) {
type = {{{ cDefine('SOCK_STREAM') }}};
}
if (!node && !service) {
return {{{ cDefine('EAI_NONAME') }}};
}
if (flags & ~({{{ cDefine('AI_PASSIVE') }}}|{{{ cDefine('AI_CANONNAME') }}}|{{{ cDefine('AI_NUMERICHOST') }}}|
{{{ cDefine('AI_NUMERICSERV') }}}|{{{ cDefine('AI_V4MAPPED') }}}|{{{ cDefine('AI_ALL') }}}|{{{ cDefine('AI_ADDRCONFIG') }}})) {
return {{{ cDefine('EAI_BADFLAGS') }}};
}
if (hint !== 0 && ({{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}} & {{{ cDefine('AI_CANONNAME') }}}) && !node) {
return {{{ cDefine('EAI_BADFLAGS') }}};
}
if (flags & {{{ cDefine('AI_ADDRCONFIG') }}}) {
// TODO
return {{{ cDefine('EAI_NONAME') }}};
}
if (type !== 0 && type !== {{{ cDefine('SOCK_STREAM') }}} && type !== {{{ cDefine('SOCK_DGRAM') }}}) {
return {{{ cDefine('EAI_SOCKTYPE') }}};
}
if (family !== {{{ cDefine('AF_UNSPEC') }}} && family !== {{{ cDefine('AF_INET') }}} && family !== {{{ cDefine('AF_INET6') }}}) {
return {{{ cDefine('EAI_FAMILY') }}};
}
if (service) {
service = Pointer_stringify(service);
port = parseInt(service, 10);
if (isNaN(port)) {
if (flags & {{{ cDefine('AI_NUMERICSERV') }}}) {
return {{{ cDefine('EAI_NONAME') }}};
}
// TODO support resolving well-known service names from:
// http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
return {{{ cDefine('EAI_SERVICE') }}};
}
}
if (!node) {
if (family === {{{ cDefine('AF_UNSPEC') }}}) {
family = {{{ cDefine('AF_INET') }}};
}
if ((flags & {{{ cDefine('AI_PASSIVE') }}}) === 0) {
if (family === {{{ cDefine('AF_INET') }}}) {
addr = _htonl({{{ cDefine('INADDR_LOOPBACK') }}});
} else {
addr = [0, 0, 0, 1];
}
}
ai = allocaddrinfo(family, type, proto, null, addr, port);
{{{ makeSetValue('out', '0', 'ai', '*') }}};
return 0;
}
//
// try as a numeric address
//
node = Pointer_stringify(node);
addr = __inet_pton4_raw(node);
if (addr !== null) {
// incoming node is a valid ipv4 address
if (family === {{{ cDefine('AF_UNSPEC') }}} || family === {{{ cDefine('AF_INET') }}}) {
family = {{{ cDefine('AF_INET') }}};
}
else if (family === {{{ cDefine('AF_INET6') }}} && (flags & {{{ cDefine('AI_V4MAPPED') }}})) {
addr = [0, 0, _htonl(0xffff), addr];
family = {{{ cDefine('AF_INET6') }}};
} else {
return {{{ cDefine('EAI_NONAME') }}};
}
} else {
addr = __inet_pton6_raw(node);
if (addr !== null) {
// incoming node is a valid ipv6 address
if (family === {{{ cDefine('AF_UNSPEC') }}} || family === {{{ cDefine('AF_INET6') }}}) {
family = {{{ cDefine('AF_INET6') }}};
} else {
return {{{ cDefine('EAI_NONAME') }}};
}
}
}
if (addr != null) {
ai = allocaddrinfo(family, type, proto, node, addr, port);
{{{ makeSetValue('out', '0', 'ai', '*') }}};
return 0;
}
if (flags & {{{ cDefine('AI_NUMERICHOST') }}}) {
return {{{ cDefine('EAI_NONAME') }}};
}
//
// try as a hostname
//
// resolve the hostname to a temporary fake address
node = DNS.lookup_name(node);
addr = __inet_pton4_raw(node);
if (family === {{{ cDefine('AF_UNSPEC') }}}) {
family = {{{ cDefine('AF_INET') }}};
} else if (family === {{{ cDefine('AF_INET6') }}}) {
addr = [0, 0, _htonl(0xffff), addr];
}
ai = allocaddrinfo(family, type, proto, null, addr, port);
{{{ makeSetValue('out', '0', 'ai', '*') }}};
return 0;
},
freeaddrinfo__deps: ['$Sockets'],
freeaddrinfo: function(ai) {
var sa = {{{ makeGetValue('ai', C_STRUCTS.addrinfo.ai_addr, '*') }}};
_free(sa);
_free(ai);
},
getnameinfo__deps: ['$Sockets', '$DNS', '_read_sockaddr'],
getnameinfo: function (sa, salen, node, nodelen, serv, servlen, flags) {
var info = __read_sockaddr(sa, salen);
if (info.errno) {
return {{{ cDefine('EAI_FAMILY') }}};
}
var port = info.port;
var addr = info.addr;
if (node && nodelen) {
var lookup;
if ((flags & {{{ cDefine('NI_NUMERICHOST') }}}) || !(lookup = DNS.lookup_addr(addr))) {
if (flags & {{{ cDefine('NI_NAMEREQD') }}}) {
return {{{ cDefine('EAI_NONAME') }}};
}
} else {
addr = lookup;
}
if (addr.length >= nodelen) {
return {{{ cDefine('EAI_OVERFLOW') }}};
}
writeStringToMemory(addr, node);
}
if (serv && servlen) {
port = '' + port;
if (port.length > servlen) {
return {{{ cDefine('EAI_OVERFLOW') }}};
}
writeStringToMemory(port, serv);
}
return 0;
},
// Can't use a literal for $GAI_ERRNO_MESSAGES as was done for $ERRNO_MESSAGES as the keys (e.g. EAI_BADFLAGS)
// are actually negative numbers and you can't have expressions as keys in JavaScript literals.
$GAI_ERRNO_MESSAGES: {},
gai_strerror__deps: ['$GAI_ERRNO_MESSAGES'],
gai_strerror: function(val) {
var buflen = 256;
// On first call to gai_strerror we initialise the buffer and populate the error messages.
if (!_gai_strerror.buffer) {
_gai_strerror.buffer = _malloc(buflen);
GAI_ERRNO_MESSAGES['0'] = 'Success';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_BADFLAGS') }}}] = 'Invalid value for \'ai_flags\' field';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_NONAME') }}}] = 'NAME or SERVICE is unknown';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_AGAIN') }}}] = 'Temporary failure in name resolution';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_FAIL') }}}] = 'Non-recoverable failure in name res';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_FAMILY') }}}] = '\'ai_family\' not supported';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_SOCKTYPE') }}}] = '\'ai_socktype\' not supported';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_SERVICE') }}}] = 'SERVICE not supported for \'ai_socktype\'';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_MEMORY') }}}] = 'Memory allocation failure';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_SYSTEM') }}}] = 'System error returned in \'errno\'';
GAI_ERRNO_MESSAGES['' + {{{ cDefine('EAI_OVERFLOW') }}}] = 'Argument buffer overflow';
}
var msg = 'Unknown error';
if (val in GAI_ERRNO_MESSAGES) {
if (GAI_ERRNO_MESSAGES[val].length > buflen - 1) {
msg = 'Message too long'; // EMSGSIZE message. This should never occur given the GAI_ERRNO_MESSAGES above.
} else {
msg = GAI_ERRNO_MESSAGES[val];
}
}
writeAsciiToMemory(msg, _gai_strerror.buffer);
return _gai_strerror.buffer;
},
// Implement netdb.h protocol entry (getprotoent, getprotobyname, getprotobynumber, setprotoent, endprotoent)
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/getprotobyname.html
// The Protocols object holds our 'fake' protocols 'database'.
$Protocols: {
list: [],
map: {}
},
setprotoent__deps: ['$Protocols'],
setprotoent: function(stayopen) {
// void setprotoent(int stayopen);
// Allocate and populate a protoent structure given a name, protocol number and array of aliases
function allocprotoent(name, proto, aliases) {
// write name into buffer
var nameBuf = _malloc(name.length + 1);
writeAsciiToMemory(name, nameBuf);
// write aliases into buffer
var j = 0;
var length = aliases.length;
var aliasListBuf = _malloc((length + 1) * 4); // Use length + 1 so we have space for the terminating NULL ptr.
for (var i = 0; i < length; i++, j += 4) {
var alias = aliases[i];
var aliasBuf = _malloc(alias.length + 1);
writeAsciiToMemory(alias, aliasBuf);
{{{ makeSetValue('aliasListBuf', 'j', 'aliasBuf', 'i8*') }}};
}
{{{ makeSetValue('aliasListBuf', 'j', '0', 'i8*') }}}; // Terminating NULL pointer.
// generate protoent
var pe = _malloc({{{ C_STRUCTS.protoent.__size__ }}});
{{{ makeSetValue('pe', C_STRUCTS.protoent.p_name, 'nameBuf', 'i8*') }}};
{{{ makeSetValue('pe', C_STRUCTS.protoent.p_aliases, 'aliasListBuf', 'i8**') }}};
{{{ makeSetValue('pe', C_STRUCTS.protoent.p_proto, 'proto', 'i32') }}};
return pe;
};
// Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial
// to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful.
var list = Protocols.list;
var map = Protocols.map;
if (list.length === 0) {
var entry = allocprotoent('tcp', 6, ['TCP']);
list.push(entry);
map['tcp'] = map['6'] = entry;
entry = allocprotoent('udp', 17, ['UDP']);
list.push(entry);
map['udp'] = map['17'] = entry;
}
_setprotoent.index = 0;
},
endprotoent: function() {
// void endprotoent(void);
// We're not using a real protocol database so we don't do a real close.
},
getprotoent__deps: ['setprotoent', '$Protocols'],
getprotoent: function(number) {
// struct protoent *getprotoent(void);
// reads the next entry from the protocols 'database' or return NULL if 'eof'
if (_setprotoent.index === Protocols.list.length) {
return 0;
} else {
var result = Protocols.list[_setprotoent.index++];
return result;
}
},
getprotobyname__deps: ['setprotoent', '$Protocols'],
getprotobyname: function(name) {
// struct protoent *getprotobyname(const char *);
name = Pointer_stringify(name);
_setprotoent(true);
var result = Protocols.map[name];
return result;
},
getprotobynumber__deps: ['setprotoent', '$Protocols'],
getprotobynumber: function(number) {
// struct protoent *getprotobynumber(int proto);
_setprotoent(true);
var result = Protocols.map[number];
return result;
},
// ==========================================================================
// sockets. Note that the implementation assumes all sockets are always
// nonblocking
// ==========================================================================
#if SOCKET_WEBRTC
$Sockets__deps: ['__setErrNo', '$ERRNO_CODES',
function() { return 'var SocketIO = ' + read('socket.io.js') + ';\n' },
function() { return 'var Peer = ' + read('wrtcp.js') + ';\n' }],
#else
$Sockets__deps: ['__setErrNo', '$ERRNO_CODES'],
#endif
$Sockets: {
BUFFER_SIZE: 10*1024, // initial size
MAX_BUFFER_SIZE: 10*1024*1024, // maximum size we will grow the buffer
nextFd: 1,
fds: {},
nextport: 1,
maxport: 65535,
peer: null,
connections: {},
portmap: {},
localAddr: 0xfe00000a, // Local address is always 10.0.0.254
addrPool: [ 0x0200000a, 0x0300000a, 0x0400000a, 0x0500000a,
0x0600000a, 0x0700000a, 0x0800000a, 0x0900000a, 0x0a00000a,
0x0b00000a, 0x0c00000a, 0x0d00000a, 0x0e00000a] /* 0x0100000a is reserved */
},
#if SOCKET_WEBRTC
/* WebRTC sockets supports several options on the Module object.
* Module['host']: true if this peer is hosting, false otherwise
* Module['webrtc']['broker']: hostname for the p2p broker that this peer should use
* Module['webrtc']['session']: p2p session for that this peer will join, or undefined if this peer is hosting
* Module['webrtc']['hostOptions']: options to pass into p2p library if this peer is hosting
* Module['webrtc']['onpeer']: function(peer, route), invoked when this peer is ready to connect
* Module['webrtc']['onconnect']: function(peer), invoked when a new peer connection is ready
* Module['webrtc']['ondisconnect']: function(peer), invoked when an existing connection is closed
* Module['webrtc']['onerror']: function(error), invoked when an error occurs
*/
socket__deps: ['$FS', '$Sockets'],
socket: function(family, type, protocol) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_SOCKET') }}}, family, type, protocol);
#endif
var INCOMING_QUEUE_LENGTH = 64;
var info = FS.createStream({
addr: null,
port: null,
inQueue: new CircularBuffer(INCOMING_QUEUE_LENGTH),
header: new Uint16Array(2),
bound: false,
socket: true,
stream_ops: {}
});
assert(info.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
}
// Open the peer connection if we don't have it already
if (null == Sockets.peer) {
var host = Module['host'];
var broker = Module['webrtc']['broker'];
var session = Module['webrtc']['session'];
var peer = new Peer(broker);
var listenOptions = Module['webrtc']['hostOptions'] || {};
peer.onconnection = function peer_onconnection(connection) {
console.log('connected');
var addr;
/* If this peer is connecting to the host, assign 10.0.0.1 to the host so it can be
reached at a known address.
*/
// Assign 10.0.0.1 to the host
if (session && session === connection['route']) {
addr = 0x0100000a; // 10.0.0.1
} else {
addr = Sockets.addrPool.shift();
}
connection['addr'] = addr;
Sockets.connections[addr] = connection;
connection.ondisconnect = function connection_ondisconnect() {
console.log('disconnect');
// Don't return the host address (10.0.0.1) to the pool
if (!(session && session === Sockets.connections[addr]['route'])) {
Sockets.addrPool.push(addr);
}
delete Sockets.connections[addr];
if (Module['webrtc']['ondisconnect'] && 'function' === typeof Module['webrtc']['ondisconnect']) {
Module['webrtc']['ondisconnect'](peer);
}
};
connection.onerror = function connection_onerror(error) {
if (Module['webrtc']['onerror'] && 'function' === typeof Module['webrtc']['onerror']) {
Module['webrtc']['onerror'](error);
}
};
connection.onmessage = function connection_onmessage(label, message) {
if ('unreliable' === label) {
handleMessage(addr, message.data);
}
}
if (Module['webrtc']['onconnect'] && 'function' === typeof Module['webrtc']['onconnect']) {
Module['webrtc']['onconnect'](peer);
}
};
peer.onpending = function peer_onpending(pending) {
console.log('pending from: ', pending['route'], '; initiated by: ', (pending['incoming']) ? 'remote' : 'local');
};
peer.onerror = function peer_onerror(error) {
console.error(error);
};
peer.onroute = function peer_onroute(route) {
if (Module['webrtc']['onpeer'] && 'function' === typeof Module['webrtc']['onpeer']) {
Module['webrtc']['onpeer'](peer, route);
}
};
function handleMessage(addr, message) {
#if SOCKET_DEBUG
Module.print("received " + message.byteLength + " raw bytes");
#endif
var header = new Uint16Array(message, 0, 2);
if (Sockets.portmap[header[1]]) {
Sockets.portmap[header[1]].inQueue.push([addr, message]);
} else {
console.log("unable to deliver message: ", addr, header[1], message);
}
}
window.onbeforeunload = function window_onbeforeunload() {
var ids = Object.keys(Sockets.connections);
ids.forEach(function(id) {
Sockets.connections[id].close();
});
}
Sockets.peer = peer;
}
function CircularBuffer(max_length) {
var buffer = new Array(++ max_length);
var head = 0;
var tail = 0;
var length = 0;
return {
push: function(element) {
buffer[tail ++] = element;
length = Math.min(++ length, max_length - 1);
tail = tail % max_length;
if (tail === head) {
head = (head + 1) % max_length;
}
},
shift: function(element) {
if (length < 1) return undefined;
var element = buffer[head];
-- length;
head = (head + 1) % max_length;
return element;
},
length: function() {
return length;
}
};
};
return info.fd;
},
mkport__deps: ['$Sockets'],
mkport: function() {
for(var i = 0; i < Sockets.maxport; ++ i) {
var port = Sockets.nextport ++;
Sockets.nextport = (Sockets.nextport > Sockets.maxport) ? 1 : Sockets.nextport;
if (!Sockets.portmap[port]) {
return port;
}
}
assert(false, 'all available ports are in use!');
},
connect: function() {
// Stub: connection-oriented sockets are not supported yet.
},
bind__deps: ['$FS', '$Sockets', '_inet_ntop4_raw', 'ntohs', 'mkport'],
bind: function(fd, addr, addrlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_BIND') }}}, fd, addr, addrlen);
#endif
var info = FS.getStream(fd);
if (!info) return -1;
if (addr) {
info.port = _ntohs(getValue(addr + {{{ C_STRUCTS.sockaddr_in.sin_port }}}, 'i16'));
// info.addr = getValue(addr + {{{ C_STRUCTS.sockaddr_in.sin_addr.s_addr }}}, 'i32');
}
if (!info.port) {
info.port = _mkport();
}
info.addr = Sockets.localAddr; // 10.0.0.254
info.host = __inet_ntop4_raw(info.addr);
info.close = function info_close() {
Sockets.portmap[info.port] = undefined;
}
Sockets.portmap[info.port] = info;
console.log("bind: ", info.host, info.port);
info.bound = true;
},
sendmsg__deps: ['$FS', '$Sockets', 'bind', '_inet_ntop4_raw', 'ntohs'],
sendmsg: function(fd, msg, flags) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_SENDMSG') }}}, fd, msg, flags);
#endif
var info = FS.getStream(fd);
if (!info) return -1;
// if we are not connected, use the address info in the message
if (!info.bound) {
_bind(fd);
}
var name = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_name, '*') }}};
assert(name, 'sendmsg on non-connected socket, and no name/address in the message');
var port = _ntohs(getValue(name + {{{ C_STRUCTS.sockaddr_in.sin_port }}}, 'i16'));
var addr = getValue(name + {{{ C_STRUCTS.sockaddr_in.sin_addr.s_addr }}}, 'i32');
var connection = Sockets.connections[addr];
// var host = __inet_ntop4_raw(addr);
if (!(connection && connection.connected)) {
___setErrNo(ERRNO_CODES.EWOULDBLOCK);
return -1;
}
var iov = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_iov, 'i8*') }}};
var num = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}};
#if SOCKET_DEBUG
Module.print('sendmsg vecs: ' + num);
#endif
var totalSize = 0;
for (var i = 0; i < num; i++) {
totalSize += {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
}
var data = new Uint8Array(totalSize);
var ret = 0;
for (var i = 0; i < num; i++) {
var currNum = {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
#if SOCKET_DEBUG
Module.print('sendmsg curr size: ' + currNum);
#endif
if (!currNum) continue;
var currBuf = {{{ makeGetValue('iov', '8*i', 'i8*') }}};
data.set(HEAPU8.subarray(currBuf, currBuf+currNum), ret);
ret += currNum;
}
info.header[0] = info.port; // src port
info.header[1] = port; // dst port
#if SOCKET_DEBUG
Module.print('sendmsg port: ' + info.header[0] + ' -> ' + info.header[1]);
Module.print('sendmsg bytes: ' + data.length + ' | ' + Array.prototype.slice.call(data));
#endif
var buffer = new Uint8Array(info.header.byteLength + data.byteLength);
buffer.set(new Uint8Array(info.header.buffer));
buffer.set(data, info.header.byteLength);
connection.send('unreliable', buffer.buffer);
return ret;
},
recvmsg__deps: ['$FS', '$Sockets', 'bind', '__setErrNo', '$ERRNO_CODES', 'htons'],
recvmsg: function(fd, msg, flags) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_RECVMSG') }}}, fd, msg, flags);
#endif
var info = FS.getStream(fd);
if (!info) return -1;
// if we are not connected, use the address info in the message
if (!info.port) {
console.log('recvmsg on unbound socket');
assert(false, 'cannot receive on unbound socket');
}
if (info.inQueue.length() == 0) {
___setErrNo(ERRNO_CODES.EWOULDBLOCK);
return -1;
}
var entry = info.inQueue.shift();
var addr = entry[0];
var message = entry[1];
var header = new Uint16Array(message, 0, info.header.length);
var buffer = new Uint8Array(message, info.header.byteLength);
var bytes = buffer.length;
#if SOCKET_DEBUG
Module.print('recvmsg port: ' + header[1] + ' <- ' + header[0]);
Module.print('recvmsg bytes: ' + bytes + ' | ' + Array.prototype.slice.call(buffer));
#endif
// write source
var name = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_name, '*') }}};
{{{ makeSetValue('name', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'addr', 'i32') }}};
{{{ makeSetValue('name', C_STRUCTS.sockaddr_in.sin_port, '_htons(header[0])', 'i16') }}};
// write data
var ret = bytes;
var iov = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_iov, 'i8*') }}};
var num = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}};
var bufferPos = 0;
for (var i = 0; i < num && bytes > 0; i++) {
var currNum = {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
#if SOCKET_DEBUG
Module.print('recvmsg loop ' + [i, num, bytes, currNum]);
#endif
if (!currNum) continue;
currNum = Math.min(currNum, bytes); // XXX what should happen when we partially fill a buffer..?
bytes -= currNum;
var currBuf = {{{ makeGetValue('iov', '8*i', 'i8*') }}};
#if SOCKET_DEBUG
Module.print('recvmsg call recv ' + currNum);
#endif
HEAPU8.set(buffer.subarray(bufferPos, bufferPos + currNum), currBuf);
bufferPos += currNum;
}
return ret;
},
shutdown__deps: ['$FS'],
shutdown: function(fd, how) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_SHUTDOWN') }}}, fd, how);
#endif
var stream = FS.getStream(fd);
if (!stream) return -1;
stream.close();
FS.closeStream(stream);
},
ioctl__deps: ['$FS'],
ioctl: function(fd, request, varargs) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_IOCTL') }}}, fd, request, varargs);
#endif
var info = FS.getStream(fd);
if (!info) return -1;
var bytes = 0;
if (info.hasData()) {
bytes = info.inQueue[0].length;
}
var dest = {{{ makeGetValue('varargs', '0', 'i32') }}};
{{{ makeSetValue('dest', '0', 'bytes', 'i32') }}};
return 0;
},
setsockopt: function(d, level, optname, optval, optlen) {
#if SOCKET_DEBUG
console.log('ignoring setsockopt command');
#endif
return 0;
},
accept__deps: ['$FS'],
accept: function(fd, addr, addrlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_ACCEPT') }}}, fd, addr, addrlen);
#endif
// 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.getStream(fd);
if (!info) return -1;
if (addr) {
setValue(addr + {{{ C_STRUCTS.sockaddr_in.sin_addr.s_addr }}}, info.addr, 'i32');
setValue(addr + {{{ C_STRUCTS.sockaddr_in.sin_port }}}, info.port, 'i32');
setValue(addrlen, {{{ C_STRUCTS.sockaddr_in.__size__ }}}, 'i32');
}
return fd;
},
select__deps: ['$FS'],
select: function(nfds, readfds, writefds, exceptfds, timeout) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_5({{{ cDefine('EM_PROXIED_SELECT') }}}, nfds, readfds, writefds, exceptfds, timeout);
#endif
// readfds are supported,
// writefds checks socket open status
// exceptfds not supported
// timeout is always 0 - fully async
assert(!exceptfds);
var errorCondition = 0;
function canRead(info) {
return info.inQueue.length() > 0;
}
function canWrite(info) {
return true;
}
function checkfds(nfds, fds, can) {
if (!fds) return 0;
var bitsSet = 0;
var dstLow = 0;
var dstHigh = 0;
var srcLow = {{{ makeGetValue('fds', 0, 'i32') }}};
var srcHigh = {{{ makeGetValue('fds', 4, 'i32') }}};
nfds = Math.min(64, nfds); // fd sets have 64 bits
for (var fd = 0; fd < nfds; fd++) {
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.getStream(fd);
if (info && can(info)) {
// set bit
fd < 32 ? (dstLow = dstLow | mask) : (dstHigh = dstHigh | mask);
bitsSet++;
}
}
}
{{{ makeSetValue('fds', 0, 'dstLow', 'i32') }}};
{{{ makeSetValue('fds', 4, 'dstHigh', 'i32') }}};
return bitsSet;
}
var totalHandles = checkfds(nfds, readfds, canRead) + checkfds(nfds, writefds, canWrite);
if (errorCondition) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
} else {
return totalHandles;
}
},
#else
// ==========================================================================
// socket.h
// ==========================================================================
_read_sockaddr__deps: ['$Sockets', '_inet_ntop4_raw', '_inet_ntop6_raw'],
_read_sockaddr: function (sa, salen) {
// family / port offsets are common to both sockaddr_in and sockaddr_in6
var family = {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_family, 'i16') }}};
var port = _ntohs({{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_port, 'i16') }}});
var addr;
switch (family) {
case {{{ cDefine('AF_INET') }}}:
if (salen !== {{{ C_STRUCTS.sockaddr_in.__size__ }}}) {
return { errno: ERRNO_CODES.EINVAL };
}
addr = {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'i32') }}};
addr = __inet_ntop4_raw(addr);
break;
case {{{ cDefine('AF_INET6') }}}:
if (salen !== {{{ C_STRUCTS.sockaddr_in6.__size__ }}}) {
return { errno: ERRNO_CODES.EINVAL };
}
addr = [
{{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+0, 'i32') }}},
{{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+4, 'i32') }}},
{{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+8, 'i32') }}},
{{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+12, 'i32') }}}
];
addr = __inet_ntop6_raw(addr);
break;
default:
return { errno: ERRNO_CODES.EAFNOSUPPORT };
}
return { family: family, addr: addr, port: port };
},
_write_sockaddr__deps: ['$Sockets', '_inet_pton4_raw', '_inet_pton6_raw'],
_write_sockaddr: function (sa, family, addr, port) {
switch (family) {
case {{{ cDefine('AF_INET') }}}:
addr = __inet_pton4_raw(addr);
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_family, 'family', 'i16') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'addr', 'i32') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_port, '_htons(port)', 'i16') }}};
break;
case {{{ cDefine('AF_INET6') }}}:
addr = __inet_pton6_raw(addr);
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_family, 'family', 'i32') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+0, 'addr[0]', 'i32') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+4, 'addr[1]', 'i32') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+8, 'addr[2]', 'i32') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+12, 'addr[3]', 'i32') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_port, '_htons(port)', 'i16') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_flowinfo, '0', 'i32') }}};
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_scope_id, '0', 'i32') }}};
break;
default:
return { errno: ERRNO_CODES.EAFNOSUPPORT };
}
// kind of lame, but let's match _read_sockaddr's interface
return {};
},
socket__deps: ['$FS', '$SOCKFS'],
socket: function(family, type, protocol) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_SOCKET') }}}, family, type, protocol);
#endif
var sock = SOCKFS.createSocket(family, type, protocol);
assert(sock.stream.fd < 64); // select() assumes socket fd values are in 0..63
return sock.stream.fd;
},
socketpair__deps: ['$ERRNO_CODES', '__setErrNo'],
socketpair: function(domain, type, protocol, sv) {
// int socketpair(int domain, int type, int protocol, int sv[2]);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/socketpair.html
___setErrNo(ERRNO_CODES.EOPNOTSUPP);
return -1;
},
shutdown__deps: ['$SOCKFS', '$ERRNO_CODES', '__setErrNo'],
shutdown: function(fd, how) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_SHUTDOWN') }}}, fd, how);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
_close(fd);
},
bind__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_read_sockaddr'],
bind: function(fd, addrp, addrlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_BIND') }}}, fd, addrp, addrlen);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
var info = __read_sockaddr(addrp, addrlen);
if (info.errno) {
___setErrNo(info.errno);
return -1;
}
var port = info.port;
var addr = DNS.lookup_addr(info.addr) || info.addr;
try {
sock.sock_ops.bind(sock, addr, port);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
connect__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_read_sockaddr'],
connect: function(fd, addrp, addrlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_CONNECT') }}}, fd, addrp, addrlen);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
var info = __read_sockaddr(addrp, addrlen);
if (info.errno) {
___setErrNo(info.errno);
return -1;
}
var port = info.port;
var addr = DNS.lookup_addr(info.addr) || info.addr;
try {
sock.sock_ops.connect(sock, addr, port);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
listen__deps: ['$FS', '$SOCKFS', '$ERRNO_CODES', '__setErrNo'],
listen: function(fd, backlog) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_2({{{ cDefine('EM_PROXIED_LISTEN') }}}, fd, backlog);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
sock.sock_ops.listen(sock, backlog);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
accept__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_write_sockaddr'],
accept: function(fd, addr, addrlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_ACCEPT') }}}, fd, addr, addrlen);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
var newsock = sock.sock_ops.accept(sock);
if (addr) {
var res = __write_sockaddr(addr, newsock.family, DNS.lookup_name(newsock.daddr), newsock.dport);
assert(!res.errno);
}
return newsock.stream.fd;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
getsockname__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_write_sockaddr'],
getsockname: function (fd, addr, addrlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_GETSOCKNAME') }}}, fd, addr, addrlen);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
var info = sock.sock_ops.getname(sock);
var res = __write_sockaddr(addr, sock.family, DNS.lookup_name(info.addr), info.port);
assert(!res.errno);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
getpeername__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_write_sockaddr'],
getpeername: function (fd, addr, addrlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_GETPEERNAME') }}}, fd, addr, addrlen);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
try {
var info = sock.sock_ops.getname(sock, true);
var res = __write_sockaddr(addr, sock.family, DNS.lookup_name(info.addr), info.port);
assert(!res.errno);
return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
send__deps: ['$SOCKFS', '$ERRNO_CODES', '__setErrNo', 'write'],
send: function(fd, buf, len, flags) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_SEND') }}}, fd, buf, len, flags);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
// TODO honor flags
return _write(fd, buf, len);
},
recv__deps: ['$SOCKFS', '$ERRNO_CODES', '__setErrNo', 'read'],
recv: function(fd, buf, len, flags) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_RECV') }}}, fd, buf, len, flags);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
// TODO honor flags
return _read(fd, buf, len);
},
sendto__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_read_sockaddr'],
sendto: function(fd, message, length, flags, dest_addr, dest_len) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_6({{{ cDefine('EM_PROXIED_SENDTO') }}}, fd, message, length, flags, dest_addr, dest_len);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
// read the address and port to send to
var info = __read_sockaddr(dest_addr, dest_len);
if (info.errno) {
___setErrNo(info.errno);
return -1;
}
var port = info.port;
var addr = DNS.lookup_addr(info.addr) || info.addr;
// send the message
try {
var slab = {{{ makeGetSlabs('message', 'i8', true) }}};
return sock.sock_ops.sendmsg(sock, slab, message, length, addr, port);
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
recvfrom__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_write_sockaddr'],
recvfrom: function(fd, buf, len, flags, addr, addrlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_6({{{ cDefine('EM_PROXIED_RECVFROM') }}}, fd, buf, len, flags, addr, addrlen);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
// read from the socket
var msg;
try {
msg = sock.sock_ops.recvmsg(sock, len);
} catch (e) {
FS.handleFSError(e);
return -1;
}
if (!msg) {
// socket is closed
return 0;
}
// write the source address out
if (addr) {
var res = __write_sockaddr(addr, sock.family, DNS.lookup_name(msg.addr), msg.port);
assert(!res.errno);
}
// write the buffer out
HEAPU8.set(msg.buffer, buf);
return msg.buffer.byteLength;
},
sendmsg__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_read_sockaddr'],
sendmsg: function(fd, message, flags) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_SENDMSG') }}}, fd, message, flags);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
var iov = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iov, '*') }}};
var num = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}};
// read the address and port to send to
var addr;
var port;
var name = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_name, '*') }}};
var namelen = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_namelen, 'i32') }}};
if (name) {
var info = __read_sockaddr(name, namelen);
if (info.errno) {
___setErrNo(info.errno);
return -1;
}
port = info.port;
addr = DNS.lookup_addr(info.addr) || info.addr;
}
// concatenate scatter-gather arrays into one message buffer
var total = 0;
for (var i = 0; i < num; i++) {
total += {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}};
}
var view = new Uint8Array(total);
var offset = 0;
for (var i = 0; i < num; i++) {
var iovbase = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_base, 'i8*') }}};
var iovlen = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}};
for (var j = 0; j < iovlen; j++) {
view[offset++] = {{{ makeGetValue('iovbase', 'j', 'i8') }}};
}
}
// write the buffer
try {
return sock.sock_ops.sendmsg(sock, view, 0, total, addr, port);
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
recvmsg__deps: ['$FS', '$SOCKFS', '$DNS', '$ERRNO_CODES', '__setErrNo', '_write_sockaddr'],
recvmsg: function(fd, message, flags) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_RECVMSG') }}}, fd, message, flags);
#endif
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
var iov = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iov, 'i8*') }}};
var num = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}};
// get the total amount of data we can read across all arrays
var total = 0;
for (var i = 0; i < num; i++) {
total += {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}};
}
// try to read total data
var msg;
try {
msg = sock.sock_ops.recvmsg(sock, total);
} catch (e) {
FS.handleFSError(e);
return -1;
}
if (!msg) {
// socket is closed
return 0;
}
// TODO honor flags:
// MSG_OOB
// Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific.
// MSG_PEEK
// Peeks at the incoming message.
// MSG_WAITALL
// Requests that the function block until the full amount of data requested can be returned. The function may return a smaller amount of data if a signal is caught, if the connection is terminated, if MSG_PEEK was specified, or if an error is pending for the socket.
// write the source address out
var name = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_name, '*') }}};
if (name) {
var res = __write_sockaddr(name, sock.family, DNS.lookup_name(msg.addr), msg.port);
assert(!res.errno);
}
// write the buffer out to the scatter-gather arrays
var bytesRead = 0;
var bytesRemaining = msg.buffer.byteLength;
for (var i = 0; bytesRemaining > 0 && i < num; i++) {
var iovbase = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_base, 'i8*') }}};
var iovlen = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}};
if (!iovlen) {
continue;
}
var length = Math.min(iovlen, bytesRemaining);
var buf = msg.buffer.subarray(bytesRead, bytesRead + length);
HEAPU8.set(buf, iovbase + bytesRead);
bytesRead += length;
bytesRemaining -= length;
}
// TODO set msghdr.msg_flags
// MSG_EOR
// End of record was received (if supported by the protocol).
// MSG_OOB
// Out-of-band data was received.
// MSG_TRUNC
// Normal data was truncated.
// MSG_CTRUNC
return bytesRead;
},
setsockopt: function(fd, level, optname, optval, optlen) {
#if SOCKET_DEBUG
console.log('ignoring setsockopt command');
#endif
return 0;
},
getsockopt__deps: ['$SOCKFS', '__setErrNo', '$ERRNO_CODES'],
getsockopt: function(fd, level, optname, optval, optlen) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_5({{{ cDefine('EM_PROXIED_GETSOCKOPT') }}}, fd, level, optname, optval, optlen);
#endif
// int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getsockopt.html
// Minimal getsockopt aimed at resolving https://github.com/kripken/emscripten/issues/2211
// so only supports SOL_SOCKET with SO_ERROR.
var sock = SOCKFS.getSocket(fd);
if (!sock) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
if (level === {{{ cDefine('SOL_SOCKET') }}}) {
if (optname === {{{ cDefine('SO_ERROR') }}}) {
{{{ makeSetValue('optval', 0, 'sock.error', 'i32') }}};
{{{ makeSetValue('optlen', 0, 4, 'i32') }}};
sock.error = null; // Clear the error (The SO_ERROR option obtains and then clears this field).
return 0;
} else {
___setErrNo(ERRNO_CODES.ENOPROTOOPT); // The option is unknown at the level indicated.
#if ASSERTIONS
Runtime.warnOnce('getsockopt() returning an error as we currently only support optname SO_ERROR');
#endif
return -1;
}
} else {
___setErrNo(ERRNO_CODES.ENOPROTOOPT); //The option is unknown at the level indicated.
#if ASSERTIONS
Runtime.warnOnce('getsockopt() returning an error as we only support level SOL_SOCKET');
#endif
return -1;
}
},
mkport: function() { throw 'TODO' },
// ==========================================================================
// select.h
// ==========================================================================
select__deps: ['$FS', '__DEFAULT_POLLMASK'],
select: function(nfds, readfds, writefds, exceptfds, timeout) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_5({{{ cDefine('EM_PROXIED_SELECT') }}}, nfds, readfds, writefds, exceptfds, timeout);
#endif
// readfds are supported,
// writefds checks socket open status
// exceptfds not supported
// timeout is always 0 - fully async
assert(nfds <= 64, 'nfds must be less than or equal to 64'); // fd sets have 64 bits
assert(!exceptfds, 'exceptfds not supported');
var total = 0;
var srcReadLow = (readfds ? {{{ makeGetValue('readfds', 0, 'i32') }}} : 0),
srcReadHigh = (readfds ? {{{ makeGetValue('readfds', 4, 'i32') }}} : 0);
var srcWriteLow = (writefds ? {{{ makeGetValue('writefds', 0, 'i32') }}} : 0),
srcWriteHigh = (writefds ? {{{ makeGetValue('writefds', 4, 'i32') }}} : 0);
var srcExceptLow = (exceptfds ? {{{ makeGetValue('exceptfds', 0, 'i32') }}} : 0),
srcExceptHigh = (exceptfds ? {{{ makeGetValue('exceptfds', 4, 'i32') }}} : 0);
var dstReadLow = 0,
dstReadHigh = 0;
var dstWriteLow = 0,
dstWriteHigh = 0;
var dstExceptLow = 0,
dstExceptHigh = 0;
var allLow = (readfds ? {{{ makeGetValue('readfds', 0, 'i32') }}} : 0) |
(writefds ? {{{ makeGetValue('writefds', 0, 'i32') }}} : 0) |
(exceptfds ? {{{ makeGetValue('exceptfds', 0, 'i32') }}} : 0);
var allHigh = (readfds ? {{{ makeGetValue('readfds', 4, 'i32') }}} : 0) |
(writefds ? {{{ makeGetValue('writefds', 4, 'i32') }}} : 0) |
(exceptfds ? {{{ makeGetValue('exceptfds', 4, 'i32') }}} : 0);
function get(fd, low, high, val) {
return (fd < 32 ? (low & val) : (high & val));
}
for (var fd = 0; fd < nfds; fd++) {
var mask = 1 << (fd % 32);
if (!(get(fd, allLow, allHigh, mask))) {
continue; // index isn't in the set
}
var stream = FS.getStream(fd);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
var flags = ___DEFAULT_POLLMASK;
if (stream.stream_ops.poll) {
flags = stream.stream_ops.poll(stream);
}
if ((flags & {{{ cDefine('POLLIN') }}}) && get(fd, srcReadLow, srcReadHigh, mask)) {
fd < 32 ? (dstReadLow = dstReadLow | mask) : (dstReadHigh = dstReadHigh | mask);
total++;
}
if ((flags & {{{ cDefine('POLLOUT') }}}) && get(fd, srcWriteLow, srcWriteHigh, mask)) {
fd < 32 ? (dstWriteLow = dstWriteLow | mask) : (dstWriteHigh = dstWriteHigh | mask);
total++;
}
if ((flags & {{{ cDefine('POLLPRI') }}}) && get(fd, srcExceptLow, srcExceptHigh, mask)) {
fd < 32 ? (dstExceptLow = dstExceptLow | mask) : (dstExceptHigh = dstExceptHigh | mask);
total++;
}
}
if (readfds) {
{{{ makeSetValue('readfds', '0', 'dstReadLow', 'i32') }}};
{{{ makeSetValue('readfds', '4', 'dstReadHigh', 'i32') }}};
}
if (writefds) {
{{{ makeSetValue('writefds', '0', 'dstWriteLow', 'i32') }}};
{{{ makeSetValue('writefds', '4', 'dstWriteHigh', 'i32') }}};
}
if (exceptfds) {
{{{ makeSetValue('exceptfds', '0', 'dstExceptLow', 'i32') }}};
{{{ makeSetValue('exceptfds', '4', 'dstExceptHigh', 'i32') }}};
}
return total;
},
// ==========================================================================
// sys/ioctl.h
// ==========================================================================
ioctl__deps: ['$FS'],
ioctl: function(fd, request, varargs) {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_3({{{ cDefine('EM_PROXIED_IOCTL') }}}, fd, request, varargs);
#endif
var stream = FS.getStream(fd);
if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
var arg = {{{ makeGetValue('varargs', '0', 'i32') }}};
try {
return FS.ioctl(stream, request, arg);
} catch (e) {
FS.handleFSError(e);
return -1;
}
},
#endif
// pty.h
openpty: function() { throw 'openpty: TODO' },
forkpty: function() { throw 'forkpty: TODO' },
// grp.h
initgroups: function() { throw 'initgroups: TODO' },
// pwd.h
getpwnam: function() { throw 'getpwnam: TODO' },
setpwent: function() { throw 'setpwent: TODO' },
getpwent: function() { throw 'getpwent: TODO' },
endpwent: function() { throw 'endpwent: TODO' },
// ==========================================================================
// emscripten.h
// ==========================================================================
emscripten_run_script: function(ptr) {
eval(Pointer_stringify(ptr));
},
emscripten_run_script_int: function(ptr) {
return eval(Pointer_stringify(ptr))|0;
},
emscripten_run_script_string: function(ptr) {
var s = eval(Pointer_stringify(ptr)) + '';
var me = _emscripten_run_script_string;
if (!me.bufferSize || me.bufferSize < s.length+1) {
if (me.bufferSize) _free(me.buffer);
me.bufferSize = s.length+1;
me.buffer = _malloc(me.bufferSize);
}
writeStringToMemory(s, me.buffer);
return me.buffer;
},
emscripten_random: function() {
return Math.random();
},
emscripten_get_now: function() {
if (!_emscripten_get_now.actual) {
if (ENVIRONMENT_IS_NODE) {
_emscripten_get_now.actual = function _emscripten_get_now_actual() {
var t = process['hrtime']();
return t[0] * 1e3 + t[1] / 1e6;
}
} else if (typeof dateNow !== 'undefined') {
_emscripten_get_now.actual = dateNow;
} else if (typeof self === 'object' && self['performance'] && typeof self['performance']['now'] === 'function') {
_emscripten_get_now.actual = function _emscripten_get_now_actual() { return self['performance']['now'](); };
} else if (typeof performance === 'object' && typeof performance['now'] === 'function') {
_emscripten_get_now.actual = function _emscripten_get_now_actual() { return performance['now'](); };
} else {
_emscripten_get_now.actual = Date.now;
}
}
return _emscripten_get_now.actual();
},
emscripten_get_now_res: function() { // return resolution of get_now, in nanoseconds
if (ENVIRONMENT_IS_NODE) {
return 1; // nanoseconds
} else if (typeof dateNow !== 'undefined' ||
((ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && self['performance'] && self['performance']['now'])) {
return 1000; // microseconds (1/1000 of a millisecond)
} else {
return 1000*1000; // milliseconds
}
},
emscripten_get_now_is_monotonic__deps: ['emscripten_get_now'],
emscripten_get_now_is_monotonic: function() {
// return whether emscripten_get_now is guaranteed monotonic; the Date.now
// implementation is not :(
return ENVIRONMENT_IS_NODE || (typeof dateNow !== 'undefined') ||
((ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && self['performance'] && self['performance']['now']);
},
// Returns [parentFuncArguments, functionName, paramListName]
_emscripten_traverse_stack: function(args) {
if (!args || !args.callee || !args.callee.name) {
return [null, '', ''];
}
var funstr = args.callee.toString();
var funcname = args.callee.name;
var str = '(';
var first = true;
for(i in args) {
var a = args[i];
if (!first) {
str += ", ";
}
first = false;
if (typeof a === 'number' || typeof a === 'string') {
str += a;
} else {
str += '(' + typeof a + ')';
}
}
str += ')';
var caller = args.callee.caller;
args = caller ? caller.arguments : [];
if (first)
str = '';
return [args, funcname, str];
},
emscripten_get_callstack_js__deps: ['_emscripten_traverse_stack'],
emscripten_get_callstack_js: function(flags) {
var callstack = jsStackTrace();
// Find the symbols in the callstack that corresponds to the functions that report callstack information, and remove everyhing up to these from the output.
var iThisFunc = callstack.lastIndexOf('_emscripten_log');
var iThisFunc2 = callstack.lastIndexOf('_emscripten_get_callstack');
var iNextLine = callstack.indexOf('\n', Math.max(iThisFunc, iThisFunc2))+1;
callstack = callstack.slice(iNextLine);
// If user requested to see the original source stack, but no source map information is available, just fall back to showing the JS stack.
if (flags & 8/*EM_LOG_C_STACK*/ && typeof emscripten_source_map === 'undefined') {
Runtime.warnOnce('Source map information is not available, emscripten_log with EM_LOG_C_STACK will be ignored. Build with "--pre-js $EMSCRIPTEN/src/emscripten-source-map.min.js" linker flag to add source map loading to code.');
flags ^= 8/*EM_LOG_C_STACK*/;
flags |= 16/*EM_LOG_JS_STACK*/;
}
var stack_args = null;
if (flags & 128 /*EM_LOG_FUNC_PARAMS*/) {
// To get the actual parameters to the functions, traverse the stack via the unfortunately deprecated 'arguments.callee' method, if it works:
var stack_args = __emscripten_traverse_stack(arguments);
while (stack_args[1].indexOf('_emscripten_') >= 0)
stack_args = __emscripten_traverse_stack(stack_args[0]);
}
// Process all lines:
lines = callstack.split('\n');
callstack = '';
var newFirefoxRe = new RegExp('\\s*(.*?)@(.*?):([0-9]+):([0-9]+)'); // New FF30 with column info: extract components of form ' Object._main@http://server.com:4324:12'
var firefoxRe = new RegExp('\\s*(.*?)@(.*):(.*)(:(.*))?'); // Old FF without column info: extract components of form ' Object._main@http://server.com:4324'
var chromeRe = new RegExp('\\s*at (.*?) \\\((.*):(.*):(.*)\\\)'); // Extract components of form ' at Object._main (http://server.com/file.html:4324:12)'
for(l in lines) {
var line = lines[l];
var jsSymbolName = '';
var file = '';
var lineno = 0;
var column = 0;
var parts = chromeRe.exec(line);
if (parts && parts.length == 5) {
jsSymbolName = parts[1];
file = parts[2];
lineno = parts[3];
column = parts[4];
} else {
parts = newFirefoxRe.exec(line);
if (!parts) parts = firefoxRe.exec(line);
if (parts && parts.length >= 4) {
jsSymbolName = parts[1];
file = parts[2];
lineno = parts[3];
column = parts[4]|0; // Old Firefox doesn't carry column information, but in new FF30, it is present. See https://bugzilla.mozilla.org/show_bug.cgi?id=762556
} else {
// Was not able to extract this line for demangling/sourcemapping purposes. Output it as-is.
callstack += line + '\n';
continue;
}
}
// Try to demangle the symbol, but fall back to showing the original JS symbol name if not available.
var cSymbolName = (flags & 32/*EM_LOG_DEMANGLE*/) ? demangle(jsSymbolName) : jsSymbolName;
if (!cSymbolName) {
cSymbolName = jsSymbolName;
}
var haveSourceMap = false;
if (flags & 8/*EM_LOG_C_STACK*/) {
var orig = emscripten_source_map.originalPositionFor({line: lineno, column: column});
haveSourceMap = (orig && orig.source);
if (haveSourceMap) {
if (flags & 64/*EM_LOG_NO_PATHS*/) {
orig.source = orig.source.substring(orig.source.replace(/\\/g, "/").lastIndexOf('/')+1);
}
callstack += ' at ' + cSymbolName + ' (' + orig.source + ':' + orig.line + ':' + orig.column + ')\n';
}
}
if ((flags & 16/*EM_LOG_JS_STACK*/) || !haveSourceMap) {
if (flags & 64/*EM_LOG_NO_PATHS*/) {
file = file.substring(file.replace(/\\/g, "/").lastIndexOf('/')+1);
}
callstack += (haveSourceMap ? (' = '+jsSymbolName) : (' at '+cSymbolName)) + ' (' + file + ':' + lineno + ':' + column + ')\n';
}
// If we are still keeping track with the callstack by traversing via 'arguments.callee', print the function parameters as well.
if (flags & 128 /*EM_LOG_FUNC_PARAMS*/ && stack_args[0]) {
if (stack_args[1] == jsSymbolName && stack_args[2].length > 0) {
callstack = callstack.replace(/\s+$/, '');
callstack += ' with values: ' + stack_args[1] + stack_args[2] + '\n';
}
stack_args = __emscripten_traverse_stack(stack_args[0]);
}
}
// Trim extra whitespace at the end of the output.
callstack = callstack.replace(/\s+$/, '');
return callstack;
},
emscripten_get_callstack__deps: ['emscripten_get_callstack_js'],
emscripten_get_callstack: function(flags, str, maxbytes) {
var callstack = _emscripten_get_callstack_js(flags);
// User can query the required amount of bytes to hold the callstack.
if (!str || maxbytes <= 0) {
return callstack.length+1;
}
// Truncate output to avoid writing past bounds.
if (callstack.length > maxbytes-1) {
callstack = callstack.slice(0, maxbytes-1);
}
// Output callstack string as C string to HEAP.
writeStringToMemory(callstack, str, false);
// Return number of bytes written.
return callstack.length+1;
},
emscripten_log_js__deps: ['emscripten_get_callstack_js'],
emscripten_log_js: function(flags, str) {
if (flags & 24/*EM_LOG_C_STACK | EM_LOG_JS_STACK*/) {
str = str.replace(/\s+$/, ''); // Ensure the message and the callstack are joined cleanly with exactly one newline.
str += (str.length > 0 ? '\n' : '') + _emscripten_get_callstack_js(flags);
}
if (flags & 1 /*EM_LOG_CONSOLE*/) {
if (flags & 4 /*EM_LOG_ERROR*/) {
console.error(str);
} else if (flags & 2 /*EM_LOG_WARN*/) {
console.warn(str);
} else {
console.log(str);
}
} else if (flags & 6 /*EM_LOG_ERROR|EM_LOG_WARN*/) {
Module.printErr(str);
} else {
Module.print(str);
}
},
emscripten_log__deps: ['_formatString', 'emscripten_log_js'],
emscripten_log: function(flags, varargs) {
// Extract the (optionally-existing) printf format specifier field from varargs.
var format = {{{ makeGetValue('varargs', '0', 'i32', undefined, undefined, true) }}};
varargs += Math.max(Runtime.getNativeFieldSize('i32'), Runtime.getAlignSize('i32', null, true));
var str = '';
if (format) {
var result = __formatString(format, varargs);
for(var i = 0 ; i < result.length; ++i) {
str += String.fromCharCode(result[i]);
}
}
_emscripten_log_js(flags, str);
},
emscripten_get_compiler_setting: function(name) {
name = Pointer_stringify(name);
var ret = Runtime.getCompilerSetting(name);
if (typeof ret === 'number') return ret;
if (!_emscripten_get_compiler_setting.cache) _emscripten_get_compiler_setting.cache = {};
var cache = _emscripten_get_compiler_setting.cache;
var fullname = name + '__str';
var fullret = cache[fullname];
if (fullret) return fullret;
return cache[fullname] = allocate(intArrayFromString(ret + ''), 'i8', ALLOC_NORMAL);
},
emscripten_debugger: function() {
debugger;
},
//============================
// i64 math
//============================
i64Add__asm: true,
i64Add__sig: 'iiiii',
i64Add: function(a, b, c, d) {
/*
x = a + b*2^32
y = c + d*2^32
result = l + h*2^32
*/
a = a|0; b = b|0; c = c|0; d = d|0;
var l = 0, h = 0;
l = (a + c)>>>0;
h = (b + d + (((l>>>0) < (a>>>0))|0))>>>0; // Add carry from low word to high word on overflow.
{{{ makeStructuralReturn(['l|0', 'h'], true) }}};
},
llvm_uadd_with_overflow_i64__asm: true,
llvm_uadd_with_overflow_i64__sig: 'iiiii',
llvm_uadd_with_overflow_i64: function(a, b, c, d) {
a = a|0; b = b|0; c = c|0; d = d|0;
var l = 0, h = 0, overflow = 0;
l = (a + c)>>>0;
h = (b + d)>>>0;
overflow = ((h>>>0) < (b>>>0))|0; // Return whether addition overflowed even the high word.
if ((l>>>0) < (a>>>0)) {
h = (h + 1)>>>0; // Add carry from low word to high word on overflow.
overflow = overflow | (!h); // Check again for overflow.
}
{{{ makeStructuralReturn(['l|0', 'h', 'overflow'], true) }}};
},
i64Subtract__asm: true,
i64Subtract__sig: 'iiiii',
i64Subtract: function(a, b, c, d) {
a = a|0; b = b|0; c = c|0; d = d|0;
var l = 0, h = 0;
l = (a - c)>>>0;
h = (b - d)>>>0;
h = (b - d - (((c>>>0) > (a>>>0))|0))>>>0; // Borrow one from high word to low word on underflow.
{{{ makeStructuralReturn(['l|0', 'h'], true) }}};
},
bitshift64Shl__asm: true,
bitshift64Shl__sig: 'iiii',
bitshift64Shl: function(low, high, bits) {
low = low|0; high = high|0; bits = bits|0;
var ander = 0;
if ((bits|0) < 32) {
ander = ((1 << bits) - 1)|0;
{{{ makeSetTempRet0('(high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits))') }}};
return low << bits;
}
{{{ makeSetTempRet0('low << (bits - 32)') }}};
return 0;
},
bitshift64Ashr__asm: true,
bitshift64Ashr__sig: 'iiii',
bitshift64Ashr: function(low, high, bits) {
low = low|0; high = high|0; bits = bits|0;
var ander = 0;
if ((bits|0) < 32) {
ander = ((1 << bits) - 1)|0;
{{{ makeSetTempRet0('high >> bits') }}};
return (low >>> bits) | ((high&ander) << (32 - bits));
}
{{{ makeSetTempRet0('(high|0) < 0 ? -1 : 0') }}};
return (high >> (bits - 32))|0;
},
bitshift64Lshr__asm: true,
bitshift64Lshr__sig: 'iiii',
bitshift64Lshr: function(low, high, bits) {
low = low|0; high = high|0; bits = bits|0;
var ander = 0;
if ((bits|0) < 32) {
ander = ((1 << bits) - 1)|0;
{{{ makeSetTempRet0('high >>> bits') }}};
return (low >>> bits) | ((high&ander) << (32 - bits));
}
{{{ makeSetTempRet0('0') }}};
return (high >>> (bits - 32))|0;
},
// misc shims for musl
__lock: function() {},
__unlock: function() {},
__lockfile: function() { return 1 },
__unlockfile: function(){},
// ubsan (undefined behavior sanitizer) support
__ubsan_handle_float_cast_overflow: function(id, post) {
abort('Undefined behavior! ubsan_handle_float_cast_overflow: ' + [id, post]);
},
// misc definitions to avoid unnecessary unresolved symbols from fastcomp
emscripten_prep_setjmp: true,
emscripten_cleanup_setjmp: true,
emscripten_check_longjmp: true,
emscripten_get_longjmp_result: true,
emscripten_setjmp: true,
emscripten_preinvoke: true,
emscripten_postinvoke: true,
emscripten_resume: true,
emscripten_landingpad: true,
getHigh32: true,
setHigh32: true,
FtoILow: true,
FtoIHigh: true,
DtoILow: true,
DtoIHigh: true,
BDtoILow: true,
BDtoIHigh: true,
SItoF: true,
UItoF: true,
SItoD: true,
UItoD: true,
BItoD: true,
llvm_dbg_value: true,
llvm_ctlz_i32: true,
emscripten_asm_const: true,
emscripten_asm_const_int: true,
emscripten_asm_const_double: true,
};
function autoAddDeps(object, name) {
name = [name];
for (var item in object) {
if (item.substr(-6) != '__deps') {
if (!object[item + '__deps']) {
object[item + '__deps'] = name;
} else {
object[item + '__deps'].push(name[0]); // add to existing list
}
}
}
}
=============
Internal compiler error in src/compiler.js! Please raise a bug report at https://github.com/kripken/emscripten/issues/ with a log of the build and the input files used to run. Exception message: "XXX missing C define _SC_PHYS_PAGES!" | undefined
Traceback (most recent call last):
File "/opt/emsdk_portable/emscripten/master/emscripten.py", line 1062, in <module>
_main(environ=os.environ)
File "/opt/emsdk_portable/emscripten/master/emscripten.py", line 1052, in _main
temp_files.run_and_clean(lambda: main(
File "/opt/emsdk_portable/emscripten/master/tools/tempfiles.py", line 39, in run_and_clean
return func()
File "/opt/emsdk_portable/emscripten/master/emscripten.py", line 1058, in <lambda>
DEBUG_CACHE=DEBUG_CACHE,
File "/opt/emsdk_portable/emscripten/master/emscripten.py", line 959, in main
temp_files=temp_files, DEBUG=DEBUG, DEBUG_CACHE=DEBUG_CACHE)
File "/opt/emsdk_portable/emscripten/master/emscripten.py", line 197, in emscript
cwd=path_from_root('src'), error_limit=300)
File "/opt/emsdk_portable/emscripten/master/tools/jsrun.py", line 75, in run_js
raise Exception('Expected the command ' + str(command) + ' to finish with return code ' + str(assert_returncode) + ', but it returned with code ' + str(proc.returncode) + ' instead! Output: ' + str(ret)[:error_limit])
Exception: Expected the command ['node', '/opt/emsdk_portable/emscripten/master/src/compiler.js', '/tmp/tmp3g6xpq.txt', '/opt/emsdk_portable/emscripten/master/src/library_pthread_stub.js'] to finish with return code 0, but it returned with code 1 instead! Output: // The Module object: Our interface to the outside world. We import
// and export values on it, and do the work to get that through
// closure compiler if necessary. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(Module) { ..gener
Traceback (most recent call last):
File "/opt/emsdk_portable/emscripten/master/emcc", line 1294, in <module>
final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args)
File "/opt/emsdk_portable/emscripten/master/tools/shared.py", line 1535, in emscripten
assert os.path.exists(filename + '.o.js'), 'Emscripten failed to generate .js'
AssertionError: Emscripten failed to generate .js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment