~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to src/library.js

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//"use strict";
 
2
 
 
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.
 
6
//
 
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.
 
13
//
 
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.
 
17
 
 
18
LibraryManager.library = {
 
19
  // ==========================================================================
 
20
  // File system base.
 
21
  // ==========================================================================
 
22
 
 
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)',
 
28
 
 
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;',
 
41
  $FS: {
 
42
    // The path to the current folder.
 
43
    currentPath: '/',
 
44
    // The inode to assign to the next created object.
 
45
    nextInode: 2,
 
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
 
51
    // holes, however.
 
52
    streams: [null],
 
53
#if ASSERTIONS
 
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
 
57
    },
 
58
#endif
 
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) {
 
65
      var ret = parts[0];
 
66
      for (var i = 1; i < parts.length; i++) {
 
67
        if (ret[ret.length-1] != '/') ret += '/';
 
68
        ret += parts[i];
 
69
      }
 
70
      if (forceRelative && ret[0] == '/') ret = ret.substr(1);
 
71
      return ret;
 
72
    },
 
73
    // Converts any path to an absolute path. Resolves embedded "." and ".."
 
74
    // parts.
 
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();
 
81
      var absolute = [''];
 
82
      while (parts.length) {
 
83
        var part = parts.pop();
 
84
        if (part == '' || part == '.') {
 
85
          // Nothing.
 
86
        } else if (part == '..') {
 
87
          if (absolute.length > 1) absolute.pop();
 
88
        } else {
 
89
          absolute.push(part);
 
90
        }
 
91
      }
 
92
      return absolute.length == 1 ? '/' : absolute.join('/');
 
93
    },
 
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) {
 
105
      var ret = {
 
106
        isRoot: false,
 
107
        exists: false,
 
108
        error: 0,
 
109
        name: null,
 
110
        path: null,
 
111
        object: null,
 
112
        parentExists: false,
 
113
        parentPath: null,
 
114
        parentObject: null
 
115
      };
 
116
#if FS_LOG
 
117
      var inputPath = path;
 
118
      function log() {
 
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 + '}');
 
131
      }
 
132
#endif
 
133
      path = FS.absolutePath(path);
 
134
      if (path == '/') {
 
135
        ret.isRoot = true;
 
136
        ret.exists = ret.parentExists = true;
 
137
        ret.name = '/';
 
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;
 
150
            ret.name = path[0];
 
151
          }
 
152
          var target = path.shift();
 
153
          if (!current.isFolder) {
 
154
            ret.error = ERRNO_CODES.ENOTDIR;
 
155
            break;
 
156
          } else if (!current.read) {
 
157
            ret.error = ERRNO_CODES.EACCES;
 
158
            break;
 
159
          } else if (!current.contents.hasOwnProperty(target)) {
 
160
            ret.error = ERRNO_CODES.ENOENT;
 
161
            break;
 
162
          }
 
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;
 
167
              break;
 
168
            }
 
169
            var link = FS.absolutePath(current.link, traversed.join('/'));
 
170
            ret = FS.analyzePath([link].concat(path).join('/'),
 
171
                                 dontResolveLastLink, linksVisited + 1);
 
172
#if FS_LOG
 
173
            log();
 
174
#endif
 
175
            return ret;
 
176
          }
 
177
          traversed.push(target);
 
178
          if (path.length == 0) {
 
179
            ret.exists = true;
 
180
            ret.path = traversed.join('/');
 
181
            ret.object = current;
 
182
          }
 
183
        }
 
184
      }
 
185
#if FS_LOG
 
186
      log();
 
187
#endif
 
188
      return ret;
 
189
    },
 
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) {
 
194
      FS.ensureRoot();
 
195
      var ret = FS.analyzePath(path, dontResolveLastLink);
 
196
      if (ret.exists) {
 
197
        return ret.object;
 
198
      } else {
 
199
        ___setErrNo(ret.error);
 
200
        return null;
 
201
      }
 
202
    },
 
203
    // Creates a file system record: file, link, device or folder.
 
204
    createObject: function(parent, name, properties, canRead, canWrite) {
 
205
#if FS_LOG
 
206
      Module['print']('FS.createObject("' + parent + '", ' +
 
207
                                      '"' + name + '", ' +
 
208
                                          JSON.stringify(properties) + ', ' +
 
209
                                          canRead + ', ' +
 
210
                                          canWrite + ')');
 
211
#endif
 
212
      if (!parent) parent = '/';
 
213
      if (typeof parent === 'string') parent = FS.findObject(parent);
 
214
 
 
215
      if (!parent) {
 
216
        ___setErrNo(ERRNO_CODES.EACCES);
 
217
        throw new Error('Parent path must exist.');
 
218
      }
 
219
      if (!parent.isFolder) {
 
220
        ___setErrNo(ERRNO_CODES.ENOTDIR);
 
221
        throw new Error('Parent must be a folder.');
 
222
      }
 
223
      if (!parent.write && !FS.ignorePermissions) {
 
224
        ___setErrNo(ERRNO_CODES.EACCES);
 
225
        throw new Error('Parent folder must be writeable.');
 
226
      }
 
227
      if (!name || name == '.' || name == '..') {
 
228
        ___setErrNo(ERRNO_CODES.ENOENT);
 
229
        throw new Error('Name must not be empty.');
 
230
      }
 
231
      if (parent.contents.hasOwnProperty(name)) {
 
232
        ___setErrNo(ERRNO_CODES.EEXIST);
 
233
        throw new Error("Can't overwrite object.");
 
234
      }
 
235
 
 
236
      parent.contents[name] = {
 
237
        read: canRead === undefined ? true : canRead,
 
238
        write: canWrite === undefined ? false : canWrite,
 
239
        timestamp: Date.now(),
 
240
        inodeNumber: FS.nextInode++
 
241
      };
 
242
      for (var key in properties) {
 
243
        if (properties.hasOwnProperty(key)) {
 
244
          parent.contents[name][key] = properties[key];
 
245
        }
 
246
      }
 
247
 
 
248
      return parent.contents[name];
 
249
    },
 
250
    // Creates a folder.
 
251
    createFolder: function(parent, name, canRead, canWrite) {
 
252
      var properties = {isFolder: true, isDevice: false, contents: {}};
 
253
      return FS.createObject(parent, name, properties, canRead, canWrite);
 
254
    },
 
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();
 
262
        if (!part) continue;
 
263
        if (!current.contents.hasOwnProperty(part)) {
 
264
          FS.createFolder(current, part, canRead, canWrite);
 
265
        }
 
266
        current = current.contents[part];
 
267
      }
 
268
      return current;
 
269
    },
 
270
 
 
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);
 
275
    },
 
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);
 
281
        data = dataArray;
 
282
      }
 
283
      var properties = {
 
284
        isDevice: false,
 
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
 
286
      };
 
287
      return FS.createFile(parent, name, properties, canRead, canWrite);
 
288
    },
 
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) {
 
293
 
 
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
 
301
        }
 
302
        LazyUint8Array.prototype.get = function(idx) {
 
303
          if (idx > this.length-1 || idx < 0) {
 
304
            return undefined;
 
305
          }
 
306
          var chunkOffset = idx % chunkSize;
 
307
          var chunkNum = Math.floor(idx / chunkSize);
 
308
          return this.getter(chunkNum)[chunkOffset];
 
309
        }
 
310
        LazyUint8Array.prototype.setDataGetter = function(getter) {
 
311
          this.getter = getter;
 
312
        }
 
313
  
 
314
        // Find length
 
315
        var xhr = new XMLHttpRequest();
 
316
        xhr.open('HEAD', url, false);
 
317
        xhr.send(null);
 
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"));
 
320
        var header;
 
321
        var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
 
322
#if SMALL_XHR_CHUNKS
 
323
        var chunkSize = 1024; // Chunk size in bytes
 
324
#else
 
325
        var chunkSize = 1024*1024; // Chunk size in bytes
 
326
#endif
 
327
        if (!hasByteServing) chunkSize = datalength;
 
328
  
 
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!");
 
333
  
 
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);
 
338
  
 
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');
 
343
          }
 
344
  
 
345
          xhr.send(null);
 
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 || []);
 
349
          } else {
 
350
            return intArrayFromString(xhr.responseText || '', true);
 
351
          }
 
352
        });
 
353
  
 
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);
 
361
          }
 
362
          if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
 
363
          return lazyArray.chunks[chunkNum];
 
364
        });
 
365
        var properties = { isDevice: false, contents: lazyArray };
 
366
      } else {
 
367
        var properties = { isDevice: false, url: url };
 
368
      }
 
369
 
 
370
      return FS.createFile(parent, name, properties, canRead, canWrite);
 
371
    },
 
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
 
376
    // that happens.
 
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) {
 
385
      Browser.init();
 
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);
 
391
          }
 
392
          if (onload) onload();
 
393
          removeRunDependency('cp ' + fullname);
 
394
        }
 
395
        var handled = false;
 
396
        Module['preloadPlugins'].forEach(function(plugin) {
 
397
          if (handled) return;
 
398
          if (plugin['canHandle'](fullname)) {
 
399
            plugin['handle'](byteArray, fullname, finish, function() {
 
400
              if (onerror) onerror();
 
401
              removeRunDependency('cp ' + fullname);
 
402
            });
 
403
            handled = true;
 
404
          }
 
405
        });
 
406
        if (!handled) finish(byteArray);
 
407
      }
 
408
      addRunDependency('cp ' + fullname);
 
409
      if (typeof url == 'string') {
 
410
        Browser.asyncLoad(url, function(byteArray) {
 
411
          processData(byteArray);
 
412
        }, onerror);
 
413
      } else {
 
414
        processData(url);
 
415
      }
 
416
    },
 
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);
 
421
    },
 
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.');
 
430
      }
 
431
      var ops = {isDevice: true, input: input, output: output};
 
432
      return FS.createFile(parent, name, ops, Boolean(input), Boolean(output));
 
433
    },
 
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;
 
438
      var success = 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']) {
 
442
        // Command-line.
 
443
        try {
 
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);
 
447
        } catch (e) {
 
448
          success = false;
 
449
        }
 
450
      } else {
 
451
        throw new Error('Cannot load without read() or XMLHttpRequest.');
 
452
      }
 
453
      if (!success) ___setErrNo(ERRNO_CODES.EIO);
 
454
      return success;
 
455
    },
 
456
    ensureRoot: function() {
 
457
      if (FS.root) return;
 
458
      // The main file system tree. All the contents are inside this.
 
459
      FS.root = {
 
460
        read: true,
 
461
        write: true,
 
462
        isFolder: true,
 
463
        isDevice: false,
 
464
        timestamp: Date.now(),
 
465
        inodeNumber: 1,
 
466
        contents: {}
 
467
      };
 
468
    },
 
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;
 
475
 
 
476
      FS.ensureRoot();
 
477
 
 
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'];
 
482
 
 
483
      // Default handlers.
 
484
      var stdinOverridden = true, stdoutOverridden = true, stderrOverridden = true;
 
485
      if (!input) {
 
486
        stdinOverridden = false;
 
487
        input = function() {
 
488
          if (!input.cache || !input.cache.length) {
 
489
            var result;
 
490
            if (typeof window != 'undefined' &&
 
491
                typeof window.prompt == 'function') {
 
492
              // Browser.
 
493
              result = window.prompt('Input: ');
 
494
              if (result === null) result = String.fromCharCode(0); // cancel ==> EOF
 
495
            } else if (typeof readline == 'function') {
 
496
              // Command line.
 
497
              result = readline();
 
498
            }
 
499
            if (!result) result = '';
 
500
            input.cache = intArrayFromString(result + '\n', true);
 
501
          }
 
502
          return input.cache.shift();
 
503
        };
 
504
      }
 
505
      var utf8 = new Runtime.UTF8Processor();
 
506
      function simpleOutput(val) {
 
507
        if (val === null || val === {{{ charCode('\n') }}}) {
 
508
          output.printer(output.buffer.join(''));
 
509
          output.buffer = [];
 
510
        } else {
 
511
          output.buffer.push(utf8.processCChar(val));
 
512
        }
 
513
      }
 
514
      if (!output) {
 
515
        stdoutOverridden = false;
 
516
        output = simpleOutput;
 
517
      }
 
518
      if (!output.printer) output.printer = Module['print'];
 
519
      if (!output.buffer) output.buffer = [];
 
520
      if (!error) {
 
521
        stderrOverridden = false;
 
522
        error = simpleOutput;
 
523
      }
 
524
      if (!error.printer) error.printer = Module['print'];
 
525
      if (!error.buffer) error.buffer = [];
 
526
 
 
527
      // Create the temporary folder, if not already created
 
528
      try {
 
529
        FS.createFolder('/', 'tmp', true, true);
 
530
      } catch(e) {}
 
531
 
 
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);
 
538
 
 
539
      // Create default streams.
 
540
      FS.streams[1] = {
 
541
        path: '/dev/stdin',
 
542
        object: stdin,
 
543
        position: 0,
 
544
        isRead: true,
 
545
        isWrite: false,
 
546
        isAppend: false,
 
547
        isTerminal: !stdinOverridden,
 
548
        error: false,
 
549
        eof: false,
 
550
        ungotten: []
 
551
      };
 
552
      FS.streams[2] = {
 
553
        path: '/dev/stdout',
 
554
        object: stdout,
 
555
        position: 0,
 
556
        isRead: false,
 
557
        isWrite: true,
 
558
        isAppend: false,
 
559
        isTerminal: !stdoutOverridden,
 
560
        error: false,
 
561
        eof: false,
 
562
        ungotten: []
 
563
      };
 
564
      FS.streams[3] = {
 
565
        path: '/dev/stderr',
 
566
        object: stderr,
 
567
        position: 0,
 
568
        isRead: false,
 
569
        isWrite: true,
 
570
        isAppend: false,
 
571
        isTerminal: !stderrOverridden,
 
572
        error: false,
 
573
        eof: false,
 
574
        ungotten: []
 
575
      };
 
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*') }}};
 
580
 
 
581
      // Other system paths
 
582
      FS.createPath('/', 'dev/shm/tmp', true, true); // temp files
 
583
 
 
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
 
587
      }
 
588
      FS.streams[_stdin] = FS.streams[1];
 
589
      FS.streams[_stdout] = FS.streams[2];
 
590
      FS.streams[_stderr] = FS.streams[3];
 
591
#if ASSERTIONS
 
592
      FS.checkStreams();
 
593
      assert(FS.streams.length < 1024); // at this early stage, we should not have a large set of file descriptors - just a few
 
594
#endif
 
595
      allocate([ allocate(
 
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') }}});
 
598
    },
 
599
 
 
600
    quit: function() {
 
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') }}});
 
605
    },
 
606
 
 
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);
 
611
      return path;
 
612
    },
 
613
 
 
614
    deleteFile: function(path) {
 
615
      path = FS.analyzePath(path);
 
616
      if (!path.parentExists || !path.exists) {
 
617
        throw 'Invalid path ' + path;
 
618
      }
 
619
      delete path.parentObject.contents[path.name];
 
620
    }
 
621
  },
 
622
 
 
623
  // ==========================================================================
 
624
  // dirent.h
 
625
  // ==========================================================================
 
626
 
 
627
  __dirent_struct_layout: Runtime.generateStructInfo([
 
628
    ['i32', 'd_ino'],
 
629
    ['b1024', 'd_name'],
 
630
    ['i32', 'd_off'],
 
631
    ['i32', 'd_reclen'],
 
632
    ['i32', 'd_type']]),
 
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));
 
640
    if (path === null) {
 
641
      ___setErrNo(ERRNO_CODES.ENOENT);
 
642
      return 0;
 
643
    }
 
644
    var target = FS.findObject(path);
 
645
    if (target === null) return 0;
 
646
    if (!target.isFolder) {
 
647
      ___setErrNo(ERRNO_CODES.ENOTDIR);
 
648
      return 0;
 
649
    } else if (!target.read) {
 
650
      ___setErrNo(ERRNO_CODES.EACCES);
 
651
      return 0;
 
652
    }
 
653
    var id = FS.streams.length; // Keep dense
 
654
    var contents = [];
 
655
    for (var key in target.contents) contents.push(key);
 
656
    FS.streams[id] = {
 
657
      path: path,
 
658
      object: target,
 
659
      // An index into contents. Special values: -2 is ".", -1 is "..".
 
660
      position: -2,
 
661
      isRead: true,
 
662
      isWrite: false,
 
663
      isAppend: false,
 
664
      error: false,
 
665
      eof: false,
 
666
      ungotten: [],
 
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.
 
670
      contents: contents,
 
671
      // Each stream has its own area for readdir() returns.
 
672
      currentEntry: _malloc(___dirent_struct_layout.__size__)
 
673
    };
 
674
#if ASSERTIONS
 
675
    FS.checkStreams();
 
676
#endif
 
677
    return id;
 
678
  },
 
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);
 
685
    } else {
 
686
      _free(FS.streams[dirp].currentEntry);
 
687
      FS.streams[dirp] = null;
 
688
      return 0;
 
689
    }
 
690
  },
 
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);
 
697
    } else {
 
698
      return FS.streams[dirp].position;
 
699
    }
 
700
  },
 
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);
 
707
    } else {
 
708
      var entries = 0;
 
709
      for (var key in FS.streams[dirp].contents) entries++;
 
710
      if (loc >= entries) {
 
711
        ___setErrNo(ERRNO_CODES.EINVAL);
 
712
      } else {
 
713
        FS.streams[dirp].position = loc;
 
714
      }
 
715
    }
 
716
  },
 
717
  rewinddir__deps: ['seekdir'],
 
718
  rewinddir: function(dirp) {
 
719
    // void rewinddir(DIR *dirp);
 
720
    // http://pubs.opengroup.org/onlinepubs/007908799/xsh/rewinddir.html
 
721
    _seekdir(dirp, -2);
 
722
  },
 
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);
 
729
    }
 
730
    var stream = FS.streams[dirp];
 
731
    var loc = stream.position;
 
732
    var entries = 0;
 
733
    for (var key in stream.contents) entries++;
 
734
    if (loc < -2 || loc >= entries) {
 
735
      {{{ makeSetValue('result', '0', '0', 'i8*') }}}
 
736
    } else {
 
737
      var name, inode, type;
 
738
      if (loc === -2) {
 
739
        name = '.';
 
740
        inode = 1;  // Really undefined.
 
741
        type = 4; //DT_DIR
 
742
      } else if (loc === -1) {
 
743
        name = '..';
 
744
        inode = 1;  // Really undefined.
 
745
        type = 4; //DT_DIR
 
746
      } else {
 
747
        var object;
 
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.
 
755
      }
 
756
      stream.position++;
 
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') }}}
 
763
      }
 
764
      {{{ makeSetValue('entry + offsets.d_name', 'i', '0', 'i8') }}}
 
765
      {{{ makeSetValue('entry', 'offsets.d_type', 'type', 'i8') }}}
 
766
      {{{ makeSetValue('result', '0', 'entry', 'i8*') }}}
 
767
    }
 
768
    return 0;
 
769
  },
 
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);
 
776
      return 0;
 
777
    } else {
 
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) {
 
781
        return 0;
 
782
      } else {
 
783
        return FS.streams[dirp].currentEntry;
 
784
      }
 
785
    }
 
786
  },
 
787
  __01readdir64_: 'readdir',
 
788
  // TODO: Check if we need to link any other aliases.
 
789
 
 
790
  // ==========================================================================
 
791
  // utime.h
 
792
  // ==========================================================================
 
793
 
 
794
  __utimbuf_struct_layout: Runtime.generateStructInfo([
 
795
    ['i32', 'actime'],
 
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
 
801
    var time;
 
802
    if (times) {
 
803
      // NOTE: We don't keep track of access timestamps.
 
804
      var offset = ___utimbuf_struct_layout.modtime;
 
805
      time = {{{ makeGetValue('times', 'offset', 'i32') }}}
 
806
      time *= 1000;
 
807
    } else {
 
808
      time = Date.now();
 
809
    }
 
810
    var file = FS.findObject(Pointer_stringify(path));
 
811
    if (file === null) return -1;
 
812
    if (!file.write) {
 
813
      ___setErrNo(ERRNO_CODES.EPERM);
 
814
      return -1;
 
815
    }
 
816
    file.timestamp = time;
 
817
    return 0;
 
818
  },
 
819
 
 
820
  utimes: function() { throw 'utimes not implemented' },
 
821
 
 
822
  // ==========================================================================
 
823
  // libgen.h
 
824
  // ==========================================================================
 
825
 
 
826
  __libgenSplitName: function(path) {
 
827
    if (path === 0 || {{{ makeGetValue('path', 0, 'i8') }}} === 0) {
 
828
      // Null or empty results in '.'.
 
829
      var me = ___libgenSplitName;
 
830
      if (!me.ret) {
 
831
        me.ret = allocate([{{{ charCode('.') }}}, 0], 'i8', ALLOC_NORMAL);
 
832
      }
 
833
      return [me.ret, -1];
 
834
    } else {
 
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);
 
841
        } else {
 
842
          allSlashes = false;
 
843
        }
 
844
      }
 
845
      var length = i;
 
846
      if (allSlashes) {
 
847
        // All slashes result in a single slash.
 
848
        {{{ makeSetValue('path', '1', '0', 'i8') }}}
 
849
        return [path, -1];
 
850
      } else {
 
851
        // Strip trailing slashes.
 
852
        while (slashPositions.length &&
 
853
               slashPositions[slashPositions.length - 1] == length - 1) {
 
854
          {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}}
 
855
          length--;
 
856
        }
 
857
        return [path, slashPositions.pop()];
 
858
      }
 
859
    }
 
860
  },
 
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;
 
867
  },
 
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') }}}
 
878
    }
 
879
    return result[0];
 
880
  },
 
881
 
 
882
  // ==========================================================================
 
883
  // sys/stat.h
 
884
  // ==========================================================================
 
885
 
 
886
  __stat_struct_layout: Runtime.generateStructInfo([
 
887
    ['i32', 'st_dev'],
 
888
    ['i32', 'st_ino'],
 
889
    ['i32', 'st_mode'],
 
890
    ['i32', 'st_nlink'],
 
891
    ['i32', 'st_uid'],
 
892
    ['i32', 'st_gid'],
 
893
    ['i32', 'st_rdev'],
 
894
    ['i32', 'st_size'],
 
895
    ['i32', 'st_atime'],
 
896
    ['i32', 'st_spare1'],
 
897
    ['i32', 'st_mtime'],
 
898
    ['i32', 'st_spare2'],
 
899
    ['i32', 'st_ctime'],
 
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;
 
912
 
 
913
    var offsets = ___stat_struct_layout;
 
914
 
 
915
    // Constants.
 
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') }}}
 
920
 
 
921
    // Variables.
 
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') }}}
 
932
    }
 
933
    {{{ makeSetValue('buf', 'offsets.st_atime', 'time', 'i32') }}}
 
934
    {{{ makeSetValue('buf', 'offsets.st_mtime', 'time', 'i32') }}}
 
935
    {{{ makeSetValue('buf', 'offsets.st_ctime', 'time', 'i32') }}}
 
936
    var mode = 0;
 
937
    var size = 0;
 
938
    var blocks = 0;
 
939
    var dev = 0;
 
940
    var rdev = 0;
 
941
    if (obj.isDevice) {
 
942
      //  Device numbers reuse inode numbers.
 
943
      dev = rdev = obj.inodeNumber;
 
944
      size = blocks = 0;
 
945
      mode = 0x2000;  // S_IFCHR.
 
946
    } else {
 
947
      dev = 1;
 
948
      rdev = 0;
 
949
      // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
 
950
      //       but this is not required by the standard.
 
951
      if (obj.isFolder) {
 
952
        size = 4096;
 
953
        blocks = 1;
 
954
        mode = 0x4000;  // S_IFDIR.
 
955
      } else {
 
956
        var data = obj.contents || obj.link;
 
957
        size = data.length;
 
958
        blocks = Math.ceil(data.length / 4096);
 
959
        mode = obj.link === undefined ? 0x8000 : 0xA000;  // S_IFREG, S_IFLNK.
 
960
      }
 
961
    }
 
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') }}}
 
969
 
 
970
    return 0;
 
971
  },
 
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);
 
977
  },
 
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);
 
984
      return -1;
 
985
    } else {
 
986
      var pathArray = intArrayFromString(FS.streams[fildes].path);
 
987
      return _stat(allocate(pathArray, 'i8', ALLOC_STACK), buf);
 
988
    }
 
989
  },
 
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);
 
997
      return -1;
 
998
    } else {
 
999
      var properties = {contents: [], isFolder: Boolean(mode & 0x4000)};  // S_IFDIR.
 
1000
      path = FS.analyzePath(Pointer_stringify(path));
 
1001
      try {
 
1002
        FS.createObject(path.parentObject, path.name, properties,
 
1003
                        mode & 0x100, mode & 0x80);  // S_IRUSR, S_IWUSR.
 
1004
        return 0;
 
1005
      } catch (e) {
 
1006
        return -1;
 
1007
      }
 
1008
    }
 
1009
  },
 
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.
 
1015
  },
 
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);
 
1025
    return -1;
 
1026
  },
 
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();
 
1036
    return 0;
 
1037
  },
 
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);
 
1044
      return -1;
 
1045
    } else {
 
1046
      var pathArray = intArrayFromString(FS.streams[fildes].path);
 
1047
      return _chmod(allocate(pathArray, 'i8', ALLOC_STACK), mode);
 
1048
    }
 
1049
  },
 
1050
  lchmod: function() { throw 'TODO: lchmod' },
 
1051
 
 
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;
 
1060
    return oldMask;
 
1061
  },
 
1062
  stat64: 'stat',
 
