3
// An implementation of a libc for the web. Basically, implementations of
4
// the various standard C libraries, that can be called from compiled code,
5
// and work using the actual JavaScript environment.
7
// We search the Library object when there is an external function. If the
8
// entry in the Library is a function, we insert it. If it is a string, we
9
// do another lookup in the library (a simple way to write a function once,
10
// if it can be called by different names). We also allow dependencies,
11
// using __deps. Initialization code to be run after allocating all
12
// global constants can be defined by __postset.
14
// Note that the full function name will be '_' + the name in the Library
15
// object. For convenience, the short name appears here. Note that if you add a
16
// new function with an '_', it will not be found.
18
LibraryManager.library = {
19
// ==========================================================================
21
// ==========================================================================
23
// keep this low in memory, because we flatten arrays with them in them
24
stdin: 'allocate(1, "i32*", ALLOC_STACK)',
25
stdout: 'allocate(1, "i32*", ALLOC_STACK)',
26
stderr: 'allocate(1, "i32*", ALLOC_STACK)',
27
_impure_ptr: 'allocate(1, "i32*", ALLOC_STACK)',
29
$FS__deps: ['$ERRNO_CODES', '__setErrNo', 'stdin', 'stdout', 'stderr', '_impure_ptr'],
30
$FS__postset: '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' +
31
'__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });' +
32
'__ATEXIT__.push({ func: function() { FS.quit() } });' +
33
// export some names through closure
34
'Module["FS_createFolder"] = FS.createFolder;' +
35
'Module["FS_createPath"] = FS.createPath;' +
36
'Module["FS_createDataFile"] = FS.createDataFile;' +
37
'Module["FS_createPreloadedFile"] = FS.createPreloadedFile;' +
38
'Module["FS_createLazyFile"] = FS.createLazyFile;' +
39
'Module["FS_createLink"] = FS.createLink;' +
40
'Module["FS_createDevice"] = FS.createDevice;',
42
// The path to the current folder.
44
// The inode to assign to the next created object.
46
// Currently opened file or directory streams. Padded with null so the zero
47
// index is unused, as the indices are used as pointers. This is not split
48
// into separate fileStreams and folderStreams lists because the pointers
49
// must be interchangeable, e.g. when used in fdopen().
50
// streams is kept as a dense array. It may contain |null| to fill in
54
checkStreams: function() {
55
for (var i in FS.streams) if (FS.streams.hasOwnProperty(i)) assert(i >= 0 && i < FS.streams.length); // no keys not in dense span
56
for (var i = 0; i < FS.streams.length; i++) assert(typeof FS.streams[i] == 'object'); // no non-null holes in dense span
59
// Whether we are currently ignoring permissions. Useful when preparing the
60
// filesystem and creating files inside read-only folders.
61
// This is set to false when the runtime is initialized, allowing you
62
// to modify the filesystem freely before run() is called.
63
ignorePermissions: true,
64
joinPath: function(parts, forceRelative) {
66
for (var i = 1; i < parts.length; i++) {
67
if (ret[ret.length-1] != '/') ret += '/';
70
if (forceRelative && ret[0] == '/') ret = ret.substr(1);
73
// Converts any path to an absolute path. Resolves embedded "." and ".."
75
absolutePath: function(relative, base) {
76
if (typeof relative !== 'string') return null;
77
if (base === undefined) base = FS.currentPath;
78
if (relative && relative[0] == '/') base = '';
79
var full = base + '/' + relative;
80
var parts = full.split('/').reverse();
82
while (parts.length) {
83
var part = parts.pop();
84
if (part == '' || part == '.') {
86
} else if (part == '..') {
87
if (absolute.length > 1) absolute.pop();
92
return absolute.length == 1 ? '/' : absolute.join('/');
94
// Analyzes a relative or absolute path returning a description, containing:
95
// isRoot: Whether the path points to the root.
96
// exists: Whether the object at the path exists.
97
// error: If !exists, this will contain the errno code of the cause.
98
// name: The base name of the object (null if !parentExists).
99
// path: The absolute path to the object, with all links resolved.
100
// object: The filesystem record of the object referenced by the path.
101
// parentExists: Whether the parent of the object exist and is a folder.
102
// parentPath: The absolute path to the parent folder.
103
// parentObject: The filesystem record of the parent folder.
104
analyzePath: function(path, dontResolveLastLink, linksVisited) {
117
var inputPath = path;
119
Module['print']('FS.analyzePath("' + inputPath + '", ' +
120
dontResolveLastLink + ', ' +
121
linksVisited + ') => {' +
122
'isRoot: ' + ret.isRoot + ', ' +
123
'exists: ' + ret.exists + ', ' +
124
'error: ' + ret.error + ', ' +
125
'name: "' + ret.name + '", ' +
126
'path: "' + ret.path + '", ' +
127
'object: ' + ret.object + ', ' +
128
'parentExists: ' + ret.parentExists + ', ' +
129
'parentPath: "' + ret.parentPath + '", ' +
130
'parentObject: ' + ret.parentObject + '}');
133
path = FS.absolutePath(path);
136
ret.exists = ret.parentExists = true;
138
ret.path = ret.parentPath = '/';
139
ret.object = ret.parentObject = FS.root;
140
} else if (path !== null) {
141
linksVisited = linksVisited || 0;
142
path = path.slice(1).split('/');
143
var current = FS.root;
144
var traversed = [''];
145
while (path.length) {
146
if (path.length == 1 && current.isFolder) {
147
ret.parentExists = true;
148
ret.parentPath = traversed.length == 1 ? '/' : traversed.join('/');
149
ret.parentObject = current;
152
var target = path.shift();
153
if (!current.isFolder) {
154
ret.error = ERRNO_CODES.ENOTDIR;
156
} else if (!current.read) {
157
ret.error = ERRNO_CODES.EACCES;
159
} else if (!current.contents.hasOwnProperty(target)) {
160
ret.error = ERRNO_CODES.ENOENT;
163
current = current.contents[target];
164
if (current.link && !(dontResolveLastLink && path.length == 0)) {
165
if (linksVisited > 40) { // Usual Linux SYMLOOP_MAX.
166
ret.error = ERRNO_CODES.ELOOP;
169
var link = FS.absolutePath(current.link, traversed.join('/'));
170
ret = FS.analyzePath([link].concat(path).join('/'),
171
dontResolveLastLink, linksVisited + 1);
177
traversed.push(target);
178
if (path.length == 0) {
180
ret.path = traversed.join('/');
181
ret.object = current;
190
// Finds the file system object at a given path. If dontResolveLastLink is
191
// set to true and the object is a symbolic link, it will be returned as is
192
// instead of being resolved. Links embedded in the path are still resolved.
193
findObject: function(path, dontResolveLastLink) {
195
var ret = FS.analyzePath(path, dontResolveLastLink);
199
___setErrNo(ret.error);
203
// Creates a file system record: file, link, device or folder.
204
createObject: function(parent, name, properties, canRead, canWrite) {
206
Module['print']('FS.createObject("' + parent + '", ' +
208
JSON.stringify(properties) + ', ' +
212
if (!parent) parent = '/';
213
if (typeof parent === 'string') parent = FS.findObject(parent);
216
___setErrNo(ERRNO_CODES.EACCES);
217
throw new Error('Parent path must exist.');
219
if (!parent.isFolder) {
220
___setErrNo(ERRNO_CODES.ENOTDIR);
221
throw new Error('Parent must be a folder.');
223
if (!parent.write && !FS.ignorePermissions) {
224
___setErrNo(ERRNO_CODES.EACCES);
225
throw new Error('Parent folder must be writeable.');
227
if (!name || name == '.' || name == '..') {
228
___setErrNo(ERRNO_CODES.ENOENT);
229
throw new Error('Name must not be empty.');
231
if (parent.contents.hasOwnProperty(name)) {
232
___setErrNo(ERRNO_CODES.EEXIST);
233
throw new Error("Can't overwrite object.");
236
parent.contents[name] = {
237
read: canRead === undefined ? true : canRead,
238
write: canWrite === undefined ? false : canWrite,
239
timestamp: Date.now(),
240
inodeNumber: FS.nextInode++
242
for (var key in properties) {
243
if (properties.hasOwnProperty(key)) {
244
parent.contents[name][key] = properties[key];
248
return parent.contents[name];
251
createFolder: function(parent, name, canRead, canWrite) {
252
var properties = {isFolder: true, isDevice: false, contents: {}};
253
return FS.createObject(parent, name, properties, canRead, canWrite);
255
// Creates a folder and all its missing parents.
256
createPath: function(parent, path, canRead, canWrite) {
257
var current = FS.findObject(parent);
258
if (current === null) throw new Error('Invalid parent.');
259
path = path.split('/').reverse();
260
while (path.length) {
261
var part = path.pop();
263
if (!current.contents.hasOwnProperty(part)) {
264
FS.createFolder(current, part, canRead, canWrite);
266
current = current.contents[part];
271
// Creates a file record, given specific properties.
272
createFile: function(parent, name, properties, canRead, canWrite) {
273
properties.isFolder = false;
274
return FS.createObject(parent, name, properties, canRead, canWrite);
276
// Creates a file record from existing data.
277
createDataFile: function(parent, name, data, canRead, canWrite) {
278
if (typeof data === 'string') {
279
var dataArray = new Array(data.length);
280
for (var i = 0, len = data.length; i < len; ++i) dataArray[i] = data.charCodeAt(i);
285
contents: data.subarray ? data.subarray(0) : data // as an optimization, create a new array wrapper (not buffer) here, to help JS engines understand this object
287
return FS.createFile(parent, name, properties, canRead, canWrite);
289
// Creates a file record for lazy-loading from a URL. XXX This requires a synchronous
290
// XHR, which is not possible in browsers except in a web worker! Use preloading,
291
// either --preload-file in emcc or FS.createPreloadedFile
292
createLazyFile: function(parent, name, url, canRead, canWrite) {
294
if (typeof XMLHttpRequest !== 'undefined') {
295
if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
296
// Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
297
var LazyUint8Array = function(chunkSize, length) {
298
this.length = length;
299
this.chunkSize = chunkSize;
300
this.chunks = []; // Loaded chunks. Index is the chunk number
302
LazyUint8Array.prototype.get = function(idx) {
303
if (idx > this.length-1 || idx < 0) {
306
var chunkOffset = idx % chunkSize;
307
var chunkNum = Math.floor(idx / chunkSize);
308
return this.getter(chunkNum)[chunkOffset];
310
LazyUint8Array.prototype.setDataGetter = function(getter) {
311
this.getter = getter;
315
var xhr = new XMLHttpRequest();
316
xhr.open('HEAD', url, false);
318
if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
319
var datalength = Number(xhr.getResponseHeader("Content-length"));
321
var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
323
var chunkSize = 1024; // Chunk size in bytes
325
var chunkSize = 1024*1024; // Chunk size in bytes
327
if (!hasByteServing) chunkSize = datalength;
329
// Function to get a range from the remote URL.
330
var doXHR = (function(from, to) {
331
if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
332
if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
334
// TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
335
var xhr = new XMLHttpRequest();
336
xhr.open('GET', url, false);
337
if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
339
// Some hints to the browser that we want binary data.
340
if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
341
if (xhr.overrideMimeType) {
342
xhr.overrideMimeType('text/plain; charset=x-user-defined');
346
if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
347
if (xhr.response !== undefined) {
348
return new Uint8Array(xhr.response || []);
350
return intArrayFromString(xhr.responseText || '', true);
354
var lazyArray = new LazyUint8Array(chunkSize, datalength);
355
lazyArray.setDataGetter(function(chunkNum) {
356
var start = chunkNum * lazyArray.chunkSize;
357
var end = (chunkNum+1) * lazyArray.chunkSize - 1; // including this byte
358
end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
359
if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
360
lazyArray.chunks[chunkNum] = doXHR(start, end);
362
if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
363
return lazyArray.chunks[chunkNum];
365
var properties = { isDevice: false, contents: lazyArray };
367
var properties = { isDevice: false, url: url };
370
return FS.createFile(parent, name, properties, canRead, canWrite);
372
// Preloads a file asynchronously. You can call this before run, for example in
373
// preRun. run will be delayed until this file arrives and is set up.
374
// If you call it after run(), you may want to pause the main loop until it
375
// completes, if so, you can use the onload parameter to be notified when
377
// In addition to normally creating the file, we also asynchronously preload
378
// the browser-friendly versions of it: For an image, we preload an Image
379
// element and for an audio, and Audio. These are necessary for SDL_Image
380
// and _Mixer to find the files in preloadedImages/Audios.
381
// You can also call this with a typed array instead of a url. It will then
382
// do preloading for the Image/Audio part, as if the typed array were the
383
// result of an XHR that you did manually.
384
createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile) {
386
var fullname = FS.joinPath([parent, name], true);
387
function processData(byteArray) {
388
function finish(byteArray) {
389
if (!dontCreateFile) {
390
FS.createDataFile(parent, name, byteArray, canRead, canWrite);
392
if (onload) onload();
393
removeRunDependency('cp ' + fullname);
396
Module['preloadPlugins'].forEach(function(plugin) {
398
if (plugin['canHandle'](fullname)) {
399
plugin['handle'](byteArray, fullname, finish, function() {
400
if (onerror) onerror();
401
removeRunDependency('cp ' + fullname);
406
if (!handled) finish(byteArray);
408
addRunDependency('cp ' + fullname);
409
if (typeof url == 'string') {
410
Browser.asyncLoad(url, function(byteArray) {
411
processData(byteArray);
417
// Creates a link to a specific local path.
418
createLink: function(parent, name, target, canRead, canWrite) {
419
var properties = {isDevice: false, link: target};
420
return FS.createFile(parent, name, properties, canRead, canWrite);
422
// Creates a character device with input and output callbacks:
423
// input: Takes no parameters, returns a byte value or null if no data is
424
// currently available.
425
// output: Takes a byte value; doesn't return anything. Can also be passed
426
// null to perform a flush of any cached data.
427
createDevice: function(parent, name, input, output) {
428
if (!(input || output)) {
429
throw new Error('A device must have at least one callback defined.');
431
var ops = {isDevice: true, input: input, output: output};
432
return FS.createFile(parent, name, ops, Boolean(input), Boolean(output));
434
// Makes sure a file's contents are loaded. Returns whether the file has
435
// been loaded successfully. No-op for files that have been loaded already.
436
forceLoadFile: function(obj) {
437
if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
439
if (typeof XMLHttpRequest !== 'undefined') {
440
throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
441
} else if (Module['read']) {
444
// WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
445
// read() will try to parse UTF8.
446
obj.contents = intArrayFromString(Module['read'](obj.url), true);
451
throw new Error('Cannot load without read() or XMLHttpRequest.');
453
if (!success) ___setErrNo(ERRNO_CODES.EIO);
456
ensureRoot: function() {
458
// The main file system tree. All the contents are inside this.
464
timestamp: Date.now(),
469
// Initializes the filesystems with stdin/stdout/stderr devices, given
470
// optional handlers.
471
init: function(input, output, error) {
472
// Make sure we initialize only once.
473
assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
474
FS.init.initialized = true;
478
// Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
479
input = input || Module['stdin'];
480
output = output || Module['stdout'];
481
error = error || Module['stderr'];
484
var stdinOverridden = true, stdoutOverridden = true, stderrOverridden = true;
486
stdinOverridden = false;
488
if (!input.cache || !input.cache.length) {
490
if (typeof window != 'undefined' &&
491
typeof window.prompt == 'function') {
493
result = window.prompt('Input: ');
494
if (result === null) result = String.fromCharCode(0); // cancel ==> EOF
495
} else if (typeof readline == 'function') {
499
if (!result) result = '';
500
input.cache = intArrayFromString(result + '\n', true);
502
return input.cache.shift();
505
var utf8 = new Runtime.UTF8Processor();
506
function simpleOutput(val) {
507
if (val === null || val === {{{ charCode('\n') }}}) {
508
output.printer(output.buffer.join(''));
511
output.buffer.push(utf8.processCChar(val));
515
stdoutOverridden = false;
516
output = simpleOutput;
518
if (!output.printer) output.printer = Module['print'];
519
if (!output.buffer) output.buffer = [];
521
stderrOverridden = false;
522
error = simpleOutput;
524
if (!error.printer) error.printer = Module['print'];
525
if (!error.buffer) error.buffer = [];
527
// Create the temporary folder, if not already created
529
FS.createFolder('/', 'tmp', true, true);
532
// Create the I/O devices.
533
var devFolder = FS.createFolder('/', 'dev', true, true);
534
var stdin = FS.createDevice(devFolder, 'stdin', input);
535
var stdout = FS.createDevice(devFolder, 'stdout', null, output);
536
var stderr = FS.createDevice(devFolder, 'stderr', null, error);
537
FS.createDevice(devFolder, 'tty', input, output);
539
// Create default streams.
547
isTerminal: !stdinOverridden,
559
isTerminal: !stdoutOverridden,
571
isTerminal: !stderrOverridden,
576
assert(Math.max(_stdin, _stdout, _stderr) < 1024); // make sure these are low, we flatten arrays with these
577
{{{ makeSetValue(makeGlobalUse('_stdin'), 0, 1, 'void*') }}};
578
{{{ makeSetValue(makeGlobalUse('_stdout'), 0, 2, 'void*') }}};
579
{{{ makeSetValue(makeGlobalUse('_stderr'), 0, 3, 'void*') }}};
581
// Other system paths
582
FS.createPath('/', 'dev/shm/tmp', true, true); // temp files
584
// Newlib initialization
585
for (var i = FS.streams.length; i < Math.max(_stdin, _stdout, _stderr) + {{{ QUANTUM_SIZE }}}; i++) {
586
FS.streams[i] = null; // Make sure to keep FS.streams dense
588
FS.streams[_stdin] = FS.streams[1];
589
FS.streams[_stdout] = FS.streams[2];
590
FS.streams[_stderr] = FS.streams[3];
593
assert(FS.streams.length < 1024); // at this early stage, we should not have a large set of file descriptors - just a few
596
{{{ Runtime.QUANTUM_SIZE === 4 ? '[0, 0, 0, 0, _stdin, 0, 0, 0, _stdout, 0, 0, 0, _stderr, 0, 0, 0]' : '[0, _stdin, _stdout, _stderr]' }}},
597
'void*', ALLOC_STATIC) ], 'void*', ALLOC_NONE, {{{ makeGlobalUse('__impure_ptr') }}});
601
if (!FS.init.initialized) return;
602
// Flush any partially-printed lines in stdout and stderr. Careful, they may have been closed
603
if (FS.streams[2] && FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output({{{ charCode('\n') }}});
604
if (FS.streams[3] && FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output({{{ charCode('\n') }}});
607
// Standardizes a path. Useful for making comparisons of pathnames work in a consistent manner.
608
// For example, ./file and file are really the same, so this function will remove ./
609
standardizePath: function(path) {
610
if (path.substr(0, 2) == './') path = path.substr(2);
614
deleteFile: function(path) {
615
path = FS.analyzePath(path);
616
if (!path.parentExists || !path.exists) {
617
throw 'Invalid path ' + path;
619
delete path.parentObject.contents[path.name];
623
// ==========================================================================
625
// ==========================================================================
627
__dirent_struct_layout: Runtime.generateStructInfo([
633
opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
634
opendir: function(dirname) {
635
// DIR *opendir(const char *dirname);
636
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/opendir.html
637
// NOTE: Calculating absolute path redundantly since we need to associate it
638
// with the opened stream.
639
var path = FS.absolutePath(Pointer_stringify(dirname));
641
___setErrNo(ERRNO_CODES.ENOENT);
644
var target = FS.findObject(path);
645
if (target === null) return 0;
646
if (!target.isFolder) {
647
___setErrNo(ERRNO_CODES.ENOTDIR);
649
} else if (!target.read) {
650
___setErrNo(ERRNO_CODES.EACCES);
653
var id = FS.streams.length; // Keep dense
655
for (var key in target.contents) contents.push(key);
659
// An index into contents. Special values: -2 is ".", -1 is "..".
667
// Folder-specific properties:
668
// Remember the contents at the time of opening in an array, so we can
669
// seek between them relying on a single order.
671
// Each stream has its own area for readdir() returns.
672
currentEntry: _malloc(___dirent_struct_layout.__size__)
679
closedir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
680
closedir: function(dirp) {
681
// int closedir(DIR *dirp);
682
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/closedir.html
683
if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
684
return ___setErrNo(ERRNO_CODES.EBADF);
686
_free(FS.streams[dirp].currentEntry);
687
FS.streams[dirp] = null;
691
telldir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
692
telldir: function(dirp) {
693
// long int telldir(DIR *dirp);
694
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/telldir.html
695
if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
696
return ___setErrNo(ERRNO_CODES.EBADF);
698
return FS.streams[dirp].position;
701
seekdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
702
seekdir: function(dirp, loc) {
703
// void seekdir(DIR *dirp, long int loc);
704
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/seekdir.html
705
if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
706
___setErrNo(ERRNO_CODES.EBADF);
709
for (var key in FS.streams[dirp].contents) entries++;
710
if (loc >= entries) {
711
___setErrNo(ERRNO_CODES.EINVAL);
713
FS.streams[dirp].position = loc;
717
rewinddir__deps: ['seekdir'],
718
rewinddir: function(dirp) {
719
// void rewinddir(DIR *dirp);
720
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/rewinddir.html
723
readdir_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
724
readdir_r: function(dirp, entry, result) {
725
// int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
726
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/readdir_r.html
727
if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
728
return ___setErrNo(ERRNO_CODES.EBADF);
730
var stream = FS.streams[dirp];
731
var loc = stream.position;
733
for (var key in stream.contents) entries++;
734
if (loc < -2 || loc >= entries) {
735
{{{ makeSetValue('result', '0', '0', 'i8*') }}}
737
var name, inode, type;
740
inode = 1; // Really undefined.
742
} else if (loc === -1) {
744
inode = 1; // Really undefined.
748
name = stream.contents[loc];
749
object = stream.object.contents[name];
750
inode = object.inodeNumber;
751
type = object.isDevice ? 2 // DT_CHR, character device.
752
: object.isFolder ? 4 // DT_DIR, directory.
753
: object.link !== undefined ? 10 // DT_LNK, symbolic link.
754
: 8; // DT_REG, regular file.
757
var offsets = ___dirent_struct_layout;
758
{{{ makeSetValue('entry', 'offsets.d_ino', 'inode', 'i32') }}}
759
{{{ makeSetValue('entry', 'offsets.d_off', 'stream.position', 'i32') }}}
760
{{{ makeSetValue('entry', 'offsets.d_reclen', 'name.length + 1', 'i32') }}}
761
for (var i = 0; i < name.length; i++) {
762
{{{ makeSetValue('entry + offsets.d_name', 'i', 'name.charCodeAt(i)', 'i8') }}}
764
{{{ makeSetValue('entry + offsets.d_name', 'i', '0', 'i8') }}}
765
{{{ makeSetValue('entry', 'offsets.d_type', 'type', 'i8') }}}
766
{{{ makeSetValue('result', '0', 'entry', 'i8*') }}}
770
readdir__deps: ['readdir_r', '__setErrNo', '$ERRNO_CODES'],
771
readdir: function(dirp) {
772
// struct dirent *readdir(DIR *dirp);
773
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/readdir_r.html
774
if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
775
___setErrNo(ERRNO_CODES.EBADF);
778
if (!_readdir.result) _readdir.result = _malloc(4);
779
_readdir_r(dirp, FS.streams[dirp].currentEntry, _readdir.result);
780
if ({{{ makeGetValue(0, '_readdir.result', 'i8*') }}} === 0) {
783
return FS.streams[dirp].currentEntry;
787
__01readdir64_: 'readdir',
788
// TODO: Check if we need to link any other aliases.
790
// ==========================================================================
792
// ==========================================================================
794
__utimbuf_struct_layout: Runtime.generateStructInfo([
796
['i32', 'modtime']]),
797
utime__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__utimbuf_struct_layout'],
798
utime: function(path, times) {
799
// int utime(const char *path, const struct utimbuf *times);
800
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/utime.h.html
803
// NOTE: We don't keep track of access timestamps.
804
var offset = ___utimbuf_struct_layout.modtime;
805
time = {{{ makeGetValue('times', 'offset', 'i32') }}}
810
var file = FS.findObject(Pointer_stringify(path));
811
if (file === null) return -1;
813
___setErrNo(ERRNO_CODES.EPERM);
816
file.timestamp = time;
820
utimes: function() { throw 'utimes not implemented' },
822
// ==========================================================================
824
// ==========================================================================
826
__libgenSplitName: function(path) {
827
if (path === 0 || {{{ makeGetValue('path', 0, 'i8') }}} === 0) {
828
// Null or empty results in '.'.
829
var me = ___libgenSplitName;
831
me.ret = allocate([{{{ charCode('.') }}}, 0], 'i8', ALLOC_NORMAL);
835
var slash = {{{ charCode('/') }}};
836
var allSlashes = true;
837
var slashPositions = [];
838
for (var i = 0; {{{ makeGetValue('path', 'i', 'i8') }}} !== 0; i++) {
839
if ({{{ makeGetValue('path', 'i', 'i8') }}} === slash) {
840
slashPositions.push(i);
847
// All slashes result in a single slash.
848
{{{ makeSetValue('path', '1', '0', 'i8') }}}
851
// Strip trailing slashes.
852
while (slashPositions.length &&
853
slashPositions[slashPositions.length - 1] == length - 1) {
854
{{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}}
857
return [path, slashPositions.pop()];
861
basename__deps: ['__libgenSplitName'],
862
basename: function(path) {
863
// char *basename(char *path);
864
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/basename.html
865
var result = ___libgenSplitName(path);
866
return result[0] + result[1] + 1;
868
__xpg_basename: 'basename',
869
dirname__deps: ['__libgenSplitName'],
870
dirname: function(path) {
871
// char *dirname(char *path);
872
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/dirname.html
873
var result = ___libgenSplitName(path);
874
if (result[1] == 0) {
875
{{{ makeSetValue('result[0]', 1, '0', 'i8') }}}
876
} else if (result[1] !== -1) {
877
{{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}}
882
// ==========================================================================
884
// ==========================================================================
886
__stat_struct_layout: Runtime.generateStructInfo([
896
['i32', 'st_spare1'],
898
['i32', 'st_spare2'],
900
['i32', 'st_spare3'],
901
['i32', 'st_blksize'],
902
['i32', 'st_blocks'],
903
['i32', 'st_spare4']]),
904
stat__deps: ['$FS', '__stat_struct_layout'],
905
stat: function(path, buf, dontResolveLastLink) {
906
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
907
// int stat(const char *path, struct stat *buf);
908
// NOTE: dontResolveLastLink is a shortcut for lstat(). It should never be
909
// used in client code.
910
var obj = FS.findObject(Pointer_stringify(path), dontResolveLastLink);
911
if (obj === null || !FS.forceLoadFile(obj)) return -1;
913
var offsets = ___stat_struct_layout;
916
{{{ makeSetValue('buf', 'offsets.st_nlink', '1', 'i32') }}}
917
{{{ makeSetValue('buf', 'offsets.st_uid', '0', 'i32') }}}
918
{{{ makeSetValue('buf', 'offsets.st_gid', '0', 'i32') }}}
919
{{{ makeSetValue('buf', 'offsets.st_blksize', '4096', 'i32') }}}
922
{{{ makeSetValue('buf', 'offsets.st_ino', 'obj.inodeNumber', 'i32') }}}
923
var time = Math.floor(obj.timestamp / 1000);
924
if (offsets.st_atime === undefined) {
925
offsets.st_atime = offsets.st_atim.tv_sec;
926
offsets.st_mtime = offsets.st_mtim.tv_sec;
927
offsets.st_ctime = offsets.st_ctim.tv_sec;
928
var nanosec = (obj.timestamp % 1000) * 1000;
929
{{{ makeSetValue('buf', 'offsets.st_atim.tv_nsec', 'nanosec', 'i32') }}}
930
{{{ makeSetValue('buf', 'offsets.st_mtim.tv_nsec', 'nanosec', 'i32') }}}
931
{{{ makeSetValue('buf', 'offsets.st_ctim.tv_nsec', 'nanosec', 'i32') }}}
933
{{{ makeSetValue('buf', 'offsets.st_atime', 'time', 'i32') }}}
934
{{{ makeSetValue('buf', 'offsets.st_mtime', 'time', 'i32') }}}
935
{{{ makeSetValue('buf', 'offsets.st_ctime', 'time', 'i32') }}}
942
// Device numbers reuse inode numbers.
943
dev = rdev = obj.inodeNumber;
945
mode = 0x2000; // S_IFCHR.
949
// NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
950
// but this is not required by the standard.
954
mode = 0x4000; // S_IFDIR.
956
var data = obj.contents || obj.link;
958
blocks = Math.ceil(data.length / 4096);
959
mode = obj.link === undefined ? 0x8000 : 0xA000; // S_IFREG, S_IFLNK.
962
{{{ makeSetValue('buf', 'offsets.st_dev', 'dev', 'i32') }}};
963
{{{ makeSetValue('buf', 'offsets.st_rdev', 'rdev', 'i32') }}};
964
{{{ makeSetValue('buf', 'offsets.st_size', 'size', 'i32') }}}
965
{{{ makeSetValue('buf', 'offsets.st_blocks', 'blocks', 'i32') }}}
966
if (obj.read) mode |= 0x16D; // S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH.
967
if (obj.write) mode |= 0x92; // S_IWUSR | S_IWGRP | S_IWOTH.
968
{{{ makeSetValue('buf', 'offsets.st_mode', 'mode', 'i32') }}}
972
lstat__deps: ['stat'],
973
lstat: function(path, buf) {
974
// int lstat(const char *path, struct stat *buf);
975
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/lstat.html
976
return _stat(path, buf, true);
978
fstat__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'stat'],
979
fstat: function(fildes, buf) {
980
// int fstat(int fildes, struct stat *buf);
981
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fstat.html
982
if (!FS.streams[fildes]) {
983
___setErrNo(ERRNO_CODES.EBADF);
986
var pathArray = intArrayFromString(FS.streams[fildes].path);
987
return _stat(allocate(pathArray, 'i8', ALLOC_STACK), buf);
990
mknod__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
991
mknod: function(path, mode, dev) {
992
// int mknod(const char *path, mode_t mode, dev_t dev);
993
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mknod.html
994
if (dev !== 0 || !(mode & 0xC000)) { // S_IFREG | S_IFDIR.
995
// Can't create devices or pipes through mknod().
996
___setErrNo(ERRNO_CODES.EINVAL);
999
var properties = {contents: [], isFolder: Boolean(mode & 0x4000)}; // S_IFDIR.
1000
path = FS.analyzePath(Pointer_stringify(path));
1002
FS.createObject(path.parentObject, path.name, properties,
1003
mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
1010
mkdir__deps: ['mknod'],
1011
mkdir: function(path, mode) {
1012
// int mkdir(const char *path, mode_t mode);
1013
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkdir.html
1014
return _mknod(path, 0x4000 | (mode & 0x180), 0); // S_IFDIR, S_IRUSR | S_IWUSR.
1016
mkfifo__deps: ['__setErrNo', '$ERRNO_CODES'],
1017
mkfifo: function(path, mode) {
1018
// int mkfifo(const char *path, mode_t mode);
1019
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkfifo.html
1020
// NOTE: We support running only a single process, and named pipes require
1021
// blocking, which we can't provide. The error code is not very
1022
// accurate, but it's the closest among those allowed in the standard
1023
// and unlikely to result in retries.
1024
___setErrNo(ERRNO_CODES.EROFS);
1027
chmod__deps: ['$FS'],
1028
chmod: function(path, mode) {
1029
// int chmod(const char *path, mode_t mode);
1030
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/chmod.html
1031
var obj = FS.findObject(Pointer_stringify(path));
1032
if (obj === null) return -1;
1033
obj.read = mode & 0x100; // S_IRUSR.
1034
obj.write = mode & 0x80; // S_IWUSR.
1035
obj.timestamp = Date.now();
1038
fchmod__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'chmod'],
1039
fchmod: function(fildes, mode) {
1040
// int fchmod(int fildes, mode_t mode);
1041
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fchmod.html
1042
if (!FS.streams[fildes]) {
1043
___setErrNo(ERRNO_CODES.EBADF);
1046
var pathArray = intArrayFromString(FS.streams[fildes].path);
1047
return _chmod(allocate(pathArray, 'i8', ALLOC_STACK), mode);
1050
lchmod: function() { throw 'TODO: lchmod' },
1052
umask__deps: ['$FS'],
1053
umask: function(newMask) {
1054
// mode_t umask(mode_t cmask);
1055
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/umask.html
1056
// NOTE: This value isn't actually used for anything.
1057
if (_umask.cmask === undefined) _umask.cmask = 0x1FF; // S_IRWXU | S_IRWXG | S_IRWXO.
1058
var oldMask = _umask.cmask;
1059
_umask.cmask = newMask;
1064
__01fstat64_: 'fstat',
1065
__01stat64_: 'stat',
1066
__01lstat64_: 'lstat',
1068
// TODO: Check if other aliases are needed.
1070
// ==========================================================================
1072
// ==========================================================================
1074
__statvfs_struct_layout: Runtime.generateStructInfo([
1076
['i32', 'f_frsize'],
1077
['i32', 'f_blocks'],
1079
['i32', 'f_bavail'],
1082
['i32', 'f_favail'],
1085
['i32', 'f_namemax']]),
1086
statvfs__deps: ['$FS', '__statvfs_struct_layout'],
1087
statvfs: function(path, buf) {
1088
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
1089
// int statvfs(const char *restrict path, struct statvfs *restrict buf);
1090
var offsets = ___statvfs_struct_layout;
1091
// NOTE: None of the constants here are true. We're just returning safe and
1093
{{{ makeSetValue('buf', 'offsets.f_bsize', '4096', 'i32') }}}
1094
{{{ makeSetValue('buf', 'offsets.f_frsize', '4096', 'i32') }}}
1095
{{{ makeSetValue('buf', 'offsets.f_blocks', '1000000', 'i32') }}}
1096
{{{ makeSetValue('buf', 'offsets.f_bfree', '500000', 'i32') }}}
1097
{{{ makeSetValue('buf', 'offsets.f_bavail', '500000', 'i32') }}}
1098
{{{ makeSetValue('buf', 'offsets.f_files', 'FS.nextInode', 'i32') }}}
1099
{{{ makeSetValue('buf', 'offsets.f_ffree', '1000000', 'i32') }}}
1100
{{{ makeSetValue('buf', 'offsets.f_favail', '1000000', 'i32') }}}
1101
{{{ makeSetValue('buf', 'offsets.f_fsid', '42', 'i32') }}}
1102
{{{ makeSetValue('buf', 'offsets.f_flag', '2', 'i32') }}} // ST_NOSUID
1103
{{{ makeSetValue('buf', 'offsets.f_namemax', '255', 'i32') }}}
1106
fstatvfs__deps: ['statvfs'],
1107
fstatvfs: function(fildes, buf) {
1108
// int fstatvfs(int fildes, struct statvfs *buf);
1109
// http://pubs.opengroup.org/onlinepubs/009604499/functions/statvfs.html
1110
return _statvfs(0, buf);
1112
__01statvfs64_: 'statvfs',
1113
__01fstatvfs64_: 'fstatvfs',
1115
// ==========================================================================
1117
// ==========================================================================
1119
__flock_struct_layout: Runtime.generateStructInfo([
1121
['i16', 'l_whence'],
1126
open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
1127
open: function(path, oflag, varargs) {
1128
// int open(const char *path, int oflag, ...);
1129
// http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
1130
// NOTE: This implementation tries to mimic glibc rather than strictly
1131
// following the POSIX standard.
1133
var mode = {{{ makeGetValue('varargs', 0, 'i32') }}};
1136
var accessMode = oflag & {{{ cDefine('O_ACCMODE') }}};
1137
var isWrite = accessMode != {{{ cDefine('O_RDONLY') }}};
1138
var isRead = accessMode != {{{ cDefine('O_WRONLY') }}};
1139
var isCreate = Boolean(oflag & {{{ cDefine('O_CREAT') }}});
1140
var isExistCheck = Boolean(oflag & {{{ cDefine('O_EXCL') }}});
1141
var isTruncate = Boolean(oflag & {{{ cDefine('O_TRUNC') }}});
1142
var isAppend = Boolean(oflag & {{{ cDefine('O_APPEND') }}});
1145
var origPath = path;
1146
path = FS.analyzePath(Pointer_stringify(path));
1147
if (!path.parentExists) {
1148
___setErrNo(path.error);
1151
var target = path.object || null;
1154
// Verify the file exists, create if needed and allowed.
1156
if (isCreate && isExistCheck) {
1157
___setErrNo(ERRNO_CODES.EEXIST);
1160
if ((isWrite || isCreate || isTruncate) && target.isFolder) {
1161
___setErrNo(ERRNO_CODES.EISDIR);
1164
if (isRead && !target.read || isWrite && !target.write) {
1165
___setErrNo(ERRNO_CODES.EACCES);
1168
if (isTruncate && !target.isDevice) {
1169
target.contents = [];
1171
if (!FS.forceLoadFile(target)) {
1172
___setErrNo(ERRNO_CODES.EIO);
1176
finalPath = path.path;
1179
___setErrNo(ERRNO_CODES.ENOENT);
1182
if (!path.parentObject.write) {
1183
___setErrNo(ERRNO_CODES.EACCES);
1186
target = FS.createDataFile(path.parentObject, path.name, [],
1187
mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
1188
finalPath = path.parentPath + '/' + path.name;
1190
// Actually create an open stream.
1191
var id = FS.streams.length; // Keep dense
1192
if (target.isFolder) {
1193
var entryBuffer = 0;
1194
if (___dirent_struct_layout) {
1195
entryBuffer = _malloc(___dirent_struct_layout.__size__);
1198
for (var key in target.contents) contents.push(key);
1202
// An index into contents. Special values: -2 is ".", -1 is "..".
1210
// Folder-specific properties:
1211
// Remember the contents at the time of opening in an array, so we can
1212
// seek between them relying on a single order.
1214
// Each stream has its own area for readdir() returns.
1215
currentEntry: entryBuffer
1235
creat__deps: ['open'],
1236
creat: function(path, mode) {
1237
// int creat(const char *path, mode_t mode);
1238
// http://pubs.opengroup.org/onlinepubs/009695399/functions/creat.html
1239
return _open(path, {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_TRUNC') }}}, allocate([mode, 0, 0, 0], 'i32', ALLOC_STACK));
1241
mkstemp__deps: ['creat'],
1242
mkstemp: function(template) {
1243
if (!_mkstemp.counter) _mkstemp.counter = 0;
1244
var c = (_mkstemp.counter++).toString();
1246
while (c.length < rep.length) c = '0' + c;
1247
writeArrayToMemory(intArrayFromString(c), template + Pointer_stringify(template).indexOf(rep));
1248
return _creat(template, 0600);
1250
fcntl__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__flock_struct_layout'],
1251
fcntl: function(fildes, cmd, varargs, dup2) {
1252
// int fcntl(int fildes, int cmd, ...);
1253
// http://pubs.opengroup.org/onlinepubs/009695399/functions/fcntl.html
1254
if (!FS.streams[fildes]) {
1255
___setErrNo(ERRNO_CODES.EBADF);
1258
var stream = FS.streams[fildes];
1260
case {{{ cDefine('F_DUPFD') }}}:
1261
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
1263
___setErrNo(ERRNO_CODES.EINVAL);
1267
for (var member in stream) {
1268
newStream[member] = stream[member];
1270
arg = dup2 ? arg : Math.max(arg, FS.streams.length); // dup2 wants exactly arg; fcntl wants a free descriptor >= arg
1271
for (var i = FS.streams.length; i < arg; i++) {
1272
FS.streams[i] = null; // Keep dense
1274
FS.streams[arg] = newStream;
1279
case {{{ cDefine('F_GETFD') }}}:
1280
case {{{ cDefine('F_SETFD') }}}:
1281
return 0; // FD_CLOEXEC makes no sense for a single process.
1282
case {{{ cDefine('F_GETFL') }}}:
1284
if (stream.isRead && stream.isWrite) flags = {{{ cDefine('O_RDWR') }}};
1285
else if (!stream.isRead && stream.isWrite) flags = {{{ cDefine('O_WRONLY') }}};
1286
else if (stream.isRead && !stream.isWrite) flags = {{{ cDefine('O_RDONLY') }}};
1287
if (stream.isAppend) flags |= {{{ cDefine('O_APPEND') }}};
1288
// Synchronization and blocking flags are irrelevant to us.
1290
case {{{ cDefine('F_SETFL') }}}:
1291
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
1292
stream.isAppend = Boolean(arg | {{{ cDefine('O_APPEND') }}});
1293
// Synchronization and blocking flags are irrelevant to us.
1295
case {{{ cDefine('F_GETLK') }}}:
1296
case {{{ cDefine('F_GETLK64') }}}:
1297
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
1298
var offset = ___flock_struct_layout.l_type;
1299
// We're always unlocked.
1300
{{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}}
1302
case {{{ cDefine('F_SETLK') }}}:
1303
case {{{ cDefine('F_SETLKW') }}}:
1304
case {{{ cDefine('F_SETLK64') }}}:
1305
case {{{ cDefine('F_SETLKW64') }}}:
1306
// Pretend that the locking is successful.
1308
case {{{ cDefine('F_SETOWN') }}}:
1309
case {{{ cDefine('F_GETOWN') }}}:
1310
// These are for sockets. We don't have them fully implemented yet.
1311
___setErrNo(ERRNO_CODES.EINVAL);
1314
___setErrNo(ERRNO_CODES.EINVAL);
1317
// Should never be reached. Only to silence strict warnings.
1320
posix_fadvise: function(fd, offset, len, advice) {
1321
// int posix_fadvise(int fd, off_t offset, off_t len, int advice);
1322
// http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fadvise.html
1323
// Advise as much as you wish. We don't care.
1326
posix_madvise: 'posix_fadvise',
1327
posix_fallocate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1328
posix_fallocate: function(fd, offset, len) {
1329
// int posix_fallocate(int fd, off_t offset, off_t len);
1330
// http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate.html
1331
if (!FS.streams[fd] || FS.streams[fd].link ||
1332
FS.streams[fd].isFolder || FS.streams[fd].isDevice) {
1333
___setErrNo(ERRNO_CODES.EBADF);
1336
var contents = FS.streams[fd].object.contents;
1337
var limit = offset + len;
1338
while (limit > contents.length) contents.push(0);
1342
// ==========================================================================
1344
// ==========================================================================
1346
__pollfd_struct_layout: Runtime.generateStructInfo([
1349
['i16', 'revents']]),
1350
poll__deps: ['$FS', '__pollfd_struct_layout'],
1351
poll: function(fds, nfds, timeout) {
1352
// int poll(struct pollfd fds[], nfds_t nfds, int timeout);
1353
// http://pubs.opengroup.org/onlinepubs/009695399/functions/poll.html
1354
// NOTE: This is pretty much a no-op mimicking glibc.
1355
var offsets = ___pollfd_struct_layout;
1357
for (var i = 0; i < nfds; i++) {
1358
var pollfd = fds + ___pollfd_struct_layout.__size__ * i;
1359
var fd = {{{ makeGetValue('pollfd', 'offsets.fd', 'i32') }}};
1360
var events = {{{ makeGetValue('pollfd', 'offsets.events', 'i16') }}};
1362
if (FS.streams[fd]) {
1363
var stream = FS.streams[fd];
1364
if (events & {{{ cDefine('POLLIN') }}}) revents |= {{{ cDefine('POLLIN') }}};
1365
if (events & {{{ cDefine('POLLOUT') }}}) revents |= {{{ cDefine('POLLOUT') }}};
1367
if (events & {{{ cDefine('POLLNVAL') }}}) revents |= {{{ cDefine('POLLNVAL') }}};
1369
if (revents) nonzero++;
1370
{{{ makeSetValue('pollfd', 'offsets.revents', 'revents', 'i16') }}}
1375
// ==========================================================================
1377
// ==========================================================================
1379
access__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1380
access: function(path, amode) {
1381
// int access(const char *path, int amode);
1382
// http://pubs.opengroup.org/onlinepubs/000095399/functions/access.html
1383
path = Pointer_stringify(path);
1384
var target = FS.findObject(path);
1385
if (target === null) return -1;
1386
if ((amode & 2 && !target.write) || // W_OK.
1387
((amode & 1 || amode & 4) && !target.read)) { // X_OK, R_OK.
1388
___setErrNo(ERRNO_CODES.EACCES);
1394
chdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1395
chdir: function(path) {
1396
// int chdir(const char *path);
1397
// http://pubs.opengroup.org/onlinepubs/000095399/functions/chdir.html
1398
// NOTE: The path argument may be a string, to simplify fchdir().
1399
if (typeof path !== 'string') path = Pointer_stringify(path);
1400
path = FS.analyzePath(path);
1402
___setErrNo(path.error);
1404
} else if (!path.object.isFolder) {
1405
___setErrNo(ERRNO_CODES.ENOTDIR);
1408
FS.currentPath = path.path;
1412
chown__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1413
chown: function(path, owner, group, dontResolveLastLink) {
1414
// int chown(const char *path, uid_t owner, gid_t group);
1415
// http://pubs.opengroup.org/onlinepubs/000095399/functions/chown.html
1416
// We don't support multiple users, so changing ownership makes no sense.
1417
// NOTE: The path argument may be a string, to simplify fchown().
1418
// NOTE: dontResolveLastLink is a shortcut for lchown(). It should never be
1419
// used in client code.
1420
if (typeof path !== 'string') path = Pointer_stringify(path);
1421
var target = FS.findObject(path, dontResolveLastLink);
1422
if (target === null) return -1;
1423
target.timestamp = Date.now();
1426
chroot__deps: ['__setErrNo', '$ERRNO_CODES'],
1427
chroot: function(path) {
1428
// int chroot(const char *path);
1429
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/chroot.html
1430
___setErrNo(ERRNO_CODES.EACCES);
1433
close__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1434
close: function(fildes) {
1435
// int close(int fildes);
1436
// http://pubs.opengroup.org/onlinepubs/000095399/functions/close.html
1437
if (FS.streams[fildes]) {
1438
if (FS.streams[fildes].currentEntry) {
1439
_free(FS.streams[fildes].currentEntry);
1441
FS.streams[fildes] = null;
1444
___setErrNo(ERRNO_CODES.EBADF);
1448
dup__deps: ['fcntl'],
1449
dup: function(fildes) {
1450
// int dup(int fildes);
1451
// http://pubs.opengroup.org/onlinepubs/000095399/functions/dup.html
1452
return _fcntl(fildes, 0, allocate([0, 0, 0, 0], 'i32', ALLOC_STACK)); // F_DUPFD.
1454
dup2__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'fcntl', 'close'],
1455
dup2: function(fildes, fildes2) {
1456
// int dup2(int fildes, int fildes2);
1457
// http://pubs.opengroup.org/onlinepubs/000095399/functions/dup.html
1459
___setErrNo(ERRNO_CODES.EBADF);
1461
} else if (fildes === fildes2 && FS.streams[fildes]) {
1465
return _fcntl(fildes, 0, allocate([fildes2, 0, 0, 0], 'i32', ALLOC_STACK), true); // F_DUPFD.
1468
fchown__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'chown'],
1469
fchown: function(fildes, owner, group) {
1470
// int fchown(int fildes, uid_t owner, gid_t group);
1471
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fchown.html
1472
if (FS.streams[fildes]) {
1473
return _chown(FS.streams[fildes].path, owner, group);
1475
___setErrNo(ERRNO_CODES.EBADF);
1479
fchdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'chdir'],
1480
fchdir: function(fildes) {
1481
// int fchdir(int fildes);
1482
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fchdir.html
1483
if (FS.streams[fildes]) {
1484
return _chdir(FS.streams[fildes].path);
1486
___setErrNo(ERRNO_CODES.EBADF);
1490
ctermid__deps: ['strcpy'],
1491
ctermid: function(s) {
1492
// char *ctermid(char *s);
1493
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ctermid.html
1494
if (!_ctermid.ret) {
1495
var arr = intArrayFromString('/dev/tty');
1496
_ctermid.ret = allocate(arr, 'i8', ALLOC_NORMAL);
1498
return s ? _strcpy(s, _ctermid.ret) : _ctermid.ret;
1500
crypt: function(key, salt) {
1501
// char *(const char *, const char *);
1502
// http://pubs.opengroup.org/onlinepubs/000095399/functions/crypt.html
1503
// TODO: Implement (probably compile from C).
1504
___setErrNo(ERRNO_CODES.ENOSYS);
1507
encrypt: function(block, edflag) {
1508
// void encrypt(char block[64], int edflag);
1509
// http://pubs.opengroup.org/onlinepubs/000095399/functions/encrypt.html
1510
// TODO: Implement (probably compile from C).
1511
___setErrNo(ERRNO_CODES.ENOSYS);
1513
fpathconf__deps: ['__setErrNo', '$ERRNO_CODES'],
1514
fpathconf: function(fildes, name) {
1515
// long fpathconf(int fildes, int name);
1516
// http://pubs.opengroup.org/onlinepubs/000095399/functions/encrypt.html
1517
// NOTE: The first parameter is ignored, so pathconf == fpathconf.
1518
// The constants here aren't real values. Just mimicking glibc.
1520
case {{{ cDefine('_PC_LINK_MAX') }}}:
1522
case {{{ cDefine('_PC_MAX_CANON') }}}:
1523
case {{{ cDefine('_PC_MAX_INPUT') }}}:
1524
case {{{ cDefine('_PC_NAME_MAX') }}}:
1526
case {{{ cDefine('_PC_PATH_MAX') }}}:
1527
case {{{ cDefine('_PC_PIPE_BUF') }}}:
1528
case {{{ cDefine('_PC_REC_MIN_XFER_SIZE') }}}:
1529
case {{{ cDefine('_PC_REC_XFER_ALIGN') }}}:
1530
case {{{ cDefine('_PC_ALLOC_SIZE_MIN') }}}:
1532
case {{{ cDefine('_PC_CHOWN_RESTRICTED') }}}:
1533
case {{{ cDefine('_PC_NO_TRUNC') }}}:
1534
case {{{ cDefine('_PC_2_SYMLINKS') }}}:
1536
case {{{ cDefine('_PC_VDISABLE') }}}:
1538
case {{{ cDefine('_PC_SYNC_IO') }}}:
1539
case {{{ cDefine('_PC_ASYNC_IO') }}}:
1540
case {{{ cDefine('_PC_PRIO_IO') }}}:
1541
case {{{ cDefine('_PC_SOCK_MAXBUF') }}}:
1542
case {{{ cDefine('_PC_REC_INCR_XFER_SIZE') }}}:
1543
case {{{ cDefine('_PC_REC_MAX_XFER_SIZE') }}}:
1544
case {{{ cDefine('_PC_SYMLINK_MAX') }}}:
1546
case {{{ cDefine('_PC_FILESIZEBITS') }}}:
1549
___setErrNo(ERRNO_CODES.EINVAL);
1552
pathconf: 'fpathconf',
1553
fsync__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1554
fsync: function(fildes) {
1555
// int fsync(int fildes);
1556
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fsync.html
1557
if (FS.streams[fildes]) {
1558
// We write directly to the file system, so there's nothing to do here.
1561
___setErrNo(ERRNO_CODES.EBADF);
1566
truncate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1567
truncate: function(path, length) {
1568
// int truncate(const char *path, off_t length);
1569
// http://pubs.opengroup.org/onlinepubs/000095399/functions/truncate.html
1570
// NOTE: The path argument may be a string, to simplify ftruncate().
1572
___setErrNo(ERRNO_CODES.EINVAL);
1575
if (typeof path !== 'string') path = Pointer_stringify(path);
1576
var target = FS.findObject(path);
1577
if (target === null) return -1;
1578
if (target.isFolder) {
1579
___setErrNo(ERRNO_CODES.EISDIR);
1581
} else if (target.isDevice) {
1582
___setErrNo(ERRNO_CODES.EINVAL);
1584
} else if (!target.write) {
1585
___setErrNo(ERRNO_CODES.EACCES);
1588
var contents = target.contents;
1589
if (length < contents.length) contents.length = length;
1590
else while (length > contents.length) contents.push(0);
1591
target.timestamp = Date.now();
1596
ftruncate__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'truncate'],
1597
ftruncate: function(fildes, length) {
1598
// int ftruncate(int fildes, off_t length);
1599
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ftruncate.html
1600
if (FS.streams[fildes] && FS.streams[fildes].isWrite) {
1601
return _truncate(FS.streams[fildes].path, length);
1602
} else if (FS.streams[fildes]) {
1603
___setErrNo(ERRNO_CODES.EINVAL);
1606
___setErrNo(ERRNO_CODES.EBADF);
1610
getcwd__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1611
getcwd: function(buf, size) {
1612
// char *getcwd(char *buf, size_t size);
1613
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getcwd.html
1615
___setErrNo(ERRNO_CODES.EINVAL);
1617
} else if (size < FS.currentPath.length + 1) {
1618
___setErrNo(ERRNO_CODES.ERANGE);
1621
for (var i = 0; i < FS.currentPath.length; i++) {
1622
{{{ makeSetValue('buf', 'i', 'FS.currentPath.charCodeAt(i)', 'i8') }}}
1624
{{{ makeSetValue('buf', 'i', '0', 'i8') }}}
1628
getwd__deps: ['getcwd'],
1629
getwd: function(path_name) {
1630
// char *getwd(char *path_name);
1631
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getwd.html
1632
return _getcwd(path_name, 4096); // PATH_MAX.
1634
isatty__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1635
isatty: function(fildes) {
1636
// int isatty(int fildes);
1637
// http://pubs.opengroup.org/onlinepubs/000095399/functions/isatty.html
1638
if (!FS.streams[fildes]) {
1639
___setErrNo(ERRNO_CODES.EBADF);
1642
if (FS.streams[fildes].isTerminal) return 1;
1643
___setErrNo(ERRNO_CODES.ENOTTY);
1646
lchown__deps: ['chown'],
1647
lchown: function(path, owner, group) {
1648
// int lchown(const char *path, uid_t owner, gid_t group);
1649
// http://pubs.opengroup.org/onlinepubs/000095399/functions/lchown.html
1650
return _chown(path, owner, group, true);
1652
link__deps: ['__setErrNo', '$ERRNO_CODES'],
1653
link: function(path1, path2) {
1654
// int link(const char *path1, const char *path2);
1655
// http://pubs.opengroup.org/onlinepubs/000095399/functions/link.html
1656
// We don't support hard links.
1657
___setErrNo(ERRNO_CODES.EMLINK);
1660
lockf__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1661
lockf: function(fildes, func, size) {
1662
// int lockf(int fildes, int function, off_t size);
1663
// http://pubs.opengroup.org/onlinepubs/000095399/functions/lockf.html
1664
if (FS.streams[fildes]) {
1665
// Pretend whatever locking or unlocking operation succeeded. Locking does
1666
// not make much sense, since we have a single process/thread.
1669
___setErrNo(ERRNO_CODES.EBADF);
1673
lseek__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1674
lseek: function(fildes, offset, whence) {
1675
// off_t lseek(int fildes, off_t offset, int whence);
1676
// http://pubs.opengroup.org/onlinepubs/000095399/functions/lseek.html
1677
if (FS.streams[fildes] && !FS.streams[fildes].object.isDevice) {
1678
var stream = FS.streams[fildes];
1679
var position = offset;
1680
if (whence === 1) { // SEEK_CUR.
1681
position += stream.position;
1682
} else if (whence === 2) { // SEEK_END.
1683
position += stream.object.contents.length;
1686
___setErrNo(ERRNO_CODES.EINVAL);
1689
stream.ungotten = [];
1690
stream.position = position;
1694
___setErrNo(ERRNO_CODES.EBADF);
1698
pipe__deps: ['__setErrNo', '$ERRNO_CODES'],
1699
pipe: function(fildes) {
1700
// int pipe(int fildes[2]);
1701
// http://pubs.opengroup.org/onlinepubs/000095399/functions/pipe.html
1702
// It is possible to implement this using two device streams, but pipes make
1703
// little sense in a single-threaded environment, so we do not support them.
1704
___setErrNo(ERRNO_CODES.ENOSYS);
1707
pread__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1708
pread: function(fildes, buf, nbyte, offset) {
1709
// ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
1710
// http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
1711
var stream = FS.streams[fildes];
1712
if (!stream || stream.object.isDevice) {
1713
___setErrNo(ERRNO_CODES.EBADF);
1715
} else if (!stream.isRead) {
1716
___setErrNo(ERRNO_CODES.EACCES);
1718
} else if (stream.object.isFolder) {
1719
___setErrNo(ERRNO_CODES.EISDIR);
1721
} else if (nbyte < 0 || offset < 0) {
1722
___setErrNo(ERRNO_CODES.EINVAL);
1726
while (stream.ungotten.length && nbyte > 0) {
1727
{{{ makeSetValue('buf++', '0', 'stream.ungotten.pop()', 'i8') }}}
1731
var contents = stream.object.contents;
1732
var size = Math.min(contents.length - offset, nbyte);
1733
#if USE_TYPED_ARRAYS == 2
1734
if (contents.subarray) { // typed array
1735
HEAPU8.set(contents.subarray(offset, offset+size), buf);
1738
if (contents.slice) { // normal array
1739
for (var i = 0; i < size; i++) {
1740
{{{ makeSetValue('buf', 'i', 'contents[offset + i]', 'i8') }}}
1743
for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
1744
{{{ makeSetValue('buf', 'i', 'contents.get(offset + i)', 'i8') }}}
1751
read__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'pread'],
1752
read: function(fildes, buf, nbyte) {
1753
// ssize_t read(int fildes, void *buf, size_t nbyte);
1754
// http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
1755
var stream = FS.streams[fildes];
1757
___setErrNo(ERRNO_CODES.EBADF);
1759
} else if (!stream.isRead) {
1760
___setErrNo(ERRNO_CODES.EACCES);
1762
} else if (nbyte < 0) {
1763
___setErrNo(ERRNO_CODES.EINVAL);
1767
if (stream.object.isDevice) {
1768
if (stream.object.input) {
1770
while (stream.ungotten.length && nbyte > 0) {
1771
{{{ makeSetValue('buf++', '0', 'stream.ungotten.pop()', 'i8') }}}
1775
for (var i = 0; i < nbyte; i++) {
1777
var result = stream.object.input();
1779
___setErrNo(ERRNO_CODES.EIO);
1782
if (result === null || result === undefined) break;
1784
{{{ makeSetValue('buf', 'i', 'result', 'i8') }}}
1788
___setErrNo(ERRNO_CODES.ENXIO);
1792
var ungotSize = stream.ungotten.length;
1793
bytesRead = _pread(fildes, buf, nbyte, stream.position);
1794
if (bytesRead != -1) {
1795
stream.position += (stream.ungotten.length - ungotSize) + bytesRead;
1803
// http://pubs.opengroup.org/onlinepubs/000095399/functions/sync.html
1804
// All our writing is already synchronized. This is a no-op.
1806
rmdir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1807
rmdir: function(path) {
1808
// int rmdir(const char *path);
1809
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html
1810
path = FS.analyzePath(Pointer_stringify(path));
1811
if (!path.parentExists || !path.exists) {
1812
___setErrNo(path.error);
1814
} else if (!path.object.write || path.isRoot) {
1815
___setErrNo(ERRNO_CODES.EACCES);
1817
} else if (!path.object.isFolder) {
1818
___setErrNo(ERRNO_CODES.ENOTDIR);
1821
for (var i in path.object.contents) {
1822
___setErrNo(ERRNO_CODES.ENOTEMPTY);
1825
if (path.path == FS.currentPath) {
1826
___setErrNo(ERRNO_CODES.EBUSY);
1829
delete path.parentObject.contents[path.name];
1834
unlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1835
unlink: function(path) {
1836
// int unlink(const char *path);
1837
// http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html
1838
path = FS.analyzePath(Pointer_stringify(path));
1839
if (!path.parentExists || !path.exists) {
1840
___setErrNo(path.error);
1842
} else if (path.object.isFolder) {
1843
___setErrNo(ERRNO_CODES.EISDIR);
1845
} else if (!path.object.write) {
1846
___setErrNo(ERRNO_CODES.EACCES);
1849
delete path.parentObject.contents[path.name];
1853
ttyname__deps: ['ttyname_r'],
1854
ttyname: function(fildes) {
1855
// char *ttyname(int fildes);
1856
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ttyname.html
1857
if (!_ttyname.ret) _ttyname.ret = _malloc(256);
1858
return _ttyname_r(fildes, _ttyname.ret, 256) ? 0 : _ttyname.ret;
1860
ttyname_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1861
ttyname_r: function(fildes, name, namesize) {
1862
// int ttyname_r(int fildes, char *name, size_t namesize);
1863
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ttyname.html
1864
var stream = FS.streams[fildes];
1866
return ___setErrNo(ERRNO_CODES.EBADF);
1868
var object = stream.object;
1869
if (!object.isDevice || !object.input || !object.output) {
1870
return ___setErrNo(ERRNO_CODES.ENOTTY);
1872
var ret = stream.path;
1873
if (namesize < ret.length + 1) {
1874
return ___setErrNo(ERRNO_CODES.ERANGE);
1876
for (var i = 0; i < ret.length; i++) {
1877
{{{ makeSetValue('name', 'i', 'ret.charCodeAt(i)', 'i8') }}}
1879
{{{ makeSetValue('name', 'i', '0', 'i8') }}}
1885
symlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1886
symlink: function(path1, path2) {
1887
// int symlink(const char *path1, const char *path2);
1888
// http://pubs.opengroup.org/onlinepubs/000095399/functions/symlink.html
1889
var path = FS.analyzePath(Pointer_stringify(path2), true);
1890
if (!path.parentExists) {
1891
___setErrNo(path.error);
1893
} else if (path.exists) {
1894
___setErrNo(ERRNO_CODES.EEXIST);
1897
FS.createLink(path.parentPath, path.name,
1898
Pointer_stringify(path1), true, true);
1902
readlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1903
readlink: function(path, buf, bufsize) {
1904
// ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);
1905
// http://pubs.opengroup.org/onlinepubs/000095399/functions/readlink.html
1906
var target = FS.findObject(Pointer_stringify(path), true);
1907
if (target === null) return -1;
1908
if (target.link !== undefined) {
1909
var length = Math.min(bufsize - 1, target.link.length);
1910
for (var i = 0; i < length; i++) {
1911
{{{ makeSetValue('buf', 'i', 'target.link.charCodeAt(i)', 'i8') }}}
1913
if (bufsize - 1 > length) {{{ makeSetValue('buf', 'i', '0', 'i8') }}}
1916
___setErrNo(ERRNO_CODES.EINVAL);
1920
pwrite__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
1921
pwrite: function(fildes, buf, nbyte, offset) {
1922
// ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
1923
// http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
1924
var stream = FS.streams[fildes];
1925
if (!stream || stream.object.isDevice) {
1926
___setErrNo(ERRNO_CODES.EBADF);
1928
} else if (!stream.isWrite) {
1929
___setErrNo(ERRNO_CODES.EACCES);
1931
} else if (stream.object.isFolder) {
1932
___setErrNo(ERRNO_CODES.EISDIR);
1934
} else if (nbyte < 0 || offset < 0) {
1935
___setErrNo(ERRNO_CODES.EINVAL);
1938
var contents = stream.object.contents;
1939
while (contents.length < offset) contents.push(0);
1940
for (var i = 0; i < nbyte; i++) {
1941
contents[offset + i] = {{{ makeGetValue('buf', 'i', 'i8', undefined, 1) }}};
1943
stream.object.timestamp = Date.now();
1947
write__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'pwrite'],
1948
write: function(fildes, buf, nbyte) {
1949
// ssize_t write(int fildes, const void *buf, size_t nbyte);
1950
// http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
1951
var stream = FS.streams[fildes];
1953
___setErrNo(ERRNO_CODES.EBADF);
1955
} else if (!stream.isWrite) {
1956
___setErrNo(ERRNO_CODES.EACCES);
1958
} else if (nbyte < 0) {
1959
___setErrNo(ERRNO_CODES.EINVAL);
1962
if (stream.object.isDevice) {
1963
if (stream.object.output) {
1964
for (var i = 0; i < nbyte; i++) {
1966
stream.object.output({{{ makeGetValue('buf', 'i', 'i8') }}});
1968
___setErrNo(ERRNO_CODES.EIO);
1972
stream.object.timestamp = Date.now();
1975
___setErrNo(ERRNO_CODES.ENXIO);
1979
var bytesWritten = _pwrite(fildes, buf, nbyte, stream.position);
1980
if (bytesWritten != -1) stream.position += bytesWritten;
1981
return bytesWritten;
1985
alarm: function(seconds) {
1986
// unsigned alarm(unsigned seconds);
1987
// http://pubs.opengroup.org/onlinepubs/000095399/functions/alarm.html
1988
// We don't support signals, and there's no way to indicate failure, so just
1993
confstr__deps: ['__setErrNo', '$ERRNO_CODES', '$ENV'],
1994
confstr: function(name, buf, len) {
1995
// size_t confstr(int name, char *buf, size_t len);
1996
// http://pubs.opengroup.org/onlinepubs/000095399/functions/confstr.html
1999
case {{{ cDefine('_CS_PATH') }}}:
2000
value = ENV['PATH'] || '/';
2002
case {{{ cDefine('_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS') }}}:
2004
value = 'POSIX_V6_ILP32_OFF32\nPOSIX_V6_ILP32_OFFBIG';
2006
case {{{ cDefine('_CS_GNU_LIBC_VERSION') }}}:
2007
// This JS implementation was tested against this glibc version.
2008
value = 'glibc 2.14';
2010
case {{{ cDefine('_CS_GNU_LIBPTHREAD_VERSION') }}}:
2011
// We don't support pthreads.
2014
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFF32_LIBS') }}}:
2015
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFFBIG_LIBS') }}}:
2016
case {{{ cDefine('_CS_POSIX_V6_LP64_OFF64_CFLAGS') }}}:
2017
case {{{ cDefine('_CS_POSIX_V6_LP64_OFF64_LDFLAGS') }}}:
2018
case {{{ cDefine('_CS_POSIX_V6_LP64_OFF64_LIBS') }}}:
2019
case {{{ cDefine('_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS') }}}:
2020
case {{{ cDefine('_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS') }}}:
2021
case {{{ cDefine('_CS_POSIX_V6_LPBIG_OFFBIG_LIBS') }}}:
2024
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFF32_CFLAGS') }}}:
2025
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFF32_LDFLAGS') }}}:
2026
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS') }}}:
2029
case {{{ cDefine('_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS') }}}:
2030
value = '-m32 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64';
2033
___setErrNo(ERRNO_CODES.EINVAL);
2036
if (len == 0 || buf == 0) {
2037
return value.length + 1;
2039
var length = Math.min(len, value.length);
2040
for (var i = 0; i < length; i++) {
2041
{{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}}
2043
if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}}
2047
execl__deps: ['__setErrNo', '$ERRNO_CODES'],
2048
execl: function(/* ... */) {
2049
// int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
2050
// http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html
2051
// We don't support executing external code.
2052
___setErrNo(ERRNO_CODES.ENOEXEC);
2060
_exit: function(status) {
2061
// void _exit(int status);
2062
// http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
2064
function ExitStatus() {
2065
this.name = "ExitStatus";
2066
this.message = "Program terminated with exit(" + status + ")";
2067
this.status = status;
2068
Module.print('Exit Status: ' + status);
2070
ExitStatus.prototype = new Error();
2071
ExitStatus.prototype.constructor = ExitStatus;
2076
throw new ExitStatus();
2078
fork__deps: ['__setErrNo', '$ERRNO_CODES'],
2080
// pid_t fork(void);
2081
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fork.html
2082
// We don't support multiple processes.
2083
___setErrNo(ERRNO_CODES.EAGAIN);
2087
getgid: function() {
2088
// gid_t getgid(void);
2089
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getgid.html
2090
// We have just one process/group/user, all with ID 0.
2099
getresuid: function(ruid, euid, suid) {
2100
// int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
2101
// http://linux.die.net/man/2/getresuid
2102
// We have just one process/group/user, all with ID 0.
2103
{{{ makeSetValue('ruid', '0', '0', 'i32') }}}
2104
{{{ makeSetValue('euid', '0', '0', 'i32') }}}
2105
{{{ makeSetValue('suid', '0', '0', 'i32') }}}
2108
getresgid: 'getresuid',
2109
getgroups__deps: ['__setErrNo', '$ERRNO_CODES'],
2110
getgroups: function(gidsetsize, grouplist) {
2111
// int getgroups(int gidsetsize, gid_t grouplist[]);
2112
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getgroups.html
2113
if (gidsetsize < 1) {
2114
___setErrNo(ERRNO_CODES.EINVAL);
2117
{{{ makeSetValue('grouplist', '0', '0', 'i32') }}}
2121
// TODO: Implement initgroups (grp.h).
2122
setgroups__deps: ['__setErrNo', '$ERRNO_CODES', 'sysconf'],
2123
setgroups: function (ngroups, gidset) {
2124
// int setgroups(int ngroups, const gid_t *gidset);
2125
// https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/setgroups.2.html
2126
if (ngroups < 1 || ngroups > _sysconf({{{ cDefine('_SC_NGROUPS_MAX') }}})) {
2127
___setErrNo(ERRNO_CODES.EINVAL);
2130
// We have just one process/user/group, so it makes no sense to set groups.
2131
___setErrNo(ERRNO_CODES.EPERM);
2135
gethostid: function() {
2136
// long gethostid(void);
2137
// http://pubs.opengroup.org/onlinepubs/000095399/functions/gethostid.html
2140
gethostname__deps: ['__setErrNo', '$ERRNO_CODES'],
2141
gethostname: function(name, namelen) {
2142
// int gethostname(char *name, size_t namelen);
2143
// http://pubs.opengroup.org/onlinepubs/000095399/functions/gethostname.html
2144
var host = 'emscripten';
2145
if (typeof window !== 'undefined' && window.location.host) {
2146
host = window.location.host;
2148
var length = Math.min(namelen, host.length);
2149
for (var i = 0; i < length; i++) {
2150
{{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}}
2152
if (namelen > length) {
2153
{{{ makeSetValue('name', 'i', '0', 'i8') }}}
2156
___setErrNo(ERRNO_CODES.ENAMETOOLONG);
2160
getlogin__deps: ['getlogin_r'],
2161
getlogin: function() {
2162
// char *getlogin(void);
2163
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getlogin.html
2164
if (!_getlogin.ret) _getlogin.ret = _malloc(8);
2165
return _getlogin_r(_getlogin.ret, 8) ? 0 : _getlogin.ret;
2167
getlogin_r__deps: ['__setErrNo', '$ERRNO_CODES'],
2168
getlogin_r: function(name, namesize) {
2169
// int getlogin_r(char *name, size_t namesize);
2170
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getlogin.html
2172
if (namesize < ret.length + 1) {
2173
return ___setErrNo(ERRNO_CODES.ERANGE);
2175
for (var i = 0; i < ret.length; i++) {
2176
{{{ makeSetValue('name', 'i', 'ret.charCodeAt(i)', 'i8') }}}
2178
{{{ makeSetValue('name', 'i', '0', 'i8') }}}
2182
getpagesize: function() {
2183
// int getpagesize(void);
2186
getopt: function(argc, argv, optstring) {
2187
// int getopt(int argc, char * const argv[], const char *optstring);
2188
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html
2189
// TODO: Implement (probably compile from C).
2192
getpgid: function(pid) {
2193
// pid_t getpgid(pid_t pid);
2194
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getpgid.html
2195
// There can only be one process, and its group ID is 0.
2199
nice__deps: ['__setErrNo', '$ERRNO_CODES'],
2200
nice: function(incr) {
2201
// int nice(int incr);
2202
// http://pubs.opengroup.org/onlinepubs/000095399/functions/nice.html
2203
// Niceness makes no sense in a single-process environment.
2204
___setErrNo(ERRNO_CODES.EPERM);
2207
pause__deps: ['__setErrNo', '$ERRNO_CODES'],
2210
// http://pubs.opengroup.org/onlinepubs/000095399/functions/pause.html
2211
// We don't support signals, so we return immediately.
2212
___setErrNo(ERRNO_CODES.EINTR);
2215
setgid__deps: ['__setErrNo', '$ERRNO_CODES'],
2216
setgid: function(gid) {
2217
// int setgid(gid_t gid);
2218
// http://pubs.opengroup.org/onlinepubs/000095399/functions/setgid.html
2219
// We have just one process/group/user, so it makes no sense to set IDs.
2220
___setErrNo(ERRNO_CODES.EPERM);
2228
setpgid__deps: ['__setErrNo', '$ERRNO_CODES'],
2229
setpgid: function(pid, pgid) {
2230
// int setpgid(pid_t pid, pid_t pgid);
2231
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getpgid.html
2232
// We have just one process/group/user, so it makes no sense to set IDs.
2233
___setErrNo(ERRNO_CODES.EPERM);
2236
setregid: 'setpgid',
2237
setreuid: 'setpgid',
2238
// NOTE: These do not match the signatures, but they all use the same stub.
2239
setresuid: 'setpgid',
2240
setresgid: 'setpgid',
2241
sleep__deps: ['usleep'],
2242
sleep: function(seconds) {
2243
// unsigned sleep(unsigned seconds);
2244
// http://pubs.opengroup.org/onlinepubs/000095399/functions/sleep.html
2245
return _usleep(seconds * 1e6);
2247
usleep: function(useconds) {
2248
// int usleep(useconds_t useconds);
2249
// http://pubs.opengroup.org/onlinepubs/000095399/functions/usleep.html
2250
// We're single-threaded, so use a busy loop. Super-ugly.
2251
var msec = useconds / 1000;
2252
var start = Date.now();
2253
while (Date.now() - start < msec) {
2258
swab: function(src, dest, nbytes) {
2259
// void swab(const void *restrict src, void *restrict dest, ssize_t nbytes);
2260
// http://pubs.opengroup.org/onlinepubs/000095399/functions/swab.html
2261
if (nbytes < 0) return;
2262
nbytes -= nbytes % 2;
2263
for (var i = 0; i < nbytes; i += 2) {
2264
var first = {{{ makeGetValue('src', 'i', 'i8') }}};
2265
var second = {{{ makeGetValue('src', 'i + 1', 'i8') }}};
2266
{{{ makeSetValue('dest', 'i', 'second', 'i8') }}}
2267
{{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}}
2270
tcgetpgrp: function(fildes) {
2271
// pid_t tcgetpgrp(int fildes);
2272
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tcgetpgrp.html
2273
// Our only process always runs with group ID 0.
2276
tcsetpgrp__deps: ['__setErrNo', '$ERRNO_CODES'],
2277
tcsetpgrp: function(fildes, pgid_id) {
2278
// int tcsetpgrp(int fildes, pid_t pgid_id);
2279
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tcsetpgrp.html
2280
// We don't support multiple processes or groups with ID other than 0.
2281
___setErrNo(ERRNO_CODES.EINVAL);
2284
sysconf__deps: ['__setErrNo', '$ERRNO_CODES'],
2285
sysconf: function(name) {
2286
// long sysconf(int name);
2287
// http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
2289
case {{{ cDefine('_SC_PAGE_SIZE') }}}: return PAGE_SIZE;
2290
case {{{ cDefine('_SC_ADVISORY_INFO') }}}:
2291
case {{{ cDefine('_SC_BARRIERS') }}}:
2292
case {{{ cDefine('_SC_ASYNCHRONOUS_IO') }}}:
2293
case {{{ cDefine('_SC_CLOCK_SELECTION') }}}:
2294
case {{{ cDefine('_SC_CPUTIME') }}}:
2295
case {{{ cDefine('_SC_FSYNC') }}}:
2296
case {{{ cDefine('_SC_IPV6') }}}:
2297
case {{{ cDefine('_SC_MAPPED_FILES') }}}:
2298
case {{{ cDefine('_SC_MEMLOCK') }}}:
2299
case {{{ cDefine('_SC_MEMLOCK_RANGE') }}}:
2300
case {{{ cDefine('_SC_MEMORY_PROTECTION') }}}:
2301
case {{{ cDefine('_SC_MESSAGE_PASSING') }}}:
2302
case {{{ cDefine('_SC_MONOTONIC_CLOCK') }}}:
2303
case {{{ cDefine('_SC_PRIORITIZED_IO') }}}:
2304
case {{{ cDefine('_SC_PRIORITY_SCHEDULING') }}}:
2305
case {{{ cDefine('_SC_RAW_SOCKETS') }}}:
2306
case {{{ cDefine('_SC_READER_WRITER_LOCKS') }}}:
2307
case {{{ cDefine('_SC_REALTIME_SIGNALS') }}}:
2308
case {{{ cDefine('_SC_SEMAPHORES') }}}:
2309
case {{{ cDefine('_SC_SHARED_MEMORY_OBJECTS') }}}:
2310
case {{{ cDefine('_SC_SPAWN') }}}:
2311
case {{{ cDefine('_SC_SPIN_LOCKS') }}}:
2312
case {{{ cDefine('_SC_SYNCHRONIZED_IO') }}}:
2313
case {{{ cDefine('_SC_THREAD_ATTR_STACKADDR') }}}:
2314
case {{{ cDefine('_SC_THREAD_ATTR_STACKSIZE') }}}:
2315
case {{{ cDefine('_SC_THREAD_CPUTIME') }}}:
2316
case {{{ cDefine('_SC_THREAD_PRIO_INHERIT') }}}:
2317
case {{{ cDefine('_SC_THREAD_PRIO_PROTECT') }}}:
2318
case {{{ cDefine('_SC_THREAD_PRIORITY_SCHEDULING') }}}:
2319
case {{{ cDefine('_SC_THREAD_PROCESS_SHARED') }}}:
2320
case {{{ cDefine('_SC_THREAD_SAFE_FUNCTIONS') }}}:
2321
case {{{ cDefine('_SC_THREADS') }}}:
2322
case {{{ cDefine('_SC_TIMEOUTS') }}}:
2323
case {{{ cDefine('_SC_TIMERS') }}}:
2324
case {{{ cDefine('_SC_VERSION') }}}:
2325
case {{{ cDefine('_SC_2_C_BIND') }}}:
2326
case {{{ cDefine('_SC_2_C_DEV') }}}:
2327
case {{{ cDefine('_SC_2_CHAR_TERM') }}}:
2328
case {{{ cDefine('_SC_2_LOCALEDEF') }}}:
2329
case {{{ cDefine('_SC_2_SW_DEV') }}}:
2330
case {{{ cDefine('_SC_2_VERSION') }}}:
2332
case {{{ cDefine('_SC_MQ_OPEN_MAX') }}}:
2333
case {{{ cDefine('_SC_XOPEN_STREAMS') }}}:
2334
case {{{ cDefine('_SC_XBS5_LP64_OFF64') }}}:
2335
case {{{ cDefine('_SC_XBS5_LPBIG_OFFBIG') }}}:
2336
case {{{ cDefine('_SC_AIO_LISTIO_MAX') }}}:
2337
case {{{ cDefine('_SC_AIO_MAX') }}}:
2338
case {{{ cDefine('_SC_SPORADIC_SERVER') }}}:
2339
case {{{ cDefine('_SC_THREAD_SPORADIC_SERVER') }}}:
2340
case {{{ cDefine('_SC_TRACE') }}}:
2341
case {{{ cDefine('_SC_TRACE_EVENT_FILTER') }}}:
2342
case {{{ cDefine('_SC_TRACE_EVENT_NAME_MAX') }}}:
2343
case {{{ cDefine('_SC_TRACE_INHERIT') }}}:
2344
case {{{ cDefine('_SC_TRACE_LOG') }}}:
2345
case {{{ cDefine('_SC_TRACE_NAME_MAX') }}}:
2346
case {{{ cDefine('_SC_TRACE_SYS_MAX') }}}:
2347
case {{{ cDefine('_SC_TRACE_USER_EVENT_MAX') }}}:
2348
case {{{ cDefine('_SC_TYPED_MEMORY_OBJECTS') }}}:
2349
case {{{ cDefine('_SC_V6_LP64_OFF64') }}}:
2350
case {{{ cDefine('_SC_V6_LPBIG_OFFBIG') }}}:
2351
case {{{ cDefine('_SC_2_FORT_DEV') }}}:
2352
case {{{ cDefine('_SC_2_FORT_RUN') }}}:
2353
case {{{ cDefine('_SC_2_PBS') }}}:
2354
case {{{ cDefine('_SC_2_PBS_ACCOUNTING') }}}:
2355
case {{{ cDefine('_SC_2_PBS_CHECKPOINT') }}}:
2356
case {{{ cDefine('_SC_2_PBS_LOCATE') }}}:
2357
case {{{ cDefine('_SC_2_PBS_MESSAGE') }}}:
2358
case {{{ cDefine('_SC_2_PBS_TRACK') }}}:
2359
case {{{ cDefine('_SC_2_UPE') }}}:
2360
case {{{ cDefine('_SC_THREAD_THREADS_MAX') }}}:
2361
case {{{ cDefine('_SC_SEM_NSEMS_MAX') }}}:
2362
case {{{ cDefine('_SC_SYMLOOP_MAX') }}}:
2363
case {{{ cDefine('_SC_TIMER_MAX') }}}:
2365
case {{{ cDefine('_SC_V6_ILP32_OFF32') }}}:
2366
case {{{ cDefine('_SC_V6_ILP32_OFFBIG') }}}:
2367
case {{{ cDefine('_SC_JOB_CONTROL') }}}:
2368
case {{{ cDefine('_SC_REGEXP') }}}:
2369
case {{{ cDefine('_SC_SAVED_IDS') }}}:
2370
case {{{ cDefine('_SC_SHELL') }}}:
2371
case {{{ cDefine('_SC_XBS5_ILP32_OFF32') }}}:
2372
case {{{ cDefine('_SC_XBS5_ILP32_OFFBIG') }}}:
2373
case {{{ cDefine('_SC_XOPEN_CRYPT') }}}:
2374
case {{{ cDefine('_SC_XOPEN_ENH_I18N') }}}:
2375
case {{{ cDefine('_SC_XOPEN_LEGACY') }}}:
2376
case {{{ cDefine('_SC_XOPEN_REALTIME') }}}:
2377
case {{{ cDefine('_SC_XOPEN_REALTIME_THREADS') }}}:
2378
case {{{ cDefine('_SC_XOPEN_SHM') }}}:
2379
case {{{ cDefine('_SC_XOPEN_UNIX') }}}:
2381
case {{{ cDefine('_SC_THREAD_KEYS_MAX') }}}:
2382
case {{{ cDefine('_SC_IOV_MAX') }}}:
2383
case {{{ cDefine('_SC_GETGR_R_SIZE_MAX') }}}:
2384
case {{{ cDefine('_SC_GETPW_R_SIZE_MAX') }}}:
2385
case {{{ cDefine('_SC_OPEN_MAX') }}}:
2387
case {{{ cDefine('_SC_RTSIG_MAX') }}}:
2388
case {{{ cDefine('_SC_EXPR_NEST_MAX') }}}:
2389
case {{{ cDefine('_SC_TTY_NAME_MAX') }}}:
2391
case {{{ cDefine('_SC_ATEXIT_MAX') }}}:
2392
case {{{ cDefine('_SC_DELAYTIMER_MAX') }}}:
2393
case {{{ cDefine('_SC_SEM_VALUE_MAX') }}}:
2395
case {{{ cDefine('_SC_SIGQUEUE_MAX') }}}:
2396
case {{{ cDefine('_SC_CHILD_MAX') }}}:
2398
case {{{ cDefine('_SC_BC_SCALE_MAX') }}}:
2399
case {{{ cDefine('_SC_BC_BASE_MAX') }}}:
2401
case {{{ cDefine('_SC_LINE_MAX') }}}:
2402
case {{{ cDefine('_SC_BC_DIM_MAX') }}}:
2404
case {{{ cDefine('_SC_ARG_MAX') }}}: return 2097152;
2405
case {{{ cDefine('_SC_NGROUPS_MAX') }}}: return 65536;
2406
case {{{ cDefine('_SC_MQ_PRIO_MAX') }}}: return 32768;
2407
case {{{ cDefine('_SC_RE_DUP_MAX') }}}: return 32767;
2408
case {{{ cDefine('_SC_THREAD_STACK_MIN') }}}: return 16384;
2409
case {{{ cDefine('_SC_BC_STRING_MAX') }}}: return 1000;
2410
case {{{ cDefine('_SC_XOPEN_VERSION') }}}: return 700;
2411
case {{{ cDefine('_SC_LOGIN_NAME_MAX') }}}: return 256;
2412
case {{{ cDefine('_SC_COLL_WEIGHTS_MAX') }}}: return 255;
2413
case {{{ cDefine('_SC_CLK_TCK') }}}: return 100;
2414
case {{{ cDefine('_SC_HOST_NAME_MAX') }}}: return 64;
2415
case {{{ cDefine('_SC_AIO_PRIO_DELTA_MAX') }}}: return 20;
2416
case {{{ cDefine('_SC_STREAM_MAX') }}}: return 16;
2417
case {{{ cDefine('_SC_TZNAME_MAX') }}}: return 6;
2418
case {{{ cDefine('_SC_THREAD_DESTRUCTOR_ITERATIONS') }}}: return 4;
2419
case {{{ cDefine('_SC_NPROCESSORS_ONLN') }}}: return 1;
2421
___setErrNo(ERRNO_CODES.EINVAL);
2424
sbrk: function(bytes) {
2425
// Implement a Linux-like 'memory area' for our 'process'.
2426
// Changes the size of the memory area by |bytes|; returns the
2427
// address of the previous top ('break') of the memory area
2429
// We need to make sure no one else allocates unfreeable memory!
2430
// We must control this entirely. So we don't even need to do
2431
// unfreeable allocations - the HEAP is ours, from STATICTOP up.
2432
// TODO: We could in theory slice off the top of the HEAP when
2433
// sbrk gets a negative increment in |bytes|...
2436
STATICTOP = alignMemoryPage(STATICTOP); // make sure we start out aligned
2439
_sbrk.DYNAMIC_START = STATICTOP;
2442
var ret = STATICTOP;
2443
if (bytes != 0) Runtime.staticAlloc(bytes);
2444
return ret; // Previous break location.
2448
ftruncate64: 'ftruncate',
2449
__01open64_: 'open',
2450
__01lseek64_: 'lseek',
2451
__01truncate64_: 'truncate',
2452
__01ftruncate64_: 'ftruncate',
2453
// TODO: Check if any other aliases are needed.
2455
// ==========================================================================
2457
// ==========================================================================
2459
_isFloat: function(text) {
2460
return !!(/^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?$/.exec(text));
2464
_scanString__deps: ['_isFloat'],
2465
_scanString: function(format, get, unget, varargs) {
2466
if (!__scanString.whiteSpace) {
2467
__scanString.whiteSpace = {};
2468
__scanString.whiteSpace[{{{ charCode(' ') }}}] = 1;
2469
__scanString.whiteSpace[{{{ charCode('\t') }}}] = 1;
2470
__scanString.whiteSpace[{{{ charCode('\n') }}}] = 1;
2471
__scanString.whiteSpace[' '] = 1;
2472
__scanString.whiteSpace['\t'] = 1;
2473
__scanString.whiteSpace['\n'] = 1;
2475
// Supports %x, %4x, %d.%d, %lld, %s, %f, %lf.
2476
// TODO: Support all format specifiers.
2477
format = Pointer_stringify(format);
2479
if (format.indexOf('%n') >= 0) {
2480
// need to track soFar
2487
unget = function() {
2492
var formatIndex = 0;
2499
for (var formatIndex = 0; formatIndex < format.length;) {
2500
if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') {
2501
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
2502
argIndex += Runtime.getAlignSize('void*', null, true);
2503
{{{ makeSetValue('argPtr', 0, 'soFar', 'i32') }}};
2508
// TODO: Support strings like "%5c" etc.
2509
if (format[formatIndex] === '%' && format[formatIndex+1] == 'c') {
2510
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
2511
argIndex += Runtime.getAlignSize('void*', null, true);
2514
{{{ makeSetValue('argPtr', 0, 'next', 'i8') }}}
2519
// remove whitespace
2522
if (next == 0) return fields;
2523
if (!(next in __scanString.whiteSpace)) break;
2527
if (format[formatIndex] === '%') {
2529
var suppressAssignment = false;
2530
if (format[formatIndex] == '*') {
2531
suppressAssignment = true;
2534
var maxSpecifierStart = formatIndex;
2535
while (format[formatIndex].charCodeAt(0) >= {{{ charCode('0') }}} &&
2536
format[formatIndex].charCodeAt(0) <= {{{ charCode('9') }}}) {
2540
if (formatIndex != maxSpecifierStart) {
2541
max_ = parseInt(format.slice(maxSpecifierStart, formatIndex), 10);
2545
var longLong = false;
2546
if (format[formatIndex] == 'l') {
2549
if(format[formatIndex] == 'l') {
2553
} else if (format[formatIndex] == 'h') {
2557
var type = format[formatIndex];
2561
// 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
2562
if (type == 'f' || type == 'e' || type == 'g' || type == 'E') {
2566
buffer.push(String.fromCharCode(next));
2567
if (__isFloat(buffer.join(''))) {
2568
last = buffer.length;
2572
for (var i = 0; i < buffer.length - last + 1; i++) {
2575
buffer.length = last;
2579
while ((curr < max_ || isNaN(max_)) && next > 0) {
2580
if (!(next in __scanString.whiteSpace) && // stop on whitespace
2582
((type === 'd' || type == 'u' || type == 'i') && ((next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) ||
2583
(first && next == {{{ charCode('-') }}}))) ||
2584
(type === 'x' && (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}} ||
2585
next >= {{{ charCode('a') }}} && next <= {{{ charCode('f') }}} ||
2586
next >= {{{ charCode('A') }}} && next <= {{{ charCode('F') }}}))) &&
2587
(formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up
2588
buffer.push(String.fromCharCode(next));
2598
if (buffer.length === 0) return 0; // Failure.
2599
if (suppressAssignment) continue;
2601
var text = buffer.join('');
2602
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
2603
argIndex += Runtime.getAlignSize('void*', null, true);
2605
case 'd': case 'u': case 'i':
2607
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i16') }}};
2608
} else if(longLong) {
2609
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i64') }}};
2611
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}};
2615
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}}
2621
// fallthrough intended
2623
{{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}}
2625
{{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}}
2629
var array = intArrayFromString(text);
2630
for (var j = 0; j < array.length; j++) {
2631
{{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}}
2636
} else if (format[formatIndex] in __scanString.whiteSpace) {
2638
while (next in __scanString.whiteSpace) {
2639
if (next <= 0) break mainLoop; // End of input.
2647
if (format[formatIndex].charCodeAt(0) !== next) {
2656
// Performs printf-style formatting.
2657
// format: A pointer to the format string.
2658
// varargs: A pointer to the start of the arguments list.
2659
// Returns the resulting string string as a character array.
2660
_formatString__deps: ['strlen', '_reallyNegative'],
2661
_formatString: function(format, varargs) {
2662
var textIndex = format;
2664
function getNextArg(type) {
2665
// NOTE: Explicitly ignoring type safety. Otherwise this fails:
2666
// int x = 4; printf("%c\n", (char)x);
2668
if (type === 'double') {
2669
ret = {{{ makeGetValue('varargs', 'argIndex', 'double', undefined, undefined, true) }}};
2670
#if USE_TYPED_ARRAYS == 2
2671
} else if (type == 'i64') {
2674
ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
2675
{{{ makeGetValue('varargs', 'argIndex+8', 'i32', undefined, undefined, true) }}}];
2676
argIndex += {{{ STACK_ALIGN }}}; // each 32-bit chunk is in a 64-bit block
2678
ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
2679
{{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true) }}}];
2683
} else if (type == 'i64') {
2684
ret = {{{ makeGetValue('varargs', 'argIndex', 'i64', undefined, undefined, true) }}};
2687
type = 'i32'; // varargs are always i32, i64, or double
2688
ret = {{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}};
2690
argIndex += Math.max(Runtime.getNativeFieldSize(type), Runtime.getAlignSize(type, null, true));
2695
var curr, next, currArg;
2697
var startTextIndex = textIndex;
2698
curr = {{{ makeGetValue(0, 'textIndex', 'i8') }}};
2699
if (curr === 0) break;
2700
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
2701
if (curr == {{{ charCode('%') }}}) {
2703
var flagAlwaysSigned = false;
2704
var flagLeftAlign = false;
2705
var flagAlternative = false;
2706
var flagZeroPad = false;
2707
flagsLoop: while (1) {
2709
case {{{ charCode('+') }}}:
2710
flagAlwaysSigned = true;
2712
case {{{ charCode('-') }}}:
2713
flagLeftAlign = true;
2715
case {{{ charCode('#') }}}:
2716
flagAlternative = true;
2718
case {{{ charCode('0') }}}:
2729
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
2734
if (next == {{{ charCode('*') }}}) {
2735
width = getNextArg('i32');
2737
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
2739
while (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) {
2740
width = width * 10 + (next - {{{ charCode('0') }}});
2742
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
2746
// Handle precision.
2747
var precisionSet = false;
2748
if (next == {{{ charCode('.') }}}) {
2750
precisionSet = true;
2752
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
2753
if (next == {{{ charCode('*') }}}) {
2754
precision = getNextArg('i32');
2758
var precisionChr = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
2759
if (precisionChr < {{{ charCode('0') }}} ||
2760
precisionChr > {{{ charCode('9') }}}) break;
2761
precision = precision * 10 + (precisionChr - {{{ charCode('0') }}});
2765
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
2767
var precision = 6; // Standard default.
2770
// Handle integer sizes. WARNING: These assume a 32-bit architecture!
2772
switch (String.fromCharCode(next)) {
2774
var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}};
2775
if (nextNext == {{{ charCode('h') }}}) {
2777
argSize = 1; // char (actually i32 in varargs)
2779
argSize = 2; // short (actually i32 in varargs)
2783
var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}};
2784
if (nextNext == {{{ charCode('l') }}}) {
2786
argSize = 8; // long long
2788
argSize = 4; // long
2791
case 'L': // long long
2792
case 'q': // int64_t
2793
case 'j': // intmax_t
2797
case 't': // ptrdiff_t
2798
case 'I': // signed ptrdiff_t or unsigned size_t
2804
if (argSize) textIndex++;
2805
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
2807
// Handle type specifier.
2808
switch (String.fromCharCode(next)) {
2809
case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
2811
var signed = next == {{{ charCode('d') }}} || next == {{{ charCode('i') }}};
2812
argSize = argSize || 4;
2813
var currArg = getNextArg('i' + (argSize * 8));
2814
#if PRECISE_I64_MATH
2815
var origArg = currArg;
2818
#if USE_TYPED_ARRAYS == 2
2819
// Flatten i64-1 [low, high] into a (slightly rounded) double
2821
currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == {{{ charCode('u') }}});
2824
// Truncate to requested size.
2826
var limit = Math.pow(256, argSize) - 1;
2827
currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
2829
// Format the number.
2830
var currAbsArg = Math.abs(currArg);
2832
if (next == {{{ charCode('d') }}} || next == {{{ charCode('i') }}}) {
2833
#if PRECISE_I64_MATH
2834
if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else
2836
argText = reSign(currArg, 8 * argSize, 1).toString(10);
2837
} else if (next == {{{ charCode('u') }}}) {
2838
#if PRECISE_I64_MATH
2839
if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else
2841
argText = unSign(currArg, 8 * argSize, 1).toString(10);
2842
currArg = Math.abs(currArg);
2843
} else if (next == {{{ charCode('o') }}}) {
2844
argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
2845
} else if (next == {{{ charCode('x') }}} || next == {{{ charCode('X') }}}) {
2846
prefix = flagAlternative ? '0x' : '';
2847
#if PRECISE_I64_MATH
2848
if (argSize == 8 && i64Math) {
2850
argText = (origArg[1]>>>0).toString(16);
2851
var lower = (origArg[0]>>>0).toString(16);
2852
while (lower.length < 8) lower = '0' + lower;
2855
argText = (origArg[0]>>>0).toString(16);
2860
// Represent negative numbers in hex as 2's complement.
2862
argText = (currAbsArg - 1).toString(16);
2864
for (var i = 0; i < argText.length; i++) {
2865
buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
2867
argText = buffer.join('');
2868
while (argText.length < argSize * 2) argText = 'f' + argText;
2870
argText = currAbsArg.toString(16);
2872
if (next == {{{ charCode('X') }}}) {
2873
prefix = prefix.toUpperCase();
2874
argText = argText.toUpperCase();
2876
} else if (next == {{{ charCode('p') }}}) {
2877
if (currAbsArg === 0) {
2881
argText = currAbsArg.toString(16);
2885
while (argText.length < precision) {
2886
argText = '0' + argText;
2890
// Add sign if needed
2891
if (flagAlwaysSigned) {
2893
prefix = '-' + prefix;
2895
prefix = '+' + prefix;
2900
while (prefix.length + argText.length < width) {
2901
if (flagLeftAlign) {
2905
argText = '0' + argText;
2907
prefix = ' ' + prefix;
2912
// Insert the result into the buffer.
2913
argText = prefix + argText;
2914
argText.split('').forEach(function(chr) {
2915
ret.push(chr.charCodeAt(0));
2919
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
2921
var currArg = getNextArg('double');
2923
if (isNaN(currArg)) {
2925
flagZeroPad = false;
2926
} else if (!isFinite(currArg)) {
2927
argText = (currArg < 0 ? '-' : '') + 'inf';
2928
flagZeroPad = false;
2930
var isGeneral = false;
2931
var effectivePrecision = Math.min(precision, 20);
2933
// Convert g/G to f/F or e/E, as per:
2934
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
2935
if (next == {{{ charCode('g') }}} || next == {{{ charCode('G') }}}) {
2937
precision = precision || 1;
2938
var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
2939
if (precision > exponent && exponent >= -4) {
2940
next = ((next == {{{ charCode('g') }}}) ? 'f' : 'F').charCodeAt(0);
2941
precision -= exponent + 1;
2943
next = ((next == {{{ charCode('g') }}}) ? 'e' : 'E').charCodeAt(0);
2946
effectivePrecision = Math.min(precision, 20);
2949
if (next == {{{ charCode('e') }}} || next == {{{ charCode('E') }}}) {
2950
argText = currArg.toExponential(effectivePrecision);
2951
// Make sure the exponent has at least 2 digits.
2952
if (/[eE][-+]\d$/.test(argText)) {
2953
argText = argText.slice(0, -1) + '0' + argText.slice(-1);
2955
} else if (next == {{{ charCode('f') }}} || next == {{{ charCode('F') }}}) {
2956
argText = currArg.toFixed(effectivePrecision);
2957
if (currArg === 0 && __reallyNegative(currArg)) {
2958
argText = '-' + argText;
2962
var parts = argText.split('e');
2963
if (isGeneral && !flagAlternative) {
2964
// Discard trailing zeros and periods.
2965
while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
2966
(parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
2967
parts[0] = parts[0].slice(0, -1);
2970
// Make sure we have a period in alternative mode.
2971
if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
2972
// Zero pad until required precision.
2973
while (precision > effectivePrecision++) parts[0] += '0';
2975
argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
2977
// Capitalize 'E' if needed.
2978
if (next == {{{ charCode('E') }}}) argText = argText.toUpperCase();
2981
if (flagAlwaysSigned && currArg >= 0) {
2982
argText = '+' + argText;
2987
while (argText.length < width) {
2988
if (flagLeftAlign) {
2991
if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
2992
argText = argText[0] + '0' + argText.slice(1);
2994
argText = (flagZeroPad ? '0' : ' ') + argText;
3000
if (next < {{{ charCode('a') }}}) argText = argText.toUpperCase();
3002
// Insert the result into the buffer.
3003
argText.split('').forEach(function(chr) {
3004
ret.push(chr.charCodeAt(0));
3010
var arg = getNextArg('i8*') || nullString;
3011
var argLength = _strlen(arg);
3012
if (precisionSet) argLength = Math.min(argLength, precision);
3013
if (!flagLeftAlign) {
3014
while (argLength < width--) {
3015
ret.push({{{ charCode(' ') }}});
3018
for (var i = 0; i < argLength; i++) {
3019
ret.push({{{ makeGetValue('arg++', 0, 'i8', null, true) }}});
3021
if (flagLeftAlign) {
3022
while (argLength < width--) {
3023
ret.push({{{ charCode(' ') }}});
3030
if (flagLeftAlign) ret.push(getNextArg('i8'));
3031
while (--width > 0) {
3032
ret.push({{{ charCode(' ') }}});
3034
if (!flagLeftAlign) ret.push(getNextArg('i8'));
3038
// Write the length written so far to the next parameter.
3039
var ptr = getNextArg('i32*');
3040
{{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}}
3044
// Literal percent sign.
3049
// Unknown specifiers remain untouched.
3050
for (var i = startTextIndex; i < textIndex + 2; i++) {
3051
ret.push({{{ makeGetValue(0, 'i', 'i8') }}});
3056
// TODO: Support a/A (hex float) and m (last error) specifiers.
3057
// TODO: Support %1${specifier} for arg selection.
3065
// NOTE: Invalid stream pointers passed to these functions would cause a crash
3066
// in native code. We, on the other hand, just ignore them, since it's
3068
clearerr__deps: ['$FS'],
3069
clearerr: function(stream) {
3070
// void clearerr(FILE *stream);
3071
// http://pubs.opengroup.org/onlinepubs/000095399/functions/clearerr.html
3072
if (FS.streams[stream]) FS.streams[stream].error = false;
3074
fclose__deps: ['close', 'fsync'],
3075
fclose: function(stream) {
3076
// int fclose(FILE *stream);
3077
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fclose.html
3079
return _close(stream);
3081
fdopen__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
3082
fdopen: function(fildes, mode) {
3083
// FILE *fdopen(int fildes, const char *mode);
3084
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fdopen.html
3085
if (FS.streams[fildes]) {
3086
var stream = FS.streams[fildes];
3087
mode = Pointer_stringify(mode);
3088
if ((mode.indexOf('w') != -1 && !stream.isWrite) ||
3089
(mode.indexOf('r') != -1 && !stream.isRead) ||
3090
(mode.indexOf('a') != -1 && !stream.isAppend) ||
3091
(mode.indexOf('+') != -1 && (!stream.isRead || !stream.isWrite))) {
3092
___setErrNo(ERRNO_CODES.EINVAL);
3095
stream.error = false;
3100
___setErrNo(ERRNO_CODES.EBADF);
3104
feof__deps: ['$FS'],
3105
feof: function(stream) {
3106
// int feof(FILE *stream);
3107
// http://pubs.opengroup.org/onlinepubs/000095399/functions/feof.html
3108
return Number(FS.streams[stream] && FS.streams[stream].eof);
3110
ferror__deps: ['$FS'],
3111
ferror: function(stream) {
3112
// int ferror(FILE *stream);
3113
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ferror.html
3114
return Number(FS.streams[stream] && FS.streams[stream].error);
3116
fflush__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
3117
fflush: function(stream) {
3118
// int fflush(FILE *stream);
3119
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
3120
var flush = function(filedes) {
3121
// Right now we write all data directly, except for output devices.
3122
if (FS.streams[filedes] && FS.streams[filedes].object.output) {
3123
if (!FS.streams[filedes].isTerminal) { // don't flush terminals, it would cause a \n to also appear
3124
FS.streams[filedes].object.output(null);
3130
for (var i = 0; i < FS.streams.length; i++) if (FS.streams[i]) flush(i);
3136
___setErrNo(ERRNO_CODES.EIO);
3140
fgetc__deps: ['$FS', 'read'],
3141
fgetc__postset: '_fgetc.ret = allocate([0], "i8", ALLOC_STATIC);',
3142
fgetc: function(stream) {
3143
// int fgetc(FILE *stream);
3144
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetc.html
3145
if (!FS.streams[stream]) return -1;
3146
var streamObj = FS.streams[stream];
3147
if (streamObj.eof || streamObj.error) return -1;
3148
var ret = _read(stream, _fgetc.ret, 1);
3150
streamObj.eof = true;
3152
} else if (ret == -1) {
3153
streamObj.error = true;
3156
return {{{ makeGetValue('_fgetc.ret', '0', 'i8', null, 1) }}};
3160
getc_unlocked: 'fgetc',
3161
getchar__deps: ['fgetc', 'stdin'],
3162
getchar: function() {
3163
// int getchar(void);
3164
// http://pubs.opengroup.org/onlinepubs/000095399/functions/getchar.html
3165
return _fgetc({{{ makeGetValue(makeGlobalUse('_stdin'), '0', 'void*') }}});
3167
fgetpos__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
3168
fgetpos: function(stream, pos) {
3169
// int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
3170
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetpos.html
3171
if (FS.streams[stream]) {
3172
stream = FS.streams[stream];
3173
if (stream.object.isDevice) {
3174
___setErrNo(ERRNO_CODES.ESPIPE);
3177
{{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}}
3178
var state = (stream.eof ? 1 : 0) + (stream.error ? 2 : 0);
3179
{{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}}
3183
___setErrNo(ERRNO_CODES.EBADF);
3187
fgets__deps: ['fgetc'],
3188
fgets: function(s, n, stream) {
3189
// char *fgets(char *restrict s, int n, FILE *restrict stream);
3190
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fgets.html
3191
if (!FS.streams[stream]) return 0;
3192
var streamObj = FS.streams[stream];
3193
if (streamObj.error || streamObj.eof) return 0;
3195
for (var i = 0; i < n - 1 && byte_ != {{{ charCode('\n') }}}; i++) {
3196
byte_ = _fgetc(stream);
3198
if (streamObj.error || (streamObj.eof && i == 0)) return 0;
3199
else if (streamObj.eof) break;
3201
{{{ makeSetValue('s', 'i', 'byte_', 'i8') }}}
3203
{{{ makeSetValue('s', 'i', '0', 'i8') }}}
3206
gets__deps: ['fgets'],
3208
// char *gets(char *s);
3209
// http://pubs.opengroup.org/onlinepubs/000095399/functions/gets.html
3210
return _fgets(s, 1e6, {{{ makeGetValue(makeGlobalUse('_stdin'), '0', 'void*') }}});
3212
fileno: function(stream) {
3213
// int fileno(FILE *stream);
3214
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
3215
// We use file descriptor numbers and FILE* streams interchangeably.
3218
ftrylockfile: function() {
3219
// int ftrylockfile(FILE *file);
3220
// http://pubs.opengroup.org/onlinepubs/000095399/functions/flockfile.html
3221
// Locking is useless in a single-threaded environment. Pretend to succeed.
3224
flockfile: 'ftrylockfile',
3225
funlockfile: 'ftrylockfile',
3226
fopen__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'open'],
3227
fopen: function(filename, mode) {
3228
// FILE *fopen(const char *restrict filename, const char *restrict mode);
3229
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fopen.html
3231
mode = Pointer_stringify(mode);
3232
if (mode[0] == 'r') {
3233
if (mode.indexOf('+') != -1) {
3234
flags = {{{ cDefine('O_RDWR') }}};
3236
flags = {{{ cDefine('O_RDONLY') }}};
3238
} else if (mode[0] == 'w') {
3239
if (mode.indexOf('+') != -1) {
3240
flags = {{{ cDefine('O_RDWR') }}};
3242
flags = {{{ cDefine('O_WRONLY') }}};
3244
flags |= {{{ cDefine('O_CREAT') }}};
3245
flags |= {{{ cDefine('O_TRUNC') }}};
3246
} else if (mode[0] == 'a') {
3247
if (mode.indexOf('+') != -1) {
3248
flags = {{{ cDefine('O_RDWR') }}};
3250
flags = {{{ cDefine('O_WRONLY') }}};
3252
flags |= {{{ cDefine('O_CREAT') }}};
3253
flags |= {{{ cDefine('O_APPEND') }}};
3255
___setErrNo(ERRNO_CODES.EINVAL);
3258
var ret = _open(filename, flags, allocate([0x1FF, 0, 0, 0], 'i32', ALLOC_STACK)); // All creation permissions.
3259
return (ret == -1) ? 0 : ret;
3261
fputc__deps: ['$FS', 'write'],
3262
fputc__postset: '_fputc.ret = allocate([0], "i8", ALLOC_STATIC);',
3263
fputc: function(c, stream) {
3264
// int fputc(int c, FILE *stream);
3265
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
3266
var chr = unSign(c & 0xFF);
3267
{{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}}
3268
var ret = _write(stream, _fputc.ret, 1);
3270
if (FS.streams[stream]) FS.streams[stream].error = true;
3277
putc_unlocked: 'fputc',
3278
putchar__deps: ['fputc', 'stdout'],
3279
putchar: function(c) {
3280
// int putchar(int c);
3281
// http://pubs.opengroup.org/onlinepubs/000095399/functions/putchar.html
3282
return _fputc(c, {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}});
3284
putchar_unlocked: 'putchar',
3285
fputs__deps: ['write', 'strlen'],
3286
fputs: function(s, stream) {
3287
// int fputs(const char *restrict s, FILE *restrict stream);
3288
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
3289
return _write(stream, s, _strlen(s));
3291
puts__deps: ['fputs', 'fputc', 'stdout'],
3293
// int puts(const char *s);
3294
// http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html
3295
// NOTE: puts() always writes an extra newline.
3296
var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}};
3297
var ret = _fputs(s, stdout);
3301
var newlineRet = _fputc({{{ charCode('\n') }}}, stdout);
3302
return (newlineRet < 0) ? -1 : ret + 1;
3305
fread__deps: ['$FS', 'read'],
3306
fread: function(ptr, size, nitems, stream) {
3307
// size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
3308
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fread.html
3309
var bytesToRead = nitems * size;
3310
if (bytesToRead == 0) return 0;
3311
var bytesRead = _read(stream, ptr, bytesToRead);
3312
var streamObj = FS.streams[stream];
3313
if (bytesRead == -1) {
3314
if (streamObj) streamObj.error = true;
3317
if (bytesRead < bytesToRead) streamObj.eof = true;
3318
return Math.floor(bytesRead / size);
3321
freopen__deps: ['$FS', 'fclose', 'fopen', '__setErrNo', '$ERRNO_CODES'],
3322
freopen: function(filename, mode, stream) {
3323
// FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
3324
// http://pubs.opengroup.org/onlinepubs/000095399/functions/freopen.html
3326
if (!FS.streams[stream]) {
3327
___setErrNo(ERRNO_CODES.EBADF);
3330
if (_freopen.buffer) _free(_freopen.buffer);
3331
filename = intArrayFromString(FS.streams[stream].path);
3332
filename = allocate(filename, 'i8', ALLOC_NORMAL);
3335
return _fopen(filename, mode);
3337
fseek__deps: ['$FS', 'lseek'],
3338
fseek: function(stream, offset, whence) {
3339
// int fseek(FILE *stream, long offset, int whence);
3340
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fseek.html
3341
var ret = _lseek(stream, offset, whence);
3345
FS.streams[stream].eof = false;
3351
fsetpos__deps: ['$FS', 'lseek', '__setErrNo', '$ERRNO_CODES'],
3352
fsetpos: function(stream, pos) {
3353
// int fsetpos(FILE *stream, const fpos_t *pos);
3354
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fsetpos.html
3355
if (FS.streams[stream]) {
3356
if (FS.streams[stream].object.isDevice) {
3357
___setErrNo(ERRNO_CODES.EPIPE);
3360
FS.streams[stream].position = {{{ makeGetValue('pos', '0', 'i32') }}};
3361
var state = {{{ makeGetValue('pos', Runtime.getNativeTypeSize('i32'), 'i32') }}};
3362
FS.streams[stream].eof = Boolean(state & 1);
3363
FS.streams[stream].error = Boolean(state & 2);
3367
___setErrNo(ERRNO_CODES.EBADF);
3371
ftell__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
3372
ftell: function(stream) {
3373
// long ftell(FILE *stream);
3374
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ftell.html
3375
if (FS.streams[stream]) {
3376
stream = FS.streams[stream];
3377
if (stream.object.isDevice) {
3378
___setErrNo(ERRNO_CODES.ESPIPE);
3381
return stream.position;
3384
___setErrNo(ERRNO_CODES.EBADF);
3390
fwrite__deps: ['$FS', 'write'],
3391
fwrite: function(ptr, size, nitems, stream) {
3392
// size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
3393
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
3394
var bytesToWrite = nitems * size;
3395
if (bytesToWrite == 0) return 0;
3396
var bytesWritten = _write(stream, ptr, bytesToWrite);
3397
if (bytesWritten == -1) {
3398
if (FS.streams[stream]) FS.streams[stream].error = true;
3401
return Math.floor(bytesWritten / size);
3404
popen__deps: ['__setErrNo', '$ERRNO_CODES'],
3405
popen: function(command, mode) {
3406
// FILE *popen(const char *command, const char *mode);
3407
// http://pubs.opengroup.org/onlinepubs/000095399/functions/popen.html
3408
// We allow only one process, so no pipes.
3409
___setErrNo(ERRNO_CODES.EMFILE);
3412
pclose__deps: ['__setErrNo', '$ERRNO_CODES'],
3413
pclose: function(stream) {
3414
// int pclose(FILE *stream);
3415
// http://pubs.opengroup.org/onlinepubs/000095399/functions/pclose.html
3416
// We allow only one process, so no pipes.
3417
___setErrNo(ERRNO_CODES.ECHILD);
3420
perror__deps: ['puts', 'fputs', 'fputc', 'strerror', '__errno_location'],
3421
perror: function(s) {
3422
// void perror(const char *s);
3423
// http://pubs.opengroup.org/onlinepubs/000095399/functions/perror.html
3424
var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}};
3427
_fputc({{{ charCode(':') }}}, stdout);
3428
_fputc({{{ charCode(' ') }}}, stdout);
3430
var errnum = {{{ makeGetValue('___errno_location()', '0', 'i32') }}};
3431
_puts(_strerror(errnum));
3433
remove__deps: ['unlink', 'rmdir'],
3434
remove: function(path) {
3435
// int remove(const char *path);
3436
// http://pubs.opengroup.org/onlinepubs/000095399/functions/remove.html
3437
var ret = _unlink(path);
3438
if (ret == -1) ret = _rmdir(path);
3441
rename__deps: ['__setErrNo', '$ERRNO_CODES'],
3442
rename: function(old, new_) {
3443
// int rename(const char *old, const char *new);
3444
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rename.html
3445
var oldObj = FS.analyzePath(Pointer_stringify(old));
3446
var newObj = FS.analyzePath(Pointer_stringify(new_));
3447
if (newObj.path == oldObj.path) {
3449
} else if (!oldObj.exists) {
3450
___setErrNo(oldObj.error);
3452
} else if (oldObj.isRoot || oldObj.path == FS.currentPath) {
3453
___setErrNo(ERRNO_CODES.EBUSY);
3455
} else if (newObj.path && newObj.path.indexOf(oldObj.path) == 0) {
3456
___setErrNo(ERRNO_CODES.EINVAL);
3458
} else if (newObj.exists && newObj.object.isFolder) {
3459
___setErrNo(ERRNO_CODES.EISDIR);
3462
delete oldObj.parentObject.contents[oldObj.name];
3463
newObj.parentObject.contents[newObj.name] = oldObj.object;
3467
rewind__deps: ['$FS', 'fseek'],
3468
rewind: function(stream) {
3469
// void rewind(FILE *stream);
3470
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rewind.html
3471
_fseek(stream, 0, 0); // SEEK_SET.
3472
if (FS.streams[stream]) FS.streams[stream].error = false;
3474
setvbuf: function(stream, buf, type, size) {
3475
// int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size);
3476
// http://pubs.opengroup.org/onlinepubs/000095399/functions/setvbuf.html
3477
// TODO: Implement custom buffering.
3480
setbuf__deps: ['setvbuf'],
3481
setbuf: function(stream, buf) {
3482
// void setbuf(FILE *restrict stream, char *restrict buf);
3483
// http://pubs.opengroup.org/onlinepubs/000095399/functions/setbuf.html
3484
if (buf) _setvbuf(stream, buf, 0, 8192); // _IOFBF, BUFSIZ.
3485
else _setvbuf(stream, buf, 2, 8192); // _IONBF, BUFSIZ.
3487
tmpnam__deps: ['$FS'],
3488
tmpnam: function(s, dir, prefix) {
3489
// char *tmpnam(char *s);
3490
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpnam.html
3491
// NOTE: The dir and prefix arguments are for internal use only.
3492
var folder = FS.findObject(dir || '/tmp');
3493
if (!folder || !folder.isFolder) {
3495
folder = FS.findObject(dir);
3496
if (!folder || !folder.isFolder) return 0;
3498
var name = prefix || 'file';
3500
name += String.fromCharCode(65 + Math.floor(Math.random() * 25));
3501
} while (name in folder.contents);
3502
var result = dir + '/' + name;
3503
if (!_tmpnam.buffer) _tmpnam.buffer = _malloc(256);
3504
if (!s) s = _tmpnam.buffer;
3505
for (var i = 0; i < result.length; i++) {
3506
{{{ makeSetValue('s', 'i', 'result.charCodeAt(i)', 'i8') }}};
3508
{{{ makeSetValue('s', 'i', '0', 'i8') }}};
3511
tempnam__deps: ['tmpnam'],
3512
tempnam: function(dir, pfx) {
3513
// char *tempnam(const char *dir, const char *pfx);
3514
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tempnam.html
3515
return _tmpnam(0, Pointer_stringify(dir), Pointer_stringify(pfx));
3517
tmpfile__deps: ['tmpnam', 'fopen'],
3518
tmpfile: function() {
3519
// FILE *tmpfile(void);
3520
// http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpfile.html
3521
// TODO: Delete the created file on closing.
3522
if (_tmpfile.mode) {
3523
_tmpfile.mode = allocate(intArrayFromString('w+'), 'i8', ALLOC_NORMAL);
3525
return _fopen(_tmpnam(0), _tmpfile.mode);
3527
ungetc__deps: ['$FS'],
3528
ungetc: function(c, stream) {
3529
// int ungetc(int c, FILE *stream);
3530
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ungetc.html
3531
if (FS.streams[stream]) {
3532
c = unSign(c & 0xFF);
3533
FS.streams[stream].ungotten.push(c);
3539
system__deps: ['__setErrNo', '$ERRNO_CODES'],
3540
system: function(command) {
3541
// int system(const char *command);
3542
// http://pubs.opengroup.org/onlinepubs/000095399/functions/system.html
3543
// Can't call external programs.
3544
___setErrNo(ERRNO_CODES.EAGAIN);
3547
fscanf__deps: ['$FS', '__setErrNo', '$ERRNO_CODES',
3548
'_scanString', 'getc', 'ungetc'],
3549
fscanf: function(stream, format, varargs) {
3550
// int fscanf(FILE *restrict stream, const char *restrict format, ... );
3551
// http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
3552
if (FS.streams[stream]) {
3554
var get = function() { var ret = _fgetc(stream); stack.push(ret); return ret };
3555
var unget = function(c) { return _ungetc(stack.pop(), stream) };
3556
return __scanString(format, get, unget, varargs);
3561
scanf__deps: ['fscanf'],
3562
scanf: function(format, varargs) {
3563
// int scanf(const char *restrict format, ... );
3564
// http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
3565
var stdin = {{{ makeGetValue(makeGlobalUse('_stdin'), '0', 'void*') }}};
3566
return _fscanf(stdin, format, varargs);
3568
sscanf__deps: ['_scanString'],
3569
sscanf: function(s, format, varargs) {
3570
// int sscanf(const char *restrict s, const char *restrict format, ... );
3571
// http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
3573
var get = function() { return {{{ makeGetValue('s', 'index++', 'i8') }}}; };
3574
var unget = function() { index--; };
3575
return __scanString(format, get, unget, varargs);
3577
snprintf__deps: ['_formatString'],
3578
snprintf: function(s, n, format, varargs) {
3579
// int snprintf(char *restrict s, size_t n, const char *restrict format, ...);
3580
// http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
3581
var result = __formatString(format, varargs);
3582
var limit = (n === undefined) ? result.length
3583
: Math.min(result.length, Math.max(n - 1, 0));
3586
var buf = _malloc(limit+1);
3587
{{{ makeSetValue('s', '0', 'buf', 'i8*') }}};
3590
for (var i = 0; i < limit; i++) {
3591
{{{ makeSetValue('s', 'i', 'result[i]', 'i8') }}};
3593
if (limit < n || (n === undefined)) {{{ makeSetValue('s', 'i', '0', 'i8') }}};
3594
return result.length;
3596
fprintf__deps: ['fwrite', '_formatString'],
3597
fprintf: function(stream, format, varargs) {
3598
// int fprintf(FILE *restrict stream, const char *restrict format, ...);
3599
// http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
3600
var result = __formatString(format, varargs);
3601
var stack = Runtime.stackSave();
3602
var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
3603
Runtime.stackRestore(stack);
3606
printf__deps: ['fprintf'],
3607
printf: function(format, varargs) {
3608
// int printf(const char *restrict format, ...);
3609
// http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
3610
var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}};
3611
return _fprintf(stdout, format, varargs);
3613
sprintf__deps: ['snprintf'],
3614
sprintf: function(s, format, varargs) {
3615
// int sprintf(char *restrict s, const char *restrict format, ...);
3616
// http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
3617
return _snprintf(s, undefined, format, varargs);
3619
asprintf__deps: ['sprintf'],
3620
asprintf: function(s, format, varargs) {
3621
return _sprintf(-s, format, varargs);
3625
// va_arg is just like our varargs
3626
vfprintf: 'fprintf',
3627
vsnprintf: 'snprintf',
3629
vsprintf: 'sprintf',
3630
vasprintf: 'asprintf',
3637
// convert va_arg into varargs
3638
vfprintf__deps: ['fprintf'],
3639
vfprintf: function(s, f, va_arg) {
3640
return _fprintf(s, f, {{{ makeGetValue('va_arg', 0, '*') }}});
3642
vsnprintf__deps: ['snprintf'],
3643
vsnprintf: function(s, n, format, va_arg) {
3644
return _snprintf(s, n, format, {{{ makeGetValue('va_arg', 0, '*') }}});
3646
vprintf__deps: ['printf'],
3647
vprintf: function(format, va_arg) {
3648
return _printf(format, {{{ makeGetValue('va_arg', 0, '*') }}});
3650
vsprintf__deps: ['sprintf'],
3651
vsprintf: function(s, format, va_arg) {
3652
return _sprintf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
3654
vasprintf__deps: ['asprintf'],
3655
vasprintf: function(s, format, va_arg) {
3656
return _asprintf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
3658
vscanf__deps: ['scanf'],
3659
vscanf: function(format, va_arg) {
3660
return _scanf(format, {{{ makeGetValue('va_arg', 0, '*') }}});
3662
vfscanf__deps: ['fscanf'],
3663
vfscanf: function(s, format, va_arg) {
3664
return _fscanf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
3666
vsscanf__deps: ['sscanf'],
3667
vsscanf: function(s, format, va_arg) {
3668
return _sscanf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
3673
__01fopen64_: 'fopen',
3674
__01freopen64_: 'freopen',
3675
__01fseeko64_: 'fseek',
3676
__01ftello64_: 'ftell',
3677
__01tmpfile64_: 'tmpfile',
3678
__isoc99_fscanf: 'fscanf',
3679
// TODO: Check if any other aliases are needed.
3682
_ZNSo3putEc: 'putchar',
3683
_ZNSo5flushEv__deps: ['fflush', 'stdout'],
3684
_ZNSo5flushEv: function() {
3685
_fflush({{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}});
3688
// ==========================================================================
3690
// ==========================================================================
3692
mmap__deps: ['$FS'],
3693
mmap: function(start, num, prot, flags, stream, offset) {
3694
/* FIXME: Since mmap is normally implemented at the kernel level,
3695
* this implementation simply uses malloc underneath the call to
3698
if (!_mmap.mappings) _mmap.mappings = {};
3700
var ptr = _malloc(num);
3702
var info = FS.streams[stream];
3703
if (!info) return -1;
3704
var contents = info.object.contents;
3705
contents = Array.prototype.slice.call(contents, offset, offset+num);
3706
ptr = allocate(contents, 'i8', ALLOC_NORMAL);
3708
// align to page size
3710
if (ptr % PAGE_SIZE != 0) {
3712
ptr = _malloc(num + PAGE_SIZE);
3713
ret = alignMemoryPage(ptr);
3714
_memcpy(ret, old, num);
3718
_memset(ret, 0, num);
3720
_mmap.mappings[ret] = { malloc: ptr, num: num };
3723
__01mmap64_: 'mmap',
3725
munmap: function(start, num) {
3726
if (!_mmap.mappings) _mmap.mappings = {};
3727
// TODO: support unmmap'ing parts of allocations
3728
var info = _mmap.mappings[start];
3729
if (!info) return 0;
3730
if (num == info.num) {
3731
_mmap.mappings[start] = null;
3737
// TODO: Implement mremap.
3739
// ==========================================================================
3741
// ==========================================================================
3743
// tiny, fake malloc/free implementation. If the program actually uses malloc,
3744
// a compiled version will be used; this will only be used if the runtime
3745
// needs to allocate something, for which this is good enough if otherwise
3746
// no malloc is needed.
3747
malloc: function(bytes) {
3748
/* Over-allocate to make sure it is byte-aligned by 8.
3749
* This will leak memory, but this is only the dummy
3750
* implementation (replaced by dlmalloc normally) so
3753
var ptr = Runtime.staticAlloc(bytes + 8);
3754
return (ptr+8) & 0xFFFFFFF8;
3758
calloc__deps: ['malloc'],
3759
calloc: function(n, s) {
3760
var ret = _malloc(n*s);
3761
_memset(ret, 0, n*s);
3767
#if USE_TYPED_ARRAYS == 2
3768
llabs__deps: [function() { Types.preciseI64MathUsed = 1 }],
3769
llabs: function(lo, hi) {
3770
i64Math.abs(lo, hi);
3771
{{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]) }}};
3774
llabs: function(lo, hi) {
3775
throw 'unsupported llabs';
3779
exit__deps: ['_exit'],
3780
exit: function(status) {
3784
_ZSt9terminatev__deps: ['exit'],
3785
_ZSt9terminatev: function() {
3789
atexit: function(func, arg) {
3790
__ATEXIT__.unshift({ func: func, arg: arg });
3792
__cxa_atexit: 'atexit',
3796
throw 'abort() at ' + (new Error().stack);
3799
bsearch: function(key, base, num, size, compar) {
3800
var cmp = function(x, y) {
3801
return Runtime.dynCall('iii', compar, [x, y])
3805
var mid, test, addr;
3807
while (left < right) {
3808
mid = (left + right) >>> 1;
3809
addr = base + (mid * size);
3810
test = cmp(key, addr);
3814
} else if (test > 0) {
3824
realloc__deps: ['memcpy'],
3825
realloc: function(ptr, size) {
3826
// Very simple, inefficient implementation - if you use a real malloc, best to use
3827
// a real realloc with it
3829
if (ptr) _free(ptr);
3832
var ret = _malloc(size);
3834
_memcpy(ret, ptr, size); // might be some invalid reads
3840
_parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'],
3841
_parseInt: function(str, endptr, base, min, max, bits, unsign) {
3843
while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
3845
// Check for a plus/minus sign.
3847
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('-') }}}) {
3850
} else if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('+') }}}) {
3855
var finalBase = base;
3857
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('0') }}}) {
3858
if ({{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('x') }}} ||
3859
{{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('X') }}}) {
3868
if (!finalBase) finalBase = 10;
3873
while ((chr = {{{ makeGetValue('str', 0, 'i8') }}}) != 0) {
3874
var digit = parseInt(String.fromCharCode(chr), finalBase);
3878
ret = ret * finalBase + digit;
3888
{{{ makeSetValue('endptr', 0, 'str', '*') }}}
3891
// Unsign if needed.
3893
if (Math.abs(ret) > max) {
3895
___setErrNo(ERRNO_CODES.ERANGE);
3897
ret = unSign(ret, bits);
3902
if (ret > max || ret < min) {
3903
ret = ret > max ? max : min;
3904
___setErrNo(ERRNO_CODES.ERANGE);
3907
#if USE_TYPED_ARRAYS == 2
3909
{{{ makeStructuralReturn(splitI64('ret')) }}};
3915
#if USE_TYPED_ARRAYS == 2
3916
_parseInt64__deps: ['isspace', '__setErrNo', '$ERRNO_CODES', function() { Types.preciseI64MathUsed = 1 }],
3917
_parseInt64: function(str, endptr, base, min, max, unsign) {
3920
while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
3922
// Check for a plus/minus sign.
3923
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('-') }}}) {
3925
} else if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('+') }}}) {
3931
var finalBase = base;
3933
if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('0') }}}) {
3934
if ({{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('x') }}} ||
3935
{{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('X') }}}) {
3941
ok = true; // we saw an initial zero, perhaps the entire thing is just "0"
3945
if (!finalBase) finalBase = 10;
3949
while ((chr = {{{ makeGetValue('str', 0, 'i8') }}}) != 0) {
3950
var digit = parseInt(String.fromCharCode(chr), finalBase);
3959
___setErrNo(ERRNO_CODES.EINVAL);
3960
{{{ makeStructuralReturn(['0', '0']) }}};
3965
{{{ makeSetValue('endptr', 0, 'str', '*') }}}
3969
i64Math.fromString(Pointer_stringify(start, str - start), finalBase, min, max, unsign);
3971
___setErrNo(ERRNO_CODES.ERANGE); // not quite correct
3974
{{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]) }}};
3977
strtoll__deps: ['_parseInt64'],
3978
strtoll: function(str, endptr, base) {
3979
return __parseInt64(str, endptr, base, '-9223372036854775808', '9223372036854775807'); // LLONG_MIN, LLONG_MAX.
3981
strtoll_l: 'strtoll', // no locale support yet
3982
strtol__deps: ['_parseInt'],
3983
strtol: function(str, endptr, base) {
3984
return __parseInt(str, endptr, base, -2147483648, 2147483647, 32); // LONG_MIN, LONG_MAX.
3986
strtol_l: 'strtol', // no locale support yet
3987
strtoul__deps: ['_parseInt'],
3988
strtoul: function(str, endptr, base) {
3989
return __parseInt(str, endptr, base, 0, 4294967295, 32, true); // ULONG_MAX.
3991
strtoul_l: 'strtoul', // no locale support yet
3992
strtoull__deps: ['_parseInt64'],
3993
strtoull: function(str, endptr, base) {
3994
return __parseInt64(str, endptr, base, 0, '18446744073709551615', true); // ULONG_MAX.
3996
strtoull_l: 'strtoull', // no locale support yet
3998
atoi__deps: ['strtol'],
3999
atoi: function(ptr) {
4000
return _strtol(ptr, null, 10);
4004
atoll__deps: ['strtoll'],
4005
atoll: function(ptr) {
4006
return _strtoll(ptr, null, 10);
4009
qsort__deps: ['memcpy'],
4010
qsort: function(base, num, size, cmp) {
4011
if (num == 0 || size == 0) return;
4012
// forward calls to the JavaScript sort method
4013
// first, sort the items logically
4014
var comparator = function(x, y) {
4015
return Runtime.dynCall('iii', cmp, [x, y]);
4018
for (var i = 0; i < num; i++) keys.push(i);
4019
keys.sort(function(a, b) {
4020
return comparator(base+a*size, base+b*size);
4023
var temp = _malloc(num*size);
4024
_memcpy(temp, base, num*size);
4025
for (var i = 0; i < num; i++) {
4026
if (keys[i] == i) continue; // already in place
4027
_memcpy(base+i*size, temp+keys[i]*size, size);
4032
environ: 'allocate(1, "i32*", ALLOC_STACK)',
4033
__environ__deps: ['environ'],
4034
__environ: '_environ',
4035
__buildEnvironment__deps: ['__environ'],
4036
__buildEnvironment: function(env) {
4037
// WARNING: Arbitrary limit!
4038
var MAX_ENV_VALUES = 64;
4039
var TOTAL_ENV_SIZE = 1024;
4041
// Statically allocate memory for the environment.
4044
if (!___buildEnvironment.called) {
4045
___buildEnvironment.called = true;
4046
// Set default values. Use string keys for Closure Compiler compatibility.
4047
ENV['USER'] = 'root';
4050
ENV['HOME'] = '/home/emscripten';
4051
ENV['LANG'] = 'en_US.UTF-8';
4052
ENV['_'] = './this.program';
4054
poolPtr = allocate(TOTAL_ENV_SIZE, 'i8', ALLOC_STATIC);
4055
envPtr = allocate(MAX_ENV_VALUES * {{{ Runtime.QUANTUM_SIZE }}},
4056
'i8*', ALLOC_STATIC);
4057
{{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}}
4058
{{{ makeSetValue(makeGlobalUse('_environ'), 0, 'envPtr', 'i8*') }}};
4060
envPtr = {{{ makeGetValue(makeGlobalUse('_environ'), '0', 'i8**') }}};
4061
poolPtr = {{{ makeGetValue('envPtr', '0', 'i8*') }}};
4064
// Collect key=value lines.
4067
for (var key in env) {
4068
if (typeof env[key] === 'string') {
4069
var line = key + '=' + env[key];
4071
totalSize += line.length;
4074
if (totalSize > TOTAL_ENV_SIZE) {
4075
throw new Error('Environment size exceeded TOTAL_ENV_SIZE!');
4079
var ptrSize = {{{ Runtime.getNativeTypeSize('i8*') }}};
4080
for (var i = 0; i < strings.length; i++) {
4081
var line = strings[i];
4082
for (var j = 0; j < line.length; j++) {
4083
{{{ makeSetValue('poolPtr', 'j', 'line.charCodeAt(j)', 'i8') }}};
4085
{{{ makeSetValue('poolPtr', 'j', '0', 'i8') }}};
4086
{{{ makeSetValue('envPtr', 'i * ptrSize', 'poolPtr', 'i8*') }}};
4087
poolPtr += line.length + 1;
4089
{{{ makeSetValue('envPtr', 'strings.length * ptrSize', '0', 'i8*') }}};
4091
$ENV__deps: ['__buildEnvironment'],
4092
$ENV__postset: '___buildEnvironment(ENV);',
4094
getenv__deps: ['$ENV'],
4095
getenv: function(name) {
4096
// char *getenv(const char *name);
4097
// http://pubs.opengroup.org/onlinepubs/009695399/functions/getenv.html
4098
if (name === 0) return 0;
4099
name = Pointer_stringify(name);
4100
if (!ENV.hasOwnProperty(name)) return 0;
4102
if (_getenv.ret) _free(_getenv.ret);
4103
_getenv.ret = allocate(intArrayFromString(ENV[name]), 'i8', ALLOC_NORMAL);
4106
clearenv__deps: ['$ENV', '__buildEnvironment'],
4107
clearenv: function(name) {
4108
// int clearenv (void);
4109
// http://www.gnu.org/s/hello/manual/libc/Environment-Access.html#index-clearenv-3107
4111
___buildEnvironment(ENV);
4114
setenv__deps: ['$ENV', '__buildEnvironment', '$ERRNO_CODES', '__setErrNo'],
4115
setenv: function(envname, envval, overwrite) {
4116
// int setenv(const char *envname, const char *envval, int overwrite);
4117
// http://pubs.opengroup.org/onlinepubs/009695399/functions/setenv.html
4118
if (envname === 0) {
4119
___setErrNo(ERRNO_CODES.EINVAL);
4122
var name = Pointer_stringify(envname);
4123
var val = Pointer_stringify(envval);
4124
if (name === '' || name.indexOf('=') !== -1) {
4125
___setErrNo(ERRNO_CODES.EINVAL);
4128
if (ENV.hasOwnProperty(name) && !overwrite) return 0;
4130
___buildEnvironment(ENV);
4133
unsetenv__deps: ['$ENV', '__buildEnvironment', '$ERRNO_CODES', '__setErrNo'],
4134
unsetenv: function(name) {
4135
// int unsetenv(const char *name);
4136
// http://pubs.opengroup.org/onlinepubs/009695399/functions/unsetenv.html
4138
___setErrNo(ERRNO_CODES.EINVAL);
4141
name = Pointer_stringify(name);
4142
if (name === '' || name.indexOf('=') !== -1) {
4143
___setErrNo(ERRNO_CODES.EINVAL);
4146
if (ENV.hasOwnProperty(name)) {
4148
___buildEnvironment(ENV);
4152
putenv__deps: ['$ENV', '__buildEnvironment', '$ERRNO_CODES', '__setErrNo'],
4153
putenv: function(string) {
4154
// int putenv(char *string);
4155
// http://pubs.opengroup.org/onlinepubs/009695399/functions/putenv.html
4156
// WARNING: According to the standard (and the glibc implementation), the
4157
// string is taken by reference so future changes are reflected.
4158
// We copy it instead, possibly breaking some uses.
4160
___setErrNo(ERRNO_CODES.EINVAL);
4163
string = Pointer_stringify(string);
4164
var splitPoint = string.indexOf('=')
4165
if (string === '' || string.indexOf('=') === -1) {
4166
___setErrNo(ERRNO_CODES.EINVAL);
4169
var name = string.slice(0, splitPoint);
4170
var value = string.slice(splitPoint + 1);
4171
if (!(name in ENV) || ENV[name] !== value) {
4173
___buildEnvironment(ENV);
4178
getloadavg: function(loadavg, nelem) {
4179
// int getloadavg(double loadavg[], int nelem);
4180
// http://linux.die.net/man/3/getloadavg
4181
var limit = Math.min(nelem, 3);
4182
var doubleSize = {{{ Runtime.getNativeTypeSize('double') }}};
4183
for (var i = 0; i < limit; i++) {
4184
{{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}}
4189
// Use browser's Math.random(). We can't set a seed, though.
4190
srand: function(seed) {}, // XXX ignored
4192
return Math.floor(Math.random()*0x80000000);
4194
rand_r: function(seed) { // XXX ignores the seed
4195
return Math.floor(Math.random()*0x80000000);
4198
drand48: function() {
4199
return Math.random();
4202
realpath__deps: ['$FS', '__setErrNo'],
4203
realpath: function(file_name, resolved_name) {
4204
// char *realpath(const char *restrict file_name, char *restrict resolved_name);
4205
// http://pubs.opengroup.org/onlinepubs/009604499/functions/realpath.html
4206
var absolute = FS.analyzePath(Pointer_stringify(file_name));
4207
if (absolute.error) {
4208
___setErrNo(absolute.error);
4211
var size = Math.min(4095, absolute.path.length); // PATH_MAX - 1.
4212
for (var i = 0; i < size; i++) {
4213
{{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}}
4215
{{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}}
4216
return resolved_name;
4222
// ==========================================================================
4224
// ==========================================================================
4226
// FIXME: memcpy, memmove and memset should all return their destination pointers.
4228
memcpy__inline: function (dest, src, num, align) {
4232
ret += "assert(" + num + " % 1 === 0);"; //, 'memcpy given ' + " + num + " + ' bytes to copy. Problem with quantum=1 corrections perhaps?');";
4235
ret += makeCopyValues(dest, src, num, 'null', null, align);
4240
memcpy__sig: 'iiii',
4241
memcpy: function (dest, src, num) {
4242
dest = dest|0; src = src|0; num = num|0;
4245
if ((dest&3) == (src&3)) {
4247
if ((num|0) == 0) return ret|0;
4248
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
4253
while ((num|0) >= 4) {
4254
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i32'), 'i32') }}};
4260
while ((num|0) > 0) {
4261
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
4269
llvm_memcpy_i32: 'memcpy',
4270
llvm_memcpy_i64: 'memcpy',
4271
llvm_memcpy_p0i8_p0i8_i32: 'memcpy',
4272
llvm_memcpy_p0i8_p0i8_i64: 'memcpy',
4274
memmove__sig: 'viii',
4276
memmove__deps: ['memcpy'],
4277
memmove: function(dest, src, num) {
4278
dest = dest|0; src = src|0; num = num|0;
4279
if (((src|0) < (dest|0)) & ((dest|0) < ((src + num)|0))) {
4280
// Unlikely case: Copy backwards in a safe manner
4281
src = (src + num)|0;
4282
dest = (dest + num)|0;
4283
while ((num|0) > 0) {
4284
dest = (dest - 1)|0;
4287
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
4290
_memcpy(dest, src, num);
4293
llvm_memmove_i32: 'memmove',
4294
llvm_memmove_i64: 'memmove',
4295
llvm_memmove_p0i8_p0i8_i32: 'memmove',
4296
llvm_memmove_p0i8_p0i8_i64: 'memmove',
4298
memset__inline: function(ptr, value, num, align) {
4299
return makeSetValues(ptr, 0, value, 'null', num, align);
4301
memset__sig: 'viii',
4303
memset: function(ptr, value, num) {
4304
#if USE_TYPED_ARRAYS == 2
4305
ptr = ptr|0; value = value|0; num = num|0;
4306
var stop = 0, value4 = 0, stop4 = 0, unaligned = 0;
4307
stop = (ptr + num)|0;
4308
if ((num|0) >= {{{ Math.round(2.5*UNROLL_LOOP_MAX) }}}) {
4309
// This is unaligned, but quite large, so work hard to get to aligned settings
4310
value = value & 0xff;
4311
unaligned = ptr & 3;
4312
value4 = value | (value << 8) | (value << 16) | (value << 24);
4315
unaligned = (ptr + 4 - unaligned)|0;
4316
while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num
4317
{{{ makeSetValueAsm('ptr', 0, 'value', 'i8') }}};
4321
while ((ptr|0) < (stop4|0)) {
4322
{{{ makeSetValueAsm('ptr', 0, 'value4', 'i32') }}};
4326
while ((ptr|0) < (stop|0)) {
4327
{{{ makeSetValueAsm('ptr', 0, 'value', 'i8') }}};
4331
{{{ makeSetValues('ptr', '0', 'value', 'null', 'num') }}};
4334
llvm_memset_i32: 'memset',
4335
llvm_memset_p0i8_i32: 'memset',
4336
llvm_memset_p0i8_i64: 'memset',
4340
strlen: function(ptr) {
4344
while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}) {
4345
curr = (curr + 1)|0;
4347
return (curr - ptr)|0;
4350
strspn: function(pstr, pset) {
4351
var str = pstr, set, strcurr, setcurr;
4353
strcurr = {{{ makeGetValue('str', '0', 'i8') }}};
4354
if (!strcurr) return str - pstr;
4357
setcurr = {{{ makeGetValue('set', '0', 'i8') }}};
4358
if (!setcurr || setcurr == strcurr) break;
4361
if (!setcurr) return str - pstr;
4366
strcspn: function(pstr, pset) {
4367
var str = pstr, set, strcurr, setcurr;
4369
strcurr = {{{ makeGetValue('str', '0', 'i8') }}};
4370
if (!strcurr) return str - pstr;
4373
setcurr = {{{ makeGetValue('set', '0', 'i8') }}};
4374
if (!setcurr || setcurr == strcurr) break;
4377
if (setcurr) return str - pstr;
4384
strcpy: function(pdest, psrc) {
4385
pdest = pdest|0; psrc = psrc|0;
4388
{{{ makeCopyValues('(pdest+i)|0', '(psrc+i)|0', 1, 'i8', null, 1) }}};
4390
} while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}});
4394
stpcpy: function(pdest, psrc) {
4397
{{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}};
4399
} while ({{{ makeGetValue('psrc', 'i-1', 'i8') }}} != 0);
4400
return pdest + i - 1;
4404
strncpy__sig: 'iiii',
4405
strncpy: function(pdest, psrc, num) {
4406
pdest = pdest|0; psrc = psrc|0; num = num|0;
4407
var padding = 0, curr = 0, i = 0;
4408
while ((i|0) < (num|0)) {
4409
curr = padding ? 0 : {{{ makeGetValueAsm('psrc', 'i', 'i8') }}};
4410
{{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}}
4411
padding = padding ? 1 : ({{{ makeGetValueAsm('psrc', 'i', 'i8') }}} == 0);
4417
strlwr__deps:['tolower'],
4418
strlwr: function(pstr){
4421
var x = {{{ makeGetValue('pstr', 'i', 'i8') }}};
4423
{{{ makeSetValue('pstr', 'i', '_tolower(x)', 'i8') }}};
4428
strupr__deps:['toupper'],
4429
strupr: function(pstr){
4432
var x = {{{ makeGetValue('pstr', 'i', 'i8') }}};
4434
{{{ makeSetValue('pstr', 'i', '_toupper(x)', 'i8') }}};
4441
strcat__deps: ['strlen'],
4442
strcat: function(pdest, psrc) {
4443
pdest = pdest|0; psrc = psrc|0;
4445
pdest = (pdest + (_strlen(pdest)|0))|0;
4447
{{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}};
4449
} while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}});
4453
strncat__deps: ['strlen'],
4454
strncat: function(pdest, psrc, num) {
4455
var len = _strlen(pdest);
4458
{{{ makeCopyValues('pdest+len+i', 'psrc+i', 1, 'i8', null, 1) }}};
4459
if ({{{ makeGetValue('pdest', 'len+i', 'i8') }}} == 0) break;
4462
{{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}}
4469
strcmp__deps: ['strncmp'],
4470
strcmp: function(px, py) {
4471
return _strncmp(px, py, TOTAL_MEMORY);
4473
// We always assume ASCII locale.
4476
strcasecmp__asm: true,
4477
strcasecmp__sig: 'iii',
4478
strcasecmp__deps: ['strncasecmp'],
4479
strcasecmp: function(px, py) {
4480
px = px|0; py = py|0;
4481
return _strncasecmp(px, py, -1)|0;
4484
strncmp: function(px, py, n) {
4487
var x = {{{ makeGetValue('px', 'i', 'i8', 0, 1) }}};
4488
var y = {{{ makeGetValue('py', 'i', 'i8', 0, 1) }}};
4489
if (x == y && x == 0) return 0;
4490
if (x == 0) return -1;
4491
if (y == 0) return 1;
4496
return x > y ? 1 : -1;
4502
strncasecmp__asm: true,
4503
strncasecmp__sig: 'iiii',
4504
strncasecmp__deps: ['tolower'],
4505
strncasecmp: function(px, py, n) {
4506
px = px|0; py = py|0; n = n|0;
4507
var i = 0, x = 0, y = 0;
4508
while ((i>>>0) < (n>>>0)) {
4509
x = _tolower({{{ makeGetValueAsm('px', 'i', 'i8', 0, 1) }}})|0;
4510
y = _tolower({{{ makeGetValueAsm('py', 'i', 'i8', 0, 1) }}})|0;
4511
if (((x|0) == (y|0)) & ((x|0) == 0)) return 0;
4512
if ((x|0) == 0) return -1;
4513
if ((y|0) == 0) return 1;
4514
if ((x|0) == (y|0)) {
4518
return ((x>>>0) > (y>>>0) ? 1 : -1)|0;
4525
memcmp__sig: 'iiii',
4526
memcmp: function(p1, p2, num) {
4527
p1 = p1|0; p2 = p2|0; num = num|0;
4528
var i = 0, v1 = 0, v2 = 0;
4529
while ((i|0) < (num|0)) {
4530
var v1 = {{{ makeGetValueAsm('p1', 'i', 'i8', true) }}};
4531
var v2 = {{{ makeGetValueAsm('p2', 'i', 'i8', true) }}};
4532
if ((v1|0) != (v2|0)) return ((v1|0) > (v2|0) ? 1 : -1)|0;
4538
memchr: function(ptr, chr, num) {
4540
for (var i = 0; i < num; i++) {
4541
if ({{{ makeGetValue('ptr', 0, 'i8') }}} == chr) return ptr;
4547
strstr: function(ptr1, ptr2) {
4548
var check = 0, start;
4554
var curr1 = {{{ makeGetValue('ptr1++', 0, 'i8') }}};
4555
var curr2 = {{{ makeGetValue('check++', 0, 'i8') }}};
4556
if (curr2 == 0) return start;
4557
if (curr2 != curr1) {
4558
// rewind to one character after start, to find ez in eeez
4566
strchr: function(ptr, chr) {
4570
var val = {{{ makeGetValue('ptr', 0, 'i8') }}};
4571
if (val == chr) return ptr;
4577
strrchr__deps: ['strlen'],
4578
strrchr: function(ptr, chr) {
4579
var ptr2 = ptr + _strlen(ptr);
4581
if ({{{ makeGetValue('ptr2', 0, 'i8') }}} == chr) return ptr2;
4583
} while (ptr2 >= ptr);
4588
strdup__deps: ['strlen'],
4589
strdup: function(ptr) {
4590
var len = _strlen(ptr);
4591
var newStr = _malloc(len + 1);
4592
{{{ makeCopyValues('newStr', 'ptr', 'len', 'null', null, 1) }}};
4593
{{{ makeSetValue('newStr', 'len', '0', 'i8') }}};
4597
strndup__deps: ['strdup', 'strlen'],
4598
strndup: function(ptr, size) {
4599
var len = _strlen(ptr);
4602
return _strdup(ptr);
4609
var newStr = _malloc(size + 1);
4610
{{{ makeCopyValues('newStr', 'ptr', 'size', 'null', null, 1) }}};
4611
{{{ makeSetValue('newStr', 'size', '0', 'i8') }}};
4615
strpbrk: function(ptr1, ptr2) {
4619
var curr = {{{ makeGetValue('ptr2++', 0, 'i8') }}};
4621
searchSet[curr] = 1;
4624
curr = {{{ makeGetValue('ptr1', 0, 'i8') }}};
4626
if (curr in searchSet) return ptr1;
4633
strtok__deps: ['__strtok_state', 'strtok_r'],
4634
strtok__postset: '___strtok_state = Runtime.staticAlloc(4);',
4635
strtok: function(s, delim) {
4636
return _strtok_r(s, delim, ___strtok_state);
4639
// Translated from newlib; for the original source and licensing, see library_strtok_r.c
4640
strtok_r: function(s, delim, lasts) {
4641
var skip_leading_delim = 1;
4647
if (s == 0 && (s = getValue(lasts, 'i8*')) == 0) {
4652
c = getValue(s++, 'i8');
4653
for (spanp = delim; (sc = getValue(spanp++, 'i8')) != 0;) {
4655
if (skip_leading_delim) {
4658
setValue(lasts, s, 'i8*');
4659
setValue(s - 1, 0, 'i8');
4668
setValue(lasts, 0, 'i8*');
4674
c = getValue(s++, 'i8');
4677
if ((sc = getValue(spanp++, 'i8')) == c) {
4681
setValue(s - 1, 0, 'i8');
4683
setValue(lasts, s, 'i8*');
4688
abort('strtok_r error!');
4691
strerror_r__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo'],
4692
strerror_r: function(errnum, strerrbuf, buflen) {
4693
if (errnum in ERRNO_MESSAGES) {
4694
if (ERRNO_MESSAGES[errnum].length > buflen - 1) {
4695
return ___setErrNo(ERRNO_CODES.ERANGE);
4697
var msg = ERRNO_MESSAGES[errnum];
4698
for (var i = 0; i < msg.length; i++) {
4699
{{{ makeSetValue('strerrbuf', 'i', 'msg.charCodeAt(i)', 'i8') }}}
4701
{{{ makeSetValue('strerrbuf', 'i', 0, 'i8') }}}
4705
return ___setErrNo(ERRNO_CODES.EINVAL);
4708
strerror__deps: ['strerror_r'],
4709
strerror: function(errnum) {
4710
if (!_strerror.buffer) _strerror.buffer = _malloc(256);
4711
_strerror_r(errnum, _strerror.buffer, 256);
4712
return _strerror.buffer;
4715
// ==========================================================================
4717
// ==========================================================================
4719
isascii: function(chr) {
4720
return chr >= 0 && (chr & 0x80) == 0;
4722
toascii: function(chr) {
4725
toupper: function(chr) {
4726
if (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) {
4727
return chr - {{{ charCode('a') }}} + {{{ charCode('A') }}};
4732
_toupper: 'toupper',
4736
tolower: function(chr) {
4738
if ((chr|0) < {{{ charCode('A') }}}) return chr|0;
4739
if ((chr|0) > {{{ charCode('Z') }}}) return chr|0;
4740
return (chr - {{{ charCode('A') }}} + {{{ charCode('a') }}})|0;
4742
_tolower: 'tolower',
4744
// The following functions are defined as macros in glibc.
4745
islower: function(chr) {
4746
return chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}};
4748
isupper: function(chr) {
4749
return chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}};
4751
isalpha: function(chr) {
4752
return (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) ||
4753
(chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}});
4755
isdigit: function(chr) {
4756
return chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}};
4758
isdigit_l: 'isdigit', // no locale support yet
4759
isxdigit: function(chr) {
4760
return (chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}) ||
4761
(chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('f') }}}) ||
4762
(chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('F') }}});
4764
isxdigit_l: 'isxdigit', // no locale support yet
4765
isalnum: function(chr) {
4766
return (chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}) ||
4767
(chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) ||
4768
(chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}});
4770
ispunct: function(chr) {
4771
return (chr >= {{{ charCode('!') }}} && chr <= {{{ charCode('/') }}}) ||
4772
(chr >= {{{ charCode(':') }}} && chr <= {{{ charCode('@') }}}) ||
4773
(chr >= {{{ charCode('[') }}} && chr <= {{{ charCode('`') }}}) ||
4774
(chr >= {{{ charCode('{') }}} && chr <= {{{ charCode('~') }}});
4776
isspace: function(chr) {
4777
return chr in { 32: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0 };
4779
isblank: function(chr) {
4780
return chr == {{{ charCode(' ') }}} || chr == {{{ charCode('\t') }}};
4782
iscntrl: function(chr) {
4783
return (0 <= chr && chr <= 0x1F) || chr === 0x7F;
4785
isprint: function(chr) {
4786
return 0x1F < chr && chr < 0x7F;
4789
// Lookup tables for glibc ctype implementation.
4790
__ctype_b_loc: function() {
4791
// http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---ctype-b-loc.html
4792
var me = ___ctype_b_loc;
4795
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,
4796
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,
4797
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,
4798
49156,49156,49156,49156,49156,49156,49156,49156,49156,49156,49156,49156,55304,55304,55304,55304,55304,55304,55304,55304,
4799
55304,55304,49156,49156,49156,49156,49156,49156,49156,54536,54536,54536,54536,54536,54536,50440,50440,50440,50440,50440,
4800
50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,50440,49156,49156,49156,49156,49156,
4801
49156,54792,54792,54792,54792,54792,54792,50696,50696,50696,50696,50696,50696,50696,50696,50696,50696,50696,50696,50696,
4802
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,
4803
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,
4804
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
4806
var i16size = {{{ Runtime.getNativeTypeSize('i16') }}};
4807
var arr = _malloc(values.length * i16size);
4808
for (var i = 0; i < values.length; i++) {
4809
{{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}}
4811
me.ret = allocate([arr + 128 * i16size], 'i16*', ALLOC_NORMAL);
4815
__ctype_tolower_loc: function() {
4816
// http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/libutil---ctype-tolower-loc.html
4817
var me = ___ctype_tolower_loc;
4820
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,
4821
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,
4822
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,
4823
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,
4824
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,
4825
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,
4826
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,
4827
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,
4828
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,
4829
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,
4830
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,
4831
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,
4834
var i32size = {{{ Runtime.getNativeTypeSize('i32') }}};
4835
var arr = _malloc(values.length * i32size);
4836
for (var i = 0; i < values.length; i++) {
4837
{{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}
4839
me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
4843
__ctype_toupper_loc: function() {
4844
// http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/libutil---ctype-toupper-loc.html
4845
var me = ___ctype_toupper_loc;
4848
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,
4849
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,
4850
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,
4851
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,
4852
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,
4853
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,
4854
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,
4855
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,
4856
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,
4857
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,
4858
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,
4859
235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
4861
var i32size = {{{ Runtime.getNativeTypeSize('i32') }}};
4862
var arr = _malloc(values.length * i32size);
4863
for (var i = 0; i < values.length; i++) {
4864
{{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}
4866
me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
4871
// ==========================================================================
4873
// ==========================================================================
4875
llvm_va_start__inline: function(ptr) {
4876
// varargs - we received a pointer to the varargs as a final 'extra' parameter called 'varrp'
4878
return makeSetValue(ptr, 0, 'varrp', 'void*');
4881
// 4-word structure: start, current offset
4882
return makeSetValue(ptr, 0, 'varrp', 'void*') + ';' + makeSetValue(ptr, 4, 0, 'void*');
4886
llvm_va_end: function() {},
4888
llvm_va_copy: function(ppdest, ppsrc) {
4889
{{{ makeCopyValues('ppdest', 'ppsrc', Runtime.QUANTUM_SIZE, 'null', null, 1) }}};
4890
/* Alternate implementation that copies the actual DATA; it assumes the va_list is prefixed by its size
4891
var psrc = IHEAP[ppsrc]-1;
4892
var num = IHEAP[psrc]; // right before the data, is the number of (flattened) values
4893
var pdest = _malloc(num+1);
4894
_memcpy(pdest, psrc, num+1);
4895
IHEAP[ppdest] = pdest+1;
4899
llvm_bswap_i16: function(x) {
4900
return ((x&0xff)<<8) | ((x>>8)&0xff);
4903
llvm_bswap_i32: function(x) {
4904
return ((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24);
4907
llvm_bswap_i64__deps: ['llvm_bswap_i32'],
4908
llvm_bswap_i64: function(l, h) {
4909
var retl = _llvm_bswap_i32(h)>>>0;
4910
var reth = _llvm_bswap_i32(l)>>>0;
4911
#if USE_TYPED_ARRAYS == 2
4912
{{{ makeStructuralReturn(['retl', 'reth']) }}};
4914
throw 'unsupported';
4918
llvm_ctlz_i32__deps: [function() {
4920
for (var i = 0; i < 8; i++) {
4921
if (x & (1 << (7-i))) {
4927
return 'var ctlz_i8 = allocate([' + range(256).map(function(x) { return ctlz(x) }).join(',') + '], "i8", ALLOC_STACK);';
4929
llvm_ctlz_i32__asm: true,
4930
llvm_ctlz_i32__sig: 'ii',
4931
llvm_ctlz_i32: function(x) {
4934
ret = {{{ makeGetValueAsm('ctlz_i8', 'x >>> 24', 'i8') }}};
4935
if ((ret|0) < 8) return ret|0;
4936
var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 16)&0xff', 'i8') }}};
4937
if ((ret|0) < 8) return (ret + 8)|0;
4938
var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 8)&0xff', 'i8') }}};
4939
if ((ret|0) < 8) return (ret + 16)|0;
4940
return ({{{ makeGetValueAsm('ctlz_i8', 'x&0xff', 'i8') }}} + 24)|0;
4943
llvm_ctlz_i64__deps: ['llvm_ctlz_i32'],
4944
llvm_ctlz_i64: function(l, h) {
4945
var ret = _llvm_ctlz_i32(h);
4946
if (ret == 32) ret += _llvm_ctlz_i32(l);
4947
#if USE_TYPED_ARRAYS == 2
4948
{{{ makeStructuralReturn(['ret', '0']) }}};
4954
llvm_cttz_i32__deps: [function() {
4956
for (var i = 0; i < 8; i++) {
4963
return 'var cttz_i8 = allocate([' + range(256).map(function(x) { return cttz(x) }).join(',') + '], "i8", ALLOC_STACK);';
4965
llvm_cttz_i32__asm: true,
4966
llvm_cttz_i32__sig: 'ii',
4967
llvm_cttz_i32: function(x) {
4970
ret = {{{ makeGetValueAsm('cttz_i8', 'x & 0xff', 'i8') }}};
4971
if ((ret|0) < 8) return ret|0;
4972
var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 8)&0xff', 'i8') }}};
4973
if ((ret|0) < 8) return (ret + 8)|0;
4974
var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 16)&0xff', 'i8') }}};
4975
if ((ret|0) < 8) return (ret + 16)|0;
4976
return ({{{ makeGetValueAsm('cttz_i8', 'x >>> 24', 'i8') }}} + 24)|0;
4979
llvm_cttz_i64__deps: ['llvm_cttz_i32'],
4980
llvm_cttz_i64: function(l, h) {
4981
var ret = _llvm_cttz_i32(l);
4982
if (ret == 32) ret += _llvm_cttz_i32(h);
4983
#if USE_TYPED_ARRAYS == 2
4984
{{{ makeStructuralReturn(['ret', '0']) }}};
4990
llvm_ctpop_i32: function(x) {
4999
llvm_ctpop_i64__deps: ['llvm_ctpop_i32'],
5000
llvm_ctpop_i64: function(l, h) {
5001
return _llvm_ctpop_i32(l) + _llvm_ctpop_i32(h);
5004
llvm_trap: function() {
5005
throw 'trap! ' + new Error().stack;
5008
__assert_fail: function(condition, file, line) {
5010
throw 'Assertion failed: ' + Pointer_stringify(condition) + ' at ' + new Error().stack;
5013
__assert_func: function(filename, line, func, condition) {
5014
throw 'Assertion failed: ' + (condition ? Pointer_stringify(condition) : 'unknown condition') + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + new Error().stack;
5017
__cxa_guard_acquire: function(variable) {
5018
if (!{{{ makeGetValue(0, 'variable', 'i8', null, null, 1) }}}) { // ignore SAFE_HEAP stuff because llvm mixes i64 and i8 here
5019
{{{ makeSetValue(0, 'variable', '1', 'i8') }}};
5024
__cxa_guard_release: function() {},
5025
__cxa_guard_abort: function() {},
5027
_ZTVN10__cxxabiv119__pointer_type_infoE: [0], // is a pointer
5028
_ZTVN10__cxxabiv117__class_type_infoE: [1], // no inherited classes
5029
_ZTVN10__cxxabiv120__si_class_type_infoE: [2], // yes inherited classes
5032
__cxa_allocate_exception: function(size) {
5033
return _malloc(size);
5035
__cxa_free_exception: function(ptr) {
5038
__cxa_throw__sig: 'viii',
5039
__cxa_throw__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'],
5040
__cxa_throw: function(ptr, type, destructor) {
5041
if (!___cxa_throw.initialized) {
5043
{{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv119__pointer_type_infoE'), '0', '0', 'i32') }}}; // Workaround for libcxxabi integration bug
5046
{{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv117__class_type_infoE'), '0', '1', 'i32') }}}; // Workaround for libcxxabi integration bug
5049
{{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv120__si_class_type_infoE'), '0', '2', 'i32') }}}; // Workaround for libcxxabi integration bug
5051
___cxa_throw.initialized = true;
5054
Module.printErr('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + new Error().stack);
5056
{{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}}
5057
{{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'type', 'void*') }}}
5058
{{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'destructor', 'void*') }}}
5059
if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
5060
__ZSt18uncaught_exceptionv.uncaught_exception = 1;
5062
__ZSt18uncaught_exceptionv.uncaught_exception++;
5064
{{{ makeThrow('ptr') }}};
5066
__cxa_rethrow__deps: ['llvm_eh_exception', '__cxa_end_catch'],
5067
__cxa_rethrow: function() {
5068
___cxa_end_catch.rethrown = true;
5069
{{{ makeThrow(makeGetValue('_llvm_eh_exception.buf', '0', 'void*')) }}};
5071
llvm_eh_exception__postset: '_llvm_eh_exception.buf = allocate(12, "void*", ALLOC_STATIC);',
5072
llvm_eh_exception: function() {
5073
return {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
5075
llvm_eh_selector__jsargs: true,
5076
llvm_eh_selector: function(unused_exception_value, personality/*, varargs*/) {
5077
var type = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}}
5078
for (var i = 2; i < arguments.length; i++) {
5079
if (arguments[i] == type) return type;
5083
llvm_eh_typeid_for: function(type) {
5086
__cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv'],
5087
__cxa_begin_catch: function(ptr) {
5088
__ZSt18uncaught_exceptionv.uncaught_exception--;
5091
__cxa_end_catch__deps: ['llvm_eh_exception', '__cxa_free_exception'],
5092
__cxa_end_catch: function() {
5093
if (___cxa_end_catch.rethrown) {
5094
___cxa_end_catch.rethrown = false;
5097
// Clear state flag.
5104
{{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}}
5105
// Call destructor if one is registered then clear it.
5106
var ptr = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
5107
var destructor = {{{ makeGetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'void*') }}};
5109
Runtime.dynCall('vi', destructor, [ptr]);
5110
{{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}}
5112
// Free ptr if it isn't null.
5114
___cxa_free_exception(ptr);
5115
{{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}}
5118
__cxa_get_exception_ptr__deps: ['llvm_eh_exception'],
5119
__cxa_get_exception_ptr: function(ptr) {
5122
_ZSt18uncaught_exceptionv: function() { // std::uncaught_exception()
5123
return !!__ZSt18uncaught_exceptionv.uncaught_exception;
5125
__cxa_uncaught_exception__deps: ['_Zst18uncaught_exceptionv'],
5126
__cxa_uncaught_exception: function() {
5127
return !!__ZSt18uncaught_exceptionv.uncaught_exception;
5130
__cxa_call_unexpected: function(exception) {
5131
Module.printErr('Unexpected exception thrown, this is not properly supported - aborting');
5136
_Unwind_Resume_or_Rethrow: function(ptr) {
5137
{{{ makeThrow('ptr') }}};
5139
_Unwind_RaiseException: function(ptr) {
5140
{{{ makeThrow('ptr') }}};
5142
_Unwind_DeleteException: function(ptr) {},
5144
terminate: '__cxa_call_unexpected',
5146
__gxx_personality_v0: function() {
5149
__cxa_is_number_type: function(type) {
5150
var isNumber = false;
5151
try { if (type == {{{ makeGlobalUse('__ZTIi') }}}) isNumber = true } catch(e){}
5152
try { if (type == {{{ makeGlobalUse('__ZTIj') }}}) isNumber = true } catch(e){}
5153
try { if (type == {{{ makeGlobalUse('__ZTIl') }}}) isNumber = true } catch(e){}
5154
try { if (type == {{{ makeGlobalUse('__ZTIm') }}}) isNumber = true } catch(e){}
5155
try { if (type == {{{ makeGlobalUse('__ZTIx') }}}) isNumber = true } catch(e){}
5156
try { if (type == {{{ makeGlobalUse('__ZTIy') }}}) isNumber = true } catch(e){}
5157
try { if (type == {{{ makeGlobalUse('__ZTIf') }}}) isNumber = true } catch(e){}
5158
try { if (type == {{{ makeGlobalUse('__ZTId') }}}) isNumber = true } catch(e){}
5159
try { if (type == {{{ makeGlobalUse('__ZTIe') }}}) isNumber = true } catch(e){}
5160
try { if (type == {{{ makeGlobalUse('__ZTIc') }}}) isNumber = true } catch(e){}
5161
try { if (type == {{{ makeGlobalUse('__ZTIa') }}}) isNumber = true } catch(e){}
5162
try { if (type == {{{ makeGlobalUse('__ZTIh') }}}) isNumber = true } catch(e){}
5163
try { if (type == {{{ makeGlobalUse('__ZTIs') }}}) isNumber = true } catch(e){}
5164
try { if (type == {{{ makeGlobalUse('__ZTIt') }}}) isNumber = true } catch(e){}
5168
// Finds a suitable catch clause for when an exception is thrown.
5169
// In normal compilers, this functionality is handled by the C++
5170
// 'personality' routine. This is passed a fairly complex structure
5171
// relating to the context of the exception and makes judgements
5172
// about how to handle it. Some of it is about matching a suitable
5173
// catch clause, and some of it is about unwinding. We already handle
5174
// unwinding using 'if' blocks around each function, so the remaining
5175
// functionality boils down to picking a suitable 'catch' block.
5176
// We'll do that here, instead, to keep things simpler.
5178
__cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type', '__resumeException'],
5179
__cxa_find_matching_catch: function(thrown, throwntype) {
5180
if (thrown == -1) thrown = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
5181
if (throwntype == -1) throwntype = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}};
5182
var typeArray = Array.prototype.slice.call(arguments, 2);
5184
// If throwntype is a pointer, this means a pointer has been
5185
// thrown. When a pointer is thrown, actually what's thrown
5186
// is a pointer to the pointer. We'll dereference it.
5187
if (throwntype != 0 && !___cxa_is_number_type(throwntype)) {
5188
var throwntypeInfoAddr= {{{ makeGetValue('throwntype', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}};
5189
var throwntypeInfo= {{{ makeGetValue('throwntypeInfoAddr', '0', '*') }}};
5190
if (throwntypeInfo == 0)
5191
thrown = {{{ makeGetValue('thrown', '0', '*') }}};
5193
// The different catch blocks are denoted by different types.
5194
// Due to inheritance, those types may not precisely match the
5195
// type of the thrown object. Find one which matches, and
5196
// return the type of the catch block which should be called.
5197
for (var i = 0; i < typeArray.length; i++) {
5198
if (___cxa_does_inherit(typeArray[i], throwntype, thrown))
5199
{{{ makeStructuralReturn(['thrown', 'typeArray[i]']) }}};
5201
// Shouldn't happen unless we have bogus data in typeArray
5202
// or encounter a type for which emscripten doesn't have suitable
5203
// typeinfo defined. Best-efforts match just in case.
5204
{{{ makeStructuralReturn(['thrown', 'throwntype']) }}};
5207
__resumeException__deps: [function() { Functions.libraryFunctions['__resumeException'] = 1 }], // will be called directly from compiled code
5208
__resumeException: function(ptr) {
5210
Module.print("Resuming exception");
5212
if ({{{ makeGetValue('_llvm_eh_exception.buf', 0, 'void*') }}} == 0) {{{ makeSetValue('_llvm_eh_exception.buf', 0, 'ptr', 'void*') }}};
5213
{{{ makeThrow('ptr') }}};
5216
// Recursively walks up the base types of 'possibilityType'
5217
// to see if any of them match 'definiteType'.
5218
__cxa_does_inherit__deps: ['__cxa_is_number_type'],
5219
__cxa_does_inherit: function(definiteType, possibilityType, possibility) {
5220
if (possibility == 0) return false;
5221
if (possibilityType == 0 || possibilityType == definiteType)
5223
var possibility_type_info;
5224
if (___cxa_is_number_type(possibilityType)) {
5225
possibility_type_info = possibilityType;
5227
var possibility_type_infoAddr = {{{ makeGetValue('possibilityType', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}};
5228
possibility_type_info = {{{ makeGetValue('possibility_type_infoAddr', '0', '*') }}};
5230
switch (possibility_type_info) {
5231
case 0: // possibility is a pointer
5232
// See if definite type is a pointer
5233
var definite_type_infoAddr = {{{ makeGetValue('definiteType', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}};
5234
var definite_type_info = {{{ makeGetValue('definite_type_infoAddr', '0', '*') }}};
5235
if (definite_type_info == 0) {
5236
// Also a pointer; compare base types of pointers
5237
var defPointerBaseAddr = definiteType+{{{ Runtime.QUANTUM_SIZE*2 }}};
5238
var defPointerBaseType = {{{ makeGetValue('defPointerBaseAddr', '0', '*') }}};
5239
var possPointerBaseAddr = possibilityType+{{{ Runtime.QUANTUM_SIZE*2 }}};
5240
var possPointerBaseType = {{{ makeGetValue('possPointerBaseAddr', '0', '*') }}};
5241
return ___cxa_does_inherit(defPointerBaseType, possPointerBaseType, possibility);
5243
return false; // one pointer and one non-pointer
5244
case 1: // class with no base class
5246
case 2: // class with base class
5247
var parentTypeAddr = possibilityType + {{{ Runtime.QUANTUM_SIZE*2 }}};
5248
var parentType = {{{ makeGetValue('parentTypeAddr', '0', '*') }}};
5249
return ___cxa_does_inherit(definiteType, parentType, possibility);
5251
return false; // some unencountered type
5255
_ZNSt9exceptionD2Ev: function(){}, // XXX a dependency of dlmalloc, but not actually needed if libcxx is not anyhow included
5257
_ZNSt9type_infoD2Ev: function(){},
5259
// RTTI hacks for exception handling, defining type_infos for common types.
5260
// The values are dummies. We simply use the addresses of these statically
5261
// allocated variables as unique identifiers.
5264
_ZTIj: [0], // unsigned int
5266
_ZTIm: [0], // unsigned long
5267
_ZTIx: [0], // long long
5268
_ZTIy: [0], // unsigned long long
5269
_ZTIf: [0], // float
5270
_ZTId: [0], // double
5271
_ZTIe: [0], // long double
5273
_ZTIa: [0], // signed char
5274
_ZTIh: [0], // unsigned char
5275
_ZTIs: [0], // short
5276
_ZTIt: [0], // unsigned short
5278
_ZTIPv: [0], // void*
5280
llvm_uadd_with_overflow_i8: function(x, y) {
5283
{{{ makeStructuralReturn(['(x+y) & 0xff', 'x+y > 255']) }}};
5286
llvm_umul_with_overflow_i8: function(x, y) {
5289
{{{ makeStructuralReturn(['(x*y) & 0xff', 'x*y > 255']) }}};
5292
llvm_uadd_with_overflow_i16: function(x, y) {
5295
{{{ makeStructuralReturn(['(x+y) & 0xffff', 'x+y > 65535']) }}};
5298
llvm_umul_with_overflow_i16: function(x, y) {
5301
{{{ makeStructuralReturn(['(x*y) & 0xffff', 'x*y > 65535']) }}};
5304
llvm_uadd_with_overflow_i32: function(x, y) {
5307
{{{ makeStructuralReturn(['(x+y)>>>0', 'x+y > 4294967295']) }}};
5310
llvm_umul_with_overflow_i32: function(x, y) {
5313
{{{ makeStructuralReturn(['(x*y)>>>0', 'x*y > 4294967295']) }}};
5316
llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }],
5317
llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) {
5319
Runtime.warnOnce('no overflow support in llvm_umul_with_overflow_i64');
5321
var low = ___muldi3(xl, xh, yl, yh);
5322
{{{ makeStructuralReturn(['low', 'tempRet0', '0']) }}};
5325
llvm_stacksave: function() {
5326
var self = _llvm_stacksave;
5327
if (!self.LLVM_SAVEDSTACKS) {
5328
self.LLVM_SAVEDSTACKS = [];
5330
self.LLVM_SAVEDSTACKS.push(Runtime.stackSave());
5331
return self.LLVM_SAVEDSTACKS.length-1;
5333
llvm_stackrestore: function(p) {
5334
var self = _llvm_stacksave;
5335
var ret = self.LLVM_SAVEDSTACKS[p];
5336
self.LLVM_SAVEDSTACKS.splice(p, 1);
5337
Runtime.stackRestore(ret);
5340
__cxa_pure_virtual: function() {
5342
throw 'Pure virtual function called!';
5345
llvm_flt_rounds: function() {
5346
return -1; // 'indeterminable' for FLT_ROUNDS
5349
llvm_memory_barrier: function(){},
5351
llvm_atomic_load_add_i32_p0i32: function(ptr, delta) {
5352
var ret = {{{ makeGetValue('ptr', '0', 'i32') }}};
5353
{{{ makeSetValue('ptr', '0', 'ret+delta', 'i32') }}};
5357
llvm_expect_i32__inline: function(val, expected) {
5358
return '(' + val + ')';
5361
llvm_lifetime_start: function() {},
5362
llvm_lifetime_end: function() {},
5364
llvm_invariant_start: function() {},
5365
llvm_invariant_end: function() {},
5367
llvm_objectsize_i32: function() { return -1 }, // TODO: support this
5369
llvm_dbg_declare__inline: function() { throw 'llvm_debug_declare' }, // avoid warning
5371
// ==========================================================================
5372
// llvm-mono integration
5373
// ==========================================================================
5375
llvm_mono_load_i8_p0i8: function(ptr) {
5376
return {{{ makeGetValue('ptr', 0, 'i8') }}};
5379
llvm_mono_store_i8_p0i8: function(value, ptr) {
5380
{{{ makeSetValue('ptr', 0, 'value', 'i8') }}};
5383
llvm_mono_load_i16_p0i16: function(ptr) {
5384
return {{{ makeGetValue('ptr', 0, 'i16') }}};
5387
llvm_mono_store_i16_p0i16: function(value, ptr) {
5388
{{{ makeSetValue('ptr', 0, 'value', 'i16') }}};
5391
llvm_mono_load_i32_p0i32: function(ptr) {
5392
return {{{ makeGetValue('ptr', 0, 'i32') }}};
5395
llvm_mono_store_i32_p0i32: function(value, ptr) {
5396
{{{ makeSetValue('ptr', 0, 'value', 'i32') }}};
5399
// ==========================================================================
5401
// ==========================================================================
5415
atan2: 'Math.atan2',
5416
atan2f: 'Math.atan2',
5420
// The erf and erfc functions are inspired from
5421
// http://www.digitalmars.com/archives/cplusplus/3634.html
5422
// and mruby source code at
5423
// https://github.com/mruby/mruby/blob/master/src/math.c
5424
erfc: function (x) {
5425
var MATH_TOLERANCE = 1E-12;
5426
var ONE_SQRTPI = 0.564189583547756287;
5430
var d = x * x + 0.5;
5435
if (Math.abs(x) < 2.2) {
5436
return 1.0 - _erf(x);
5439
return 2.0 - _erfc(-x);
5451
} while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE);
5452
return (ONE_SQRTPI * Math.exp(- x * x) * q2);
5455
erf__deps: ['erfc'],
5457
var MATH_TOLERANCE = 1E-12;
5458
var TWO_SQRTPI = 1.128379167095512574;
5464
if (Math.abs(x) > 2.2) {
5465
return 1.0 - _erfc(x);
5469
sum -= term / (2 * j + 1);
5472
sum += term / (2 * j + 1);
5474
} while (Math.abs(term / sum) > MATH_TOLERANCE);
5475
return (TWO_SQRTPI * sum);
5486
floor: 'Math.floor',
5487
floorf: 'Math.floor',
5490
llvm_sqrt_f32: 'Math.sqrt',
5491
llvm_sqrt_f64: 'Math.sqrt',
5492
llvm_pow_f32: 'Math.pow',
5493
llvm_pow_f64: 'Math.pow',
5494
llvm_log_f32: 'Math.log',
5495
llvm_log_f64: 'Math.log',
5496
llvm_exp_f32: 'Math.exp',
5497
llvm_exp_f64: 'Math.exp',
5498
ldexp: function(x, exp_) {
5499
return x * Math.pow(2, exp_);
5508
return Math.pow(x, 1/3);
5513
modf: function(x, intpart) {
5514
{{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}}
5515
return x - {{{ makeGetValue('intpart', 0, 'double') }}};
5517
modff: function(x, intpart) {
5518
{{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}}
5519
return x - {{{ makeGetValue('intpart', 0, 'float') }}};
5521
frexp: function(x, exp_addr) {
5522
var sig = 0, exp_ = 0;
5524
var raw_exp = Math.log(x)/Math.log(2);
5525
exp_ = Math.ceil(raw_exp);
5526
if (exp_ === raw_exp) exp_ += 1;
5527
sig = x/Math.pow(2, exp_);
5529
{{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}}
5533
finite: function(x) {
5537
isinf: function(x) {
5538
return !isNaN(x) && !isFinite(x);
5541
isnan: function(x) {
5546
_reallyNegative: function(x) {
5547
return x < 0 || (x === 0 && (1/x) === -Infinity);
5550
copysign__deps: ['_reallyNegative'],
5551
copysign: function(a, b) {
5552
return __reallyNegative(a) === __reallyNegative(b) ? a : -a;
5554
copysignf: 'copysign',
5555
__signbit__deps: ['copysign'],
5556
__signbit: function(x) {
5557
// We implement using copysign so that we get support
5558
// for negative zero (once copysign supports that).
5559
return _copysign(1.0, x) < 0;
5561
__signbitf: '__signbit',
5562
__signbitd: '__signbit',
5563
hypot: function(a, b) {
5564
return Math.sqrt(a*a + b*b);
5568
var p = Math.pow(Math.E, x);
5569
return (p - (1 / p)) / 2;
5573
var p = Math.pow(Math.E, x);
5574
return (p + (1 / p)) / 2;
5577
tanh__deps: ['sinh', 'cosh'],
5579
return _sinh(x) / _cosh(x);
5582
asinh: function(x) {
5583
return Math.log(x + Math.sqrt(x * x + 1));
5586
acosh: function(x) {
5587
return Math.log(x * 1 + Math.sqrt(x * x - 1));
5590
atanh: function(x) {
5591
return Math.log((1 + x) / (1 - x)) / 2;
5595
return Math.pow(2, x);
5598
expm1: function(x) {
5599
return Math.exp(x) - 1;
5602
round: function(x) {
5603
return (x < 0) ? -Math.round(-x) : Math.round(x);
5611
return (x > 0) ? -Math.round(-x) : Math.round(x);
5620
trunc: function(x) {
5621
return (x < 0) ? Math.ceil(x) : Math.floor(x);
5624
fdim: function(x, y) {
5625
return (x > y) ? x - y : 0;
5628
fmax: function(x, y) {
5629
return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y);
5632
fmin: function(x, y) {
5633
return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y);
5636
fma: function(x, y, z) {
5640
fmod: function(x, y) {
5646
log10: function(x) {
5647
return Math.log(x) / Math.LN10;
5650
log1p: function(x) {
5651
return Math.log(1 + x);
5655
return Math.log(x) / Math.LN2;
5663
sincos: function(x, sine, cosine) {
5664
var sineVal = Math.sin(x),
5665
cosineVal = Math.cos(x);
5666
{{{ makeSetValue('sine', '0', 'sineVal', 'double') }}};
5667
{{{ makeSetValue('cosine', '0', 'cosineVal', 'double') }}};
5670
sincosf: function(x, sine, cosine) {
5671
var sineVal = Math.sin(x),
5672
cosineVal = Math.cos(x);
5673
{{{ makeSetValue('sine', '0', 'sineVal', 'float') }}};
5674
{{{ makeSetValue('cosine', '0', 'cosineVal', 'float') }}};
5677
__div_t_struct_layout: Runtime.generateStructInfo([
5681
div__deps: ['__div_t_struct_layout'],
5682
div: function(divt, numer, denom) {
5683
var quot = Math.floor(numer / denom);
5684
var rem = numer - quot * denom;
5685
var offset = ___div_t_struct_layout.rem;
5686
{{{ makeSetValue('divt', '0', 'quot', 'i32') }}};
5687
{{{ makeSetValue('divt', 'offset', 'rem', 'i32') }}};
5691
__fpclassifyf: function(x) {
5692
if (isNaN(x)) return {{{ cDefine('FP_NAN') }}};
5693
if (!isFinite(x)) return {{{ cDefine('FP_INFINITE') }}};
5694
if (x == 0) return {{{ cDefine('FP_ZERO') }}};
5696
return {{{ cDefine('FP_NORMAL') }}};
5698
__fpclassifyd: '__fpclassifyf',
5700
// ==========================================================================
5702
// ==========================================================================
5704
__utsname_struct_layout: Runtime.generateStructInfo([
5706
['b32', 'nodename'],
5709
['b32', 'machine']]),
5710
uname__deps: ['__utsname_struct_layout'],
5711
uname: function(name) {
5712
// int uname(struct utsname *name);
5713
// http://pubs.opengroup.org/onlinepubs/009695399/functions/uname.html
5714
function copyString(element, value) {
5715
var offset = ___utsname_struct_layout[element];
5716
for (var i = 0; i < value.length; i++) {
5717
{{{ makeSetValue('name', 'offset + i', 'value.charCodeAt(i)', 'i8') }}}
5719
{{{ makeSetValue('name', 'offset + i', '0', 'i8') }}}
5724
copyString('sysname', 'Emscripten');
5725
copyString('nodename', 'emscripten');
5726
copyString('release', '1.0');
5727
copyString('version', '#1');
5728
copyString('machine', 'x86-JS');
5733
// ==========================================================================
5734
// dlfcn.h - Dynamic library loading
5736
// Some limitations:
5738
// * Minification on each file separately may not work, as they will
5739
// have different shortened names. You can in theory combine them, then
5740
// minify, then split... perhaps.
5742
// * LLVM optimizations may fail. If the child wants to access a function
5743
// in the parent, LLVM opts may remove it from the parent when it is
5744
// being compiled. Not sure how to tell LLVM to not do so.
5745
// ==========================================================================
5747
// Data for dlfcn.h.
5751
loadedLibs: {}, // handle -> [refcount, name, lib_object]
5752
loadedLibNames: {}, // name -> handle
5754
// void* dlopen(const char* filename, int flag);
5755
dlopen__deps: ['$DLFCN_DATA', '$FS', '$ENV'],
5756
dlopen: function(filename, flag) {
5757
// void *dlopen(const char *file, int mode);
5758
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
5759
filename = (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename);
5761
if (DLFCN_DATA.loadedLibNames[filename]) {
5762
// Already loaded; increment ref count and return.
5763
var handle = DLFCN_DATA.loadedLibNames[filename];
5764
DLFCN_DATA.loadedLibs[handle].refcount++;
5768
var target = FS.findObject(filename);
5769
if (!target || target.isFolder || target.isDevice) {
5770
DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename;
5773
FS.forceLoadFile(target);
5774
var lib_data = intArrayToString(target.contents);
5778
var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length);
5781
Module.printErr('Error in loading dynamic library: ' + e);
5783
DLFCN_DATA.errorMsg = 'Could not evaluate dynamic lib: ' + filename;
5787
// Not all browsers support Object.keys().
5789
for (var key in DLFCN_DATA.loadedLibs) {
5790
if (DLFCN_DATA.loadedLibs.hasOwnProperty(key)) handle++;
5793
DLFCN_DATA.loadedLibs[handle] = {
5797
cached_functions: {}
5799
DLFCN_DATA.loadedLibNames[filename] = handle;
5801
// We don't care about RTLD_NOW and RTLD_LAZY.
5802
if (flag & 256) { // RTLD_GLOBAL
5803
for (var ident in lib_module) {
5804
if (lib_module.hasOwnProperty(ident)) {
5805
Module[ident] = lib_module[ident];
5812
// int dlclose(void* handle);
5813
dlclose__deps: ['$DLFCN_DATA'],
5814
dlclose: function(handle) {
5815
// int dlclose(void *handle);
5816
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlclose.html
5817
if (!DLFCN_DATA.loadedLibs[handle]) {
5818
DLFCN_DATA.errorMsg = 'Tried to dlclose() unopened handle: ' + handle;
5821
var lib_record = DLFCN_DATA.loadedLibs[handle];
5822
if (lib_record.refcount-- == 0) {
5823
delete DLFCN_DATA.loadedLibNames[lib_record.name];
5824
delete DLFCN_DATA.loadedLibs[handle];
5829
// void* dlsym(void* handle, const char* symbol);
5830
dlsym__deps: ['$DLFCN_DATA'],
5831
dlsym: function(handle, symbol) {
5832
// void *dlsym(void *restrict handle, const char *restrict name);
5833
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
5834
symbol = '_' + Pointer_stringify(symbol);
5836
if (!DLFCN_DATA.loadedLibs[handle]) {
5837
DLFCN_DATA.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle;
5840
var lib = DLFCN_DATA.loadedLibs[handle];
5841
if (!lib.module.hasOwnProperty(symbol)) {
5842
DLFCN_DATA.errorMsg = ('Tried to lookup unknown symbol "' + symbol +
5843
'" in dynamic lib: ' + lib.name);
5846
if (lib.cached_functions.hasOwnProperty(symbol)) {
5847
return lib.cached_functions[symbol];
5849
var result = lib.module[symbol];
5850
if (typeof result == 'function') {
5851
{{{ Functions.getTable('x') }}}.push(result);
5852
{{{ Functions.getTable('x') }}}.push(0);
5853
result = {{{ Functions.getTable('x') }}}.length - 2;
5854
lib.cached_functions = result;
5861
// char* dlerror(void);
5862
dlerror__deps: ['$DLFCN_DATA'],
5863
dlerror: function() {
5864
// char *dlerror(void);
5865
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlerror.html
5866
if (DLFCN_DATA.errorMsg === null) {
5869
if (DLFCN_DATA.error) _free(DLFCN_DATA.error);
5870
var msgArr = intArrayFromString(DLFCN_DATA.errorMsg);
5871
DLFCN_DATA.error = allocate(msgArr, 'i8', ALLOC_NORMAL);
5872
DLFCN_DATA.errorMsg = null;
5873
return DLFCN_DATA.error;
5877
// ==========================================================================
5879
// ==========================================================================
5882
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/pwd.h.html
5883
getpwuid: function(uid) {
5887
// ==========================================================================
5889
// ==========================================================================
5892
if (_clock.start === undefined) _clock.start = Date.now();
5893
return Math.floor((Date.now() - _clock.start) * ({{{ cDefine('CLOCKS_PER_SEC') }}}/1000));
5896
time: function(ptr) {
5897
var ret = Math.floor(Date.now()/1000);
5899
{{{ makeSetValue('ptr', 0, 'ret', 'i32') }}}
5904
difftime: function(time1, time0) {
5905
return time1 - time0;
5908
__tm_struct_layout: Runtime.generateStructInfo([
5917
['i32', 'tm_isdst'],
5918
['i32', 'tm_gmtoff'],
5919
['i32', 'tm_zone']]),
5920
// Statically allocated time struct.
5921
__tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STACK)',
5922
// Statically allocated timezone strings.
5924
// Statically allocated time strings.
5925
__tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STACK)',
5927
mktime__deps: ['__tm_struct_layout', 'tzset'],
5928
mktime: function(tmPtr) {
5930
var offsets = ___tm_struct_layout;
5931
var year = {{{ makeGetValue('tmPtr', 'offsets.tm_year', 'i32') }}};
5932
var timestamp = new Date(year >= 1900 ? year : year + 1900,
5933
{{{ makeGetValue('tmPtr', 'offsets.tm_mon', 'i32') }}},
5934
{{{ makeGetValue('tmPtr', 'offsets.tm_mday', 'i32') }}},
5935
{{{ makeGetValue('tmPtr', 'offsets.tm_hour', 'i32') }}},
5936
{{{ makeGetValue('tmPtr', 'offsets.tm_min', 'i32') }}},
5937
{{{ makeGetValue('tmPtr', 'offsets.tm_sec', 'i32') }}},
5938
0).getTime() / 1000;
5939
{{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'new Date(timestamp).getDay()', 'i32') }}}
5940
var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24));
5941
{{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}}
5944
timelocal: 'mktime',
5946
gmtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'gmtime_r'],
5947
gmtime: function(time) {
5948
return _gmtime_r(time, ___tm_current);
5951
gmtime_r__deps: ['__tm_struct_layout', '__tm_timezones'],
5952
gmtime_r: function(time, tmPtr) {
5953
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
5954
var offsets = ___tm_struct_layout;
5955
{{{ makeSetValue('tmPtr', 'offsets.tm_sec', 'date.getUTCSeconds()', 'i32') }}}
5956
{{{ makeSetValue('tmPtr', 'offsets.tm_min', 'date.getUTCMinutes()', 'i32') }}}
5957
{{{ makeSetValue('tmPtr', 'offsets.tm_hour', 'date.getUTCHours()', 'i32') }}}
5958
{{{ makeSetValue('tmPtr', 'offsets.tm_mday', 'date.getUTCDate()', 'i32') }}}
5959
{{{ makeSetValue('tmPtr', 'offsets.tm_mon', 'date.getUTCMonth()', 'i32') }}}
5960
{{{ makeSetValue('tmPtr', 'offsets.tm_year', 'date.getUTCFullYear()-1900', 'i32') }}}
5961
{{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'date.getUTCDay()', 'i32') }}}
5962
{{{ makeSetValue('tmPtr', 'offsets.tm_gmtoff', '0', 'i32') }}}
5963
{{{ makeSetValue('tmPtr', 'offsets.tm_isdst', '0', 'i32') }}}
5965
var start = new Date(date.getFullYear(), 0, 1);
5966
var yday = Math.round((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
5967
{{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}}
5969
var timezone = "GMT";
5970
if (!(timezone in ___tm_timezones)) {
5971
___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL);
5973
{{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}}
5978
timegm__deps: ['mktime'],
5979
timegm: function(tmPtr) {
5981
var offset = {{{ makeGetValue(makeGlobalUse('__timezone'), 0, 'i32') }}};
5982
var daylight = {{{ makeGetValue(makeGlobalUse('__daylight'), 0, 'i32') }}};
5983
daylight = (daylight == 1) ? 60 * 60 : 0;
5984
var ret = _mktime(tmPtr) + offset - daylight;
5988
localtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'localtime_r'],
5989
localtime: function(time) {
5990
return _localtime_r(time, ___tm_current);
5993
localtime_r__deps: ['__tm_struct_layout', '__tm_timezones', 'tzset'],
5994
localtime_r: function(time, tmPtr) {
5996
var offsets = ___tm_struct_layout;
5997
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
5998
{{{ makeSetValue('tmPtr', 'offsets.tm_sec', 'date.getSeconds()', 'i32') }}}
5999
{{{ makeSetValue('tmPtr', 'offsets.tm_min', 'date.getMinutes()', 'i32') }}}
6000
{{{ makeSetValue('tmPtr', 'offsets.tm_hour', 'date.getHours()', 'i32') }}}
6001
{{{ makeSetValue('tmPtr', 'offsets.tm_mday', 'date.getDate()', 'i32') }}}
6002
{{{ makeSetValue('tmPtr', 'offsets.tm_mon', 'date.getMonth()', 'i32') }}}
6003
{{{ makeSetValue('tmPtr', 'offsets.tm_year', 'date.getFullYear()-1900', 'i32') }}}
6004
{{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'date.getDay()', 'i32') }}}
6006
var start = new Date(date.getFullYear(), 0, 1);
6007
var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
6008
{{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}}
6009
{{{ makeSetValue('tmPtr', 'offsets.tm_gmtoff', 'start.getTimezoneOffset() * 60', 'i32') }}}
6011
var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
6012
{{{ makeSetValue('tmPtr', 'offsets.tm_isdst', 'dst', 'i32') }}}
6014
var timezone = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | date.toString().match(/\(([A-Z]+)\)/)[1];
6015
if (!(timezone in ___tm_timezones)) {
6016
___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL);
6018
{{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}}
6023
asctime__deps: ['malloc', '__tm_formatted', 'asctime_r'],
6024
asctime: function(tmPtr) {
6025
return _asctime_r(tmPtr, ___tm_formatted);
6028
asctime_r__deps: ['__tm_formatted', 'mktime'],
6029
asctime_r: function(tmPtr, buf) {
6030
var date = new Date(_mktime(tmPtr)*1000);
6031
var formatted = date.toString();
6032
var datePart = formatted.replace(/\d{4}.*/, '').replace(/ 0/, ' ');
6033
var timePart = formatted.match(/\d{2}:\d{2}:\d{2}/)[0];
6034
formatted = datePart + timePart + ' ' + date.getFullYear() + '\n';
6035
formatted.split('').forEach(function(chr, index) {
6036
{{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}}
6038
{{{ makeSetValue('buf', '25', '0', 'i8') }}}
6042
ctime__deps: ['localtime', 'asctime'],
6043
ctime: function(timer) {
6044
return _asctime(_localtime(timer));
6047
ctime_r__deps: ['localtime', 'asctime'],
6048
ctime_r: function(timer, buf) {
6049
return _asctime_r(_localtime_r(timer, ___tm_current), buf);
6052
dysize: function(year) {
6053
var leap = ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)));
6054
return leap ? 366 : 365;
6057
// TODO: Initialize these to defaults on startup from system settings.
6058
// Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm)
6059
_tzname: 'allocate({{{ 2*Runtime.QUANTUM_SIZE }}}, "i32*", ALLOC_STACK)',
6060
_daylight: 'allocate(1, "i32*", ALLOC_STACK)',
6061
_timezone: 'allocate(1, "i32*", ALLOC_STACK)',
6062
tzset__deps: ['_tzname', '_daylight', '_timezone'],
6064
// TODO: Use (malleable) environment variables instead of system settings.
6065
if (_tzset.called) return;
6066
_tzset.called = true;
6068
{{{ makeSetValue(makeGlobalUse('__timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}}
6070
var winter = new Date(2000, 0, 1);
6071
var summer = new Date(2000, 6, 1);
6072
{{{ makeSetValue(makeGlobalUse('__daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}}
6074
var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1];
6075
var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1];
6076
var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
6077
var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
6078
{{{ makeSetValue(makeGlobalUse('__tzname'), '0', 'winterNamePtr', 'i32') }}}
6079
{{{ makeSetValue(makeGlobalUse('__tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}}
6082
stime__deps: ['$ERRNO_CODES', '__setErrNo'],
6083
stime: function(when) {
6084
___setErrNo(ERRNO_CODES.EPERM);
6088
strftime: function(s, maxsize, format, timeptr) {
6089
// size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
6090
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html
6094
strftime_l: 'strftime', // no locale support yet
6096
strptime: function(buf, format, tm) {
6097
// char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm);
6098
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html
6102
strptime_l: 'strptime', // no locale support yet
6104
getdate: function(string) {
6105
// struct tm *getdate(const char *string);
6106
// http://pubs.opengroup.org/onlinepubs/009695399/functions/getdate.html
6111
setitimer: function() { throw 'setitimer not implemented yet' },
6112
getitimer: function() { throw 'getitimer not implemented yet' },
6114
// ==========================================================================
6116
// ==========================================================================
6118
__timespec_struct_layout: Runtime.generateStructInfo([
6120
['i32', 'tv_nsec']]),
6121
nanosleep__deps: ['usleep', '__timespec_struct_layout'],
6122
nanosleep: function(rqtp, rmtp) {
6123
// int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
6124
var seconds = {{{ makeGetValue('rqtp', '___timespec_struct_layout.tv_sec', 'i32') }}};
6125
var nanoseconds = {{{ makeGetValue('rqtp', '___timespec_struct_layout.tv_nsec', 'i32') }}};
6126
{{{ makeSetValue('rmtp', '___timespec_struct_layout.tv_sec', '0', 'i32') }}}
6127
{{{ makeSetValue('rmtp', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}
6128
return _usleep((seconds * 1e6) + (nanoseconds / 1000));
6130
// TODO: Implement these for real.
6131
clock_gettime__deps: ['__timespec_struct_layout'],
6132
clock_gettime: function(clk_id, tp) {
6133
// int clock_gettime(clockid_t clk_id, struct timespec *tp);
6134
{{{ makeSetValue('tp', '___timespec_struct_layout.tv_sec', '0', 'i32') }}}
6135
{{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}
6138
clock_settime: function(clk_id, tp) {
6139
// int clock_settime(clockid_t clk_id, const struct timespec *tp);
6143
clock_getres__deps: ['__timespec_struct_layout'],
6144
clock_getres: function(clk_id, res) {
6145
// int clock_getres(clockid_t clk_id, struct timespec *res);
6146
{{{ makeSetValue('res', '___timespec_struct_layout.tv_sec', '1', 'i32') }}}
6147
{{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}
6151
// http://pubs.opengroup.org/onlinepubs/000095399/basedefs/sys/time.h.html
6152
gettimeofday: function(ptr) {
6153
// %struct.timeval = type { i32, i32 }
6154
{{{ (LibraryManager.structs.gettimeofday = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] }), null) }}}
6155
var now = Date.now();
6156
{{{ makeSetValue('ptr', LibraryManager.structs.gettimeofday[0], 'Math.floor(now/1000)', 'i32') }}}; // seconds
6157
{{{ makeSetValue('ptr', LibraryManager.structs.gettimeofday[1], 'Math.floor((now-1000*Math.floor(now/1000))*1000)', 'i32') }}}; // microseconds
6161
// ==========================================================================
6163
// ==========================================================================
6165
__timeb_struct_layout: Runtime.generateStructInfo([
6168
['i16', 'timezone'],
6171
ftime__deps: ['__timeb_struct_layout'],
6172
ftime: function(p) {
6173
var millis = Date.now();
6174
{{{ makeSetValue('p', '___timeb_struct_layout.time', 'Math.floor(millis/1000)', 'i32') }}};
6175
{{{ makeSetValue('p', '___timeb_struct_layout.millitm', 'millis % 1000', 'i16') }}};
6176
{{{ makeSetValue('p', '___timeb_struct_layout.timezone', '0', 'i16') }}}; // TODO
6177
{{{ makeSetValue('p', '___timeb_struct_layout.dstflag', '0', 'i16') }}}; // TODO
6181
// ==========================================================================
6183
// ==========================================================================
6185
__tms_struct_layout: Runtime.generateStructInfo([
6186
['i32', 'tms_utime'],
6187
['i32', 'tms_stime'],
6188
['i32', 'tms_cutime'],
6189
['i32', 'tms_cstime']]),
6190
times__deps: ['__tms_struct_layout', 'memset'],
6191
times: function(buffer) {
6192
// clock_t times(struct tms *buffer);
6193
// http://pubs.opengroup.org/onlinepubs/009695399/functions/times.html
6194
// NOTE: This is fake, since we can't calculate real CPU time usage in JS.
6196
_memset(buffer, 0, ___tms_struct_layout.__size__);
6201
// ==========================================================================
6203
// ==========================================================================
6205
// NOTE: These are fake, since we don't support the C device creation API.
6206
// http://www.kernel.org/doc/man-pages/online/pages/man3/minor.3.html
6207
makedev: function(maj, min) {
6210
gnu_dev_makedev: 'makedev',
6211
major: function(dev) {
6214
gnu_dev_major: 'major',
6215
minor: function(dev) {
6218
gnu_dev_minor: 'minor',
6220
// ==========================================================================
6223
// Basic support for setjmp/longjmp: enough to run the wikipedia example and
6224
// hopefully handle most normal behavior. We do not support cases where
6225
// longjmp behavior is undefined (for example, if the setjmp function returns
6226
// before longjmp is called).
6228
// Note that we need to emulate functions that use setjmp, and also to create
6229
// a new label we can return to. Emulation make such functions slower, this
6230
// can be alleviated by making a new function containing just the setjmp
6231
// related functionality so the slowdown is more limited.
6232
// ==========================================================================
6234
saveSetjmp__asm: true,
6235
saveSetjmp__sig: 'iii',
6236
saveSetjmp__deps: ['putchar'],
6237
saveSetjmp: function(env, label, table) {
6238
// Not particularly fast: slow table lookup of setjmpId to label. But setjmp
6239
// prevents relooping anyhow, so slowness is to be expected. And typical case
6240
// is 1 setjmp per invocation, or less.
6246
if ((label|0) == 0) abort(121);
6248
setjmpId = (setjmpId+1)|0;
6249
{{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}};
6250
while ((i|0) < {{{ 2*MAX_SETJMPS }}}) {
6251
if ({{{ makeGetValueAsm('table', 'i*4', 'i32') }}} == 0) {
6252
{{{ makeSetValueAsm('table', 'i*4', 'setjmpId', 'i32') }}};
6253
{{{ makeSetValueAsm('table', 'i*4+4', 'label', 'i32') }}};
6254
// prepare next slot
6255
{{{ makeSetValueAsm('table', 'i*4+8', '0', 'i32') }}};
6260
{{{ makePrintChars('too many setjmps in a function call, build with a higher value for MAX_SETJMPS') }}};
6265
testSetjmp__asm: true,
6266
testSetjmp__sig: 'iii',
6267
testSetjmp: function(id, table) {
6270
var i = 0, curr = 0;
6271
while ((i|0) < {{{ MAX_SETJMPS }}}) {
6272
curr = {{{ makeGetValueAsm('table', 'i*4', 'i32') }}};
6273
if ((curr|0) == 0) break;
6274
if ((curr|0) == (id|0)) {
6275
return {{{ makeGetValueAsm('table', 'i*4+4', 'i32') }}};
6283
setjmp__deps: ['saveSetjmp', 'testSetjmp'],
6285
setjmp__inline: function(env) {
6288
return '_saveSetjmp(' + env + ', label, setjmpTable)|0';
6290
return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32', undefined, undefined, undefined, undefined, ',') + ', 0)';
6295
longjmp__deps: ['saveSetjmp', 'testSetjmp'],
6297
longjmp: function(env, value) {
6299
asm.setThrew(env, value || 1);
6302
throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 };
6306
// ==========================================================================
6308
// ==========================================================================
6310
signal: function(sig, func) {
6314
sigemptyset: function(set) {
6315
// int sigemptyset(sigset_t *set);
6316
{{{ makeSetValue('set', '0', '0', 'i32') }}};
6319
sigfillset: function(set) {
6320
{{{ makeSetValue('set', '0', '-1>>>0', 'i32') }}};
6323
sigaddset: function(set, signum) {
6324
{{{ makeSetValue('set', '0', makeGetValue('set', '0', 'i32') + '| (1 << (signum-1))', 'i32') }}};
6327
sigdelset: function(set, signum) {
6328
{{{ makeSetValue('set', '0', makeGetValue('set', '0', 'i32') + '& (~(1 << (signum-1)))', 'i32') }}};
6331
sigismember: function(set, signum) {
6332
return {{{ makeGetValue('set', '0', 'i32') }}} & (1 << (signum-1));
6334
sigaction: function(set) {
6338
sigprocmask: 'sigaction',
6339
__libc_current_sigrtmin: function() {
6342
__libc_current_sigrtmax: function() {
6345
kill__deps: ['$ERRNO_CODES', '__setErrNo'],
6346
kill: function(pid, sig) {
6347
// int kill(pid_t pid, int sig);
6348
// http://pubs.opengroup.org/onlinepubs/000095399/functions/kill.html
6349
// Makes no sense in a single-process environment.
6350
___setErrNo(ERRNO_CODES.EPERM);
6355
siginterrupt: function() { throw 'siginterrupt not implemented' },
6357
// ==========================================================================
6359
// ==========================================================================
6361
wait__deps: ['$ERRNO_CODES', '__setErrNo'],
6362
wait: function(stat_loc) {
6363
// pid_t wait(int *stat_loc);
6364
// http://pubs.opengroup.org/onlinepubs/009695399/functions/wait.html
6365
// Makes no sense in a single-process environment.
6366
___setErrNo(ERRNO_CODES.ECHILD);
6369
// NOTE: These aren't really the same, but we use the same stub for them all.
6375
// ==========================================================================
6377
// ==========================================================================
6379
newlocale: function(mask, locale, base) {
6383
freelocale: function(locale) {},
6385
uselocale: function(locale) {
6389
setlocale: function(category, locale) {
6390
if (!_setlocale.ret) _setlocale.ret = allocate([0], 'i8', ALLOC_NORMAL);
6391
return _setlocale.ret;
6394
localeconv: function() {
6395
// %struct.timeval = type { char* decimal point, other stuff... }
6396
// var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] });
6397
var me = _localeconv;
6399
me.ret = allocate([allocate(intArrayFromString('.'), 'i8', ALLOC_NORMAL)], 'i8*', ALLOC_NORMAL); // just decimal point, for now
6404
__locale_mb_cur_max: function() { throw '__locale_mb_cur_max not implemented' },
6406
// ==========================================================================
6408
// ==========================================================================
6410
nl_langinfo: function(item) {
6411
// char *nl_langinfo(nl_item item);
6412
// http://pubs.opengroup.org/onlinepubs/000095399/functions/nl_langinfo.html
6415
case {{{ cDefine('CODESET') }}}:
6416
result = 'ANSI_X3.4-1968';
6418
case {{{ cDefine('D_T_FMT') }}}:
6419
result = '%a %b %e %H:%M:%S %Y';
6421
case {{{ cDefine('D_FMT') }}}:
6422
result = '%m/%d/%y';
6424
case {{{ cDefine('T_FMT') }}}:
6425
result = '%H:%M:%S';
6427
case {{{ cDefine('T_FMT_AMPM') }}}:
6428
result = '%I:%M:%S %p';
6430
case {{{ cDefine('AM_STR') }}}:
6433
case {{{ cDefine('PM_STR') }}}:
6436
case {{{ cDefine('DAY_1') }}}:
6439
case {{{ cDefine('DAY_2') }}}:
6442
case {{{ cDefine('DAY_3') }}}:
6445
case {{{ cDefine('DAY_4') }}}:
6446
result = 'Wednesday';
6448
case {{{ cDefine('DAY_5') }}}:
6449
result = 'Thursday';
6451
case {{{ cDefine('DAY_6') }}}:
6454
case {{{ cDefine('DAY_7') }}}:
6455
result = 'Saturday';
6457
case {{{ cDefine('ABDAY_1') }}}:
6460
case {{{ cDefine('ABDAY_2') }}}:
6463
case {{{ cDefine('ABDAY_3') }}}:
6466
case {{{ cDefine('ABDAY_4') }}}:
6469
case {{{ cDefine('ABDAY_5') }}}:
6472
case {{{ cDefine('ABDAY_6') }}}:
6475
case {{{ cDefine('ABDAY_7') }}}:
6478
case {{{ cDefine('MON_1') }}}:
6481
case {{{ cDefine('MON_2') }}}:
6482
result = 'February';
6484
case {{{ cDefine('MON_3') }}}:
6487
case {{{ cDefine('MON_4') }}}:
6490
case {{{ cDefine('MON_5') }}}:
6493
case {{{ cDefine('MON_6') }}}:
6496
case {{{ cDefine('MON_7') }}}:
6499
case {{{ cDefine('MON_8') }}}:
6502
case {{{ cDefine('MON_9') }}}:
6503
result = 'September';
6505
case {{{ cDefine('MON_10') }}}:
6508
case {{{ cDefine('MON_11') }}}:
6509
result = 'November';
6511
case {{{ cDefine('MON_12') }}}:
6512
result = 'December';
6514
case {{{ cDefine('ABMON_1') }}}:
6517
case {{{ cDefine('ABMON_2') }}}:
6520
case {{{ cDefine('ABMON_3') }}}:
6523
case {{{ cDefine('ABMON_4') }}}:
6526
case {{{ cDefine('ABMON_5') }}}:
6529
case {{{ cDefine('ABMON_6') }}}:
6532
case {{{ cDefine('ABMON_7') }}}:
6535
case {{{ cDefine('ABMON_8') }}}:
6538
case {{{ cDefine('ABMON_9') }}}:
6541
case {{{ cDefine('ABMON_10') }}}:
6544
case {{{ cDefine('ABMON_11') }}}:
6547
case {{{ cDefine('ABMON_12') }}}:
6550
case {{{ cDefine('ALT_DIGITS') }}}:
6553
case {{{ cDefine('RADIXCHAR') }}}:
6556
case {{{ cDefine('THOUSEP') }}}:
6559
case {{{ cDefine('YESEXPR') }}}:
6562
case {{{ cDefine('NOEXPR') }}}:
6565
case {{{ cDefine('CRNCYSTR') }}}:
6568
case {{{ cDefine('ERA') }}}:
6569
case {{{ cDefine('ERA_D_FMT') }}}:
6570
case {{{ cDefine('ERA_D_T_FMT') }}}:
6571
case {{{ cDefine('ERA_T_FMT') }}}:
6577
var me = _nl_langinfo;
6578
if (!me.ret) me.ret = _malloc(32);
6579
for (var i = 0; i < result.length; i++) {
6580
{{{ makeSetValue('me.ret', 'i', 'result.charCodeAt(i)', 'i8') }}}
6582
{{{ makeSetValue('me.ret', 'i', '0', 'i8') }}}
6586
_Z7catopenPKci: function() { throw 'catopen not implemented' },
6587
_Z7catgetsP8_nl_catdiiPKc: function() { throw 'catgets not implemented' },
6588
_Z8catcloseP8_nl_catd: function() { throw 'catclose not implemented' },
6590
// ==========================================================================
6592
// ==========================================================================
6653
ENOTRECOVERABLE: 131,
6664
EPROTONOSUPPORT: 93,
6678
2: 'No such file or directory',
6679
13: 'Permission denied',
6680
98: 'Address already in use',
6681
99: 'Cannot assign requested address',
6682
97: 'Address family not supported by protocol',
6683
11: 'Resource temporarily unavailable',
6684
114: 'Operation already in progress',
6685
9: 'Bad file descriptor',
6687
16: 'Device or resource busy',
6688
125: 'Operation canceled',
6689
10: 'No child processes',
6690
103: 'Software caused connection abort',
6691
111: 'Connection refused',
6692
104: 'Connection reset by peer',
6693
35: 'Resource deadlock avoided',
6694
89: 'Destination address required',
6695
33: 'Numerical argument out of domain',
6696
122: 'Disk quota exceeded',
6699
27: 'File too large',
6700
113: 'No route to host',
6701
43: 'Identifier removed',
6702
84: 'Invalid or incomplete multibyte or wide character',
6703
115: 'Operation now in progress',
6704
4: 'Interrupted system call',
6705
22: 'Invalid argument',
6706
5: 'Input/output error',
6707
106: 'Transport endpoint is already connected',
6708
21: 'Is a directory',
6709
40: 'Too many levels of symbolic links',
6710
24: 'Too many open files',
6711
31: 'Too many links',
6712
90: 'Message too long',
6713
72: 'Multihop attempted',
6714
36: 'File name too long',
6715
100: 'Network is down',
6716
102: 'Network dropped connection on reset',
6717
101: 'Network is unreachable',
6718
23: 'Too many open files in system',
6719
105: 'No buffer space available',
6720
61: 'No data available',
6721
19: 'No such device',
6722
8: 'Exec format error',
6723
37: 'No locks available',
6724
67: 'Link has been severed',
6725
12: 'Cannot allocate memory',
6726
42: 'No message of desired type',
6727
92: 'Protocol not available',
6728
28: 'No space left on device',
6729
63: 'Out of streams resources',
6730
60: 'Device not a stream',
6731
38: 'Function not implemented',
6732
107: 'Transport endpoint is not connected',
6733
20: 'Not a directory',
6734
39: 'Directory not empty',
6735
131: 'State not recoverable',
6736
88: 'Socket operation on non-socket',
6737
95: 'Operation not supported',
6738
25: 'Inappropriate ioctl for device',
6739
6: 'No such device or address',
6740
45: 'Op not supported on transport endpoint',
6741
75: 'Value too large for defined data type',
6743
1: 'Operation not permitted',
6745
71: 'Protocol error',
6746
93: 'Protocol not supported',
6747
91: 'Protocol wrong type for socket',
6748
34: 'Numerical result out of range',
6749
30: 'Read-only file system',
6751
3: 'No such process',
6752
116: 'Stale NFS file handle',
6753
62: 'Timer expired',
6754
110: 'Connection timed out',
6755
26: 'Text file busy',
6756
18: 'Invalid cross-device link'
6758
__setErrNo__postset: '___setErrNo(0);',
6759
__setErrNo: function(value) {
6760
// For convenient setting and returning of errno.
6761
if (!___setErrNo.ret) ___setErrNo.ret = allocate([0], 'i32', ALLOC_STATIC);
6762
{{{ makeSetValue('___setErrNo.ret', '0', 'value', 'i32') }}}
6765
__errno_location__deps: ['__setErrNo'],
6766
__errno_location: function() {
6767
return ___setErrNo.ret;
6769
__errno: '__errno_location',
6771
// ==========================================================================
6773
// ==========================================================================
6775
// TODO: Implement for real.
6776
__rlimit_struct_layout: Runtime.generateStructInfo([
6777
['i32', 'rlim_cur'],
6778
['i32', 'rlim_max']]),
6779
getrlimit__deps: ['__rlimit_struct_layout'],
6780
getrlimit: function(resource, rlp) {
6781
// int getrlimit(int resource, struct rlimit *rlp);
6782
{{{ makeSetValue('rlp', '___rlimit_struct_layout.rlim_cur', '-1', 'i32') }}} // RLIM_INFINITY
6783
{{{ makeSetValue('rlp', '___rlimit_struct_layout.rlim_max', '-1', 'i32') }}} // RLIM_INFINITY
6786
setrlimit: function(resource, rlp) {
6787
// int setrlimit(int resource, const struct rlimit *rlp)
6790
__01getrlimit64_: 'getrlimit',
6792
// TODO: Implement for real. We just do time used, and no useful data
6793
__rusage_struct_layout: Runtime.generateStructInfo([
6794
['i64', 'ru_utime'],
6795
['i64', 'ru_stime'],
6796
['i32', 'ru_maxrss'],
6797
['i32', 'ru_ixrss'],
6798
['i32', 'ru_idrss'],
6799
['i32', 'ru_isrss'],
6800
['i32', 'ru_minflt'],
6801
['i32', 'ru_majflt'],
6802
['i32', 'ru_nswap'],
6803
['i32', 'ru_inblock'],
6804
['i32', 'ru_oublock'],
6805
['i32', 'ru_msgsnd'],
6806
['i32', 'ru_msgrcv'],
6807
['i32', 'ru_nsignals'],
6808
['i32', 'ru_nvcsw'],
6809
['i32', 'ru_nivcsw']]),
6810
getrusage__deps: ['__rusage_struct_layout'],
6811
getrusage: function(resource, rlp) {
6812
// %struct.timeval = type { i32, i32 }
6813
var timeval = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] });
6815
// int getrusage(int resource, struct rusage *rlp);
6816
{{{ makeSetValue('rlp', '___rusage_struct_layout.ru_utime+timeval[0]', '1', 'i32') }}}
6817
{{{ makeSetValue('rlp', '___rusage_struct_layout.ru_utime+timeval[1]', '2', 'i32') }}}
6818
{{{ makeSetValue('rlp', '___rusage_struct_layout.ru_stime+timeval[0]', '3', 'i32') }}}
6819
{{{ makeSetValue('rlp', '___rusage_struct_layout.ru_stime+timeval[1]', '4', 'i32') }}}
6823
// ==========================================================================
6824
// sched.h (stubs only - no thread support yet!)
6825
// ==========================================================================
6826
sched_yield: function() {
6830
// ==========================================================================
6831
// pthread.h (stubs for mutexes only - no thread support yet!)
6832
// ==========================================================================
6834
pthread_mutex_init: function() {},
6835
pthread_mutex_destroy: function() {},
6836
pthread_mutexattr_init: function() {},
6837
pthread_mutexattr_settype: function() {},
6838
pthread_mutexattr_destroy: function() {},
6839
pthread_mutex_lock: function() {},
6840
pthread_mutex_unlock: function() {},
6841
pthread_mutex_trylock: function() {
6844
pthread_cond_init: function() {},
6845
pthread_cond_destroy: function() {},
6846
pthread_cond_broadcast: function() {
6849
pthread_cond_wait: function() {
6852
pthread_cond_timedwait: function() {
6855
pthread_self: function() {
6856
//FIXME: assumes only a single thread
6859
pthread_attr_init: function(attr) {
6860
/* int pthread_attr_init(pthread_attr_t *attr); */
6861
//FIXME: should allocate a pthread_attr_t
6864
pthread_getattr_np: function(thread, attr) {
6865
/* int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr); */
6866
//FIXME: should fill in attributes of the given thread in pthread_attr_t
6869
pthread_attr_destroy: function(attr) {
6870
/* int pthread_attr_destroy(pthread_attr_t *attr); */
6871
//FIXME: should destroy the pthread_attr_t struct
6874
pthread_attr_getstack: function(attr, stackaddr, stacksize) {
6875
/* int pthread_attr_getstack(const pthread_attr_t *restrict attr,
6876
void **restrict stackaddr, size_t *restrict stacksize); */
6877
/*FIXME: assumes that there is only one thread, and that attr is the
6879
{{{ makeSetValue('stackaddr', '0', 'STACK_ROOT', 'i8*') }}}
6880
{{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}}
6884
pthread_once: function(ptr, func) {
6885
if (!_pthread_once.seen) _pthread_once.seen = {};
6886
if (ptr in _pthread_once.seen) return;
6887
Runtime.dynCall('v', func);
6888
_pthread_once.seen[ptr] = 1;
6891
pthread_key_create: function(key, destructor) {
6892
if (!_pthread_key_create.keys) _pthread_key_create.keys = {};
6893
// values start at 0
6894
_pthread_key_create.keys[key] = 0;
6897
pthread_getspecific: function(key) {
6898
return _pthread_key_create.keys[key] || 0;
6901
pthread_setspecific: function(key, value) {
6902
_pthread_key_create.keys[key] = value;
6905
pthread_key_delete: ['$ERRNO_CODES'],
6906
pthread_key_delete: function(key) {
6907
if (_pthread_key_create.keys[key]) {
6908
delete _pthread_key_create.keys[key];
6911
return ERRNO_CODES.EINVAL;
6914
pthread_cleanup_push: function(routine, arg) {
6915
__ATEXIT__.push({ func: function() { Runtime.dynCall('vi', routine, [arg]) } })
6916
_pthread_cleanup_push.level = __ATEXIT__.length;
6919
pthread_cleanup_pop: function() {
6920
assert(_pthread_cleanup_push.level == __ATEXIT__.length, 'cannot pop if something else added meanwhile!');
6922
_pthread_cleanup_push.level = __ATEXIT__.length;
6925
// ==========================================================================
6927
// ==========================================================================
6929
memalign: function(boundary, size) {
6930
// leaks, and even returns an invalid pointer. Horrible hack... but then, this is a deprecated function...
6931
var ret = Runtime.staticAlloc(size + boundary);
6932
return ret + boundary - (ret % boundary);
6935
posix_memalign__deps: ['memalign'],
6936
posix_memalign: function(memptr, alignment, size) {
6937
var ptr = _memalign(alignment, size);
6938
{{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}}
6942
// ==========================================================================
6944
// ==========================================================================
6946
htonl: function(value) {
6947
return ((value & 0xff) << 24) + ((value & 0xff00) << 8) +
6948
((value & 0xff0000) >>> 8) + ((value & 0xff000000) >>> 24);
6950
htons: function(value) {
6951
return ((value & 0xff) << 8) + ((value & 0xff00) >> 8);
6956
inet_addr: function(ptr) {
6957
var b = Pointer_stringify(ptr).split(".");
6958
if (b.length !== 4) return -1; // we return -1 for error, and otherwise a uint32. this helps inet_pton differentiate
6959
return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0;
6962
inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_addr'],
6963
inet_pton: function(af, src, dst) {
6964
// int af, const char *src, void *dst
6965
if ((af ^ {{{ cDefine("AF_INET") }}}) !== 0) { ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); return -1; }
6966
var ret = _inet_addr(src);
6967
if (ret == -1 || isNaN(ret)) return 0;
6968
setValue(dst, ret, 'i32');
6972
_inet_ntop_raw: function(addr) {
6973
return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff)
6976
inet_ntop__deps: ['_inet_ntop_raw'],
6977
inet_ntop: function(af, src, dst, size) {
6978
var addr = getValue(src, 'i32');
6979
var str = __inet_ntop_raw(addr);
6980
writeStringToMemory(str.substr(0, size), dst);
6984
inet_ntoa__deps: ['inet_ntop'],
6985
inet_ntoa: function(in_addr) {
6986
if (!_inet_ntoa.buffer) {
6987
_inet_ntoa.buffer = _malloc(1024);
6989
return _inet_ntop(0, in_addr, _inet_ntoa.buffer, 1024);
6992
inet_aton__deps: ['inet_addr'],
6993
inet_aton: function(cp, inp) {
6994
var addr = _inet_addr(cp);
6995
setValue(inp, addr, 'i32');
6996
if (addr < 0) return 0;
7000
// ==========================================================================
7002
// ==========================================================================
7004
// All we can do is alias names to ips. you give this a name, it returns an
7005
// "ip" that we later know to use as a name. There is no way to do actual
7006
// name resolving clientside in a browser.
7007
// we do the aliasing in 172.29.*.*, giving us 65536 possibilities
7008
// note: lots of leaking here!
7009
__hostent_struct_layout: Runtime.generateStructInfo([
7011
['i8**', 'h_aliases'],
7012
['i32', 'h_addrtype'],
7013
['i32', 'h_length'],
7014
['i8**', 'h_addr_list'],
7016
gethostbyname__deps: ['__hostent_struct_layout'],
7017
gethostbyname: function(name) {
7018
name = Pointer_stringify(name);
7019
if (!_gethostbyname.id) {
7020
_gethostbyname.id = 1;
7021
_gethostbyname.table = {};
7023
var id = _gethostbyname.id++;
7025
var fakeAddr = 172 | (29 << 8) | ((id & 0xff) << 16) | ((id & 0xff00) << 24);
7026
_gethostbyname.table[id] = name;
7028
var ret = _malloc(___hostent_struct_layout.__size__);
7029
var nameBuf = _malloc(name.length+1);
7030
writeStringToMemory(name, nameBuf);
7031
setValue(ret+___hostent_struct_layout.h_name, nameBuf, 'i8*');
7032
var aliasesBuf = _malloc(4);
7033
setValue(aliasesBuf, 0, 'i8*');
7034
setValue(ret+___hostent_struct_layout.h_aliases, aliasesBuf, 'i8**');
7035
setValue(ret+___hostent_struct_layout.h_addrtype, {{{ cDefine("AF_INET") }}}, 'i32');
7036
setValue(ret+___hostent_struct_layout.h_length, 4, 'i32');
7037
var addrListBuf = _malloc(12);
7038
setValue(addrListBuf, addrListBuf+8, 'i32*');
7039
setValue(addrListBuf+4, 0, 'i32*');
7040
setValue(addrListBuf+8, fakeAddr, 'i32');
7041
setValue(ret+___hostent_struct_layout.h_addr_list, addrListBuf, 'i8**');
7045
gethostbyname_r__deps: ['gethostbyname'],
7046
gethostbyname_r: function(name, hostData, buffer, bufferSize, hostEntry, errnum) {
7047
var data = _gethostbyname(name);
7048
_memcpy(hostData, data, ___hostent_struct_layout.__size__);
7050
setValue(errnum, 0, 'i32');
7054
// ==========================================================================
7055
// sockets. Note that the implementation assumes all sockets are always
7057
// ==========================================================================
7059
$Sockets__deps: ['__setErrNo', '$ERRNO_CODES'],
7061
BACKEND_WEBSOCKETS: 0,
7063
BUFFER_SIZE: 10*1024, // initial size
7064
MAX_BUFFER_SIZE: 10*1024*1024, // maximum size we will grow the buffer
7066
backend: 0, // default to websockets
7069
sockaddr_in_layout: Runtime.generateStructInfo([
7070
['i32', 'sin_family'],
7071
['i16', 'sin_port'],
7072
['i32', 'sin_addr'],
7073
['i32', 'sin_zero'],
7074
['i16', 'sin_zero_b'],
7076
msghdr_layout: Runtime.generateStructInfo([
7078
['i32', 'msg_namelen'],
7080
['i32', 'msg_iovlen'],
7081
['*', 'msg_control'],
7082
['i32', 'msg_controllen'],
7083
['i32', 'msg_flags'],
7088
connect: function(info) {
7089
console.log('opening ws://' + info.host + ':' + info.port);
7090
info.socket = new WebSocket('ws://' + info.host + ':' + info.port, ['binary']);
7091
info.socket.binaryType = 'arraybuffer';
7093
var i32Temp = new Uint32Array(1);
7094
var i8Temp = new Uint8Array(i32Temp.buffer);
7097
info.hasData = function() { return info.inQueue.length > 0 }
7099
var partialBuffer = null; // in datagram mode, inQueue contains full dgram messages; this buffers incomplete data. Must begin with the beginning of a message
7102
info.socket.onmessage = function(event) {
7103
assert(typeof event.data !== 'string' && event.data.byteLength); // must get binary data!
7104
var data = new Uint8Array(event.data); // make a typed array view on the array buffer
7106
Module.print(['onmessage', data.length, '|', Array.prototype.slice.call(data)]);
7109
info.inQueue.push(data);
7111
// we added headers with message sizes, read those to find discrete messages
7112
if (partialBuffer) {
7113
// append to the partial buffer
7114
var newBuffer = new Uint8Array(partialBuffer.length + data.length);
7115
newBuffer.set(partialBuffer);
7116
newBuffer.set(data, partialBuffer.length);
7117
// forget the partial buffer and work on data
7119
partialBuffer = null;
7122
while (currPos+4 < data.length) {
7123
i8Temp.set(data.subarray(currPos, currPos+4));
7124
var currLen = i32Temp[0];
7125
assert(currLen > 0);
7126
if (currPos + 4 + currLen > data.length) {
7127
break; // not enough data has arrived
7131
Module.print(['onmessage message', currLen, '|', Array.prototype.slice.call(data.subarray(currPos, currPos+currLen))]);
7133
info.inQueue.push(data.subarray(currPos, currPos+currLen));
7136
// If data remains, buffer it
7137
if (currPos < data.length) {
7138
partialBuffer = data.subarray(currPos);
7142
function send(data) {
7143
// TODO: if browser accepts views, can optimize this
7145
Module.print('sender actually sending ' + Array.prototype.slice.call(data));
7147
// ok to use the underlying buffer, we created data and know that the buffer starts at the beginning
7148
info.socket.send(data.buffer);
7151
var intervalling = false, interval;
7152
function trySend() {
7153
if (info.socket.readyState != info.socket.OPEN) {
7154
if (!intervalling) {
7155
intervalling = true;
7156
console.log('waiting for socket in order to send');
7157
interval = setInterval(trySend, 100);
7161
for (var i = 0; i < outQueue.length; i++) {
7164
outQueue.length = 0;
7166
intervalling = false;
7167
clearInterval(interval);
7170
info.sender = function(data) {
7172
// add a header with the message size
7173
var header = new Uint8Array(4);
7174
i32Temp[0] = data.length;
7176
outQueue.push(header);
7178
outQueue.push(new Uint8Array(data));
7188
emscripten_set_network_backend__deps: ['$Sockets'],
7189
emscripten_set_network_backend: function(backend) {
7190
Sockets.backend = backend;
7193
socket__deps: ['$Sockets'],
7194
socket: function(family, type, protocol) {
7195
var fd = Sockets.nextFd++;
7196
assert(fd < 64); // select() assumes socket fd values are in 0..63
7197
var stream = type == {{{ cDefine('SOCK_STREAM') }}};
7199
assert(stream == (protocol == {{{ cDefine('IPPROTO_TCP') }}})); // if stream, must be tcp
7201
if (Sockets.backend == Sockets.BACKEND_WEBRTC) {
7202
assert(!stream); // If WebRTC, we can only support datagram, not stream
7211
connect__deps: ['$Sockets', '_inet_ntop_raw', 'htons', 'gethostbyname'],
7212
connect: function(fd, addr, addrlen) {
7213
var info = Sockets.fds[fd];
7214
if (!info) return -1;
7215
info.connected = true;
7216
info.addr = getValue(addr + Sockets.sockaddr_in_layout.sin_addr, 'i32');
7217
info.port = _htons(getValue(addr + Sockets.sockaddr_in_layout.sin_port, 'i16'));
7218
info.host = __inet_ntop_raw(info.addr);
7219
// Support 'fake' ips from gethostbyname
7220
var parts = info.host.split('.');
7221
if (parts[0] == '172' && parts[1] == '29') {
7222
var low = Number(parts[2]);
7223
var high = Number(parts[3]);
7224
info.host = _gethostbyname.table[low + 0xff*high];
7225
assert(info.host, 'problem translating fake ip ' + parts);
7228
Sockets.backends[Sockets.backend].connect(info);
7230
Module.printErr('Error in connect(): ' + e);
7231
___setErrNo(ERRNO_CODES.EACCES);
7237
recv__deps: ['$Sockets'],
7238
recv: function(fd, buf, len, flags) {
7239
var info = Sockets.fds[fd];
7240
if (!info) return -1;
7241
if (!info.hasData()) {
7242
___setErrNo(ERRNO_CODES.EAGAIN); // no data, and all sockets are nonblocking, so this is the right behavior
7245
var buffer = info.inQueue.shift();
7247
Module.print('recv: ' + [Array.prototype.slice.call(buffer)]);
7249
if (len < buffer.length) {
7251
// This is tcp (reliable), so if not all was read, keep it
7252
info.inQueue.unshift(buffer.subarray(len));
7254
Module.print('recv: put back: ' + (len - buffer.length));
7257
buffer = buffer.subarray(0, len);
7259
HEAPU8.set(buffer, buf);
7260
return buffer.length;
7263
send__deps: ['$Sockets'],
7264
send: function(fd, buf, len, flags) {
7265
var info = Sockets.fds[fd];
7266
if (!info) return -1;
7267
info.sender(HEAPU8.subarray(buf, buf+len));
7271
sendmsg__deps: ['$Sockets', 'connect'],
7272
sendmsg: function(fd, msg, flags) {
7273
var info = Sockets.fds[fd];
7274
if (!info) return -1;
7275
// if we are not connected, use the address info in the message
7276
if (!info.connected) {
7277
var name = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_name', '*') }}};
7278
assert(name, 'sendmsg on non-connected socket, and no name/address in the message');
7279
_connect(fd, name, {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_namelen', 'i32') }}});
7281
var iov = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iov', 'i8*') }}};
7282
var num = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iovlen', 'i32') }}};
7284
Module.print('sendmsg vecs: ' + num);
7287
for (var i = 0; i < num; i++) {
7288
totalSize += {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
7290
var buffer = new Uint8Array(totalSize);
7292
for (var i = 0; i < num; i++) {
7293
var currNum = {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
7295
Module.print('sendmsg curr size: ' + currNum);
7297
if (!currNum) continue;
7298
var currBuf = {{{ makeGetValue('iov', '8*i', 'i8*') }}};
7299
buffer.set(HEAPU8.subarray(currBuf, currBuf+currNum), ret);
7302
info.sender(buffer); // send all the iovs as a single message
7306
recvmsg__deps: ['$Sockets', 'connect', 'recv', '__setErrNo', '$ERRNO_CODES', 'htons'],
7307
recvmsg: function(fd, msg, flags) {
7308
var info = Sockets.fds[fd];
7309
if (!info) return -1;
7310
// if we are not connected, use the address info in the message
7311
if (!info.connected) {
7313
Module.print('recvmsg connecting');
7315
var name = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_name', '*') }}};
7316
assert(name, 'sendmsg on non-connected socket, and no name/address in the message');
7317
_connect(fd, name, {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_namelen', 'i32') }}});
7319
if (!info.hasData()) {
7320
___setErrNo(ERRNO_CODES.EWOULDBLOCK);
7323
var buffer = info.inQueue.shift();
7324
var bytes = buffer.length;
7326
Module.print('recvmsg bytes: ' + bytes);
7329
var name = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_name', '*') }}};
7330
{{{ makeSetValue('name', 'Sockets.sockaddr_in_layout.sin_addr', 'info.addr', 'i32') }}};
7331
{{{ makeSetValue('name', 'Sockets.sockaddr_in_layout.sin_port', '_htons(info.port)', 'i16') }}};
7334
var iov = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iov', 'i8*') }}};
7335
var num = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iovlen', 'i32') }}};
7337
for (var i = 0; i < num && bytes > 0; i++) {
7338
var currNum = {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
7340
Module.print('recvmsg loop ' + [i, num, bytes, currNum]);
7342
if (!currNum) continue;
7343
currNum = Math.min(currNum, bytes); // XXX what should happen when we partially fill a buffer..?
7345
var currBuf = {{{ makeGetValue('iov', '8*i', 'i8*') }}};
7347
Module.print('recvmsg call recv ' + currNum);
7349
HEAPU8.set(buffer.subarray(bufferPos, bufferPos + currNum), currBuf);
7350
bufferPos += currNum;
7353
// This is tcp (reliable), so if not all was read, keep it
7354
if (bufferPos < bytes) {
7355
info.inQueue.unshift(buffer.subarray(bufferPos));
7357
Module.print('recvmsg: put back: ' + (bytes - bufferPos));
7364
recvfrom__deps: ['$Sockets', 'connect', 'recv'],
7365
recvfrom: function(fd, buf, len, flags, addr, addrlen) {
7366
var info = Sockets.fds[fd];
7367
if (!info) return -1;
7368
// if we are not connected, use the address info in the message
7369
if (!info.connected) {
7370
//var name = {{{ makeGetValue('addr', '0', '*') }}};
7371
_connect(fd, addr, addrlen);
7373
return _recv(fd, buf, len, flags);
7376
shutdown: function(fd, how) {
7377
var info = Sockets.fds[fd];
7378
if (!info) return -1;
7379
info.socket.close();
7380
Sockets.fds[fd] = null;
7383
ioctl: function(fd, request, varargs) {
7384
var info = Sockets.fds[fd];
7385
if (!info) return -1;
7387
if (info.hasData()) {
7388
bytes = info.inQueue[0].length;
7390
var dest = {{{ makeGetValue('varargs', '0', 'i32') }}};
7391
{{{ makeSetValue('dest', '0', 'bytes', 'i32') }}};
7395
setsockopt: function(d, level, optname, optval, optlen) {
7396
console.log('ignoring setsockopt command');
7400
bind__deps: ['connect'],
7401
bind: function(fd, addr, addrlen) {
7402
return _connect(fd, addr, addrlen);
7405
listen: function(fd, backlog) {
7409
accept: function(fd, addr, addrlen) {
7410
// TODO: webrtc queued incoming connections, etc.
7411
// For now, the model is that bind does a connect, and we "accept" that one connection,
7412
// which has host:port the same as ours. We also return the same socket fd.
7413
var info = Sockets.fds[fd];
7414
if (!info) return -1;
7416
setValue(addr + Sockets.sockaddr_in_layout.sin_addr, info.addr, 'i32');
7417
setValue(addr + Sockets.sockaddr_in_layout.sin_port, info.port, 'i32');
7418
setValue(addrlen, Sockets.sockaddr_in_layout.__size__, 'i32');
7423
select: function(nfds, readfds, writefds, exceptfds, timeout) {
7424
// readfds are supported,
7425
// writefds checks socket open status
7426
// exceptfds not supported
7427
// timeout is always 0 - fully async
7430
var errorCondition = 0;
7432
function canRead(info) {
7433
// make sure hasData exists.
7434
// we do create it when the socket is connected,
7435
// but other implementations may create it lazily
7436
if ((info.socket.readyState == WebSocket.CLOSING || info.socket.readyState == WebSocket.CLOSED) && info.inQueue.length == 0) {
7437
errorCondition = -1;
7440
return info.hasData && info.hasData();
7443
function canWrite(info) {
7444
// make sure socket exists.
7445
// we do create it when the socket is connected,
7446
// but other implementations may create it lazily
7447
if ((info.socket.readyState == WebSocket.CLOSING || info.socket.readyState == WebSocket.CLOSED)) {
7448
errorCondition = -1;
7451
return info.socket && (info.socket.readyState == info.socket.OPEN);
7454
function checkfds(nfds, fds, can) {
7460
var srcLow = {{{ makeGetValue('fds', 0, 'i32') }}};
7461
var srcHigh = {{{ makeGetValue('fds', 4, 'i32') }}};
7462
nfds = Math.min(64, nfds); // fd sets have 64 bits
7464
for (var fd = 0; fd < nfds; fd++) {
7465
var mask = 1 << (fd % 32), int = fd < 32 ? srcLow : srcHigh;
7467
// index is in the set, check if it is ready for read
7468
var info = Sockets.fds[fd];
7469
if (info && can(info)) {
7471
fd < 32 ? (dstLow = dstLow | mask) : (dstHigh = dstHigh | mask);
7477
{{{ makeSetValue('fds', 0, 'dstLow', 'i32') }}};
7478
{{{ makeSetValue('fds', 4, 'dstHigh', 'i32') }}};
7482
var totalHandles = checkfds(nfds, readfds, canRead) + checkfds(nfds, writefds, canWrite);
7483
if (errorCondition) {
7484
___setErrNo(ERRNO_CODES.EBADF);
7487
return totalHandles;
7491
socketpair__deps: ['__setErrNo', '$ERRNO_CODES'],
7492
socketpair: function(domain, type, protocol, sv) {
7493
// int socketpair(int domain, int type, int protocol, int sv[2]);
7494
// http://pubs.opengroup.org/onlinepubs/009695399/functions/socketpair.html
7495
___setErrNo(ERRNO_CODES.EOPNOTSUPP);
7501
openpty: function() { throw 'openpty: TODO' },
7502
forkpty: function() { throw 'forkpty: TODO' },
7506
initgroups: function() { throw 'initgroups: TODO' },
7510
getpwnam: function() { throw 'getpwnam: TODO' },
7511
setpwent: function() { throw 'setpwent: TODO' },
7512
getpwent: function() { throw 'getpwent: TODO' },
7513
endpwent: function() { throw 'endpwent: TODO' },
7515
// ==========================================================================
7517
// ==========================================================================
7519
emscripten_run_script: function(ptr) {
7520
eval(Pointer_stringify(ptr));
7523
emscripten_run_script_int: function(ptr) {
7524
return eval(Pointer_stringify(ptr));
7527
emscripten_run_script_string: function(ptr) {
7528
var s = eval(Pointer_stringify(ptr));
7529
var me = _emscripten_run_script_string;
7530
if (!me.bufferSize || me.bufferSize < s.length+1) {
7531
if (me.bufferSize) _free(me.buffer);
7532
me.bufferSize = s.length+1;
7533
me.buffer = _malloc(me.bufferSize);
7535
writeStringToMemory(s, me.buffer);
7539
emscripten_random: function() {
7540
return Math.random();
7543
emscripten_jcache_printf___deps: ['_formatString'],
7544
emscripten_jcache_printf_: function(varargs) {
7546
if (!_emscripten_jcache_printf_.buffer) {
7547
_emscripten_jcache_printf_.buffer = _malloc(MAX);
7551
var curr = {{{ makeGetValue('varargs', '0', 'i8') }}};
7552
varargs += {{{ STACK_ALIGN }}};
7553
{{{ makeSetValue('_emscripten_jcache_printf_.buffer', 'i', 'curr', 'i8') }}};
7555
assert(i*{{{ STACK_ALIGN }}} < MAX);
7556
} while (curr != 0);
7557
Module.print(intArrayToString(__formatString(_emscripten_jcache_printf_.buffer, varargs)).replace('\\n', ''));
7558
Runtime.stackAlloc(-4*i); // free up the stack space we know is ok to free
7561
//============================
7563
//============================
7566
i64Add__sig: 'iiiii',
7567
i64Add: function(a, b, c, d) {
7573
a = a|0; b = b|0; c = c|0; d = d|0;
7576
h = (b + d + (((l>>>0) < (a>>>0))|0))>>>0; // Add carry from low word to high word on overflow.
7577
{{{ makeStructuralReturn(['l|0', 'h'], true) }}};
7579
llvm_uadd_with_overflow_i64__asm: true,
7580
llvm_uadd_with_overflow_i64__sig: 'iiiii',
7581
llvm_uadd_with_overflow_i64: function(a, b, c, d) {
7582
a = a|0; b = b|0; c = c|0; d = d|0;
7583
var l = 0, h = 0, overflow = 0;
7586
overflow = ((h>>>0) < (b>>>0))|0; // Return whether addition overflowed even the high word.
7587
if ((l>>>0) < (a>>>0)) {
7588
h = (h + 1)>>>0; // Add carry from low word to high word on overflow.
7589
overflow = overflow | (!h); // Check again for overflow.
7591
{{{ makeStructuralReturn(['l|0', 'h', 'overflow'], true) }}};
7594
i64Subtract__asm: true,
7595
i64Subtract__sig: 'iiiii',
7596
i64Subtract: function(a, b, c, d) {
7597
a = a|0; b = b|0; c = c|0; d = d|0;
7601
h = (b - d - (((c>>>0) > (a>>>0))|0))>>>0; // Borrow one from high word to low word on underflow.
7602
{{{ makeStructuralReturn(['l|0', 'h'], true) }}};
7605
bitshift64Shl__asm: true,
7606
bitshift64Shl__sig: 'iiii',
7607
bitshift64Shl: function(low, high, bits) {
7608
low = low|0; high = high|0; bits = bits|0;
7610
if ((bits|0) < 32) {
7611
ander = ((1 << bits) - 1)|0;
7612
tempRet0 = (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits));
7615
tempRet0 = low << (bits - 32);
7618
bitshift64Ashr__asm: true,
7619
bitshift64Ashr__sig: 'iiii',
7620
bitshift64Ashr: function(low, high, bits) {
7621
low = low|0; high = high|0; bits = bits|0;
7623
if ((bits|0) < 32) {
7624
ander = ((1 << bits) - 1)|0;
7625
tempRet0 = high >> bits;
7626
return (low >>> bits) | ((high&ander) << (32 - bits));
7628
tempRet0 = (high|0) < 0 ? -1 : 0;
7629
return (high >> (bits - 32))|0;
7631
bitshift64Lshr__asm: true,
7632
bitshift64Lshr__sig: 'iiii',
7633
bitshift64Lshr: function(low, high, bits) {
7634
low = low|0; high = high|0; bits = bits|0;
7636
if ((bits|0) < 32) {
7637
ander = ((1 << bits) - 1)|0;
7638
tempRet0 = high >>> bits;
7639
return (low >>> bits) | ((high&ander) << (32 - bits));
7642
return (high >>> (bits - 32))|0;
7646
function autoAddDeps(object, name) {
7648
for (var item in object) {
7649
if (item.substr(-6) != '__deps' && !object[item + '__deps']) {
7650
object[item + '__deps'] = name;