1063
  fstat64: 'fstat',
 
1064
  __01fstat64_: 'fstat',
 
1065
  __01stat64_: 'stat',
 
1066
  __01lstat64_: 'lstat',
 
1067
 
 
1068
  // TODO: Check if other aliases are needed.
 
1069
 
 
1070
  // ==========================================================================
 
1071
  // sys/statvfs.h
 
1072
  // ==========================================================================
 
1073
 
 
1074
  __statvfs_struct_layout: Runtime.generateStructInfo([
 
1075
    ['i32', 'f_bsize'],
 
1076
    ['i32', 'f_frsize'],
 
1077
    ['i32', 'f_blocks'],
 
1078
    ['i32', 'f_bfree'],
 
1079
    ['i32', 'f_bavail'],
 
1080
    ['i32', 'f_files'],
 
1081
    ['i32', 'f_ffree'],
 
1082
    ['i32', 'f_favail'],
 
1083
    ['i32', 'f_fsid'],
 
1084
    ['i32', 'f_flag'],
 
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
 
1092
    //       sane values.
 
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') }}}
 
1104
    return 0;
 
1105
  },
 
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);
 
1111
  },
 
1112
  __01statvfs64_: 'statvfs',
 
1113
  __01fstatvfs64_: 'fstatvfs',
 
1114
 
 
1115
  // ==========================================================================
 
1116
  // fcntl.h
 
1117
  // ==========================================================================
 
1118
 
 
1119
  __flock_struct_layout: Runtime.generateStructInfo([
 
1120
    ['i16', 'l_type'],
 
1121
    ['i16', 'l_whence'],
 
1122
    ['i32', 'l_start'],
 
1123
    ['i32', 'l_len'],
 
1124
    ['i16', 'l_pid'],
 
1125
    ['i16', 'l_xxx']]),
 
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.
 
1132
 
 
1133
    var mode = {{{ makeGetValue('varargs', 0, 'i32') }}};
 
1134
 
 
1135
    // Simplify flags.
 
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') }}});
 
1143
 
 
1144
    // Verify path.
 
1145
    var origPath = path;
 
1146
    path = FS.analyzePath(Pointer_stringify(path));
 
1147
    if (!path.parentExists) {
 
1148
      ___setErrNo(path.error);
 
1149
      return -1;
 
1150
    }
 
1151
    var target = path.object || null;
 
1152
    var finalPath;
 
1153
 
 
1154
    // Verify the file exists, create if needed and allowed.
 
1155
    if (target) {
 
1156
      if (isCreate && isExistCheck) {
 
1157
        ___setErrNo(ERRNO_CODES.EEXIST);
 
1158
        return -1;
 
1159
      }
 
1160
      if ((isWrite || isCreate || isTruncate) && target.isFolder) {
 
1161
        ___setErrNo(ERRNO_CODES.EISDIR);
 
1162
        return -1;
 
1163
      }
 
1164
      if (isRead && !target.read || isWrite && !target.write) {
 
1165
        ___setErrNo(ERRNO_CODES.EACCES);
 
1166
        return -1;
 
1167
      }
 
1168
      if (isTruncate && !target.isDevice) {
 
1169
        target.contents = [];
 
1170
      } else {
 
1171
        if (!FS.forceLoadFile(target)) {
 
1172
          ___setErrNo(ERRNO_CODES.EIO);
 
1173
          return -1;
 
1174
        }
 
1175
      }
 
1176
      finalPath = path.path;
 
1177
    } else {
 
1178
      if (!isCreate) {
 
1179
        ___setErrNo(ERRNO_CODES.ENOENT);
 
1180
        return -1;
 
1181
      }
 
1182
      if (!path.parentObject.write) {
 
1183
        ___setErrNo(ERRNO_CODES.EACCES);
 
1184
        return -1;
 
1185
      }
 
1186
      target = FS.createDataFile(path.parentObject, path.name, [],
 
1187
                                 mode & 0x100, mode & 0x80);  // S_IRUSR, S_IWUSR.
 
1188
      finalPath = path.parentPath + '/' + path.name;
 
1189
    }
 
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__);
 
1196
      }
 
1197
      var contents = [];
 
1198
      for (var key in target.contents) contents.push(key);
 
1199
      FS.streams[id] = {
 
1200
        path: finalPath,
 
1201
        object: target,
 
1202
        // An index into contents. Special values: -2 is ".", -1 is "..".
 
1203
        position: -2,
 
1204
        isRead: true,
 
1205
        isWrite: false,
 
1206
        isAppend: false,
 
1207
        error: false,
 
1208
        eof: false,
 
1209
        ungotten: [],
 
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.
 
1213
        contents: contents,
 
1214
        // Each stream has its own area for readdir() returns.
 
1215
        currentEntry: entryBuffer
 
1216
      };
 
1217
    } else {
 
1218
      FS.streams[id] = {
 
1219
        path: finalPath,
 
1220
        object: target,
 
1221
        position: 0,
 
1222
        isRead: isRead,
 
1223
        isWrite: isWrite,
 
1224
        isAppend: isAppend,
 
1225
        error: false,
 
1226
        eof: false,
 
1227
        ungotten: []
 
1228
      };
 
1229
    }
 
1230
#if ASSERTIONS
 
1231
    FS.checkStreams();
 
1232
#endif
 
1233
    return id;
 
1234
  },
 
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));
 
1240
  },
 
1241
  mkstemp__deps: ['creat'],
 
1242
  mkstemp: function(template) {
 
1243
    if (!_mkstemp.counter) _mkstemp.counter = 0;
 
1244
    var c = (_mkstemp.counter++).toString();
 
1245
    var rep = 'XXXXXX';
 
1246
    while (c.length < rep.length) c = '0' + c;
 
1247
    writeArrayToMemory(intArrayFromString(c), template + Pointer_stringify(template).indexOf(rep));
 
1248
    return _creat(template, 0600);
 
1249
  },
 
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);
 
1256
      return -1;
 
1257
    }
 
1258
    var stream = FS.streams[fildes];
 
1259
    switch (cmd) {
 
1260
      case {{{ cDefine('F_DUPFD') }}}:
 
1261
        var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
 
1262
        if (arg < 0) {
 
1263
          ___setErrNo(ERRNO_CODES.EINVAL);
 
1264
          return -1;
 
1265
        }
 
1266
        var newStream = {};
 
1267
        for (var member in stream) {
 
1268
          newStream[member] = stream[member];
 
1269
        }
 
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
 
1273
        }
 
1274
        FS.streams[arg] = newStream;
 
1275
#if ASSERTIONS
 
1276
        FS.checkStreams();
 
1277
#endif
 
1278
        return arg;
 
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') }}}:
 
1283
        var flags = 0;
 
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.
 
1289
        return flags;
 
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.
 
1294
        return 0;
 
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') }}}
 
1301
        return 0;
 
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.
 
1307
        return 0;
 
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);
 
1312
        return -1;
 
1313
      default:
 
1314
        ___setErrNo(ERRNO_CODES.EINVAL);
 
1315
        return -1;
 
1316
    }
 
1317
    // Should never be reached. Only to silence strict warnings.
 
1318
    return -1;
 
1319
  },
 
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.
 
1324
    return 0;
 
1325
  },
 
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);
 
1334
      return -1;
 
1335
    }
 
1336
    var contents = FS.streams[fd].object.contents;
 
1337
    var limit = offset + len;
 
1338
    while (limit > contents.length) contents.push(0);
 
1339
    return 0;
 
1340
  },
 
1341
 
 
1342
  // ==========================================================================
 
1343
  // poll.h
 
1344
  // ==========================================================================
 
1345
 
 
1346
  __pollfd_struct_layout: Runtime.generateStructInfo([
 
1347
    ['i32', 'fd'],
 
1348
    ['i16', 'events'],
 
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;
 
1356
    var nonzero = 0;
 
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') }}};
 
1361
      var revents = 0;
 
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') }}};
 
1366
      } else {
 
1367
        if (events & {{{ cDefine('POLLNVAL') }}}) revents |= {{{ cDefine('POLLNVAL') }}};
 
1368
      }
 
1369
      if (revents) nonzero++;
 
1370
      {{{ makeSetValue('pollfd', 'offsets.revents', 'revents', 'i16') }}}
 
1371
    }
 
1372
    return nonzero;
 
1373
  },
 
1374
 
 
1375
  // ==========================================================================
 
1376
  // unistd.h
 
1377
  // ==========================================================================
 
1378
 
 
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);
 
1389
      return -1;
 
1390
    } else {
 
1391
      return 0;
 
1392
    }
 
1393
  },
 
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);
 
1401
    if (!path.exists) {
 
1402
      ___setErrNo(path.error);
 
1403
      return -1;
 
1404
    } else if (!path.object.isFolder) {
 
1405
      ___setErrNo(ERRNO_CODES.ENOTDIR);
 
1406
      return -1;
 
1407
    } else {
 
1408
      FS.currentPath = path.path;
 
1409
      return 0;
 
1410
    }
 
1411
  },
 
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();
 
1424
    return 0;
 
1425
  },
 
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);
 
1431
    return -1;
 
1432
  },
 
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);
 
1440
      }
 
1441
      FS.streams[fildes] = null;
 
1442
      return 0;
 
1443
    } else {
 
1444
      ___setErrNo(ERRNO_CODES.EBADF);
 
1445
      return -1;
 
1446
    }
 
1447
  },
 
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.
 
1453
  },
 
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
 
1458
    if (fildes2 < 0) {
 
1459
      ___setErrNo(ERRNO_CODES.EBADF);
 
1460
      return -1;
 
1461
    } else if (fildes === fildes2 && FS.streams[fildes]) {
 
1462
      return fildes;
 
1463
    } else {
 
1464
      _close(fildes2);
 
1465
      return _fcntl(fildes, 0, allocate([fildes2, 0, 0, 0], 'i32', ALLOC_STACK), true);  // F_DUPFD.
 
1466
    }
 
1467
  },
 
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);
 
1474
    } else {
 
1475
      ___setErrNo(ERRNO_CODES.EBADF);
 
1476
      return -1;
 
1477
    }
 
1478
  },
 
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);
 
1485
    } else {
 
1486
      ___setErrNo(ERRNO_CODES.EBADF);
 
1487
      return -1;
 
1488
    }
 
1489
  },
 
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);
 
1497
    }
 
1498
    return s ? _strcpy(s, _ctermid.ret) : _ctermid.ret;
 
1499
  },
 
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);
 
1505
    return 0;
 
1506
  },
 
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);
 
1512
  },
 
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.
 
1519
    switch (name) {
 
1520
      case {{{ cDefine('_PC_LINK_MAX') }}}:
 
1521
        return 32000;
 
1522
      case {{{ cDefine('_PC_MAX_CANON') }}}:
 
1523
      case {{{ cDefine('_PC_MAX_INPUT') }}}:
 
1524
      case {{{ cDefine('_PC_NAME_MAX') }}}:
 
1525
        return 255;
 
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') }}}:
 
1531
        return 4096;
 
1532
      case {{{ cDefine('_PC_CHOWN_RESTRICTED') }}}:
 
1533
      case {{{ cDefine('_PC_NO_TRUNC') }}}:
 
1534
      case {{{ cDefine('_PC_2_SYMLINKS') }}}:
 
1535
        return 1;
 
1536
      case {{{ cDefine('_PC_VDISABLE') }}}:
 
1537
        return 0;
 
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') }}}:
 
1545
        return -1;
 
1546
      case {{{ cDefine('_PC_FILESIZEBITS') }}}:
 
1547
        return 64;
 
1548
    }
 
1549
    ___setErrNo(ERRNO_CODES.EINVAL);
 
1550
    return -1;
 
1551
  },
 
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.
 
1559
      return 0;
 
1560
    } else {
 
1561
      ___setErrNo(ERRNO_CODES.EBADF);
 
1562
      return -1;
 
1563
    }
 
1564
  },
 
1565
  fdatasync: 'fsync',
 
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().
 
1571
    if (length < 0) {
 
1572
      ___setErrNo(ERRNO_CODES.EINVAL);
 
1573
      return -1;
 
1574
    } else {
 
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);
 
1580
        return -1;
 
1581
      } else if (target.isDevice) {
 
1582
        ___setErrNo(ERRNO_CODES.EINVAL);
 
1583
        return -1;
 
1584
      } else if (!target.write) {
 
1585
        ___setErrNo(ERRNO_CODES.EACCES);
 
1586
        return -1;
 
1587
      } else {
 
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();
 
1592
        return 0;
 
1593
      }
 
1594
    }
 
1595
  },
 
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);
 
1604
      return -1;
 
1605
    } else {
 
1606
      ___setErrNo(ERRNO_CODES.EBADF);
 
1607
      return -1;
 
1608
    }
 
1609
  },
 
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
 
1614
    if (size == 0) {
 
1615
      ___setErrNo(ERRNO_CODES.EINVAL);
 
1616
      return 0;
 
1617
    } else if (size < FS.currentPath.length + 1) {
 
1618
      ___setErrNo(ERRNO_CODES.ERANGE);
 
1619
      return 0;
 
1620
    } else {
 
1621
      for (var i = 0; i < FS.currentPath.length; i++) {
 
1622
        {{{ makeSetValue('buf', 'i', 'FS.currentPath.charCodeAt(i)', 'i8') }}}
 
1623
      }
 
1624
      {{{ makeSetValue('buf', 'i', '0', 'i8') }}}
 
1625
      return buf;
 
1626
    }
 
1627
  },
 
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.
 
1633
  },
 
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);
 
1640
      return 0;
 
1641
    }
 
1642
    if (FS.streams[fildes].isTerminal) return 1;
 
1643
    ___setErrNo(ERRNO_CODES.ENOTTY);
 
1644
    return 0;
 
1645
  },
 
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);
 
1651
  },
 
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);
 
1658
    return -1;
 
1659
  },
 
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.
 
1667
      return 0;
 
1668
    } else {
 
1669
      ___setErrNo(ERRNO_CODES.EBADF);
 
1670
      return -1;
 
1671
    }
 
1672
  },
 
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;
 
1684
      }
 
1685
      if (position < 0) {
 
1686
        ___setErrNo(ERRNO_CODES.EINVAL);
 
1687
        return -1;
 
1688
      } else {
 
1689
        stream.ungotten = [];
 
1690
        stream.position = position;
 
1691
        return position;
 
1692
      }
 
1693
    } else {
 
1694
      ___setErrNo(ERRNO_CODES.EBADF);
 
1695
      return -1;
 
1696
    }
 
1697
  },
 
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);
 
1705
    return -1;
 
1706
  },
 
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);
 
1714
      return -1;
 
1715
    } else if (!stream.isRead) {
 
1716
      ___setErrNo(ERRNO_CODES.EACCES);
 
1717
      return -1;
 
1718
    } else if (stream.object.isFolder) {
 
1719
      ___setErrNo(ERRNO_CODES.EISDIR);
 
1720
      return -1;
 
1721
    } else if (nbyte < 0 || offset < 0) {
 
1722
      ___setErrNo(ERRNO_CODES.EINVAL);
 
1723
      return -1;
 
1724
    } else {
 
1725
      var bytesRead = 0;
 
1726
      while (stream.ungotten.length && nbyte > 0) {
 
1727
        {{{ makeSetValue('buf++', '0', 'stream.ungotten.pop()', 'i8') }}}
 
1728
        nbyte--;
 
1729
        bytesRead++;
 
1730
      }
 
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);
 
1736
      } else
 
1737
#endif
 
1738
      if (contents.slice) { // normal array
 
1739
        for (var i = 0; i < size; i++) {
 
1740
          {{{ makeSetValue('buf', 'i', 'contents[offset + i]', 'i8') }}}
 
1741
        }
 
1742
      } else {
 
1743
        for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
 
1744
          {{{ makeSetValue('buf', 'i', 'contents.get(offset + i)', 'i8') }}}
 
1745
        }
 
1746
      }
 
1747
      bytesRead += size;
 
1748
      return bytesRead;
 
1749
    }
 
1750
  },
 
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];
 
1756
    if (!stream) {
 
1757
      ___setErrNo(ERRNO_CODES.EBADF);
 
1758
      return -1;
 
1759
    } else if (!stream.isRead) {
 
1760
      ___setErrNo(ERRNO_CODES.EACCES);
 
1761
      return -1;
 
1762
    } else if (nbyte < 0) {
 
1763
      ___setErrNo(ERRNO_CODES.EINVAL);
 
1764
      return -1;
 
1765
    } else {
 
1766
      var bytesRead;
 
1767
      if (stream.object.isDevice) {
 
1768
        if (stream.object.input) {
 
1769
          bytesRead = 0;
 
1770
          while (stream.ungotten.length && nbyte > 0) {
 
1771
            {{{ makeSetValue('buf++', '0', 'stream.ungotten.pop()', 'i8') }}}
 
1772
            nbyte--;
 
1773
            bytesRead++;
 
1774
          }
 
1775
          for (var i = 0; i < nbyte; i++) {
 
1776
            try {
 
1777
              var result = stream.object.input();
 
1778
            } catch (e) {
 
1779
              ___setErrNo(ERRNO_CODES.EIO);
 
1780
              return -1;
 
1781
            }
 
1782
            if (result === null || result === undefined) break;
 
1783
            bytesRead++;
 
1784
            {{{ makeSetValue('buf', 'i', 'result', 'i8') }}}
 
1785
          }
 
1786
          return bytesRead;
 
1787
        } else {
 
1788
          ___setErrNo(ERRNO_CODES.ENXIO);
 
1789
          return -1;
 
1790
        }
 
1791
      } else {
 
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;
 
1796
        }
 
1797
        return bytesRead;
 
1798
      }
 
1799
    }
 
1800
  },
 
1801
  sync: function() {
 
1802
    // void sync(void);
 
1803
    // http://pubs.opengroup.org/onlinepubs/000095399/functions/sync.html
 
1804
    // All our writing is already synchronized. This is a no-op.
 
1805
  },
 
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);
 
1813
      return -1;
 
1814
    } else if (!path.object.write || path.isRoot) {
 
1815
      ___setErrNo(ERRNO_CODES.EACCES);
 
1816
      return -1;
 
1817
    } else if (!path.object.isFolder) {
 
1818
      ___setErrNo(ERRNO_CODES.ENOTDIR);
 
1819
      return -1;
 
1820
    } else {
 
1821
      for (var i in path.object.contents) {
 
1822
        ___setErrNo(ERRNO_CODES.ENOTEMPTY);
 
1823
        return -1;
 
1824
      }
 
1825
      if (path.path == FS.currentPath) {
 
1826
        ___setErrNo(ERRNO_CODES.EBUSY);
 
1827
        return -1;
 
1828
      } else {
 
1829
        delete path.parentObject.contents[path.name];
 
1830
        return 0;
 
1831
      }
 
1832
    }
 
1833
  },
 
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);
 
1841
      return -1;
 
1842
    } else if (path.object.isFolder) {
 
1843
      ___setErrNo(ERRNO_CODES.EISDIR);
 
1844
      return -1;
 
1845
    } else if (!path.object.write) {
 
1846
      ___setErrNo(ERRNO_CODES.EACCES);
 
1847
      return -1;
 
1848
    } else {
 
1849
      delete path.parentObject.contents[path.name];
 
1850
      return 0;
 
1851
    }
 
1852
  },
 
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;
 
1859
  },
 
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];
 
1865
    if (!stream) {
 
1866
      return ___setErrNo(ERRNO_CODES.EBADF);
 
1867
    } else {
 
1868
      var object = stream.object;
 
1869
      if (!object.isDevice || !object.input || !object.output) {
 
1870
        return ___setErrNo(ERRNO_CODES.ENOTTY);
 
1871
      } else {
 
1872
        var ret = stream.path;
 
1873
        if (namesize < ret.length + 1) {
 
1874
          return ___setErrNo(ERRNO_CODES.ERANGE);
 
1875
        } else {
 
1876
          for (var i = 0; i < ret.length; i++) {
 
1877
            {{{ makeSetValue('name', 'i', 'ret.charCodeAt(i)', 'i8') }}}
 
1878
          }
 
1879
          {{{ makeSetValue('name', 'i', '0', 'i8') }}}
 
1880
          return 0;
 
1881
        }
 
1882
      }
 
1883
    }
 
1884
  },
 
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);
 
1892
      return -1;
 
1893
    } else if (path.exists) {
 
1894
      ___setErrNo(ERRNO_CODES.EEXIST);
 
1895
      return -1;
 
1896
    } else {
 
1897
      FS.createLink(path.parentPath, path.name,
 
1898
                    Pointer_stringify(path1), true, true);
 
1899
      return 0;
 
1900
    }
 
1901
  },
 
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') }}}
 
1912
      }
 
1913
      if (bufsize - 1 > length) {{{ makeSetValue('buf', 'i', '0', 'i8') }}}
 
1914
      return i;
 
1915
    } else {
 
1916
      ___setErrNo(ERRNO_CODES.EINVAL);
 
1917
      return -1;
 
1918
    }
 
1919
  },
 
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);
 
1927
      return -1;
 
1928
    } else if (!stream.isWrite) {
 
1929
      ___setErrNo(ERRNO_CODES.EACCES);
 
1930
      return -1;
 
1931
    } else if (stream.object.isFolder) {
 
1932
      ___setErrNo(ERRNO_CODES.EISDIR);
 
1933
      return -1;
 
1934
    } else if (nbyte < 0 || offset < 0) {
 
1935
      ___setErrNo(ERRNO_CODES.EINVAL);
 
1936
      return -1;
 
1937
    } else {
 
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) }}};
 
1942
      }
 
1943
      stream.object.timestamp = Date.now();
 
1944
      return i;
 
1945
    }
 
1946
  },
 
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];
 
1952
    if (!stream) {
 
1953
      ___setErrNo(ERRNO_CODES.EBADF);
 
1954
      return -1;
 
1955
    } else if (!stream.isWrite) {
 
1956
      ___setErrNo(ERRNO_CODES.EACCES);
 
1957
      return -1;
 
1958
    } else if (nbyte < 0) {
 
1959
      ___setErrNo(ERRNO_CODES.EINVAL);
 
1960
      return -1;
 
1961
    } else {
 
1962
      if (stream.object.isDevice) {
 
1963
        if (stream.object.output) {
 
1964
          for (var i = 0; i < nbyte; i++) {
 
1965
            try {
 
1966
              stream.object.output({{{ makeGetValue('buf', 'i', 'i8') }}});
 
1967
            } catch (e) {
 
1968
              ___setErrNo(ERRNO_CODES.EIO);
 
1969
              return -1;
 
1970
            }
 
1971
          }
 
1972
          stream.object.timestamp = Date.now();
 
1973
          return i;
 
1974
        } else {
 
1975
          ___setErrNo(ERRNO_CODES.ENXIO);
 
1976
          return -1;
 
1977
        }
 
1978
      } else {
 
1979
        var bytesWritten = _pwrite(fildes, buf, nbyte, stream.position);
 
1980
        if (bytesWritten != -1) stream.position += bytesWritten;
 
1981
        return bytesWritten;
 
1982
      }
 
1983
    }
 
1984
  },
 
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
 
1989
    // fail silently.
 
1990
    return 0;
 
1991
  },
 
1992
  ualarm: 'alarm',
 
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
 
1997
    var value;
 
1998
    switch (name) {
 
1999
      case {{{ cDefine('_CS_PATH') }}}:
 
2000
        value = ENV['PATH'] || '/';
 
2001
        break;
 
2002
      case {{{ cDefine('_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS') }}}:
 
2003
        // Mimicing glibc.
 
2004
        value = 'POSIX_V6_ILP32_OFF32\nPOSIX_V6_ILP32_OFFBIG';
 
2005
        break;
 
2006
      case {{{ cDefine('_CS_GNU_LIBC_VERSION') }}}:
 
2007
        // This JS implementation was tested against this glibc version.
 
2008
        value = 'glibc 2.14';
 
2009
        break;
 
2010
      case {{{ cDefine('_CS_GNU_LIBPTHREAD_VERSION') }}}:
 
2011
        // We don't support pthreads.
 
2012
        value = '';
 
2013
        break;
 
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') }}}:
 
2022
        value = '';
 
2023
        break;
 
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') }}}:
 
2027
        value = '-m32';
 
2028
        break;
 
2029
      case {{{ cDefine('_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS') }}}:
 
2030
        value = '-m32 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64';
 
2031
        break;
 
2032
      default:
 
2033
        ___setErrNo(ERRNO_CODES.EINVAL);
 
2034
        return 0;
 
2035
    }
 
2036
    if (len == 0 || buf == 0) {
 
2037
      return value.length + 1;
 
2038
    } else {
 
2039
      var length = Math.min(len, value.length);
 
2040
      for (var i = 0; i < length; i++) {
 
2041
        {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}}
 
2042
      }
 
2043
      if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}}
 
2044
      return i;
 
2045
    }
 
2046
  },
 
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);
 
2053
    return -1;
 
2054
  },
 
2055
  execle: 'execl',
 
2056
  execlp: 'execl',
 
2057
  execv: 'execl',
 
2058
  execve: 'execl',
 
2059
  execvp: 'execl',
 
2060
  _exit: function(status) {
 
2061
    // void _exit(int status);
 
2062
    // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
 
2063
 
 
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);
 
2069
    };
 
2070
    ExitStatus.prototype = new Error();
 
2071
    ExitStatus.prototype.constructor = ExitStatus;
 
2072
 
 
2073
    exitRuntime();
 
2074
    ABORT = true;
 
2075
 
 
2076
    throw new ExitStatus();
 
2077
  },
 
2078
  fork__deps: ['__setErrNo', '$ERRNO_CODES'],
 
2079
  fork: function() {
 
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);
 
2084
    return -1;
 
2085
  },
 
2086
  vfork: 'fork',
 
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.
 
2091
    return 0;
 
2092
  },
 
2093
  getegid: 'getgid',
 
2094
  getuid: 'getgid',
 
2095
  geteuid: 'getgid',
 
2096
  getpgrp: 'getgid',
 
2097
  getpid: 'getgid',
 
2098
  getppid: 'getgid',
 
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') }}}
 
2106
    return 0;
 
2107
  },
 
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);
 
2115
      return -1;
 
2116
    } else {
 
2117
      {{{ makeSetValue('grouplist', '0', '0', 'i32') }}}
 
2118
      return 1;
 
2119
    }
 
2120
  },
 
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);
 
2128
      return -1;
 
2129
    } else {
 
2130
      // We have just one process/user/group, so it makes no sense to set groups.
 
2131
      ___setErrNo(ERRNO_CODES.EPERM);
 
2132
      return -1;
 
2133
    }
 
2134
  },
 
2135
  gethostid: function() {
 
2136
    // long gethostid(void);
 
2137
    // http://pubs.opengroup.org/onlinepubs/000095399/functions/gethostid.html
 
2138
    return 42;
 
2139
  },
 
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;
 
2147
    }
 
2148
    var length = Math.min(namelen, host.length);
 
2149
    for (var i = 0; i < length; i++) {
 
2150
      {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}}
 
2151
    }
 
2152
    if (namelen > length) {
 
2153
      {{{ makeSetValue('name', 'i', '0', 'i8') }}}
 
2154
      return 0;
 
2155
    } else {
 
2156
      ___setErrNo(ERRNO_CODES.ENAMETOOLONG);
 
2157
      return -1;
 
2158
    }
 
2159
  },
 
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;
 
2166
  },
 
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
 
2171
    var ret = 'root';
 
2172
    if (namesize < ret.length + 1) {
 
2173
      return ___setErrNo(ERRNO_CODES.ERANGE);
 
2174
    } else {
 
2175
      for (var i = 0; i < ret.length; i++) {
 
2176
        {{{ makeSetValue('name', 'i', 'ret.charCodeAt(i)', 'i8') }}}
 
2177
      }
 
2178
      {{{ makeSetValue('name', 'i', '0', 'i8') }}}
 
2179
      return 0;
 
2180
    }
 
2181
  },
 
2182
  getpagesize: function() {
 
2183
    // int getpagesize(void);
 
2184
    return PAGE_SIZE;
 
2185
  },
 
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).
 
2190
    return -1;
 
2191
  },
 
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.
 
2196
    return 0;
 
2197
  },
 
2198
  getsid: 'getpgid',
 
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);
 
2205
    return 0;
 
2206
  },
 
2207
  pause__deps: ['__setErrNo', '$ERRNO_CODES'],
 
2208
  pause: function() {
 
2209
    // int pause(void);
 
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);
 
2213
    return -1;
 
2214
  },
 
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);
 
2221
    return -1;
 
2222
  },
 
2223
  setegid: 'setgid',
 
2224
  setuid: 'setgid',
 
2225
  seteuid: 'setgid',
 
2226
  setsid: 'setgid',
 
2227
  setpgrp: 'setgid',
 
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);
 
2234
    return -1;
 
2235
  },
 
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);
 
2246
  },
 
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) {
 
2254
      // Do nothing.
 
2255
    }
 
2256
    return 0;
 
2257
  },
 
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') }}}
 
2268
    }
 
2269
  },
 
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.
 
2274
    return 0;
 
2275
  },
 
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);
 
2282
    return -1;
 
2283
  },
 
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
 
2288
    switch(name) {
 
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') }}}:
 
2331
        return 200809;
 
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') }}}:
 
2364
        return -1;
 
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') }}}:
 
2380
        return 1;
 
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') }}}:
 
2386
        return 1024;
 
2387
      case {{{ cDefine('_SC_RTSIG_MAX') }}}:
 
2388
      case {{{ cDefine('_SC_EXPR_NEST_MAX') }}}:
 
2389
      case {{{ cDefine('_SC_TTY_NAME_MAX') }}}:
 
2390
        return 32;
 
2391
      case {{{ cDefine('_SC_ATEXIT_MAX') }}}:
 
2392
      case {{{ cDefine('_SC_DELAYTIMER_MAX') }}}:
 
2393
      case {{{ cDefine('_SC_SEM_VALUE_MAX') }}}:
 
2394
        return 2147483647;
 
2395
      case {{{ cDefine('_SC_SIGQUEUE_MAX') }}}:
 
2396
      case {{{ cDefine('_SC_CHILD_MAX') }}}:
 
2397
        return 47839;
 
2398
      case {{{ cDefine('_SC_BC_SCALE_MAX') }}}:
 
2399
      case {{{ cDefine('_SC_BC_BASE_MAX') }}}:
 
2400
        return 99;
 
2401
      case {{{ cDefine('_SC_LINE_MAX') }}}:
 
2402
      case {{{ cDefine('_SC_BC_DIM_MAX') }}}:
 
2403
        return 2048;
 
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;
 
2420
    }
 
2421
    ___setErrNo(ERRNO_CODES.EINVAL);
 
2422
    return -1;
 
2423
  },
 
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
 
2428
 
 
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|...
 
2434
    var self = _sbrk;
 
2435
    if (!self.called) {
 
2436
      STATICTOP = alignMemoryPage(STATICTOP); // make sure we start out aligned
 
2437
      self.called = true;
 
2438
#if GC_SUPPORT
 
2439
      _sbrk.DYNAMIC_START = STATICTOP;
 
2440
#endif
 
2441
    }
 
2442
    var ret = STATICTOP;
 
2443
    if (bytes != 0) Runtime.staticAlloc(bytes);
 
2444
    return ret;  // Previous break location.
 
2445
  },
 
2446
  open64: 'open',
 
2447
  lseek64: 'lseek',
 
2448
  ftruncate64: 'ftruncate',
 
2449
  __01open64_: 'open',
 
2450
  __01lseek64_: 'lseek',
 
2451
  __01truncate64_: 'truncate',
 
2452
  __01ftruncate64_: 'ftruncate',
 
2453
  // TODO: Check if any other aliases are needed.
 
2454
 
 
2455
  // ==========================================================================
 
2456
  // stdio.h
 
2457
  // ==========================================================================
 
2458
 
 
2459
  _isFloat: function(text) {
 
2460
    return !!(/^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?$/.exec(text));
 
2461
  },
 
2462
 
 
2463
  // TODO: Document.
 
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;
 
2474
    }
 
2475
    // Supports %x, %4x, %d.%d, %lld, %s, %f, %lf.
 
2476
    // TODO: Support all format specifiers.
 
2477
    format = Pointer_stringify(format);
 
2478
    var soFar = 0;
 
2479
    if (format.indexOf('%n') >= 0) {
 
2480
      // need to track soFar
 
2481
      var _get = get;
 
2482
      get = function() {
 
2483
        soFar++;
 
2484
        return _get();
 
2485
      }
 
2486
      var _unget = unget;
 
2487
      unget = function() {
 
2488
        soFar--;
 
2489
        return _unget();
 
2490
      }
 
2491
    }
 
2492
    var formatIndex = 0;
 
2493
    var argsi = 0;
 
2494
    var fields = 0;
 
2495
    var argIndex = 0;
 
2496
    var next;
 
2497
 
 
2498
    mainLoop:
 
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') }}};
 
2504
        formatIndex += 2;
 
2505
        continue;
 
2506
      }
 
2507
 
 
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);
 
2512
        fields++;
 
2513
        next = get();
 
2514
        {{{ makeSetValue('argPtr', 0, 'next', 'i8') }}}
 
2515
        formatIndex += 2;
 
2516
        continue;
 
2517
      }
 
2518
 
 
2519
      // remove whitespace
 
2520
      while (1) {
 
2521
        next = get();
 
2522
        if (next == 0) return fields;
 
2523
        if (!(next in __scanString.whiteSpace)) break;
 
2524
      }
 
2525
      unget();
 
2526
 
 
2527
      if (format[formatIndex] === '%') {
 
2528
        formatIndex++;
 
2529
        var suppressAssignment = false;
 
2530
        if (format[formatIndex] == '*') {
 
2531
          suppressAssignment = true;
 
2532
          formatIndex++;
 
2533
        }
 
2534
        var maxSpecifierStart = formatIndex;
 
2535
        while (format[formatIndex].charCodeAt(0) >= {{{ charCode('0') }}} &&
 
2536
               format[formatIndex].charCodeAt(0) <= {{{ charCode('9') }}}) {
 
2537
          formatIndex++;
 
2538
        }
 
2539
        var max_;
 
2540
        if (formatIndex != maxSpecifierStart) {
 
2541
          max_ = parseInt(format.slice(maxSpecifierStart, formatIndex), 10);
 
2542
        }
 
2543
        var long_ = false;
 
2544
        var half = false;
 
2545
        var longLong = false;
 
2546
        if (format[formatIndex] == 'l') {
 
2547
          long_ = true;
 
2548
          formatIndex++;
 
2549
          if(format[formatIndex] == 'l') {
 
2550
            longLong = true;
 
2551
            formatIndex++;
 
2552
          }
 
2553
        } else if (format[formatIndex] == 'h') {
 
2554
          half = true;
 
2555
          formatIndex++;
 
2556
        }
 
2557
        var type = format[formatIndex];
 
2558
        formatIndex++;
 
2559
        var curr = 0;
 
2560
        var buffer = [];
 
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') {
 
2563
          var last = 0;
 
2564
          next = get();
 
2565
          while (next > 0) {
 
2566
            buffer.push(String.fromCharCode(next));
 
2567
            if (__isFloat(buffer.join(''))) {
 
2568
              last = buffer.length;
 
2569
            }
 
2570
            next = get();
 
2571
          }
 
2572
          for (var i = 0; i < buffer.length - last + 1; i++) {
 
2573
            unget();
 
2574
          }
 
2575
          buffer.length = last;
 
2576
        } else {
 
2577
          next = get();
 
2578
          var first = true;
 
2579
          while ((curr < max_ || isNaN(max_)) && next > 0) {
 
2580
            if (!(next in __scanString.whiteSpace) && // stop on whitespace
 
2581
                (type == 's' ||
 
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));
 
2589
              next = get();
 
2590
              curr++;
 
2591
              first = false;
 
2592
            } else {
 
2593
              break;
 
2594
            }
 
2595
          }
 
2596
          unget();
 
2597
        }
 
2598
        if (buffer.length === 0) return 0;  // Failure.
 
2599
        if (suppressAssignment) continue;
 
2600
 
 
2601
        var text = buffer.join('');
 
2602
        var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
 
2603
        argIndex += Runtime.getAlignSize('void*', null, true);
 
2604
        switch (type) {
 
2605
          case 'd': case 'u': case 'i':
 
2606
            if (half) {
 
2607
              {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i16') }}};
 
2608
            } else if(longLong) {
 
2609
              {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i64') }}};
 
2610
            } else {
 
2611
              {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}};
 
2612
            }
 
2613
            break;
 
2614
          case 'x':
 
2615
            {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}}
 
2616
            break;
 
2617
          case 'f':
 
2618
          case 'e':
 
2619
          case 'g':
 
2620
          case 'E':
 
2621
            // fallthrough intended
 
2622
            if (long_) {
 
2623
              {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}}
 
2624
            } else {
 
2625
              {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}}
 
2626
            }
 
2627
            break;
 
2628
          case 's':
 
2629
            var array = intArrayFromString(text);
 
2630
            for (var j = 0; j < array.length; j++) {
 
2631
              {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}}
 
2632
            }
 
2633
            break;
 
2634
        }
 
2635
        fields++;
 
2636
      } else if (format[formatIndex] in __scanString.whiteSpace) {
 
2637
        next = get();
 
2638
        while (next in __scanString.whiteSpace) {
 
2639
          if (next <= 0) break mainLoop;  // End of input.
 
2640
          next = get();
 
2641
        }
 
2642
        unget(next);
 
2643
        formatIndex++;
 
2644
      } else {
 
2645
        // Not a specifier.
 
2646
        next = get();
 
2647
        if (format[formatIndex].charCodeAt(0) !== next) {
 
2648
          unget(next);
 
2649
          break mainLoop;
 
2650
        }
 
2651
        formatIndex++;
 
2652
      }
 
2653
    }
 
2654
    return fields;
 
2655
  },
 
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;
 
2663
    var argIndex = 0;
 
2664
    function getNextArg(type) {
 
2665
      // NOTE: Explicitly ignoring type safety. Otherwise this fails:
 
2666
      //       int x = 4; printf("%c\n", (char)x);
 
2667
      var ret;
 
2668
      if (type === 'double') {
 
2669
        ret = {{{ makeGetValue('varargs', 'argIndex', 'double', undefined, undefined, true) }}};
 
2670
#if USE_TYPED_ARRAYS == 2
 
2671
      } else if (type == 'i64') {
 
2672
 
 
2673
#if TARGET_LE32
 
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
 
2677
#else
 
2678
        ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
 
2679
               {{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true) }}}];
 
2680
#endif
 
2681
 
 
2682
#else
 
2683
      } else if (type == 'i64') {
 
2684
        ret = {{{ makeGetValue('varargs', 'argIndex', 'i64', undefined, undefined, true) }}};
 
2685
#endif
 
2686
      } else {
 
2687
        type = 'i32'; // varargs are always i32, i64, or double
 
2688
        ret = {{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}};
 
2689
      }
 
2690
      argIndex += Math.max(Runtime.getNativeFieldSize(type), Runtime.getAlignSize(type, null, true));
 
2691
      return ret;
 
2692
    }
 
2693
 
 
2694
    var ret = [];
 
2695
    var curr, next, currArg;
 
2696
    while(1) {
 
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('%') }}}) {
 
2702
        // Handle flags.
 
2703
        var flagAlwaysSigned = false;
 
2704
        var flagLeftAlign = false;
 
2705
        var flagAlternative = false;
 
2706
        var flagZeroPad = false;
 
2707
        flagsLoop: while (1) {
 
2708
          switch (next) {
 
2709
            case {{{ charCode('+') }}}:
 
2710
              flagAlwaysSigned = true;
 
2711
              break;
 
2712
            case {{{ charCode('-') }}}:
 
2713
              flagLeftAlign = true;
 
2714
              break;
 
2715
            case {{{ charCode('#') }}}:
 
2716
              flagAlternative = true;
 
2717
              break;
 
2718
            case {{{ charCode('0') }}}:
 
2719
              if (flagZeroPad) {
 
2720
                break flagsLoop;
 
2721
              } else {
 
2722
                flagZeroPad = true;
 
2723
                break;
 
2724
              }
 
2725
            default:
 
2726
              break flagsLoop;
 
2727
          }
 
2728
          textIndex++;
 
2729
          next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
 
2730
        }
 
2731
 
 
2732
        // Handle width.
 
2733
        var width = 0;
 
2734
        if (next == {{{ charCode('*') }}}) {
 
2735
          width = getNextArg('i32');
 
2736
          textIndex++;
 
2737
          next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
 
2738
        } else {
 
2739
          while (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) {
 
2740
            width = width * 10 + (next - {{{ charCode('0') }}});
 
2741
            textIndex++;
 
2742
            next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
 
2743
          }
 
2744
        }
 
2745
 
 
2746
        // Handle precision.
 
2747
        var precisionSet = false;
 
2748
        if (next == {{{ charCode('.') }}}) {
 
2749
          var precision = 0;
 
2750
          precisionSet = true;
 
2751
          textIndex++;
 
2752
          next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
 
2753
          if (next == {{{ charCode('*') }}}) {
 
2754
            precision = getNextArg('i32');
 
2755
            textIndex++;
 
2756
          } else {
 
2757
            while(1) {
 
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') }}});
 
2762
              textIndex++;
 
2763
            }
 
2764
          }
 
2765
          next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
 
2766
        } else {
 
2767
          var precision = 6; // Standard default.
 
2768
        }
 
2769
 
 
2770
        // Handle integer sizes. WARNING: These assume a 32-bit architecture!
 
2771
        var argSize;
 
2772
        switch (String.fromCharCode(next)) {
 
2773
          case 'h':
 
2774
            var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}};
 
2775
            if (nextNext == {{{ charCode('h') }}}) {
 
2776
              textIndex++;
 
2777
              argSize = 1; // char (actually i32 in varargs)
 
2778
            } else {
 
2779
              argSize = 2; // short (actually i32 in varargs)
 
2780
            }
 
2781
            break;
 
2782
          case 'l':
 
2783
            var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}};
 
2784
            if (nextNext == {{{ charCode('l') }}}) {
 
2785
              textIndex++;
 
2786
              argSize = 8; // long long
 
2787
            } else {
 
2788
              argSize = 4; // long
 
2789
            }
 
2790
            break;
 
2791
          case 'L': // long long
 
2792
          case 'q': // int64_t
 
2793
          case 'j': // intmax_t
 
2794
            argSize = 8;
 
2795
            break;
 
2796
          case 'z': // size_t
 
2797
          case 't': // ptrdiff_t
 
2798
          case 'I': // signed ptrdiff_t or unsigned size_t
 
2799
            argSize = 4;
 
2800
            break;
 
2801
          default:
 
2802
            argSize = null;
 
2803
        }
 
2804
        if (argSize) textIndex++;
 
2805
        next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
 
2806
 
 
2807
        // Handle type specifier.
 
2808
        switch (String.fromCharCode(next)) {
 
2809
          case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
 
2810
            // Integer.
 
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;
 
2816
#endif
 
2817
            var argText;
 
2818
#if USE_TYPED_ARRAYS == 2
 
2819
            // Flatten i64-1 [low, high] into a (slightly rounded) double
 
2820
            if (argSize == 8) {
 
2821
              currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == {{{ charCode('u') }}});
 
2822
            }
 
2823
#endif
 
2824
            // Truncate to requested size.
 
2825
            if (argSize <= 4) {
 
2826
              var limit = Math.pow(256, argSize) - 1;
 
2827
              currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
 
2828
            }
 
2829
            // Format the number.
 
2830
            var currAbsArg = Math.abs(currArg);
 
2831
            var prefix = '';
 
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
 
2835
#endif
 
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
 
2840
#endif
 
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) {
 
2849
                if (origArg[1]) {
 
2850
                  argText = (origArg[1]>>>0).toString(16);
 
2851
                  var lower = (origArg[0]>>>0).toString(16);
 
2852
                  while (lower.length < 8) lower = '0' + lower;
 
2853
                  argText += lower;
 
2854
                } else {
 
2855
                  argText = (origArg[0]>>>0).toString(16);
 
2856
                }
 
2857
              } else
 
2858
#endif
 
2859
              if (currArg < 0) {
 
2860
                // Represent negative numbers in hex as 2's complement.
 
2861
                currArg = -currArg;
 
2862
                argText = (currAbsArg - 1).toString(16);
 
2863
                var buffer = [];
 
2864
                for (var i = 0; i < argText.length; i++) {
 
2865
                  buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
 
2866
                }
 
2867
                argText = buffer.join('');
 
2868
                while (argText.length < argSize * 2) argText = 'f' + argText;
 
2869
              } else {
 
2870
                argText = currAbsArg.toString(16);
 
2871
              }
 
2872
              if (next == {{{ charCode('X') }}}) {
 
2873
                prefix = prefix.toUpperCase();
 
2874
                argText = argText.toUpperCase();
 
2875
              }
 
2876
            } else if (next == {{{ charCode('p') }}}) {
 
2877
              if (currAbsArg === 0) {
 
2878
                argText = '(nil)';
 
2879
              } else {
 
2880
                prefix = '0x';
 
2881
                argText = currAbsArg.toString(16);
 
2882
              }
 
2883
            }
 
2884
            if (precisionSet) {
 
2885
              while (argText.length < precision) {
 
2886
                argText = '0' + argText;
 
2887
              }
 
2888
            }
 
2889
 
 
2890
            // Add sign if needed
 
2891
            if (flagAlwaysSigned) {
 
2892
              if (currArg < 0) {
 
2893
                prefix = '-' + prefix;
 
2894
              } else {
 
2895
                prefix = '+' + prefix;
 
2896
              }
 
2897
            }
 
2898
 
 
2899
            // Add padding.
 
2900
            while (prefix.length + argText.length < width) {
 
2901
              if (flagLeftAlign) {
 
2902
                argText += ' ';
 
2903
              } else {
 
2904
                if (flagZeroPad) {
 
2905
                  argText = '0' + argText;
 
2906
                } else {
 
2907
                  prefix = ' ' + prefix;
 
2908
                }
 
2909
              }
 
2910
            }
 
2911
 
 
2912
            // Insert the result into the buffer.
 
2913
            argText = prefix + argText;
 
2914
            argText.split('').forEach(function(chr) {
 
2915
              ret.push(chr.charCodeAt(0));
 
2916
            });
 
2917
            break;
 
2918
          }
 
2919
          case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
 
2920
            // Float.
 
2921
            var currArg = getNextArg('double');
 
2922
            var argText;
 
2923
            if (isNaN(currArg)) {
 
2924
              argText = 'nan';
 
2925
              flagZeroPad = false;
 
2926
            } else if (!isFinite(currArg)) {
 
2927
              argText = (currArg < 0 ? '-' : '') + 'inf';
 
2928
              flagZeroPad = false;
 
2929
            } else {
 
2930
              var isGeneral = false;
 
2931
              var effectivePrecision = Math.min(precision, 20);
 
2932
 
 
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') }}}) {
 
2936
                isGeneral = true;
 
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;
 
2942
                } else {
 
2943
                  next = ((next == {{{ charCode('g') }}}) ? 'e' : 'E').charCodeAt(0);
 
2944
                  precision--;
 
2945
                }
 
2946
                effectivePrecision = Math.min(precision, 20);
 
2947
              }
 
2948
 
 
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);
 
2954
                }
 
2955
              } else if (next == {{{ charCode('f') }}} || next == {{{ charCode('F') }}}) {
 
2956
                argText = currArg.toFixed(effectivePrecision);
 
2957
                if (currArg === 0 && __reallyNegative(currArg)) {
 
2958
                  argText = '-' + argText;
 
2959
                }
 
2960
              }
 
2961
 
 
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);
 
2968
                }
 
2969
              } else {
 
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';
 
2974
              }
 
2975
              argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
 
2976
 
 
2977
              // Capitalize 'E' if needed.
 
2978
              if (next == {{{ charCode('E') }}}) argText = argText.toUpperCase();
 
2979
 
 
2980
              // Add sign.
 
2981
              if (flagAlwaysSigned && currArg >= 0) {
 
2982
                argText = '+' + argText;
 
2983
              }
 
2984
            }
 
2985
 
 
2986
            // Add padding.
 
2987
            while (argText.length < width) {
 
2988
              if (flagLeftAlign) {
 
2989
                argText += ' ';
 
2990
              } else {
 
2991
                if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
 
2992
                  argText = argText[0] + '0' + argText.slice(1);
 
2993
                } else {
 
2994
                  argText = (flagZeroPad ? '0' : ' ') + argText;
 
2995
                }
 
2996
              }
 
2997
            }
 
2998
 
 
2999
            // Adjust case.
 
3000
            if (next < {{{ charCode('a') }}}) argText = argText.toUpperCase();
 
3001
 
 
3002
            // Insert the result into the buffer.
 
3003
            argText.split('').forEach(function(chr) {
 
3004
              ret.push(chr.charCodeAt(0));
 
3005
            });
 
3006
            break;
 
3007
          }
 
3008
          case 's': {
 
3009
            // String.
 
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(' ') }}});
 
3016
              }
 
3017
            }
 
3018
            for (var i = 0; i < argLength; i++) {
 
3019
              ret.push({{{ makeGetValue('arg++', 0, 'i8', null, true) }}});
 
3020
            }
 
3021
            if (flagLeftAlign) {
 
3022
              while (argLength < width--) {
 
3023
                ret.push({{{ charCode(' ') }}});
 
3024
              }
 
3025
            }
 
3026
            break;
 
3027
          }
 
3028
          case 'c': {
 
3029
            // Character.
 
3030
            if (flagLeftAlign) ret.push(getNextArg('i8'));
 
3031
            while (--width > 0) {
 
3032
              ret.push({{{ charCode(' ') }}});
 
3033
            }
 
3034
            if (!flagLeftAlign) ret.push(getNextArg('i8'));
 
3035
            break;
 
3036
          }
 
3037
          case 'n': {
 
3038
            // Write the length written so far to the next parameter.
 
3039
            var ptr = getNextArg('i32*');
 
3040
            {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}}
 
3041
            break;
 
3042
          }
 
3043
          case '%': {
 
3044
            // Literal percent sign.
 
3045
            ret.push(curr);
 
3046
            break;
 
3047
          }
 
3048
          default: {
 
3049
            // Unknown specifiers remain untouched.
 
3050
            for (var i = startTextIndex; i < textIndex + 2; i++) {
 
3051
              ret.push({{{ makeGetValue(0, 'i', 'i8') }}});
 
3052
            }
 
3053
          }
 
3054
        }
 
3055
        textIndex += 2;
 
3056
        // TODO: Support a/A (hex float) and m (last error) specifiers.
 
3057
        // TODO: Support %1${specifier} for arg selection.
 
3058
      } else {
 
3059
        ret.push(curr);
 
3060
        textIndex += 1;
 
3061
      }
 
3062
    }
 
3063
    return ret;
 
3064
  },
 
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
 
3067
  //       easier.
 
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;
 
3073
  },
 
3074
  fclose__deps: ['close', 'fsync'],
 
3075
  fclose: function(stream) {
 
3076
    // int fclose(FILE *stream);
 
3077
    // http://pubs.opengroup.org/onlinepubs/000095399/functions/fclose.html
 
3078
    _fsync(stream);
 
3079
    return _close(stream);
 
3080
  },
 
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);
 
3093
        return 0;
 
3094
      } else {
 
3095
        stream.error = false;
 
3096
        stream.eof = false;
 
3097
        return fildes;
 
3098
      }
 
3099
    } else {
 
3100
      ___setErrNo(ERRNO_CODES.EBADF);
 
3101
      return 0;
 
3102
    }
 
3103
  },
 
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);
 
3109
  },
 
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);
 
3115
  },
 
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);
 
3125
        }
 
3126
      }
 
3127
    };
 
3128
    try {
 
3129
      if (stream === 0) {
 
3130
        for (var i = 0; i < FS.streams.length; i++) if (FS.streams[i]) flush(i);
 
3131
      } else {
 
3132
        flush(stream);
 
3133
      }
 
3134
      return 0;
 
3135
    } catch (e) {
 
3136
      ___setErrNo(ERRNO_CODES.EIO);
 
3137
      return -1;
 
3138
    }
 
3139
  },
 
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);
 
3149
    if (ret == 0) {
 
3150
      streamObj.eof = true;
 
3151
      return -1;
 
3152
    } else if (ret == -1) {
 
3153
      streamObj.error = true;
 
3154
      return -1;
 
3155
    } else {
 
3156
      return {{{ makeGetValue('_fgetc.ret', '0', 'i8', null, 1) }}};
 
3157
    }
 
3158
  },
 
3159
  getc: 'fgetc',
 
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*') }}});
 
3166
  },
 
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);
 
3175
        return -1;
 
3176
      } else {
 
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') }}}
 
3180
        return 0;
 
3181
      }
 
3182
    } else {
 
3183
      ___setErrNo(ERRNO_CODES.EBADF);
 
3184
      return -1;
 
3185
    }
 
3186
  },
 
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;
 
3194
    var byte_;
 
3195
    for (var i = 0; i < n - 1 && byte_ != {{{ charCode('\n') }}}; i++) {
 
3196
      byte_ = _fgetc(stream);
 
3197
      if (byte_ == -1) {
 
3198
        if (streamObj.error || (streamObj.eof && i == 0)) return 0;
 
3199
        else if (streamObj.eof) break;
 
3200
      }
 
3201
      {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}}
 
3202
    }
 
3203
    {{{ makeSetValue('s', 'i', '0', 'i8') }}}
 
3204
    return s;
 
3205
  },
 
3206
  gets__deps: ['fgets'],
 
3207
  gets: function(s) {
 
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*') }}});
 
3211
  },
 
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.
 
3216
    return stream;
 
3217
  },
 
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.
 
3222
    return 0;
 
3223
  },
 
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
 
3230
    var flags;
 
3231
    mode = Pointer_stringify(mode);
 
3232
    if (mode[0] == 'r') {
 
3233
      if (mode.indexOf('+') != -1) {
 
3234
        flags = {{{ cDefine('O_RDWR') }}};
 
3235
      } else {
 
3236
        flags = {{{ cDefine('O_RDONLY') }}};
 
3237
      }
 
3238
    } else if (mode[0] == 'w') {
 
3239
      if (mode.indexOf('+') != -1) {
 
3240
        flags = {{{ cDefine('O_RDWR') }}};
 
3241
      } else {
 
3242
        flags = {{{ cDefine('O_WRONLY') }}};
 
3243
      }
 
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') }}};
 
3249
      } else {
 
3250
        flags = {{{ cDefine('O_WRONLY') }}};
 
3251
      }
 
3252
      flags |= {{{ cDefine('O_CREAT') }}};
 
3253
      flags |= {{{ cDefine('O_APPEND') }}};
 
3254
    } else {
 
3255
      ___setErrNo(ERRNO_CODES.EINVAL);
 
3256
      return 0;
 
3257
    }
 
3258
    var ret = _open(filename, flags, allocate([0x1FF, 0, 0, 0], 'i32', ALLOC_STACK));  // All creation permissions.
 
3259
    return (ret == -1) ? 0 : ret;
 
3260
  },
 
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);
 
3269
    if (ret == -1) {
 
3270
      if (FS.streams[stream]) FS.streams[stream].error = true;
 
3271
      return -1;
 
3272
    } else {
 
3273
      return chr;
 
3274
    }
 
3275
  },
 
3276
  putc: 'fputc',
 
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*') }}});
 
3283
  },
 
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));
 
3290
  },
 
3291
  puts__deps: ['fputs', 'fputc', 'stdout'],
 
3292
  puts: function(s) {
 
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);
 
3298
    if (ret < 0) {
 
3299
      return ret;
 
3300
    } else {
 
3301
      var newlineRet = _fputc({{{ charCode('\n') }}}, stdout);
 
3302
      return (newlineRet < 0) ? -1 : ret + 1;
 
3303
    }
 
3304
  },
 
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;
 
3315
      return 0;
 
3316
    } else {
 
3317
      if (bytesRead < bytesToRead) streamObj.eof = true;
 
3318
      return Math.floor(bytesRead / size);
 
3319
    }
 
3320
  },
 
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
 
3325
    if (!filename) {
 
3326
      if (!FS.streams[stream]) {
 
3327
        ___setErrNo(ERRNO_CODES.EBADF);
 
3328
        return 0;
 
3329
      }
 
3330
      if (_freopen.buffer) _free(_freopen.buffer);
 
3331
      filename = intArrayFromString(FS.streams[stream].path);
 
3332
      filename = allocate(filename, 'i8', ALLOC_NORMAL);
 
3333
    }
 
3334
    _fclose(stream);
 
3335
    return _fopen(filename, mode);
 
3336
  },
 
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);
 
3342
    if (ret == -1) {
 
3343
      return -1;
 
3344
    } else {
 
3345
      FS.streams[stream].eof = false;
 
3346
      return 0;
 
3347
    }
 
3348
  },
 
3349
  fseeko: 'fseek',
 
3350
  fseeko64: 'fseek',
 
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);
 
3358
        return -1;
 
3359
      } else {
 
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);
 
3364
        return 0;
 
3365
      }
 
3366
    } else {
 
3367
      ___setErrNo(ERRNO_CODES.EBADF);
 
3368
      return -1;
 
3369
    }
 
3370
  },
 
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);
 
3379
        return -1;
 
3380
      } else {
 
3381
        return stream.position;
 
3382
      }
 
3383
    } else {
 
3384
      ___setErrNo(ERRNO_CODES.EBADF);
 
3385
      return -1;
 
3386
    }
 
3387
  },
 
3388
  ftello: 'ftell',
 
3389
  ftello64: 'ftell',
 
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;
 
3399
      return 0;
 
3400
    } else {
 
3401
      return Math.floor(bytesWritten / size);
 
3402
    }
 
3403
  },
 
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);
 
3410
    return 0;
 
3411
  },
 
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);
 
3418
    return -1;
 
3419
  },
 
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*') }}};
 
3425
    if (s) {
 
3426
      _fputs(s, stdout);
 
3427
      _fputc({{{ charCode(':') }}}, stdout);
 
3428
      _fputc({{{ charCode(' ') }}}, stdout);
 
3429
    }
 
3430
    var errnum = {{{ makeGetValue('___errno_location()', '0', 'i32') }}};
 
3431
    _puts(_strerror(errnum));
 
3432
  },
 
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);
 
3439
    return ret;
 
3440
  },
 
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) {
 
3448
      return 0;
 
3449
    } else if (!oldObj.exists) {
 
3450
      ___setErrNo(oldObj.error);
 
3451
      return -1;
 
3452
    } else if (oldObj.isRoot || oldObj.path == FS.currentPath) {
 
3453
      ___setErrNo(ERRNO_CODES.EBUSY);
 
3454
      return -1;
 
3455
    } else if (newObj.path && newObj.path.indexOf(oldObj.path) == 0) {
 
3456
      ___setErrNo(ERRNO_CODES.EINVAL);
 
3457
      return -1;
 
3458
    } else if (newObj.exists && newObj.object.isFolder) {
 
3459
      ___setErrNo(ERRNO_CODES.EISDIR);
 
3460
      return -1;
 
3461
    } else {
 
3462
      delete oldObj.parentObject.contents[oldObj.name];
 
3463
      newObj.parentObject.contents[newObj.name] = oldObj.object;
 
3464
      return 0;
 
3465
    }
 
3466
  },
 
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;
 
3473
  },
 
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.
 
3478
    return 0;
 
3479
  },
 
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.
 
3486
  },
 
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) {
 
3494
      dir = '/tmp';
 
3495
      folder = FS.findObject(dir);
 
3496
      if (!folder || !folder.isFolder) return 0;
 
3497
    }
 
3498
    var name = prefix || 'file';
 
3499
    do {
 
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') }}};
 
3507
    }
 
3508
    {{{ makeSetValue('s', 'i', '0', 'i8') }}};
 
3509
    return s;
 
3510
  },
 
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));
 
3516
  },
 
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);
 
3524
    }
 
3525
    return _fopen(_tmpnam(0), _tmpfile.mode);
 
3526
  },
 
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);
 
3534
      return c;
 
3535
    } else {
 
3536
      return -1;
 
3537
    }
 
3538
  },
 
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);
 
3545
    return -1;
 
3546
  },
 
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]) {
 
3553
      var stack = [];
 
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);
 
3557
    } else {
 
3558
      return -1;
 
3559
    }
 
3560
  },
 
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);
 
3567
  },
 
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
 
3572
    var index = 0;
 
3573
    var get = function() { return {{{ makeGetValue('s', 'index++', 'i8') }}}; };
 
3574
    var unget = function() { index--; };
 
3575
    return __scanString(format, get, unget, varargs);
 
3576
  },
 
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));
 
3584
    if (s < 0) {
 
3585
      s = -s;
 
3586
      var buf = _malloc(limit+1);
 
3587
      {{{ makeSetValue('s', '0', 'buf', 'i8*') }}};
 
3588
      s = buf;
 
3589
    }
 
3590
    for (var i = 0; i < limit; i++) {
 
3591
      {{{ makeSetValue('s', 'i', 'result[i]', 'i8') }}};
 
3592
    }
 
3593
    if (limit < n || (n === undefined)) {{{ makeSetValue('s', 'i', '0', 'i8') }}};
 
3594
    return result.length;
 
3595
  },
 
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);
 
3604
    return ret;
 
3605
  },
 
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);
 
3612
  },
 
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);
 
3618
  },
 
3619
  asprintf__deps: ['sprintf'],
 
3620
  asprintf: function(s, format, varargs) {
 
3621
    return _sprintf(-s, format, varargs);
 
3622
  },
 
3623
 
 
3624
#if TARGET_X86
 
3625
  // va_arg is just like our varargs
 
3626
  vfprintf: 'fprintf',
 
3627
  vsnprintf: 'snprintf',
 
3628
  vprintf: 'printf',
 
3629
  vsprintf: 'sprintf',
 
3630
  vasprintf: 'asprintf',
 
3631
  vscanf: 'scanf',
 
3632
  vfscanf: 'fscanf',
 
3633
  vsscanf: 'sscanf',
 
3634
#endif
 
3635
 
 
3636
#if TARGET_LE32
 
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, '*') }}});
 
3641
  },
 
3642
  vsnprintf__deps: ['snprintf'],
 
3643
  vsnprintf: function(s, n, format, va_arg) {
 
3644
    return _snprintf(s, n, format, {{{ makeGetValue('va_arg', 0, '*') }}});
 
3645
  },
 
3646
  vprintf__deps: ['printf'],
 
3647
  vprintf: function(format, va_arg) {
 
3648
    return _printf(format, {{{ makeGetValue('va_arg', 0, '*') }}});
 
3649
  },
 
3650
  vsprintf__deps: ['sprintf'],
 
3651
  vsprintf: function(s, format, va_arg) {
 
3652
    return _sprintf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
 
3653
  },
 
3654
  vasprintf__deps: ['asprintf'],
 
3655
  vasprintf: function(s, format, va_arg) {
 
3656
    return _asprintf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
 
3657
  },
 
3658
  vscanf__deps: ['scanf'],
 
3659
  vscanf: function(format, va_arg) {
 
3660
    return _scanf(format, {{{ makeGetValue('va_arg', 0, '*') }}});
 
3661
  },
 
3662
  vfscanf__deps: ['fscanf'],
 
3663
  vfscanf: function(s, format, va_arg) {
 
3664
    return _fscanf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
 
3665
  },
 
3666
  vsscanf__deps: ['sscanf'],
 
3667
  vsscanf: function(s, format, va_arg) {
 
3668
    return _sscanf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
 
3669
  },
 
3670
#endif
 
3671
 
 
3672
  fopen64: 'fopen',
 
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.
 
3680
  _IO_getc: 'getc',
 
3681
  _IO_putc: 'putc',
 
3682
  _ZNSo3putEc: 'putchar',
 
3683
  _ZNSo5flushEv__deps: ['fflush', 'stdout'],
 
3684
  _ZNSo5flushEv: function() {
 
3685
    _fflush({{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}});
 
3686
  },
 
3687
 
 
3688
  // ==========================================================================
 
3689
  // sys/mman.h
 
3690
  // ==========================================================================
 
3691
 
 
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
 
3696
     * mmap.
 
3697
     */
 
3698
    if (!_mmap.mappings) _mmap.mappings = {};
 
3699
    if (stream == -1) {
 
3700
      var ptr = _malloc(num);
 
3701
    } else {
 
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);
 
3707
    }
 
3708
    // align to page size
 
3709
    var ret = ptr;
 
3710
    if (ptr % PAGE_SIZE != 0) {
 
3711
      var old = ptr;
 
3712
      ptr = _malloc(num + PAGE_SIZE);
 
3713
      ret = alignMemoryPage(ptr);
 
3714
      _memcpy(ret, old, num);
 
3715
      _free(old);
 
3716
    }
 
3717
    if (stream == -1) {
 
3718
      _memset(ret, 0, num);
 
3719
    }
 
3720
    _mmap.mappings[ret] = { malloc: ptr, num: num };
 
3721
    return ret;
 
3722
  },
 
3723
  __01mmap64_: 'mmap',
 
3724
 
 
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;
 
3732
      _free(info.malloc);
 
3733
    }
 
3734
    return 0;
 
3735
  },
 
3736
 
 
3737
  // TODO: Implement mremap.
 
3738
 
 
3739
  // ==========================================================================
 
3740
  // stdlib.h
 
3741
  // ==========================================================================
 
3742
 
 
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
 
3751
     * not an issue.
 
3752
     */
 
3753
    var ptr = Runtime.staticAlloc(bytes + 8);
 
3754
    return (ptr+8) & 0xFFFFFFF8;
 
3755
  },
 
3756
  free: function(){},
 
3757
 
 
3758
  calloc__deps: ['malloc'],
 
3759
  calloc: function(n, s) {
 
3760
    var ret = _malloc(n*s);
 
3761
    _memset(ret, 0, n*s);
 
3762
    return ret;
 
3763
  },
 
3764
 
 
3765
  abs: 'Math.abs',
 
3766
  labs: 'Math.abs',
 
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')]) }}};
 
3772
  },
 
3773
#else
 
3774
  llabs: function(lo, hi) {
 
3775
    throw 'unsupported llabs';
 
3776
  },
 
3777
#endif
 
3778
 
 
3779
  exit__deps: ['_exit'],
 
3780
  exit: function(status) {
 
3781
    __exit(status);
 
3782
  },
 
3783
 
 
3784
  _ZSt9terminatev__deps: ['exit'],
 
3785
  _ZSt9terminatev: function() {
 
3786
    _exit(-1234);
 
3787
  },
 
3788
 
 
3789
  atexit: function(func, arg) {
 
3790
    __ATEXIT__.unshift({ func: func, arg: arg });
 
3791
  },
 
3792
  __cxa_atexit: 'atexit',
 
3793
 
 
3794
  abort: function() {
 
3795
    ABORT = true;
 
3796
    throw 'abort() at ' + (new Error().stack);
 
3797
  },
 
3798
 
 
3799
  bsearch: function(key, base, num, size, compar) {
 
3800
    var cmp = function(x, y) {
 
3801
      return Runtime.dynCall('iii', compar, [x, y])
 
3802
    };
 
3803
    var left = 0;
 
3804
    var right = num;
 
3805
    var mid, test, addr;
 
3806
 
 
3807
    while (left < right) {
 
3808
      mid = (left + right) >>> 1;
 
3809
      addr = base + (mid * size);
 
3810
      test = cmp(key, addr);
 
3811
 
 
3812
      if (test < 0) {
 
3813
        right = mid;
 
3814
      } else if (test > 0) {
 
3815
        left = mid + 1;
 
3816
      } else {
 
3817
        return addr;
 
3818
      }
 
3819
    }
 
3820
 
 
3821
    return 0;
 
3822
  },
 
3823
 
 
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
 
3828
    if (!size) {
 
3829
      if (ptr) _free(ptr);
 
3830
      return 0;
 
3831
    }
 
3832
    var ret = _malloc(size);
 
3833
    if (ptr) {
 
3834
      _memcpy(ret, ptr, size); // might be some invalid reads
 
3835
      _free(ptr);
 
3836
    }
 
3837
    return ret;
 
3838
  },
 
3839
 
 
3840
  _parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'],
 
3841
  _parseInt: function(str, endptr, base, min, max, bits, unsign) {
 
3842
    // Skip space.
 
3843
    while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
 
3844
 
 
3845
    // Check for a plus/minus sign.
 
3846
    var multiplier = 1;
 
3847
    if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('-') }}}) {
 
3848
      multiplier = -1;
 
3849
      str++;
 
3850
    } else if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('+') }}}) {
 
3851
      str++;
 
3852
    }
 
3853
 
 
3854
    // Find base.
 
3855
    var finalBase = base;
 
3856
    if (!finalBase) {
 
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') }}}) {
 
3860
          finalBase = 16;
 
3861
          str += 2;
 
3862
        } else {
 
3863
          finalBase = 8;
 
3864
          str++;
 
3865
        }
 
3866
      }
 
3867
    }
 
3868
    if (!finalBase) finalBase = 10;
 
3869
 
 
3870
    // Get digits.
 
3871
    var chr;
 
3872
    var ret = 0;
 
3873
    while ((chr = {{{ makeGetValue('str', 0, 'i8') }}}) != 0) {
 
3874
      var digit = parseInt(String.fromCharCode(chr), finalBase);
 
3875
      if (isNaN(digit)) {
 
3876
        break;
 
3877
      } else {
 
3878
        ret = ret * finalBase + digit;
 
3879
        str++;
 
3880
      }
 
3881
    }
 
3882
 
 
3883
    // Apply sign.
 
3884
    ret *= multiplier;
 
3885
 
 
3886
    // Set end pointer.
 
3887
    if (endptr) {
 
3888
      {{{ makeSetValue('endptr', 0, 'str', '*') }}}
 
3889
    }
 
3890
 
 
3891
    // Unsign if needed.
 
3892
    if (unsign) {
 
3893
      if (Math.abs(ret) > max) {
 
3894
        ret = max;
 
3895
        ___setErrNo(ERRNO_CODES.ERANGE);
 
3896
      } else {
 
3897
        ret = unSign(ret, bits);
 
3898
      }
 
3899
    }
 
3900
 
 
3901
    // Validate range.
 
3902
    if (ret > max || ret < min) {
 
3903
      ret = ret > max ? max : min;
 
3904
      ___setErrNo(ERRNO_CODES.ERANGE);
 
3905
    }
 
3906
 
 
3907
#if USE_TYPED_ARRAYS == 2
 
3908
    if (bits == 64) {
 
3909
      {{{ makeStructuralReturn(splitI64('ret')) }}};
 
3910
    }
 
3911
#endif
 
3912
 
 
3913
    return ret;
 
3914
  },
 
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) {
 
3918
    var start = str;
 
3919
    // Skip space.
 
3920
    while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
 
3921
 
 
3922
    // Check for a plus/minus sign.
 
3923
    if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('-') }}}) {
 
3924
      str++;
 
3925
    } else if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('+') }}}) {
 
3926
      str++;
 
3927
    }
 
3928
 
 
3929
    // Find base.
 
3930
    var ok = false;
 
3931
    var finalBase = base;
 
3932
    if (!finalBase) {
 
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') }}}) {
 
3936
          finalBase = 16;
 
3937
          str += 2;
 
3938
        } else {
 
3939
          finalBase = 8;
 
3940
          str++;
 
3941
          ok = true; // we saw an initial zero, perhaps the entire thing is just "0"
 
3942
        }
 
3943
      }
 
3944
    }
 
3945
    if (!finalBase) finalBase = 10;
 
3946
 
 
3947
    // Get digits.
 
3948
    var chr;
 
3949
    while ((chr = {{{ makeGetValue('str', 0, 'i8') }}}) != 0) {
 
3950
      var digit = parseInt(String.fromCharCode(chr), finalBase);
 
3951
      if (isNaN(digit)) {
 
3952
        break;
 
3953
      } else {
 
3954
        str++;
 
3955
        ok = true;
 
3956
      }
 
3957
    }
 
3958
    if (!ok) {
 
3959
      ___setErrNo(ERRNO_CODES.EINVAL);
 
3960
      {{{ makeStructuralReturn(['0', '0']) }}};
 
3961
    }
 
3962
 
 
3963
    // Set end pointer.
 
3964
    if (endptr) {
 
3965
      {{{ makeSetValue('endptr', 0, 'str', '*') }}}
 
3966
    }
 
3967
 
 
3968
    try {
 
3969
      i64Math.fromString(Pointer_stringify(start, str - start), finalBase, min, max, unsign);
 
3970
    } catch(e) {
 
3971
      ___setErrNo(ERRNO_CODES.ERANGE); // not quite correct
 
3972
    }
 
3973
 
 
3974
    {{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]) }}};
 
3975
  },
 
3976
#endif
 
3977
  strtoll__deps: ['_parseInt64'],
 
3978
  strtoll: function(str, endptr, base) {
 
3979
    return __parseInt64(str, endptr, base, '-9223372036854775808', '9223372036854775807');  // LLONG_MIN, LLONG_MAX.
 
3980
  },
 
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.
 
3985
  },
 
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.
 
3990
  },
 
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.
 
3995
  },
 
3996
  strtoull_l: 'strtoull', // no locale support yet
 
3997
 
 
3998
  atoi__deps: ['strtol'],
 
3999
  atoi: function(ptr) {
 
4000
    return _strtol(ptr, null, 10);
 
4001
  },
 
4002
  atol: 'atoi',
 
4003
 
 
4004
  atoll__deps: ['strtoll'],
 
4005
  atoll: function(ptr) {
 
4006
    return _strtoll(ptr, null, 10);
 
4007
  },
 
4008
 
 
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]);
 
4016
    }
 
4017
    var keys = [];
 
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);
 
4021
    });
 
4022
    // apply the sort
 
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);
 
4028
    }
 
4029
    _free(temp);
 
4030
  },
 
4031
 
 
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;
 
4040
 
 
4041
    // Statically allocate memory for the environment.
 
4042
    var poolPtr;
 
4043
    var envPtr;
 
4044
    if (!___buildEnvironment.called) {
 
4045
      ___buildEnvironment.called = true;
 
4046
      // Set default values. Use string keys for Closure Compiler compatibility.
 
4047
      ENV['USER'] = 'root';
 
4048
      ENV['PATH'] = '/';
 
4049
      ENV['PWD'] = '/';
 
4050
      ENV['HOME'] = '/home/emscripten';
 
4051
      ENV['LANG'] = 'en_US.UTF-8';
 
4052
      ENV['_'] = './this.program';
 
4053
      // Allocate memory.
 
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*') }}};
 
4059
    } else {
 
4060
      envPtr = {{{ makeGetValue(makeGlobalUse('_environ'), '0', 'i8**') }}};
 
4061
      poolPtr = {{{ makeGetValue('envPtr', '0', 'i8*') }}};
 
4062
    }
 
4063
 
 
4064
    // Collect key=value lines.
 
4065
    var strings = [];
 
4066
    var totalSize = 0;
 
4067
    for (var key in env) {
 
4068
      if (typeof env[key] === 'string') {
 
4069
        var line = key + '=' + env[key];
 
4070
        strings.push(line);
 
4071
        totalSize += line.length;
 
4072
      }
 
4073
    }
 
4074
    if (totalSize > TOTAL_ENV_SIZE) {
 
4075
      throw new Error('Environment size exceeded TOTAL_ENV_SIZE!');
 
4076
    }
 
4077
 
 
4078
    // Make new.
 
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') }}};
 
4084
      }
 
4085
      {{{ makeSetValue('poolPtr', 'j', '0', 'i8') }}};
 
4086
      {{{ makeSetValue('envPtr', 'i * ptrSize', 'poolPtr', 'i8*') }}};
 
4087
      poolPtr += line.length + 1;
 
4088
    }
 
4089
    {{{ makeSetValue('envPtr', 'strings.length * ptrSize', '0', 'i8*') }}};
 
4090
  },
 
4091
  $ENV__deps: ['__buildEnvironment'],
 
4092
  $ENV__postset: '___buildEnvironment(ENV);',
 
4093
  $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;
 
4101
 
 
4102
    if (_getenv.ret) _free(_getenv.ret);
 
4103
    _getenv.ret = allocate(intArrayFromString(ENV[name]), 'i8', ALLOC_NORMAL);
 
4104
    return _getenv.ret;
 
4105
  },
 
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
 
4110
    ENV = {};
 
4111
    ___buildEnvironment(ENV);
 
4112
    return 0;
 
4113
  },
 
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);
 
4120
      return -1;
 
4121
    }
 
4122
    var name = Pointer_stringify(envname);
 
4123
    var val = Pointer_stringify(envval);
 
4124
    if (name === '' || name.indexOf('=') !== -1) {
 
4125
      ___setErrNo(ERRNO_CODES.EINVAL);
 
4126
      return -1;
 
4127
    }
 
4128
    if (ENV.hasOwnProperty(name) && !overwrite) return 0;
 
4129
    ENV[name] = val;
 
4130
    ___buildEnvironment(ENV);
 
4131
    return 0;
 
4132
  },
 
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
 
4137
    if (name === 0) {
 
4138
      ___setErrNo(ERRNO_CODES.EINVAL);
 
4139
      return -1;
 
4140
    }
 
4141
    name = Pointer_stringify(name);
 
4142
    if (name === '' || name.indexOf('=') !== -1) {
 
4143
      ___setErrNo(ERRNO_CODES.EINVAL);
 
4144
      return -1;
 
4145
    }
 
4146
    if (ENV.hasOwnProperty(name)) {
 
4147
      delete ENV[name];
 
4148
      ___buildEnvironment(ENV);
 
4149
    }
 
4150
    return 0;
 
4151
  },
 
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.
 
4159
    if (string === 0) {
 
4160
      ___setErrNo(ERRNO_CODES.EINVAL);
 
4161
      return -1;
 
4162
    }
 
4163
    string = Pointer_stringify(string);
 
4164
    var splitPoint = string.indexOf('=')
 
4165
    if (string === '' || string.indexOf('=') === -1) {
 
4166
      ___setErrNo(ERRNO_CODES.EINVAL);
 
4167
      return -1;
 
4168
    }
 
4169
    var name = string.slice(0, splitPoint);
 
4170
    var value = string.slice(splitPoint + 1);
 
4171
    if (!(name in ENV) || ENV[name] !== value) {
 
4172
      ENV[name] = value;
 
4173
      ___buildEnvironment(ENV);
 
4174
    }
 
4175
    return 0;
 
4176
  },
 
4177
 
 
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') }}}
 
4185
    }
 
4186
    return limit;
 
4187
  },
 
4188
 
 
4189
  // Use browser's Math.random(). We can't set a seed, though.
 
4190
  srand: function(seed) {}, // XXX ignored
 
4191
  rand: function() {
 
4192
    return Math.floor(Math.random()*0x80000000);
 
4193
  },
 
4194
  rand_r: function(seed) { // XXX ignores the seed
 
4195
    return Math.floor(Math.random()*0x80000000);
 
4196
  },
 
4197
 
 
4198
  drand48: function() {
 
4199
    return Math.random();
 
4200
  },
 
4201
 
 
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);
 
4209
      return 0;
 
4210
    } else {
 
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') }}}
 
4214
      }
 
4215
      {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}}
 
4216
      return resolved_name;
 
4217
    }
 
4218
  },
 
4219
 
 
4220
  arc4random: 'rand',
 
4221
 
 
4222
  // ==========================================================================
 
4223
  // string.h
 
4224
  // ==========================================================================
 
4225
 
 
4226
  // FIXME: memcpy, memmove and memset should all return their destination pointers.
 
4227
 
 
4228
  memcpy__inline: function (dest, src, num, align) {
 
4229
    var ret = '';
 
4230
#if ASSERTIONS
 
4231
#if ASM_JS == 0
 
4232
    ret += "assert(" + num + " % 1 === 0);"; //, 'memcpy given ' + " + num + " + ' bytes to copy. Problem with quantum=1 corrections perhaps?');";
 
4233
#endif
 
4234
#endif
 
4235
    ret += makeCopyValues(dest, src, num, 'null', null, align);
 
4236
    return ret;
 
4237
  },
 
4238
 
 
4239
  memcpy__asm: true,
 
4240
  memcpy__sig: 'iiii',
 
4241
  memcpy: function (dest, src, num) {
 
4242
    dest = dest|0; src = src|0; num = num|0;
 
4243
    var ret = 0;
 
4244
    ret = dest|0;
 
4245
    if ((dest&3) == (src&3)) {
 
4246
      while (dest & 3) {
 
4247
        if ((num|0) == 0) return ret|0;
 
4248
        {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
 
4249
        dest = (dest+1)|0;
 
4250
        src = (src+1)|0;
 
4251
        num = (num-1)|0;
 
4252
      }
 
4253
      while ((num|0) >= 4) {
 
4254
        {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i32'), 'i32') }}};
 
4255
        dest = (dest+4)|0;
 
4256
        src = (src+4)|0;
 
4257
        num = (num-4)|0;
 
4258
      }
 
4259
    }
 
4260
    while ((num|0) > 0) {
 
4261
      {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
 
4262
      dest = (dest+1)|0;
 
4263
      src = (src+1)|0;
 
4264
      num = (num-1)|0;
 
4265
    }
 
4266
    return ret|0;
 
4267
  },
 
4268
 
 
4269
  llvm_memcpy_i32: 'memcpy',
 
4270
  llvm_memcpy_i64: 'memcpy',
 
4271
  llvm_memcpy_p0i8_p0i8_i32: 'memcpy',
 
4272
  llvm_memcpy_p0i8_p0i8_i64: 'memcpy',
 
4273
 
 
4274
  memmove__sig: 'viii',
 
4275
  memmove__asm: true,
 
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;
 
4285
        src = (src - 1)|0;
 
4286
        num = (num - 1)|0;
 
4287
        {{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i8'), 'i8') }}};
 
4288
      }
 
4289
    } else {
 
4290
      _memcpy(dest, src, num);
 
4291
    }
 
4292
  },
 
4293
  llvm_memmove_i32: 'memmove',
 
4294
  llvm_memmove_i64: 'memmove',
 
4295
  llvm_memmove_p0i8_p0i8_i32: 'memmove',
 
4296
  llvm_memmove_p0i8_p0i8_i64: 'memmove',
 
4297
 
 
4298
  memset__inline: function(ptr, value, num, align) {
 
4299
    return makeSetValues(ptr, 0, value, 'null', num, align);
 
4300
  },
 
4301
  memset__sig: 'viii',
 
4302
  memset__asm: true,
 
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);
 
4313
      stop4 = stop & ~3;
 
4314
      if (unaligned) {
 
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') }}};
 
4318
          ptr = (ptr+1)|0;
 
4319
        }
 
4320
      }
 
4321
      while ((ptr|0) < (stop4|0)) {
 
4322
        {{{ makeSetValueAsm('ptr', 0, 'value4', 'i32') }}};
 
4323
        ptr = (ptr+4)|0;
 
4324
      }
 
4325
    }
 
4326
    while ((ptr|0) < (stop|0)) {
 
4327
      {{{ makeSetValueAsm('ptr', 0, 'value', 'i8') }}};
 
4328
      ptr = (ptr+1)|0;
 
4329
    }
 
4330
#else
 
4331
    {{{ makeSetValues('ptr', '0', 'value', 'null', 'num') }}};
 
4332
#endif
 
4333
  },
 
4334
  llvm_memset_i32: 'memset',
 
4335
  llvm_memset_p0i8_i32: 'memset',
 
4336
  llvm_memset_p0i8_i64: 'memset',
 
4337
 
 
4338
  strlen__sig: 'ii',
 
4339
  strlen__asm: true,
 
4340
  strlen: function(ptr) {
 
4341
    ptr = ptr|0;
 
4342
    var curr = 0;
 
4343
    curr = ptr;
 
4344
    while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}) {
 
4345
      curr = (curr + 1)|0;
 
4346
    }
 
4347
    return (curr - ptr)|0;
 
4348
  },
 
4349
 
 
4350
  strspn: function(pstr, pset) {
 
4351
    var str = pstr, set, strcurr, setcurr;
 
4352
    while (1) {
 
4353
      strcurr = {{{ makeGetValue('str', '0', 'i8') }}};
 
4354
      if (!strcurr) return str - pstr;
 
4355
      set = pset;
 
4356
      while (1) {
 
4357
        setcurr = {{{ makeGetValue('set', '0', 'i8') }}};
 
4358
        if (!setcurr || setcurr == strcurr) break;
 
4359
        set++;
 
4360
      }
 
4361
      if (!setcurr) return str - pstr;
 
4362
      str++;
 
4363
    }
 
4364
  },
 
4365
 
 
4366
  strcspn: function(pstr, pset) {
 
4367
    var str = pstr, set, strcurr, setcurr;
 
4368
    while (1) {
 
4369
      strcurr = {{{ makeGetValue('str', '0', 'i8') }}};
 
4370
      if (!strcurr) return str - pstr;
 
4371
      set = pset;
 
4372
      while (1) {
 
4373
        setcurr = {{{ makeGetValue('set', '0', 'i8') }}};
 
4374
        if (!setcurr || setcurr == strcurr) break;
 
4375
        set++;
 
4376
      }
 
4377
      if (setcurr) return str - pstr;
 
4378
      str++;
 
4379
    }
 
4380
  },
 
4381
 
 
4382
  strcpy__asm: true,
 
4383
  strcpy__sig: 'iii',
 
4384
  strcpy: function(pdest, psrc) {
 
4385
    pdest = pdest|0; psrc = psrc|0;
 
4386
    var i = 0;
 
4387
    do {
 
4388
      {{{ makeCopyValues('(pdest+i)|0', '(psrc+i)|0', 1, 'i8', null, 1) }}};
 
4389
      i = (i+1)|0;
 
4390
    } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}});
 
4391
    return pdest|0;
 
4392
  },
 
4393
 
 
4394
  stpcpy: function(pdest, psrc) {
 
4395
    var i = 0;
 
4396
    do {
 
4397
      {{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}};
 
4398
      i ++;
 
4399
    } while ({{{ makeGetValue('psrc', 'i-1', 'i8') }}} != 0);
 
4400
    return pdest + i - 1;
 
4401
  },
 
4402
 
 
4403
  strncpy__asm: true,
 
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);
 
4412
      i = (i+1)|0;
 
4413
    }
 
4414
    return pdest|0;
 
4415
  },
 
4416
  
 
4417
  strlwr__deps:['tolower'],
 
4418
  strlwr: function(pstr){
 
4419
    var i = 0;
 
4420
    while(1) {
 
4421
      var x = {{{ makeGetValue('pstr', 'i', 'i8') }}};
 
4422
      if(x == 0) break;
 
4423
      {{{ makeSetValue('pstr', 'i', '_tolower(x)', 'i8') }}};
 
4424
      i++;
 
4425
    }
 
4426
  },
 
4427
  
 
4428
  strupr__deps:['toupper'],
 
4429
  strupr: function(pstr){
 
4430
    var i = 0;
 
4431
    while(1) {
 
4432
      var x = {{{ makeGetValue('pstr', 'i', 'i8') }}};
 
4433
      if(x == 0) break;
 
4434
      {{{ makeSetValue('pstr', 'i', '_toupper(x)', 'i8') }}};
 
4435
      i++;
 
4436
    }
 
4437
  },
 
4438
 
 
4439
  strcat__asm: true,
 
4440
  strcat__sig: 'iii',
 
4441
  strcat__deps: ['strlen'],
 
4442
  strcat: function(pdest, psrc) {
 
4443
    pdest = pdest|0; psrc = psrc|0;
 
4444
    var i = 0;
 
4445
    pdest = (pdest + (_strlen(pdest)|0))|0;
 
4446
    do {
 
4447
      {{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}};
 
4448
      i = (i+1)|0;
 
4449
    } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}});
 
4450
    return pdest|0;
 
4451
  },
 
4452
 
 
4453
  strncat__deps: ['strlen'],
 
4454
  strncat: function(pdest, psrc, num) {
 
4455
    var len = _strlen(pdest);
 
4456
    var i = 0;
 
4457
    while(1) {
 
4458
      {{{ makeCopyValues('pdest+len+i', 'psrc+i', 1, 'i8', null, 1) }}};
 
4459
      if ({{{ makeGetValue('pdest', 'len+i', 'i8') }}} == 0) break;
 
4460
      i ++;
 
4461
      if (i == num) {
 
4462
        {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}}
 
4463
        break;
 
4464
      }
 
4465
    }
 
4466
    return pdest;
 
4467
  },
 
4468
 
 
4469
  strcmp__deps: ['strncmp'],
 
4470
  strcmp: function(px, py) {
 
4471
    return _strncmp(px, py, TOTAL_MEMORY);
 
4472
  },
 
4473
  // We always assume ASCII locale.
 
4474
  strcoll: 'strcmp',
 
4475
 
 
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;
 
4482
  },
 
4483
 
 
4484
  strncmp: function(px, py, n) {
 
4485
    var i = 0;
 
4486
    while (i < 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;
 
4492
      if (x == y) {
 
4493
        i ++;
 
4494
        continue;
 
4495
      } else {
 
4496
        return x > y ? 1 : -1;
 
4497
      }
 
4498
    }
 
4499
    return 0;
 
4500
  },
 
4501
 
 
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)) {
 
4515
        i = (i + 1)|0;
 
4516
        continue;
 
4517
      } else {
 
4518
        return ((x>>>0) > (y>>>0) ? 1 : -1)|0;
 
4519
      }
 
4520
    }
 
4521
    return 0;
 
4522
  },
 
4523
 
 
4524
  memcmp__asm: true,
 
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;
 
4533
      i = (i+1)|0;
 
4534
    }
 
4535
    return 0;
 
4536
  },
 
4537
 
 
4538
  memchr: function(ptr, chr, num) {
 
4539
    chr = unSign(chr);
 
4540
    for (var i = 0; i < num; i++) {
 
4541
      if ({{{ makeGetValue('ptr', 0, 'i8') }}} == chr) return ptr;
 
4542
      ptr++;
 
4543
    }
 
4544
    return 0;
 
4545
  },
 
4546
 
 
4547
  strstr: function(ptr1, ptr2) {
 
4548
    var check = 0, start;
 
4549
    do {
 
4550
      if (!check) {
 
4551
        start = ptr1;
 
4552
        check = ptr2;
 
4553
      }
 
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
 
4559
        ptr1 = start + 1;
 
4560
        check = 0;
 
4561
      }
 
4562
    } while (curr1);
 
4563
    return 0;
 
4564
  },
 
4565
 
 
4566
  strchr: function(ptr, chr) {
 
4567
    ptr--;
 
4568
    do {
 
4569
      ptr++;
 
4570
      var val = {{{ makeGetValue('ptr', 0, 'i8') }}};
 
4571
      if (val == chr) return ptr;
 
4572
    } while (val);
 
4573
    return 0;
 
4574
  },
 
4575
  index: 'strchr',
 
4576
 
 
4577
  strrchr__deps: ['strlen'],
 
4578
  strrchr: function(ptr, chr) {
 
4579
    var ptr2 = ptr + _strlen(ptr);
 
4580
    do {
 
4581
      if ({{{ makeGetValue('ptr2', 0, 'i8') }}} == chr) return ptr2;
 
4582
      ptr2--;
 
4583
    } while (ptr2 >= ptr);
 
4584
    return 0;
 
4585
  },
 
4586
  rindex: 'strrchr',
 
4587
 
 
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') }}};
 
4594
    return newStr;
 
4595
  },
 
4596
 
 
4597
  strndup__deps: ['strdup', 'strlen'],
 
4598
  strndup: function(ptr, size) {
 
4599
    var len = _strlen(ptr);
 
4600
 
 
4601
    if (size >= len) {
 
4602
      return _strdup(ptr);
 
4603
    }
 
4604
 
 
4605
    if (size < 0) {
 
4606
      size = 0;
 
4607
    }
 
4608
    
 
4609
    var newStr = _malloc(size + 1);
 
4610
    {{{ makeCopyValues('newStr', 'ptr', 'size', 'null', null, 1) }}};
 
4611
    {{{ makeSetValue('newStr', 'size', '0', 'i8') }}};
 
4612
    return newStr;
 
4613
  },
 
4614
 
 
4615
  strpbrk: function(ptr1, ptr2) {
 
4616
    var curr;
 
4617
    var searchSet = {};
 
4618
    while (1) {
 
4619
      var curr = {{{ makeGetValue('ptr2++', 0, 'i8') }}};
 
4620
      if (!curr) break;
 
4621
      searchSet[curr] = 1;
 
4622
    }
 
4623
    while (1) {
 
4624
      curr = {{{ makeGetValue('ptr1', 0, 'i8') }}};
 
4625
      if (!curr) break;
 
4626
      if (curr in searchSet) return ptr1;
 
4627
      ptr1++;
 
4628
    }
 
4629
    return 0;
 
4630
  },
 
4631
 
 
4632
  __strtok_state: 0,
 
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);
 
4637
  },
 
4638
 
 
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;
 
4642
    var spanp;
 
4643
    var c, sc;
 
4644
    var tok;
 
4645
 
 
4646
 
 
4647
    if (s == 0 && (s = getValue(lasts, 'i8*')) == 0) {
 
4648
      return 0;
 
4649
    }
 
4650
 
 
4651
    cont: while (1) {
 
4652
      c = getValue(s++, 'i8');
 
4653
      for (spanp = delim; (sc = getValue(spanp++, 'i8')) != 0;) {
 
4654
        if (c == sc) {
 
4655
          if (skip_leading_delim) {
 
4656
            continue cont;
 
4657
          } else {
 
4658
            setValue(lasts, s, 'i8*');
 
4659
            setValue(s - 1, 0, 'i8');
 
4660
            return s - 1;
 
4661
          }
 
4662
        }
 
4663
      }
 
4664
      break;
 
4665
    }
 
4666
 
 
4667
    if (c == 0) {
 
4668
      setValue(lasts, 0, 'i8*');
 
4669
      return 0;
 
4670
    }
 
4671
    tok = s - 1;
 
4672
 
 
4673
    for (;;) {
 
4674
      c = getValue(s++, 'i8');
 
4675
      spanp = delim;
 
4676
      do {
 
4677
        if ((sc = getValue(spanp++, 'i8')) == c) {
 
4678
          if (c == 0) {
 
4679
            s = 0;
 
4680
          } else {
 
4681
            setValue(s - 1, 0, 'i8');
 
4682
          }
 
4683
          setValue(lasts, s, 'i8*');
 
4684
          return tok;
 
4685
        }
 
4686
      } while (sc != 0);
 
4687
    }
 
4688
    abort('strtok_r error!');
 
4689
  },
 
4690
 
 
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);
 
4696
      } else {
 
4697
        var msg = ERRNO_MESSAGES[errnum];
 
4698
        for (var i = 0; i < msg.length; i++) {
 
4699
          {{{ makeSetValue('strerrbuf', 'i', 'msg.charCodeAt(i)', 'i8') }}}
 
4700
        }
 
4701
        {{{ makeSetValue('strerrbuf', 'i', 0, 'i8') }}}
 
4702
        return 0;
 
4703
      }
 
4704
    } else {
 
4705
      return ___setErrNo(ERRNO_CODES.EINVAL);
 
4706
    }
 
4707
  },
 
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;
 
4713
  },
 
4714
 
 
4715
  // ==========================================================================
 
4716
  // ctype.h
 
4717
  // ==========================================================================
 
4718
 
 
4719
  isascii: function(chr) {
 
4720
    return chr >= 0 && (chr & 0x80) == 0;
 
4721
  },
 
4722
  toascii: function(chr) {
 
4723
    return chr & 0x7F;
 
4724
  },
 
4725
  toupper: function(chr) {
 
4726
    if (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) {
 
4727
      return chr - {{{ charCode('a') }}} + {{{ charCode('A') }}};
 
4728
    } else {
 
4729
      return chr;
 
4730
    }
 
4731
  },
 
4732
  _toupper: 'toupper',
 
4733
 
 
4734
  tolower__asm: true,
 
4735
  tolower__sig: 'ii',
 
4736
  tolower: function(chr) {
 
4737
    chr = chr|0;
 
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;
 
4741
  },
 
4742
  _tolower: 'tolower',
 
4743
 
 
4744
  // The following functions are defined as macros in glibc.
 
4745
  islower: function(chr) {
 
4746
    return chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}};
 
4747
  },
 
4748
  isupper: function(chr) {
 
4749
    return chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}};
 
4750
  },
 
4751
  isalpha: function(chr) {
 
4752
    return (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) ||
 
4753
           (chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}});
 
4754
  },
 
4755
  isdigit: function(chr) {
 
4756
    return chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}};
 
4757
  },
 
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') }}});
 
4763
  },
 
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') }}});
 
4769
  },
 
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('~') }}});
 
4775
  },
 
4776
  isspace: function(chr) {
 
4777
    return chr in { 32: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0 };
 
4778
  },
 
4779
  isblank: function(chr) {
 
4780
    return chr == {{{ charCode(' ') }}} || chr == {{{ charCode('\t') }}};
 
4781
  },
 
4782
  iscntrl: function(chr) {
 
4783
    return (0 <= chr && chr <= 0x1F) || chr === 0x7F;
 
4784
  },
 
4785
  isprint: function(chr) {
 
4786
    return 0x1F < chr && chr < 0x7F;
 
4787
  },
 
4788
  isgraph: 'isprint',
 
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;
 
4793
    if (!me.ret) {
 
4794
      var values = [
 
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
 
4805
      ];
 
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') }}}
 
4810
      }
 
4811
      me.ret = allocate([arr + 128 * i16size], 'i16*', ALLOC_NORMAL);
 
4812
    }
 
4813
    return me.ret;
 
4814
  },
 
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;
 
4818
    if (!me.ret) {
 
4819
      var values = [
 
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,
 
4832
        254,255
 
4833
      ];
 
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') }}}
 
4838
      }
 
4839
      me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
 
4840
    }
 
4841
    return me.ret;
 
4842
  },
 
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;
 
4846
    if (!me.ret) {
 
4847
      var values = [
 
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
 
4860
      ];
 
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') }}}
 
4865
      }
 
4866
      me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
 
4867
    }
 
4868
    return me.ret;
 
4869
  },
 
4870
 
 
4871
  // ==========================================================================
 
4872
  // LLVM specifics
 
4873
  // ==========================================================================
 
4874
 
 
4875
  llvm_va_start__inline: function(ptr) {
 
4876
    // varargs - we received a pointer to the varargs as a final 'extra' parameter called 'varrp'
 
4877
#if TARGET_X86
 
4878
    return makeSetValue(ptr, 0, 'varrp', 'void*');
 
4879
#endif
 
4880
#if TARGET_LE32
 
4881
    // 4-word structure: start, current offset
 
4882
    return makeSetValue(ptr, 0, 'varrp', 'void*') + ';' + makeSetValue(ptr, 4, 0, 'void*');
 
4883
#endif
 
4884
  },
 
4885
 
 
4886
  llvm_va_end: function() {},
 
4887
 
 
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;
 
4896
    */
 
4897
  },
 
4898
 
 
4899
  llvm_bswap_i16: function(x) {
 
4900
    return ((x&0xff)<<8) | ((x>>8)&0xff);
 
4901
  },
 
4902
 
 
4903
  llvm_bswap_i32: function(x) {
 
4904
    return ((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24);
 
4905
  },
 
4906
 
 
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']) }}};
 
4913
#else
 
4914
    throw 'unsupported';
 
4915
#endif
 
4916
  },
 
4917
 
 
4918
  llvm_ctlz_i32__deps: [function() {
 
4919
    function ctlz(x) {
 
4920
      for (var i = 0; i < 8; i++) {
 
4921
        if (x & (1 << (7-i))) {
 
4922
          return i;
 
4923
        }
 
4924
      }
 
4925
      return 8;
 
4926
    }
 
4927
    return 'var ctlz_i8 = allocate([' + range(256).map(function(x) { return ctlz(x) }).join(',') + '], "i8", ALLOC_STACK);';
 
4928
  }],
 
4929
  llvm_ctlz_i32__asm: true,
 
4930
  llvm_ctlz_i32__sig: 'ii',
 
4931
  llvm_ctlz_i32: function(x) {
 
4932
    x = x|0;
 
4933
    var ret = 0;
 
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;
 
4941
  },
 
4942
 
 
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']) }}};
 
4949
#else
 
4950
    return ret;
 
4951
#endif
 
4952
  },
 
4953
 
 
4954
  llvm_cttz_i32__deps: [function() {
 
4955
    function cttz(x) {
 
4956
      for (var i = 0; i < 8; i++) {
 
4957
        if (x & (1 << i)) {
 
4958
          return i;
 
4959
        }
 
4960
      }
 
4961
      return 8;
 
4962
    }
 
4963
    return 'var cttz_i8 = allocate([' + range(256).map(function(x) { return cttz(x) }).join(',') + '], "i8", ALLOC_STACK);';
 
4964
  }],
 
4965
  llvm_cttz_i32__asm: true,
 
4966
  llvm_cttz_i32__sig: 'ii',
 
4967
  llvm_cttz_i32: function(x) {
 
4968
    x = x|0;
 
4969
    var ret = 0;
 
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;
 
4977
  },
 
4978
 
 
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']) }}};
 
4985
#else
 
4986
    return ret;
 
4987
#endif
 
4988
  },
 
4989
 
 
4990
  llvm_ctpop_i32: function(x) {
 
4991
    var ret = 0;
 
4992
    while (x) {
 
4993
      if (x&1) ret++;
 
4994
      x >>>= 1;
 
4995
    }
 
4996
    return ret;
 
4997
  },
 
4998
 
 
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);
 
5002
  },
 
5003
 
 
5004
  llvm_trap: function() {
 
5005
    throw 'trap! ' + new Error().stack;
 
5006
  },
 
5007
 
 
5008
  __assert_fail: function(condition, file, line) {
 
5009
    ABORT = true;
 
5010
    throw 'Assertion failed: ' + Pointer_stringify(condition) + ' at ' + new Error().stack;
 
5011
  },
 
5012
 
 
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;
 
5015
  },
 
5016
 
 
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') }}};
 
5020
      return 1;
 
5021
    }
 
5022
    return 0;
 
5023
  },
 
5024
  __cxa_guard_release: function() {},
 
5025
  __cxa_guard_abort: function() {},
 
5026
 
 
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
 
5030
 
 
5031
  // Exceptions
 
5032
  __cxa_allocate_exception: function(size) {
 
5033
    return _malloc(size);
 
5034
  },
 
5035
  __cxa_free_exception: function(ptr) {
 
5036
    return _free(ptr);
 
5037
  },
 
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) {
 
5042
      try {
 
5043
        {{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv119__pointer_type_infoE'), '0', '0', 'i32') }}}; // Workaround for libcxxabi integration bug
 
5044
      } catch(e){}
 
5045
      try {
 
5046
        {{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv117__class_type_infoE'), '0', '1', 'i32') }}}; // Workaround for libcxxabi integration bug
 
5047
      } catch(e){}
 
5048
      try {
 
5049
        {{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv120__si_class_type_infoE'), '0', '2', 'i32') }}}; // Workaround for libcxxabi integration bug
 
5050
      } catch(e){}
 
5051
      ___cxa_throw.initialized = true;
 
5052
    }
 
5053
#if EXCEPTION_DEBUG
 
5054
    Module.printErr('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + new Error().stack);
 
5055
#endif
 
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;
 
5061
    } else {
 
5062
      __ZSt18uncaught_exceptionv.uncaught_exception++;
 
5063
    }
 
5064
    {{{ makeThrow('ptr') }}};
 
5065
  },
 
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*')) }}};
 
5070
  },
 
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*') }}};
 
5074
  },
 
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;
 
5080
    }
 
5081
    return 0;
 
5082
  },
 
5083
  llvm_eh_typeid_for: function(type) {
 
5084
    return type;
 
5085
  },
 
5086
  __cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv'],
 
5087
  __cxa_begin_catch: function(ptr) {
 
5088
    __ZSt18uncaught_exceptionv.uncaught_exception--;
 
5089
    return ptr;
 
5090
  },
 
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;
 
5095
      return;
 
5096
    }
 
5097
    // Clear state flag.
 
5098
#if ASM_JS
 
5099
    asm.setThrew(0);
 
5100
#else
 
5101
    __THREW__ = 0;
 
5102
#endif
 
5103
    // Clear type.
 
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*') }}};
 
5108
    if (destructor) {
 
5109
      Runtime.dynCall('vi', destructor, [ptr]);
 
5110
      {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}}
 
5111
    }
 
5112
    // Free ptr if it isn't null.
 
5113
    if (ptr) {
 
5114
      ___cxa_free_exception(ptr);
 
5115
      {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}}
 
5116
    }
 
5117
  },
 
5118
  __cxa_get_exception_ptr__deps: ['llvm_eh_exception'],
 
5119
  __cxa_get_exception_ptr: function(ptr) {
 
5120
    return ptr;
 
5121
  },
 
5122
  _ZSt18uncaught_exceptionv: function() { // std::uncaught_exception()
 
5123
    return !!__ZSt18uncaught_exceptionv.uncaught_exception;
 
5124
  },
 
5125
  __cxa_uncaught_exception__deps: ['_Zst18uncaught_exceptionv'],
 
5126
  __cxa_uncaught_exception: function() {
 
5127
    return !!__ZSt18uncaught_exceptionv.uncaught_exception;
 
5128
  },
 
5129
 
 
5130
  __cxa_call_unexpected: function(exception) {
 
5131
    Module.printErr('Unexpected exception thrown, this is not properly supported - aborting');
 
5132
    ABORT = true;
 
5133
    throw exception;
 
5134
  },
 
5135
 
 
5136
  _Unwind_Resume_or_Rethrow: function(ptr) {
 
5137
    {{{ makeThrow('ptr') }}};
 
5138
  },
 
5139
  _Unwind_RaiseException: function(ptr) {
 
5140
    {{{ makeThrow('ptr') }}};
 
5141
  },
 
5142
  _Unwind_DeleteException: function(ptr) {},
 
5143
 
 
5144
  terminate: '__cxa_call_unexpected',
 
5145
 
 
5146
  __gxx_personality_v0: function() {
 
5147
  },
 
5148
 
 
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){}
 
5165
    return isNumber;
 
5166
  },
 
5167
 
 
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.
 
5177
 
 
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);
 
5183
 
 
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', '*') }}};
 
5192
    }
 
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]']) }}};
 
5200
    }
 
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']) }}};
 
5205
  },
 
5206
 
 
5207
  __resumeException__deps: [function() { Functions.libraryFunctions['__resumeException'] = 1 }], // will be called directly from compiled code
 
5208
  __resumeException: function(ptr) {
 
5209
#if EXCEPTION_DEBUG
 
5210
    Module.print("Resuming exception");
 
5211
#endif
 
5212
    if ({{{ makeGetValue('_llvm_eh_exception.buf', 0, 'void*') }}} == 0) {{{ makeSetValue('_llvm_eh_exception.buf', 0, 'ptr', 'void*') }}};
 
5213
    {{{ makeThrow('ptr') }}};
 
5214
  },
 
5215
 
 
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)
 
5222
      return true;
 
5223
    var possibility_type_info;
 
5224
    if (___cxa_is_number_type(possibilityType)) {
 
5225
      possibility_type_info = possibilityType;
 
5226
    } else {
 
5227
      var possibility_type_infoAddr = {{{ makeGetValue('possibilityType', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}};
 
5228
      possibility_type_info = {{{ makeGetValue('possibility_type_infoAddr', '0', '*') }}};
 
5229
    }
 
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);
 
5242
      } else
 
5243
        return false; // one pointer and one non-pointer
 
5244
    case 1: // class with no base class
 
5245
      return false;
 
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);
 
5250
    default:
 
5251
      return false; // some unencountered type
 
5252
    }
 
5253
  },
 
5254
 
 
5255
  _ZNSt9exceptionD2Ev: function(){}, // XXX a dependency of dlmalloc, but not actually needed if libcxx is not anyhow included
 
5256
 
 
5257
  _ZNSt9type_infoD2Ev: function(){},
 
5258
 
 
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.
 
5262
  _ZTIb: [0], // bool
 
5263
  _ZTIi: [0], // int
 
5264
  _ZTIj: [0], // unsigned int
 
5265
  _ZTIl: [0], // long
 
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
 
5272
  _ZTIc: [0], // char
 
5273
  _ZTIa: [0], // signed char
 
5274
  _ZTIh: [0], // unsigned char
 
5275
  _ZTIs: [0], // short
 
5276
  _ZTIt: [0], // unsigned short
 
5277
  _ZTIv: [0], // void
 
5278
  _ZTIPv: [0], // void*
 
5279
 
 
5280
  llvm_uadd_with_overflow_i8: function(x, y) {
 
5281
    x = x & 0xff;
 
5282
    y = y & 0xff;
 
5283
    {{{ makeStructuralReturn(['(x+y) & 0xff', 'x+y > 255']) }}};
 
5284
  },
 
5285
 
 
5286
  llvm_umul_with_overflow_i8: function(x, y) {
 
5287
    x = x & 0xff;
 
5288
    y = y & 0xff;
 
5289
    {{{ makeStructuralReturn(['(x*y) & 0xff', 'x*y > 255']) }}};
 
5290
  },
 
5291
 
 
5292
  llvm_uadd_with_overflow_i16: function(x, y) {
 
5293
    x = x & 0xffff;
 
5294
    y = y & 0xffff;
 
5295
    {{{ makeStructuralReturn(['(x+y) & 0xffff', 'x+y > 65535']) }}};
 
5296
  },
 
5297
 
 
5298
  llvm_umul_with_overflow_i16: function(x, y) {
 
5299
    x = x & 0xffff;
 
5300
    y = y & 0xffff;
 
5301
    {{{ makeStructuralReturn(['(x*y) & 0xffff', 'x*y > 65535']) }}};
 
5302
  },
 
5303
 
 
5304
  llvm_uadd_with_overflow_i32: function(x, y) {
 
5305
    x = x>>>0;
 
5306
    y = y>>>0;
 
5307
    {{{ makeStructuralReturn(['(x+y)>>>0', 'x+y > 4294967295']) }}};
 
5308
  },
 
5309
 
 
5310
  llvm_umul_with_overflow_i32: function(x, y) {
 
5311
    x = x>>>0;
 
5312
    y = y>>>0;
 
5313
    {{{ makeStructuralReturn(['(x*y)>>>0', 'x*y > 4294967295']) }}};
 
5314
  },
 
5315
 
 
5316
  llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }],
 
5317
  llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) {
 
5318
#if ASSERTIONS
 
5319
    Runtime.warnOnce('no overflow support in llvm_umul_with_overflow_i64');
 
5320
#endif
 
5321
    var low = ___muldi3(xl, xh, yl, yh);
 
5322
    {{{ makeStructuralReturn(['low', 'tempRet0', '0']) }}};
 
5323
  },
 
5324
 
 
5325
  llvm_stacksave: function() {
 
5326
    var self = _llvm_stacksave;
 
5327
    if (!self.LLVM_SAVEDSTACKS) {
 
5328
      self.LLVM_SAVEDSTACKS = [];
 
5329
    }
 
5330
    self.LLVM_SAVEDSTACKS.push(Runtime.stackSave());
 
5331
    return self.LLVM_SAVEDSTACKS.length-1;
 
5332
  },
 
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);
 
5338
  },
 
5339
 
 
5340
  __cxa_pure_virtual: function() {
 
5341
    ABORT = true;
 
5342
    throw 'Pure virtual function called!';
 
5343
  },
 
5344
 
 
5345
  llvm_flt_rounds: function() {
 
5346
    return -1; // 'indeterminable' for FLT_ROUNDS
 
5347
  },
 
5348
 
 
5349
  llvm_memory_barrier: function(){},
 
5350
 
 
5351
  llvm_atomic_load_add_i32_p0i32: function(ptr, delta) {
 
5352
    var ret = {{{ makeGetValue('ptr', '0', 'i32') }}};
 
5353
    {{{ makeSetValue('ptr', '0', 'ret+delta', 'i32') }}};
 
5354
    return ret;
 
5355
  },
 
5356
 
 
5357
  llvm_expect_i32__inline: function(val, expected) {
 
5358
    return '(' + val + ')';
 
5359
  },
 
5360
 
 
5361
  llvm_lifetime_start: function() {},
 
5362
  llvm_lifetime_end: function() {},
 
5363
 
 
5364
  llvm_invariant_start: function() {},
 
5365
  llvm_invariant_end: function() {},
 
5366
 
 
5367
  llvm_objectsize_i32: function() { return -1 }, // TODO: support this
 
5368
 
 
5369
  llvm_dbg_declare__inline: function() { throw 'llvm_debug_declare' }, // avoid warning
 
5370
 
 
5371
  // ==========================================================================
 
5372
  // llvm-mono integration
 
5373
  // ==========================================================================
 
5374
 
 
5375
  llvm_mono_load_i8_p0i8: function(ptr) {
 
5376
    return {{{ makeGetValue('ptr', 0, 'i8') }}};
 
5377
  },
 
5378
 
 
5379
  llvm_mono_store_i8_p0i8: function(value, ptr) {
 
5380
    {{{ makeSetValue('ptr', 0, 'value', 'i8') }}};
 
5381
  },
 
5382
 
 
5383
  llvm_mono_load_i16_p0i16: function(ptr) {
 
5384
    return {{{ makeGetValue('ptr', 0, 'i16') }}};
 
5385
  },
 
5386
 
 
5387
  llvm_mono_store_i16_p0i16: function(value, ptr) {
 
5388
    {{{ makeSetValue('ptr', 0, 'value', 'i16') }}};
 
5389
  },
 
5390
 
 
5391
  llvm_mono_load_i32_p0i32: function(ptr) {
 
5392
    return {{{ makeGetValue('ptr', 0, 'i32') }}};
 
5393
  },
 
5394
 
 
5395
  llvm_mono_store_i32_p0i32: function(value, ptr) {
 
5396
    {{{ makeSetValue('ptr', 0, 'value', 'i32') }}};
 
5397
  },
 
5398
 
 
5399
  // ==========================================================================
 
5400
  // math.h
 
5401
  // ==========================================================================
 
5402
 
 
5403
  cos: 'Math.cos',
 
5404
  cosf: 'Math.cos',
 
5405
  sin: 'Math.sin',
 
5406
  sinf: 'Math.sin',
 
5407
  tan: 'Math.tan',
 
5408
  tanf: 'Math.tan',
 
5409
  acos: 'Math.acos',
 
5410
  acosf: 'Math.acos',
 
5411
  asin: 'Math.asin',
 
5412
  asinf: 'Math.asin',
 
5413
  atan: 'Math.atan',
 
5414
  atanf: 'Math.atan',
 
5415
  atan2: 'Math.atan2',
 
5416
  atan2f: 'Math.atan2',
 
5417
  exp: 'Math.exp',
 
5418
  expf: 'Math.exp',
 
5419
 
 
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;
 
5427
    var a = 1;
 
5428
    var b = x;
 
5429
    var c = x;
 
5430
    var d = x * x + 0.5;
 
5431
    var n = 1.0;
 
5432
    var q2 = b / d;
 
5433
    var q1, t;
 
5434
 
 
5435
    if (Math.abs(x) < 2.2) {
 
5436
      return 1.0 - _erf(x);
 
5437
    }
 
5438
    if (x < 0) {
 
5439
      return 2.0 - _erfc(-x);
 
5440
    }
 
5441
    do {
 
5442
      t = a * n + b * x;
 
5443
      a = b;
 
5444
      b = t;
 
5445
      t = c * n + d * x;
 
5446
      c = d;
 
5447
      d = t;
 
5448
      n += 0.5;
 
5449
      q1 = q2;
 
5450
      q2 = b / d;
 
5451
    } while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE);
 
5452
    return (ONE_SQRTPI * Math.exp(- x * x) * q2);
 
5453
  },
 
5454
  erfcf: 'erfcf',
 
5455
  erf__deps: ['erfc'],
 
5456
  erf: function (x) {
 
5457
    var MATH_TOLERANCE = 1E-12;
 
5458
    var TWO_SQRTPI = 1.128379167095512574;
 
5459
    var sum = x;
 
5460
    var term = x;
 
5461
    var xsqr = x*x;
 
5462
    var j = 1;
 
5463
 
 
5464
    if (Math.abs(x) > 2.2) {
 
5465
      return 1.0 - _erfc(x);
 
5466
    }
 
5467
    do {
 
5468
      term *= xsqr / j;
 
5469
      sum -= term / (2 * j + 1);
 
5470
      ++j;
 
5471
      term *= xsqr / j;
 
5472
      sum += term / (2 * j + 1);
 
5473
      ++j;
 
5474
    } while (Math.abs(term / sum) > MATH_TOLERANCE);
 
5475
    return (TWO_SQRTPI * sum);
 
5476
  },
 
5477
  erff: 'erf',
 
5478
  log: 'Math.log',
 
5479
  logf: 'Math.log',
 
5480
  sqrt: 'Math.sqrt',
 
5481
  sqrtf: 'Math.sqrt',
 
5482
  fabs: 'Math.abs',
 
5483
  fabsf: 'Math.abs',
 
5484
  ceil: 'Math.ceil',
 
5485
  ceilf: 'Math.ceil',
 
5486
  floor: 'Math.floor',
 
5487
  floorf: 'Math.floor',
 
5488
  pow: 'Math.pow',
 
5489
  powf: 'Math.pow',
 
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_);
 
5500
  },
 
5501
  ldexpf: 'ldexp',
 
5502
  scalb: 'ldexp',
 
5503
  scalbn: 'ldexp',
 
5504
  scalbnf: 'ldexp',
 
5505
  scalbln: 'ldexp',
 
5506
  scalblnf: 'ldexp',
 
5507
  cbrt: function(x) {
 
5508
    return Math.pow(x, 1/3);
 
5509
  },
 
5510
  cbrtf: 'cbrt',
 
5511
  cbrtl: 'cbrt',
 
5512
 
 
5513
  modf: function(x, intpart) {
 
5514
    {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}}
 
5515
    return x - {{{ makeGetValue('intpart', 0, 'double') }}};
 
5516
  },
 
5517
  modff: function(x, intpart) {
 
5518
    {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}}
 
5519
    return x - {{{ makeGetValue('intpart', 0, 'float') }}};
 
5520
  },
 
5521
  frexp: function(x, exp_addr) {
 
5522
    var sig = 0, exp_ = 0;
 
5523
    if (x !== 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_);
 
5528
    }
 
5529
    {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}}
 
5530
    return sig;
 
5531
  },
 
5532
  frexpf: 'frexp',
 
5533
  finite: function(x) {
 
5534
    return isFinite(x);
 
5535
  },
 
5536
  __finite: 'finite',
 
5537
  isinf: function(x) {
 
5538
    return !isNaN(x) && !isFinite(x);
 
5539
  },
 
5540
  __isinf: 'isinf',
 
5541
  isnan: function(x) {
 
5542
    return isNaN(x);
 
5543
  },
 
5544
  __isnan: 'isnan',
 
5545
 
 
5546
  _reallyNegative: function(x) {
 
5547
    return x < 0 || (x === 0 && (1/x) === -Infinity);
 
5548
  },
 
5549
 
 
5550
  copysign__deps: ['_reallyNegative'],
 
5551
  copysign: function(a, b) {
 
5552
    return __reallyNegative(a) === __reallyNegative(b) ? a : -a;
 
5553
  },
 
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;
 
5560
  },
 
5561
  __signbitf: '__signbit',
 
5562
  __signbitd: '__signbit',
 
5563
  hypot: function(a, b) {
 
5564
     return Math.sqrt(a*a + b*b);
 
5565
  },
 
5566
  hypotf: 'hypot',
 
5567
  sinh: function(x) {
 
5568
    var p = Math.pow(Math.E, x);
 
5569
    return (p - (1 / p)) / 2;
 
5570
  },
 
5571
  sinhf: 'sinh',
 
5572
  cosh: function(x) {
 
5573
    var p = Math.pow(Math.E, x);
 
5574
    return (p + (1 / p)) / 2;
 
5575
  },
 
5576
  coshf: 'cosh',
 
5577
  tanh__deps: ['sinh', 'cosh'],
 
5578
  tanh: function(x) {
 
5579
    return _sinh(x) / _cosh(x);
 
5580
  },
 
5581
  tanhf: 'tanh',
 
5582
  asinh: function(x) {
 
5583
    return Math.log(x + Math.sqrt(x * x + 1));
 
5584
  },
 
5585
  asinhf: 'asinh',
 
5586
  acosh: function(x) {
 
5587
    return Math.log(x * 1 + Math.sqrt(x * x - 1));
 
5588
  },
 
5589
  acoshf: 'acosh',
 
5590
  atanh: function(x) {
 
5591
    return Math.log((1 + x) / (1 - x)) / 2;
 
5592
  },
 
5593
  atanhf: 'atanh',
 
5594
  exp2: function(x) {
 
5595
    return Math.pow(2, x);
 
5596
  },
 
5597
  exp2f: 'exp2',
 
5598
  expm1: function(x) {
 
5599
    return Math.exp(x) - 1;
 
5600
  },
 
5601
  expm1f: 'expm1',
 
5602
  round: function(x) {
 
5603
    return (x < 0) ? -Math.round(-x) : Math.round(x);
 
5604
  },
 
5605
  roundf: 'round',
 
5606
  lround: 'round',
 
5607
  lroundf: 'round',
 
5608
  llround: 'round',
 
5609
  llroundf: 'round',
 
5610
  rint: function(x) {
 
5611
    return (x > 0) ? -Math.round(-x) : Math.round(x);
 
5612
  },
 
5613
  rintf: 'rint',
 
5614
  lrint: 'rint',
 
5615
  lrintf: 'rint',
 
5616
  llrint: 'rint',
 
5617
  llrintf: 'rint',
 
5618
  nearbyint: 'rint',
 
5619
  nearbyintf: 'rint',
 
5620
  trunc: function(x) {
 
5621
    return (x < 0) ? Math.ceil(x) : Math.floor(x);
 
5622
  },
 
5623
  truncf: 'trunc',
 
5624
  fdim: function(x, y) {
 
5625
    return (x > y) ? x - y : 0;
 
5626
  },
 
5627
  fdimf: 'fdim',
 
5628
  fmax: function(x, y) {
 
5629
    return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y);
 
5630
  },
 
5631
  fmaxf: 'fmax',
 
5632
  fmin: function(x, y) {
 
5633
    return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y);
 
5634
  },
 
5635
  fminf: 'fmin',
 
5636
  fma: function(x, y, z) {
 
5637
    return x * y + z;
 
5638
  },
 
5639
  fmaf: 'fma',
 
5640
  fmod: function(x, y) {
 
5641
    return x % y;
 
5642
  },
 
5643
  fmodf: 'fmod',
 
5644
  remainder: 'fmod',
 
5645
  remainderf: 'fmod',
 
5646
  log10: function(x) {
 
5647
    return Math.log(x) / Math.LN10;
 
5648
  },
 
5649
  log10f: 'log10',
 
5650
  log1p: function(x) {
 
5651
    return Math.log(1 + x);
 
5652
  },
 
5653
  log1pf: 'log1p',
 
5654
  log2: function(x) {
 
5655
    return Math.log(x) / Math.LN2;
 
5656
  },
 
5657
  log2f: 'log2',
 
5658
  nan: function(x) {
 
5659
    return NaN;
 
5660
  },
 
5661
  nanf: 'nan',
 
5662
 
 
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') }}};
 
5668
  },
 
5669
 
 
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') }}};
 
5675
  },
 
5676
 
 
5677
  __div_t_struct_layout: Runtime.generateStructInfo([
 
5678
                            ['i32', 'quot'],
 
5679
                            ['i32', 'rem'],
 
5680
                          ]),
 
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') }}};
 
5688
    return divt;
 
5689
  },
 
5690
 
 
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') }}};
 
5695
    // FP_SUBNORMAL..?
 
5696
    return {{{ cDefine('FP_NORMAL') }}};
 
5697
  },
 
5698
  __fpclassifyd: '__fpclassifyf',
 
5699
 
 
5700
  // ==========================================================================
 
5701
  // sys/utsname.h
 
5702
  // ==========================================================================
 
5703
 
 
5704
  __utsname_struct_layout: Runtime.generateStructInfo([
 
5705
          ['b32', 'sysname'],
 
5706
          ['b32', 'nodename'],
 
5707
          ['b32', 'release'],
 
5708
          ['b32', 'version'],
 
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') }}}
 
5718
      }
 
5719
      {{{ makeSetValue('name', 'offset + i', '0', 'i8') }}}
 
5720
    }
 
5721
    if (name === 0) {
 
5722
      return -1;
 
5723
    } else {
 
5724
      copyString('sysname', 'Emscripten');
 
5725
      copyString('nodename', 'emscripten');
 
5726
      copyString('release', '1.0');
 
5727
      copyString('version', '#1');
 
5728
      copyString('machine', 'x86-JS');
 
5729
      return 0;
 
5730
    }
 
5731
  },
 
5732
 
 
5733
  // ==========================================================================
 
5734
  // dlfcn.h - Dynamic library loading
 
5735
  //
 
5736
  // Some limitations:
 
5737
  //
 
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.
 
5741
  //
 
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
  // ==========================================================================
 
5746
 
 
5747
  // Data for dlfcn.h.
 
5748
  $DLFCN_DATA: {
 
5749
    error: null,
 
5750
    errorMsg: null,
 
5751
    loadedLibs: {}, // handle -> [refcount, name, lib_object]
 
5752
    loadedLibNames: {}, // name -> handle
 
5753
  },
 
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);
 
5760
 
 
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++;
 
5765
      return handle;
 
5766
    }
 
5767
 
 
5768
    var target = FS.findObject(filename);
 
5769
    if (!target || target.isFolder || target.isDevice) {
 
5770
      DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename;
 
5771
      return 0;
 
5772
    } else {
 
5773
      FS.forceLoadFile(target);
 
5774
      var lib_data = intArrayToString(target.contents);
 
5775
    }
 
5776
 
 
5777
    try {
 
5778
      var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length);
 
5779
    } catch (e) {
 
5780
#if ASSERTIONS
 
5781
      Module.printErr('Error in loading dynamic library: ' + e);
 
5782
#endif
 
5783
      DLFCN_DATA.errorMsg = 'Could not evaluate dynamic lib: ' + filename;
 
5784
      return 0;
 
5785
    }
 
5786
 
 
5787
    // Not all browsers support Object.keys().
 
5788
    var handle = 1;
 
5789
    for (var key in DLFCN_DATA.loadedLibs) {
 
5790
      if (DLFCN_DATA.loadedLibs.hasOwnProperty(key)) handle++;
 
5791
    }
 
5792
 
 
5793
    DLFCN_DATA.loadedLibs[handle] = {
 
5794
      refcount: 1,
 
5795
      name: filename,
 
5796
      module: lib_module,
 
5797
      cached_functions: {}
 
5798
    };
 
5799
    DLFCN_DATA.loadedLibNames[filename] = handle;
 
5800
 
 
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];
 
5806
        }
 
5807
      }
 
5808
    }
 
5809
 
 
5810
    return handle;
 
5811
  },
 
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;
 
5819
      return 1;
 
5820
    } else {
 
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];
 
5825
      }
 
5826
      return 0;
 
5827
    }
 
5828
  },
 
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);
 
5835
 
 
5836
    if (!DLFCN_DATA.loadedLibs[handle]) {
 
5837
      DLFCN_DATA.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle;
 
5838
      return 0;
 
5839
    } else {
 
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);
 
5844
        return 0;
 
5845
      } else {
 
5846
        if (lib.cached_functions.hasOwnProperty(symbol)) {
 
5847
          return lib.cached_functions[symbol];
 
5848
        } else {
 
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;
 
5855
          }
 
5856
          return result;
 
5857
        }
 
5858
      }
 
5859
    }
 
5860
  },
 
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) {
 
5867
      return 0;
 
5868
    } else {
 
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;
 
5874
    }
 
5875
  },
 
5876
 
 
5877
  // ==========================================================================
 
5878
  // pwd.h
 
5879
  // ==========================================================================
 
5880
 
 
5881
  // TODO: Implement.
 
5882
  // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/pwd.h.html
 
5883
  getpwuid: function(uid) {
 
5884
    return 0; // NULL
 
5885
  },
 
5886
 
 
5887
  // ==========================================================================
 
5888
  // time.h
 
5889
  // ==========================================================================
 
5890
 
 
5891
  clock: function() {
 
5892
    if (_clock.start === undefined) _clock.start = Date.now();
 
5893
    return Math.floor((Date.now() - _clock.start) * ({{{ cDefine('CLOCKS_PER_SEC') }}}/1000));
 
5894
  },
 
5895
 
 
5896
  time: function(ptr) {
 
5897
    var ret = Math.floor(Date.now()/1000);
 
5898
    if (ptr) {
 
5899
      {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}}
 
5900
    }
 
5901
    return ret;
 
5902
  },
 
5903
 
 
5904
  difftime: function(time1, time0) {
 
5905
    return time1 - time0;
 
5906
  },
 
5907
 
 
5908
  __tm_struct_layout: Runtime.generateStructInfo([
 
5909
    ['i32', 'tm_sec'],
 
5910
    ['i32', 'tm_min'],
 
5911
    ['i32', 'tm_hour'],
 
5912
    ['i32', 'tm_mday'],
 
5913
    ['i32', 'tm_mon'],
 
5914
    ['i32', 'tm_year'],
 
5915
    ['i32', 'tm_wday'],
 
5916
    ['i32', 'tm_yday'],
 
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.
 
5923
  __tm_timezones: {},
 
5924
  // Statically allocated time strings.
 
5925
  __tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STACK)',
 
5926
 
 
5927
  mktime__deps: ['__tm_struct_layout', 'tzset'],
 
5928
  mktime: function(tmPtr) {
 
5929
    _tzset();
 
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') }}}
 
5942
    return timestamp;
 
5943
  },
 
5944
  timelocal: 'mktime',
 
5945
 
 
5946
  gmtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'gmtime_r'],
 
5947
  gmtime: function(time) {
 
5948
    return _gmtime_r(time, ___tm_current);
 
5949
  },
 
5950
 
 
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') }}}
 
5964
 
 
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') }}}
 
5968
 
 
5969
    var timezone = "GMT";
 
5970
    if (!(timezone in ___tm_timezones)) {
 
5971
      ___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL);
 
5972
    }
 
5973
    {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}}
 
5974
 
 
5975
    return tmPtr;
 
5976
  },
 
5977
 
 
5978
  timegm__deps: ['mktime'],
 
5979
  timegm: function(tmPtr) {
 
5980
    _tzset();
 
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;
 
5985
    return ret;
 
5986
  },
 
5987
 
 
5988
  localtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'localtime_r'],
 
5989
  localtime: function(time) {
 
5990
    return _localtime_r(time, ___tm_current);
 
5991
  },
 
5992
 
 
5993
  localtime_r__deps: ['__tm_struct_layout', '__tm_timezones', 'tzset'],
 
5994
  localtime_r: function(time, tmPtr) {
 
5995
    _tzset();
 
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') }}}
 
6005
 
 
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') }}}
 
6010
 
 
6011
    var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
 
6012
    {{{ makeSetValue('tmPtr', 'offsets.tm_isdst', 'dst', 'i32') }}}
 
6013
 
 
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);
 
6017
    }
 
6018
    {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}}
 
6019
 
 
6020
    return tmPtr;
 
6021
  },
 
6022
 
 
6023
  asctime__deps: ['malloc', '__tm_formatted', 'asctime_r'],
 
6024
  asctime: function(tmPtr) {
 
6025
    return _asctime_r(tmPtr, ___tm_formatted);
 
6026
  },
 
6027
 
 
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') }}}
 
6037
    });
 
6038
    {{{ makeSetValue('buf', '25', '0', 'i8') }}}
 
6039
    return buf;
 
6040
  },
 
6041
 
 
6042
  ctime__deps: ['localtime', 'asctime'],
 
6043
  ctime: function(timer) {
 
6044
    return _asctime(_localtime(timer));
 
6045
  },
 
6046
 
 
6047
  ctime_r__deps: ['localtime', 'asctime'],
 
6048
  ctime_r: function(timer, buf) {
 
6049
    return _asctime_r(_localtime_r(timer, ___tm_current), buf);
 
6050
  },
 
6051
 
 
6052
  dysize: function(year) {
 
6053
    var leap = ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)));
 
6054
    return leap ? 366 : 365;
 
6055
  },
 
6056
 
 
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'],
 
6063
  tzset: function() {
 
6064
    // TODO: Use (malleable) environment variables instead of system settings.
 
6065
    if (_tzset.called) return;
 
6066
    _tzset.called = true;
 
6067
 
 
6068
    {{{ makeSetValue(makeGlobalUse('__timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}}
 
6069
 
 
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') }}}
 
6073
 
 
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') }}}
 
6080
  },
 
6081
 
 
6082
  stime__deps: ['$ERRNO_CODES', '__setErrNo'],
 
6083
  stime: function(when) {
 
6084
    ___setErrNo(ERRNO_CODES.EPERM);
 
6085
    return -1;
 
6086
  },
 
6087
 
 
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
 
6091
    // TODO: Implement.
 
6092
    return 0;
 
6093
  },
 
6094
  strftime_l: 'strftime', // no locale support yet
 
6095
 
 
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
 
6099
    // TODO: Implement.
 
6100
    return 0;
 
6101
  },
 
6102
  strptime_l: 'strptime', // no locale support yet
 
6103
 
 
6104
  getdate: function(string) {
 
6105
    // struct tm *getdate(const char *string);
 
6106
    // http://pubs.opengroup.org/onlinepubs/009695399/functions/getdate.html
 
6107
    // TODO: Implement.
 
6108
    return 0;
 
6109
  },
 
6110
 
 
6111
  setitimer: function() { throw 'setitimer not implemented yet' },
 
6112
  getitimer: function() { throw 'getitimer not implemented yet' },
 
6113
 
 
6114
  // ==========================================================================
 
6115
  // sys/time.h
 
6116
  // ==========================================================================
 
6117
 
 
6118
  __timespec_struct_layout: Runtime.generateStructInfo([
 
6119
    ['i32', 'tv_sec'],
 
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));
 
6129
  },
 
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') }}}
 
6136
    return 0;
 
6137
  },
 
6138
  clock_settime: function(clk_id, tp) {
 
6139
    // int clock_settime(clockid_t clk_id, const struct timespec *tp);
 
6140
    // Nothing.
 
6141
    return 0;
 
6142
  },
 
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') }}}
 
6148
    return 0;
 
6149
  },
 
6150
 
 
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
 
6158
    return 0;
 
6159
  },
 
6160
 
 
6161
  // ==========================================================================
 
6162
  // sys/timeb.h
 
6163
  // ==========================================================================
 
6164
 
 
6165
  __timeb_struct_layout: Runtime.generateStructInfo([
 
6166
    ['i32', 'time'],
 
6167
    ['i16', 'millitm'],
 
6168
    ['i16', 'timezone'],
 
6169
    ['i16', 'dstflag']
 
6170
  ]),
 
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
 
6178
    return 0;
 
6179
  },
 
6180
 
 
6181
  // ==========================================================================
 
6182
  // sys/times.h
 
6183
  // ==========================================================================
 
6184
 
 
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.
 
6195
    if (buffer !== 0) {
 
6196
      _memset(buffer, 0, ___tms_struct_layout.__size__);
 
6197
    }
 
6198
    return 0;
 
6199
  },
 
6200
 
 
6201
  // ==========================================================================
 
6202
  // sys/types.h
 
6203
  // ==========================================================================
 
6204
 
 
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) {
 
6208
    return 0;
 
6209
  },
 
6210
  gnu_dev_makedev: 'makedev',
 
6211
  major: function(dev) {
 
6212
    return 0;
 
6213
  },
 
6214
  gnu_dev_major: 'major',
 
6215
  minor: function(dev) {
 
6216
    return 0;
 
6217
  },
 
6218
  gnu_dev_minor: 'minor',
 
6219
 
 
6220
  // ==========================================================================
 
6221
  // setjmp.h
 
6222
  //
 
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).
 
6227
  //
 
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
  // ==========================================================================
 
6233
 
 
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.
 
6241
    env = env|0;
 
6242
    label = label|0;
 
6243
    table = table|0;
 
6244
    var i = 0;
 
6245
#if ASSERTIONS
 
6246
    if ((label|0) == 0) abort(121);
 
6247
#endif
 
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') }}};
 
6256
        return 0;
 
6257
      }
 
6258
      i = (i+2)|0;
 
6259
    }
 
6260
    {{{ makePrintChars('too many setjmps in a function call, build with a higher value for MAX_SETJMPS') }}};
 
6261
    abort(0);
 
6262
    return 0;
 
6263
  },
 
6264
 
 
6265
  testSetjmp__asm: true,
 
6266
  testSetjmp__sig: 'iii',
 
6267
  testSetjmp: function(id, table) {
 
6268
    id = id|0;
 
6269
    table = table|0;
 
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') }}};
 
6276
      }
 
6277
      i = (i+2)|0;
 
6278
    }
 
6279
    return 0;
 
6280
  },
 
6281
 
 
6282
#if ASM_JS
 
6283
  setjmp__deps: ['saveSetjmp', 'testSetjmp'],
 
6284
#endif
 
6285
  setjmp__inline: function(env) {
 
6286
    // Save the label
 
6287
#if ASM_JS
 
6288
    return '_saveSetjmp(' + env + ', label, setjmpTable)|0';
 
6289
#else
 
6290
    return '(tempInt = setjmpId++, mySetjmpIds[tempInt] = 1, setjmpLabels[tempInt] = label,' + makeSetValue(env, '0', 'tempInt', 'i32', undefined, undefined, undefined, undefined,  ',') + ', 0)';
 
6291
#endif
 
6292
  },
 
6293
 
 
6294
#if ASM_JS
 
6295
  longjmp__deps: ['saveSetjmp', 'testSetjmp'],
 
6296
#endif
 
6297
  longjmp: function(env, value) {
 
6298
#if ASM_JS
 
6299
    asm.setThrew(env, value || 1);
 
6300
    throw 'longjmp';
 
6301
#else
 
6302
    throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 };
 
6303
#endif
 
6304
  },
 
6305
 
 
6306
  // ==========================================================================
 
6307
  // signal.h
 
6308
  // ==========================================================================
 
6309
 
 
6310
  signal: function(sig, func) {
 
6311
    // TODO
 
6312
    return 0;
 
6313
  },
 
6314
  sigemptyset: function(set) {
 
6315
    // int sigemptyset(sigset_t *set);
 
6316
    {{{ makeSetValue('set', '0', '0', 'i32') }}};
 
6317
    return 0;
 
6318
  },
 
6319
  sigfillset: function(set) {
 
6320
    {{{ makeSetValue('set', '0', '-1>>>0', 'i32') }}};
 
6321
    return 0;
 
6322
  },
 
6323
  sigaddset: function(set, signum) {
 
6324
    {{{ makeSetValue('set', '0', makeGetValue('set', '0', 'i32') + '| (1 << (signum-1))', 'i32') }}};
 
6325
    return 0;
 
6326
  },
 
6327
  sigdelset: function(set, signum) {
 
6328
    {{{ makeSetValue('set', '0', makeGetValue('set', '0', 'i32') + '& (~(1 << (signum-1)))', 'i32') }}};
 
6329
    return 0;
 
6330
  },
 
6331
  sigismember: function(set, signum) {
 
6332
    return {{{ makeGetValue('set', '0', 'i32') }}} & (1 << (signum-1));
 
6333
  },
 
6334
  sigaction: function(set) {
 
6335
    // TODO:
 
6336
    return 0;
 
6337
  },
 
6338
  sigprocmask: 'sigaction',
 
6339
  __libc_current_sigrtmin: function() {
 
6340
    return 0;
 
6341
  },
 
6342
  __libc_current_sigrtmax: function() {
 
6343
    return 0;
 
6344
  },
 
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);
 
6351
    return -1;
 
6352
  },
 
6353
  killpg: 'kill',
 
6354
 
 
6355
  siginterrupt: function() { throw 'siginterrupt not implemented' },
 
6356
 
 
6357
  // ==========================================================================
 
6358
  // sys/wait.h
 
6359
  // ==========================================================================
 
6360
 
 
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);
 
6367
    return -1;
 
6368
  },
 
6369
  // NOTE: These aren't really the same, but we use the same stub for them all.
 
6370
  waitid: 'wait',
 
6371
  waitpid: 'wait',
 
6372
  wait3: 'wait',
 
6373
  wait4: 'wait',
 
6374
 
 
6375
  // ==========================================================================
 
6376
  // locale.h
 
6377
  // ==========================================================================
 
6378
 
 
6379
  newlocale: function(mask, locale, base) {
 
6380
    return 0;
 
6381
  },
 
6382
 
 
6383
  freelocale: function(locale) {},
 
6384
 
 
6385
  uselocale: function(locale) {
 
6386
    return 0;
 
6387
  },
 
6388
 
 
6389
  setlocale: function(category, locale) {
 
6390
    if (!_setlocale.ret) _setlocale.ret = allocate([0], 'i8', ALLOC_NORMAL);
 
6391
    return _setlocale.ret;
 
6392
  },
 
6393
 
 
6394
  localeconv: function() {
 
6395
    // %struct.timeval = type { char* decimal point, other stuff... }
 
6396
    // var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] });
 
6397
    var me = _localeconv;
 
6398
    if (!me.ret) {
 
6399
      me.ret = allocate([allocate(intArrayFromString('.'), 'i8', ALLOC_NORMAL)], 'i8*', ALLOC_NORMAL); // just decimal point, for now
 
6400
    }
 
6401
    return me.ret;
 
6402
  },
 
6403
 
 
6404
  __locale_mb_cur_max: function() { throw '__locale_mb_cur_max not implemented' },
 
6405
 
 
6406
  // ==========================================================================
 
6407
  // langinfo.h
 
6408
  // ==========================================================================
 
6409
 
 
6410
  nl_langinfo: function(item) {
 
6411
    // char *nl_langinfo(nl_item item);
 
6412
    // http://pubs.opengroup.org/onlinepubs/000095399/functions/nl_langinfo.html
 
6413
    var result;
 
6414
    switch (item) {
 
6415
      case {{{ cDefine('CODESET') }}}:
 
6416
        result = 'ANSI_X3.4-1968';
 
6417
        break;
 
6418
      case {{{ cDefine('D_T_FMT') }}}:
 
6419
        result = '%a %b %e %H:%M:%S %Y';
 
6420
        break;
 
6421
      case {{{ cDefine('D_FMT') }}}:
 
6422
        result = '%m/%d/%y';
 
6423
        break;
 
6424
      case {{{ cDefine('T_FMT') }}}:
 
6425
        result = '%H:%M:%S';
 
6426
        break;
 
6427
      case {{{ cDefine('T_FMT_AMPM') }}}:
 
6428
        result = '%I:%M:%S %p';
 
6429
        break;
 
6430
      case {{{ cDefine('AM_STR') }}}:
 
6431
        result = 'AM';
 
6432
        break;
 
6433
      case {{{ cDefine('PM_STR') }}}:
 
6434
        result = 'PM';
 
6435
        break;
 
6436
      case {{{ cDefine('DAY_1') }}}:
 
6437
        result = 'Sunday';
 
6438
        break;
 
6439
      case {{{ cDefine('DAY_2') }}}:
 
6440
        result = 'Monday';
 
6441
        break;
 
6442
      case {{{ cDefine('DAY_3') }}}:
 
6443
        result = 'Tuesday';
 
6444
        break;
 
6445
      case {{{ cDefine('DAY_4') }}}:
 
6446
        result = 'Wednesday';
 
6447
        break;
 
6448
      case {{{ cDefine('DAY_5') }}}:
 
6449
        result = 'Thursday';
 
6450
        break;
 
6451
      case {{{ cDefine('DAY_6') }}}:
 
6452
        result = 'Friday';
 
6453
        break;
 
6454
      case {{{ cDefine('DAY_7') }}}:
 
6455
        result = 'Saturday';
 
6456
        break;
 
6457
      case {{{ cDefine('ABDAY_1') }}}:
 
6458
        result = 'Sun';
 
6459
        break;
 
6460
      case {{{ cDefine('ABDAY_2') }}}:
 
6461
        result = 'Mon';
 
6462
        break;
 
6463
      case {{{ cDefine('ABDAY_3') }}}:
 
6464
        result = 'Tue';
 
6465
        break;
 
6466
      case {{{ cDefine('ABDAY_4') }}}:
 
6467
        result = 'Wed';
 
6468
        break;
 
6469
      case {{{ cDefine('ABDAY_5') }}}:
 
6470
        result = 'Thu';
 
6471
        break;
 
6472
      case {{{ cDefine('ABDAY_6') }}}:
 
6473
        result = 'Fri';
 
6474
        break;
 
6475
      case {{{ cDefine('ABDAY_7') }}}:
 
6476
        result = 'Sat';
 
6477
        break;
 
6478
      case {{{ cDefine('MON_1') }}}:
 
6479
        result = 'January';
 
6480
        break;
 
6481
      case {{{ cDefine('MON_2') }}}:
 
6482
        result = 'February';
 
6483
        break;
 
6484
      case {{{ cDefine('MON_3') }}}:
 
6485
        result = 'March';
 
6486
        break;
 
6487
      case {{{ cDefine('MON_4') }}}:
 
6488
        result = 'April';
 
6489
        break;
 
6490
      case {{{ cDefine('MON_5') }}}:
 
6491
        result = 'May';
 
6492
        break;
 
6493
      case {{{ cDefine('MON_6') }}}:
 
6494
        result = 'June';
 
6495
        break;
 
6496
      case {{{ cDefine('MON_7') }}}:
 
6497
        result = 'July';
 
6498
        break;
 
6499
      case {{{ cDefine('MON_8') }}}:
 
6500
        result = 'August';
 
6501
        break;
 
6502
      case {{{ cDefine('MON_9') }}}:
 
6503
        result = 'September';
 
6504
        break;
 
6505
      case {{{ cDefine('MON_10') }}}:
 
6506
        result = 'October';
 
6507
        break;
 
6508
      case {{{ cDefine('MON_11') }}}:
 
6509
        result = 'November';
 
6510
        break;
 
6511
      case {{{ cDefine('MON_12') }}}:
 
6512
        result = 'December';
 
6513
        break;
 
6514
      case {{{ cDefine('ABMON_1') }}}:
 
6515
        result = 'Jan';
 
6516
        break;
 
6517
      case {{{ cDefine('ABMON_2') }}}:
 
6518
        result = 'Feb';
 
6519
        break;
 
6520
      case {{{ cDefine('ABMON_3') }}}:
 
6521
        result = 'Mar';
 
6522
        break;
 
6523
      case {{{ cDefine('ABMON_4') }}}:
 
6524
        result = 'Apr';
 
6525
        break;
 
6526
      case {{{ cDefine('ABMON_5') }}}:
 
6527
        result = 'May';
 
6528
        break;
 
6529
      case {{{ cDefine('ABMON_6') }}}:
 
6530
        result = 'Jun';
 
6531
        break;
 
6532
      case {{{ cDefine('ABMON_7') }}}:
 
6533
        result = 'Jul';
 
6534
        break;
 
6535
      case {{{ cDefine('ABMON_8') }}}:
 
6536
        result = 'Aug';
 
6537
        break;
 
6538
      case {{{ cDefine('ABMON_9') }}}:
 
6539
        result = 'Sep';
 
6540
        break;
 
6541
      case {{{ cDefine('ABMON_10') }}}:
 
6542
        result = 'Oct';
 
6543
        break;
 
6544
      case {{{ cDefine('ABMON_11') }}}:
 
6545
        result = 'Nov';
 
6546
        break;
 
6547
      case {{{ cDefine('ABMON_12') }}}:
 
6548
        result = 'Dec';
 
6549
        break;
 
6550
      case {{{ cDefine('ALT_DIGITS') }}}:
 
6551
        result = '';
 
6552
        break;
 
6553
      case {{{ cDefine('RADIXCHAR') }}}:
 
6554
        result = '.';
 
6555
        break;
 
6556
      case {{{ cDefine('THOUSEP') }}}:
 
6557
        result = '';
 
6558
        break;
 
6559
      case {{{ cDefine('YESEXPR') }}}:
 
6560
        result = '^[yY]';
 
6561
        break;
 
6562
      case {{{ cDefine('NOEXPR') }}}:
 
6563
        result = '^[nN]';
 
6564
        break;
 
6565
      case {{{ cDefine('CRNCYSTR') }}}:
 
6566
        result = '-';
 
6567
        break;
 
6568
      case {{{ cDefine('ERA') }}}:
 
6569
      case {{{ cDefine('ERA_D_FMT') }}}:
 
6570
      case {{{ cDefine('ERA_D_T_FMT') }}}:
 
6571
      case {{{ cDefine('ERA_T_FMT') }}}:
 
6572
      default:
 
6573
        result = '';
 
6574
        break;
 
6575
    }
 
6576
 
 
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') }}}
 
6581
    }
 
6582
    {{{ makeSetValue('me.ret', 'i', '0', 'i8') }}}
 
6583
    return me.ret;
 
6584
  },
 
6585
 
 
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' },
 
6589
 
 
6590
  // ==========================================================================
 
6591
  // errno.h
 
6592
  // ==========================================================================
 
6593
 
 
6594
  $ERRNO_CODES: {
 
6595
    E2BIG: 7,
 
6596
    EACCES: 13,
 
6597
    EADDRINUSE: 98,
 
6598
    EADDRNOTAVAIL: 99,
 
6599
    EAFNOSUPPORT: 97,
 
6600
    EAGAIN: 11,
 
6601
    EALREADY: 114,
 
6602
    EBADF: 9,
 
6603
    EBADMSG: 74,
 
6604
    EBUSY: 16,
 
6605
    ECANCELED: 125,
 
6606
    ECHILD: 10,
 
6607
    ECONNABORTED: 103,
 
6608
    ECONNREFUSED: 111,
 
6609
    ECONNRESET: 104,
 
6610
    EDEADLK: 35,
 
6611
    EDESTADDRREQ: 89,
 
6612
    EDOM: 33,
 
6613
    EDQUOT: 122,
 
6614
    EEXIST: 17,
 
6615
    EFAULT: 14,
 
6616
    EFBIG: 27,
 
6617
    EHOSTUNREACH: 113,
 
6618
    EIDRM: 43,
 
6619
    EILSEQ: 84,
 
6620
    EINPROGRESS: 115,
 
6621
    EINTR: 4,
 
6622
    EINVAL: 22,
 
6623
    EIO: 5,
 
6624
    EISCONN: 106,
 
6625
    EISDIR: 21,
 
6626
    ELOOP: 40,
 
6627
    EMFILE: 24,
 
6628
    EMLINK: 31,
 
6629
    EMSGSIZE: 90,
 
6630
    EMULTIHOP: 72,
 
6631
    ENAMETOOLONG: 36,
 
6632
    ENETDOWN: 100,
 
6633
    ENETRESET: 102,
 
6634
    ENETUNREACH: 101,
 
6635
    ENFILE: 23,
 
6636
    ENOBUFS: 105,
 
6637
    ENODATA: 61,
 
6638
    ENODEV: 19,
 
6639
    ENOENT: 2,
 
6640
    ENOEXEC: 8,
 
6641
    ENOLCK: 37,
 
6642
    ENOLINK: 67,
 
6643
    ENOMEM: 12,
 
6644
    ENOMSG: 42,
 
6645
    ENOPROTOOPT: 92,
 
6646
    ENOSPC: 28,
 
6647
    ENOSR: 63,
 
6648
    ENOSTR: 60,
 
6649
    ENOSYS: 38,
 
6650
    ENOTCONN: 107,
 
6651
    ENOTDIR: 20,
 
6652
    ENOTEMPTY: 39,
 
6653
    ENOTRECOVERABLE: 131,
 
6654
    ENOTSOCK: 88,
 
6655
    ENOTSUP: 95,
 
6656
    ENOTTY: 25,
 
6657
    ENXIO: 6,
 
6658
    EOPNOTSUPP: 45,
 
6659
    EOVERFLOW: 75,
 
6660
    EOWNERDEAD: 130,
 
6661
    EPERM: 1,
 
6662
    EPIPE: 32,
 
6663
    EPROTO: 71,
 
6664
    EPROTONOSUPPORT: 93,
 
6665
    EPROTOTYPE: 91,
 
6666
    ERANGE: 34,
 
6667
    EROFS: 30,
 
6668
    ESPIPE: 29,
 
6669
    ESRCH: 3,
 
6670
    ESTALE: 116,
 
6671
    ETIME: 62,
 
6672
    ETIMEDOUT: 110,
 
6673
    ETXTBSY: 26,
 
6674
    EWOULDBLOCK: 11,
 
6675
    EXDEV: 18,
 
6676
  },
 
6677
  $ERRNO_MESSAGES: {
 
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',
 
6686
    74: 'Bad message',
 
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',
 
6697
    17: 'File exists',
 
6698
    14: 'Bad address',
 
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',
 
6742
    130: 'Owner died',
 
6743
    1: 'Operation not permitted',
 
6744
    32: 'Broken pipe',
 
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',
 
6750
    29: 'Illegal seek',
 
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'
 
6757
  },
 
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') }}}
 
6763
    return value;
 
6764
  },
 
6765
  __errno_location__deps: ['__setErrNo'],
 
6766
  __errno_location: function() {
 
6767
    return ___setErrNo.ret;
 
6768
  },
 
6769
  __errno: '__errno_location',
 
6770
 
 
6771
  // ==========================================================================
 
6772
  // sys/resource.h
 
6773
  // ==========================================================================
 
6774
 
 
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
 
6784
    return 0;
 
6785
  },
 
6786
  setrlimit: function(resource, rlp) {
 
6787
    // int setrlimit(int resource, const struct rlimit *rlp)
 
6788
    return 0;
 
6789
  },
 
6790
  __01getrlimit64_: 'getrlimit',
 
6791
 
 
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'] });
 
6814
 
 
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') }}}
 
6820
    return 0;
 
6821
  },
 
6822
 
 
6823
  // ==========================================================================
 
6824
  // sched.h (stubs only - no thread support yet!)
 
6825
  // ==========================================================================
 
6826
  sched_yield: function() {
 
6827
    return 0;
 
6828
  },
 
6829
 
 
6830
  // ==========================================================================
 
6831
  // pthread.h (stubs for mutexes only - no thread support yet!)
 
6832
  // ==========================================================================
 
6833
 
 
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() {
 
6842
    return 0;
 
6843
  },
 
6844
  pthread_cond_init: function() {},
 
6845
  pthread_cond_destroy: function() {},
 
6846
  pthread_cond_broadcast: function() {
 
6847
    return 0;
 
6848
  },
 
6849
  pthread_cond_wait: function() {
 
6850
    return 0;
 
6851
  },
 
6852
  pthread_cond_timedwait: function() {
 
6853
    return 0;
 
6854
  },
 
6855
  pthread_self: function() {
 
6856
    //FIXME: assumes only a single thread
 
6857
    return 0;
 
6858
  },
 
6859
  pthread_attr_init: function(attr) {
 
6860
    /* int pthread_attr_init(pthread_attr_t *attr); */
 
6861
    //FIXME: should allocate a pthread_attr_t
 
6862
    return 0;
 
6863
  },
 
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
 
6867
    return 0;
 
6868
  },
 
6869
  pthread_attr_destroy: function(attr) {
 
6870
    /* int pthread_attr_destroy(pthread_attr_t *attr); */
 
6871
    //FIXME: should destroy the pthread_attr_t struct
 
6872
    return 0;
 
6873
  },
 
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
 
6878
      current thread*/
 
6879
    {{{ makeSetValue('stackaddr', '0', 'STACK_ROOT', 'i8*') }}}
 
6880
    {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}}
 
6881
    return 0;
 
6882
  },
 
6883
 
 
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;
 
6889
  },
 
6890
 
 
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;
 
6895
  },
 
6896
 
 
6897
  pthread_getspecific: function(key) {
 
6898
    return _pthread_key_create.keys[key] || 0;
 
6899
  },
 
6900
 
 
6901
  pthread_setspecific: function(key, value) {
 
6902
    _pthread_key_create.keys[key] = value;
 
6903
  },
 
6904
 
 
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];
 
6909
      return 0;
 
6910
    }
 
6911
    return ERRNO_CODES.EINVAL;
 
6912
  },
 
6913
 
 
6914
  pthread_cleanup_push: function(routine, arg) {
 
6915
    __ATEXIT__.push({ func: function() { Runtime.dynCall('vi', routine, [arg]) } })
 
6916
    _pthread_cleanup_push.level = __ATEXIT__.length;
 
6917
  },
 
6918
 
 
6919
  pthread_cleanup_pop: function() {
 
6920
    assert(_pthread_cleanup_push.level == __ATEXIT__.length, 'cannot pop if something else added meanwhile!');
 
6921
    __ATEXIT__.pop();
 
6922
    _pthread_cleanup_push.level = __ATEXIT__.length;
 
6923
  },
 
6924
 
 
6925
  // ==========================================================================
 
6926
  // malloc.h
 
6927
  // ==========================================================================
 
6928
 
 
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);
 
6933
  },
 
6934
 
 
6935
  posix_memalign__deps: ['memalign'],
 
6936
  posix_memalign: function(memptr, alignment, size) {
 
6937
    var ptr = _memalign(alignment, size);
 
6938
    {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}}
 
6939
    return 0;
 
6940
  },
 
6941
 
 
6942
  // ==========================================================================
 
6943
  // arpa/inet.h
 
6944
  // ==========================================================================
 
6945
 
 
6946
  htonl: function(value) {
 
6947
    return ((value & 0xff) << 24) + ((value & 0xff00) << 8) +
 
6948
           ((value & 0xff0000) >>> 8) + ((value & 0xff000000) >>> 24);
 
6949
  },
 
6950
  htons: function(value) {
 
6951
    return ((value & 0xff) << 8) + ((value & 0xff00) >> 8);
 
6952
  },
 
6953
  ntohl: 'htonl',
 
6954
  ntohs: 'htons',
 
6955
 
 
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;
 
6960
  },
 
6961
 
 
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');
 
6969
    return 1;
 
6970
  },
 
6971
 
 
6972
  _inet_ntop_raw: function(addr) {
 
6973
    return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff)
 
6974
  },
 
6975
 
 
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);
 
6981
    return dst;
 
6982
  },
 
6983
 
 
6984
  inet_ntoa__deps: ['inet_ntop'],
 
6985
  inet_ntoa: function(in_addr) {
 
6986
    if (!_inet_ntoa.buffer) {
 
6987
      _inet_ntoa.buffer = _malloc(1024);
 
6988
    }
 
6989
    return _inet_ntop(0, in_addr, _inet_ntoa.buffer, 1024);
 
6990
  },
 
6991
 
 
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;
 
6997
    return 1;
 
6998
  },
 
6999
 
 
7000
  // ==========================================================================
 
7001
  // netdb.h
 
7002
  // ==========================================================================
 
7003
 
 
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([
 
7010
    ['i8*', 'h_name'],
 
7011
    ['i8**', 'h_aliases'],
 
7012
    ['i32', 'h_addrtype'],
 
7013
    ['i32', 'h_length'],
 
7014
    ['i8**', 'h_addr_list'],
 
7015
  ]),
 
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 = {};
 
7022
      }
 
7023
    var id = _gethostbyname.id++;
 
7024
    assert(id < 65535);
 
7025
    var fakeAddr = 172 | (29 << 8) | ((id & 0xff) << 16) | ((id & 0xff00) << 24);
 
7026
    _gethostbyname.table[id] = name;
 
7027
    // generate hostent
 
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**');
 
7042
    return ret;
 
7043
  },
 
7044
 
 
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__);
 
7049
    _free(data);
 
7050
    setValue(errnum, 0, 'i32');
 
7051
    return 0;
 
7052
  },
 
7053
 
 
7054
  // ==========================================================================
 
7055
  // sockets. Note that the implementation assumes all sockets are always
 
7056
  // nonblocking
 
7057
  // ==========================================================================
 
7058
 
 
7059
  $Sockets__deps: ['__setErrNo', '$ERRNO_CODES'],
 
7060
  $Sockets: {
 
7061
    BACKEND_WEBSOCKETS: 0,
 
7062
    BACKEND_WEBRTC: 1,
 
7063
    BUFFER_SIZE: 10*1024, // initial size
 
7064
    MAX_BUFFER_SIZE: 10*1024*1024, // maximum size we will grow the buffer
 
7065
 
 
7066
    backend: 0, // default to websockets
 
7067
    nextFd: 1,
 
7068
    fds: {},
 
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'],
 
7075
    ]),
 
7076
    msghdr_layout: Runtime.generateStructInfo([
 
7077
      ['*', 'msg_name'],
 
7078
      ['i32', 'msg_namelen'],
 
7079
      ['*', 'msg_iov'],
 
7080
      ['i32', 'msg_iovlen'],
 
7081
      ['*', 'msg_control'],
 
7082
      ['i32', 'msg_controllen'],
 
7083
      ['i32', 'msg_flags'],
 
7084
    ]),
 
7085
 
 
7086
    backends: {
 
7087
      0: { // websockets
 
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';
 
7092
 
 
7093
          var i32Temp = new Uint32Array(1);
 
7094
          var i8Temp = new Uint8Array(i32Temp.buffer);
 
7095
 
 
7096
          info.inQueue = [];
 
7097
          info.hasData = function() { return info.inQueue.length > 0 }
 
7098
          if (!info.stream) {
 
7099
            var partialBuffer = null; // in datagram mode, inQueue contains full dgram messages; this buffers incomplete data. Must begin with the beginning of a message
 
7100
          }
 
7101
 
 
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
 
7105
#if SOCKET_DEBUG
 
7106
            Module.print(['onmessage', data.length, '|', Array.prototype.slice.call(data)]);
 
7107
#endif
 
7108
            if (info.stream) {
 
7109
              info.inQueue.push(data);
 
7110
            } else {
 
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
 
7118
                data = newBuffer;
 
7119
                partialBuffer = null;
 
7120
              }
 
7121
              var currPos = 0;
 
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
 
7128
                }
 
7129
                currPos += 4;
 
7130
#if SOCKET_DEBUG
 
7131
                Module.print(['onmessage message', currLen, '|', Array.prototype.slice.call(data.subarray(currPos, currPos+currLen))]);
 
7132
#endif
 
7133
                info.inQueue.push(data.subarray(currPos, currPos+currLen));
 
7134
                currPos += currLen;
 
7135
              }
 
7136
              // If data remains, buffer it
 
7137
              if (currPos < data.length) {
 
7138
                partialBuffer = data.subarray(currPos);
 
7139
              }
 
7140
            }
 
7141
          }
 
7142
          function send(data) {
 
7143
            // TODO: if browser accepts views, can optimize this
 
7144
#if SOCKET_DEBUG
 
7145
            Module.print('sender actually sending ' + Array.prototype.slice.call(data));
 
7146
#endif
 
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);
 
7149
          }
 
7150
          var outQueue = [];
 
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);
 
7158
              }
 
7159
              return;
 
7160
            }
 
7161
            for (var i = 0; i < outQueue.length; i++) {
 
7162
              send(outQueue[i]);
 
7163
            }
 
7164
            outQueue.length = 0;
 
7165
            if (intervalling) {
 
7166
              intervalling = false;
 
7167
              clearInterval(interval);
 
7168
            }
 
7169
          }
 
7170
          info.sender = function(data) {
 
7171
            if (!info.stream) {
 
7172
              // add a header with the message size
 
7173
              var header = new Uint8Array(4);
 
7174
              i32Temp[0] = data.length;
 
7175
              header.set(i8Temp);
 
7176
              outQueue.push(header);
 
7177
            }
 
7178
            outQueue.push(new Uint8Array(data));
 
7179
            trySend();
 
7180
          };
 
7181
        }
 
7182
      },
 
7183
      1: { // webrtc
 
7184
      }
 
7185
    }
 
7186
  },
 
7187
 
 
7188
  emscripten_set_network_backend__deps: ['$Sockets'],
 
7189
  emscripten_set_network_backend: function(backend) {
 
7190
    Sockets.backend = backend;
 
7191
  },
 
7192
 
 
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') }}};
 
7198
    if (protocol) {
 
7199
      assert(stream == (protocol == {{{ cDefine('IPPROTO_TCP') }}})); // if stream, must be tcp
 
7200
    }
 
7201
    if (Sockets.backend == Sockets.BACKEND_WEBRTC) {
 
7202
      assert(!stream); // If WebRTC, we can only support datagram, not stream
 
7203
    }
 
7204
    Sockets.fds[fd] = {
 
7205
      connected: false,
 
7206
      stream: stream
 
7207
    };
 
7208
    return fd;
 
7209
  },
 
7210
 
 
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);
 
7226
    }
 
7227
    try {
 
7228
      Sockets.backends[Sockets.backend].connect(info);
 
7229
    } catch(e) {
 
7230
      Module.printErr('Error in connect(): ' + e);
 
7231
      ___setErrNo(ERRNO_CODES.EACCES);
 
7232
      return -1;
 
7233
    }
 
7234
    return 0;
 
7235
  },
 
7236
 
 
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
 
7243
      return -1;
 
7244
    }
 
7245
    var buffer = info.inQueue.shift();
 
7246
#if SOCKET_DEBUG
 
7247
    Module.print('recv: ' + [Array.prototype.slice.call(buffer)]);
 
7248
#endif
 
7249
    if (len < buffer.length) {
 
7250
      if (info.stream) {
 
7251
        // This is tcp (reliable), so if not all was read, keep it
 
7252
        info.inQueue.unshift(buffer.subarray(len));
 
7253
#if SOCKET_DEBUG
 
7254
        Module.print('recv: put back: ' + (len - buffer.length));
 
7255
#endif
 
7256
      }
 
7257
      buffer = buffer.subarray(0, len);
 
7258
    }
 
7259
    HEAPU8.set(buffer, buf);
 
7260
    return buffer.length;
 
7261
  },
 
7262
 
 
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));
 
7268
    return len;
 
7269
  },
 
7270
 
 
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') }}});
 
7280
    }
 
7281
    var iov = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iov', 'i8*') }}};
 
7282
    var num = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iovlen', 'i32') }}};
 
7283
#if SOCKET_DEBUG
 
7284
      Module.print('sendmsg vecs: ' + num);
 
7285
#endif
 
7286
    var totalSize = 0;
 
7287
    for (var i = 0; i < num; i++) {
 
7288
      totalSize += {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
 
7289
    }
 
7290
    var buffer = new Uint8Array(totalSize);
 
7291
    var ret = 0;
 
7292
    for (var i = 0; i < num; i++) {
 
7293
      var currNum = {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
 
7294
#if SOCKET_DEBUG
 
7295
      Module.print('sendmsg curr size: ' + currNum);
 
7296
#endif
 
7297
      if (!currNum) continue;
 
7298
      var currBuf = {{{ makeGetValue('iov', '8*i', 'i8*') }}};
 
7299
      buffer.set(HEAPU8.subarray(currBuf, currBuf+currNum), ret);
 
7300
      ret += currNum;
 
7301
    }
 
7302
    info.sender(buffer); // send all the iovs as a single message
 
7303
    return ret;
 
7304
  },
 
7305
 
 
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) {
 
7312
#if SOCKET_DEBUG
 
7313
      Module.print('recvmsg connecting');
 
7314
#endif
 
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') }}});
 
7318
    }
 
7319
    if (!info.hasData()) {
 
7320
      ___setErrNo(ERRNO_CODES.EWOULDBLOCK);
 
7321
      return -1;
 
7322
    }
 
7323
    var buffer = info.inQueue.shift();
 
7324
    var bytes = buffer.length;
 
7325
#if SOCKET_DEBUG
 
7326
    Module.print('recvmsg bytes: ' + bytes);
 
7327
#endif
 
7328
    // write source
 
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') }}};
 
7332
    // write data
 
7333
    var ret = bytes;
 
7334
    var iov = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iov', 'i8*') }}};
 
7335
    var num = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iovlen', 'i32') }}};
 
7336
    var bufferPos = 0;
 
7337
    for (var i = 0; i < num && bytes > 0; i++) {
 
7338
      var currNum = {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
 
7339
#if SOCKET_DEBUG
 
7340
      Module.print('recvmsg loop ' + [i, num, bytes, currNum]);
 
7341
#endif
 
7342
      if (!currNum) continue;
 
7343
      currNum = Math.min(currNum, bytes); // XXX what should happen when we partially fill a buffer..?
 
7344
      bytes -= currNum;
 
7345
      var currBuf = {{{ makeGetValue('iov', '8*i', 'i8*') }}};
 
7346
#if SOCKET_DEBUG
 
7347
      Module.print('recvmsg call recv ' + currNum);
 
7348
#endif
 
7349
      HEAPU8.set(buffer.subarray(bufferPos, bufferPos + currNum), currBuf);
 
7350
      bufferPos += currNum;
 
7351
    }
 
7352
    if (info.stream) {
 
7353
      // This is tcp (reliable), so if not all was read, keep it
 
7354
      if (bufferPos < bytes) {
 
7355
        info.inQueue.unshift(buffer.subarray(bufferPos));
 
7356
#if SOCKET_DEBUG
 
7357
        Module.print('recvmsg: put back: ' + (bytes - bufferPos));
 
7358
#endif
 
7359
      }
 
7360
    }
 
7361
    return ret;
 
7362
  },
 
7363
 
 
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);
 
7372
    }
 
7373
    return _recv(fd, buf, len, flags);
 
7374
  },
 
7375
 
 
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;
 
7381
  },
 
7382
 
 
7383
  ioctl: function(fd, request, varargs) {
 
7384
    var info = Sockets.fds[fd];
 
7385
    if (!info) return -1;
 
7386
    var bytes = 0;
 
7387
    if (info.hasData()) {
 
7388
      bytes = info.inQueue[0].length;
 
7389
    }
 
7390
    var dest = {{{ makeGetValue('varargs', '0', 'i32') }}};
 
7391
    {{{ makeSetValue('dest', '0', 'bytes', 'i32') }}};
 
7392
    return 0;
 
7393
  },
 
7394
 
 
7395
  setsockopt: function(d, level, optname, optval, optlen) {
 
7396
    console.log('ignoring setsockopt command');
 
7397
    return 0;
 
7398
  },
 
7399
 
 
7400
  bind__deps: ['connect'],
 
7401
  bind: function(fd, addr, addrlen) {
 
7402
    return _connect(fd, addr, addrlen);
 
7403
  },
 
7404
 
 
7405
  listen: function(fd, backlog) {
 
7406
    return 0;
 
7407
  },
 
7408
 
 
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;
 
7415
    if (addr) {
 
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');
 
7419
    }
 
7420
    return fd;
 
7421
  },
 
7422
 
 
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
 
7428
    assert(!exceptfds);
 
7429
    
 
7430
    var errorCondition = 0;
 
7431
 
 
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;
 
7438
        return false;
 
7439
      }
 
7440
      return info.hasData && info.hasData();
 
7441
    }
 
7442
 
 
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;
 
7449
        return false;
 
7450
      }
 
7451
      return info.socket && (info.socket.readyState == info.socket.OPEN);
 
7452
    }
 
7453
 
 
7454
    function checkfds(nfds, fds, can) {
 
7455
      if (!fds) return 0;
 
7456
 
 
7457
      var bitsSet = 0;
 
7458
      var dstLow  = 0;
 
7459
      var dstHigh = 0;
 
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
 
7463
 
 
7464
      for (var fd = 0; fd < nfds; fd++) {
 
7465
        var mask = 1 << (fd % 32), int = fd < 32 ? srcLow : srcHigh;
 
7466
        if (int & mask) {
 
7467
          // index is in the set, check if it is ready for read
 
7468
          var info = Sockets.fds[fd];
 
7469
          if (info && can(info)) {
 
7470
            // set bit
 
7471
            fd < 32 ? (dstLow = dstLow | mask) : (dstHigh = dstHigh | mask);
 
7472
            bitsSet++;
 
7473
          }
 
7474
        }
 
7475
      }
 
7476
 
 
7477
      {{{ makeSetValue('fds', 0, 'dstLow', 'i32') }}};
 
7478
      {{{ makeSetValue('fds', 4, 'dstHigh', 'i32') }}};
 
7479
      return bitsSet;
 
7480
    }
 
7481
 
 
7482
    var totalHandles = checkfds(nfds, readfds, canRead) + checkfds(nfds, writefds, canWrite);
 
7483
    if (errorCondition) {
 
7484
      ___setErrNo(ERRNO_CODES.EBADF);
 
7485
      return -1;
 
7486
    } else {
 
7487
      return totalHandles;
 
7488
    }
 
7489
  },
 
7490
 
 
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);
 
7496
    return -1;
 
7497
  },
 
7498
 
 
7499
  // pty.h
 
7500
 
 
7501
  openpty: function() { throw 'openpty: TODO' },
 
7502
  forkpty: function() { throw 'forkpty: TODO' },
 
7503
 
 
7504
  // grp.h
 
7505
 
 
7506
  initgroups: function() { throw 'initgroups: TODO' },
 
7507
 
 
7508
  // pwd.h
 
7509
 
 
7510
  getpwnam: function() { throw 'getpwnam: TODO' },
 
7511
  setpwent: function() { throw 'setpwent: TODO' },
 
7512
  getpwent: function() { throw 'getpwent: TODO' },
 
7513
  endpwent: function() { throw 'endpwent: TODO' },
 
7514
 
 
7515
  // ==========================================================================
 
7516
  // emscripten.h
 
7517
  // ==========================================================================
 
7518
 
 
7519
  emscripten_run_script: function(ptr) {
 
7520
    eval(Pointer_stringify(ptr));
 
7521
  },
 
7522
 
 
7523
  emscripten_run_script_int: function(ptr) {
 
7524
    return eval(Pointer_stringify(ptr));
 
7525
  },
 
7526
 
 
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);
 
7534
    }
 
7535
    writeStringToMemory(s, me.buffer);
 
7536
    return me.buffer;
 
7537
  },
 
7538
 
 
7539
  emscripten_random: function() {
 
7540
    return Math.random();
 
7541
  },
 
7542
 
 
7543
  emscripten_jcache_printf___deps: ['_formatString'],
 
7544
  emscripten_jcache_printf_: function(varargs) {
 
7545
    var MAX = 10240;
 
7546
    if (!_emscripten_jcache_printf_.buffer) {
 
7547
      _emscripten_jcache_printf_.buffer = _malloc(MAX);
 
7548
    }
 
7549
    var i = 0;
 
7550
    do {
 
7551
      var curr = {{{ makeGetValue('varargs', '0', 'i8') }}};
 
7552
      varargs += {{{ STACK_ALIGN }}};
 
7553
      {{{ makeSetValue('_emscripten_jcache_printf_.buffer', 'i', 'curr', 'i8') }}};
 
7554
      i++;
 
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
 
7559
  },
 
7560
 
 
7561
  //============================
 
7562
  // i64 math
 
7563
  //============================
 
7564
 
 
7565
  i64Add__asm: true,
 
7566
  i64Add__sig: 'iiiii',
 
7567
  i64Add: function(a, b, c, d) {
 
7568
    /*
 
7569
      x = a + b*2^32
 
7570
      y = c + d*2^32
 
7571
      result = l + h*2^32
 
7572
    */
 
7573
    a = a|0; b = b|0; c = c|0; d = d|0;
 
7574
    var l = 0, h = 0;
 
7575
    l = (a + c)>>>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) }}};
 
7578
  },
 
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;
 
7584
    l = (a + c)>>>0;
 
7585
    h = (b + d)>>>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.
 
7590
    }
 
7591
    {{{ makeStructuralReturn(['l|0', 'h', 'overflow'], true) }}};
 
7592
  },
 
7593
 
 
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;
 
7598
    var l = 0, h = 0;
 
7599
    l = (a - c)>>>0;
 
7600
    h = (b - 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) }}};
 
7603
  },
 
7604
 
 
7605
  bitshift64Shl__asm: true,
 
7606
  bitshift64Shl__sig: 'iiii',
 
7607
  bitshift64Shl: function(low, high, bits) {
 
7608
    low = low|0; high = high|0; bits = bits|0;
 
7609
    var ander = 0;
 
7610
    if ((bits|0) < 32) {
 
7611
      ander = ((1 << bits) - 1)|0;
 
7612
      tempRet0 = (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits));
 
7613
      return low << bits;
 
7614
    }
 
7615
    tempRet0 = low << (bits - 32);
 
7616
    return 0;
 
7617
  },
 
7618
  bitshift64Ashr__asm: true,
 
7619
  bitshift64Ashr__sig: 'iiii',
 
7620
  bitshift64Ashr: function(low, high, bits) {
 
7621
    low = low|0; high = high|0; bits = bits|0;
 
7622
    var ander = 0;
 
7623
    if ((bits|0) < 32) {
 
7624
      ander = ((1 << bits) - 1)|0;
 
7625
      tempRet0 = high >> bits;
 
7626
      return (low >>> bits) | ((high&ander) << (32 - bits));
 
7627
    }
 
7628
    tempRet0 = (high|0) < 0 ? -1 : 0;
 
7629
    return (high >> (bits - 32))|0;
 
7630
  },
 
7631
  bitshift64Lshr__asm: true,
 
7632
  bitshift64Lshr__sig: 'iiii',
 
7633
  bitshift64Lshr: function(low, high, bits) {
 
7634
    low = low|0; high = high|0; bits = bits|0;
 
7635
    var ander = 0;
 
7636
    if ((bits|0) < 32) {
 
7637
      ander = ((1 << bits) - 1)|0;
 
7638
      tempRet0 = high >>> bits;
 
7639
      return (low >>> bits) | ((high&ander) << (32 - bits));
 
7640
    }
 
7641
    tempRet0 = 0;
 
7642
    return (high >>> (bits - 32))|0;
 
7643
  },
 
7644
};
 
7645
 
 
7646
function autoAddDeps(object, name) {
 
7647
  name = [name];
 
7648
  for (var item in object) {
 
7649
    if (item.substr(-6) != '__deps' && !object[item + '__deps']) {
 
7650
      object[item + '__deps'] = name;
 
7651
    }
 
7652
  }
 
7653
}
 
7654
 
 
7655