diff options
-rw-r--r-- | src/library.js | 71 | ||||
-rw-r--r-- | src/parseTools.js | 7 | ||||
-rw-r--r-- | src/runtime.js | 2 | ||||
-rw-r--r-- | src/settings.js | 3 | ||||
-rw-r--r-- | src/shell.js | 19 | ||||
-rwxr-xr-x | tests/runner.py | 26 | ||||
-rw-r--r-- | tests/stdio/test_fgetc_ungetc.c | 87 |
7 files changed, 180 insertions, 35 deletions
diff --git a/src/library.js b/src/library.js index e650a545..f7c7a3ba 100644 --- a/src/library.js +++ b/src/library.js @@ -1805,11 +1805,6 @@ LibraryManager.library = { return 0; } else { var bytesRead = 0; - while (stream.ungotten.length && nbyte > 0) { - {{{ makeSetValue('buf++', '0', 'stream.ungotten.pop()', 'i8') }}} - nbyte--; - bytesRead++; - } var contents = stream.object.contents; var size = Math.min(contents.length - offset, nbyte); assert(size >= 0); @@ -1853,11 +1848,6 @@ LibraryManager.library = { if (stream.object.isDevice) { if (stream.object.input) { bytesRead = 0; - while (stream.ungotten.length && nbyte > 0) { - {{{ makeSetValue('buf++', '0', 'stream.ungotten.pop()', 'i8') }}} - nbyte--; - bytesRead++; - } for (var i = 0; i < nbyte; i++) { try { var result = stream.object.input(); @@ -1879,11 +1869,10 @@ LibraryManager.library = { return -1; } } else { - var ungotSize = stream.ungotten.length; bytesRead = _pread(fildes, buf, nbyte, stream.position); assert(bytesRead >= -1); if (bytesRead != -1) { - stream.position += (stream.ungotten.length - ungotSize) + bytesRead; + stream.position += bytesRead; } return bytesRead; } @@ -3243,7 +3232,7 @@ LibraryManager.library = { return -1; } }, - fgetc__deps: ['$FS', 'read'], + fgetc__deps: ['$FS', 'fread'], fgetc__postset: '_fgetc.ret = allocate([0], "i8", ALLOC_STATIC);', fgetc: function(stream) { // int fgetc(FILE *stream); @@ -3251,7 +3240,7 @@ LibraryManager.library = { if (!FS.streams[stream]) return -1; var streamObj = FS.streams[stream]; if (streamObj.eof || streamObj.error) return -1; - var ret = _read(stream, _fgetc.ret, 1); + var ret = _fread(_fgetc.ret, 1, 1, stream); if (ret == 0) { streamObj.eof = true; return -1; @@ -3413,16 +3402,24 @@ LibraryManager.library = { // size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); // http://pubs.opengroup.org/onlinepubs/000095399/functions/fread.html var bytesToRead = nitems * size; - if (bytesToRead == 0) return 0; - var bytesRead = _read(stream, ptr, bytesToRead); + if (bytesToRead == 0) { + return 0; + } + var bytesRead = 0; var streamObj = FS.streams[stream]; - if (bytesRead == -1) { + while (streamObj.ungotten.length && bytesToRead > 0) { + {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}} + bytesToRead--; + bytesRead++; + } + var err = _read(stream, ptr, bytesToRead); + if (err == -1) { if (streamObj) streamObj.error = true; return 0; - } else { - if (bytesRead < bytesToRead) streamObj.eof = true; - return Math.floor(bytesRead / size); } + bytesRead += err; + if (bytesRead < bytesToRead) streamObj.eof = true; + return Math.floor(bytesRead / size); }, freopen__deps: ['$FS', 'fclose', 'fopen', '__setErrNo', '$ERRNO_CODES'], freopen: function(filename, mode, stream) { @@ -3635,13 +3632,18 @@ LibraryManager.library = { ungetc: function(c, stream) { // int ungetc(int c, FILE *stream); // http://pubs.opengroup.org/onlinepubs/000095399/functions/ungetc.html - if (FS.streams[stream]) { - c = unSign(c & 0xFF); - FS.streams[stream].ungotten.push(c); - return c; - } else { + stream = FS.streams[stream]; + if (!stream) { return -1; } + if (c === {{{ cDefine('EOF') }}}) { + // do nothing for EOF character + return c; + } + c = unSign(c & 0xFF); + stream.ungotten.push(c); + stream.eof = false; + return c; }, system__deps: ['__setErrNo', '$ERRNO_CODES'], system: function(command) { @@ -3658,8 +3660,23 @@ LibraryManager.library = { // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html if (FS.streams[stream]) { var i = _ftell(stream), SEEK_SET = 0; - var get = function () { i++; return _fgetc(stream); }; - var unget = function () { _fseek(stream, --i, SEEK_SET); }; + // if the stream does not support seeking backwards (e.g. stdin), buffer it here + var buffer = [], bufferIndex = 0; + var get = function() { + if (bufferIndex < buffer.length) { + return buffer[bufferIndex++]; + } + i++; + bufferIndex++; + var c = _fgetc(stream); + buffer.push(c); + return c; + }; + var unget = function() { + if (_fseek(stream, --i, SEEK_SET) !== 0) { + bufferIndex--; + } + }; return __scanString(format, get, unget, varargs); } else { return -1; diff --git a/src/parseTools.js b/src/parseTools.js index 72166592..b7d3ea91 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -970,10 +970,9 @@ function generateStructTypes(type) { ret[index++] = type; } else { if (Runtime.isStructType(type) && type[1] === '0') { - // this is [0 x something]. When inside another structure like here, it must be at the end, - // and it does nothing - assert(i === typeData.fields.length-1); - return; + // this is [0 x something], which does nothing + // XXX this happens in java_nbody... assert(i === typeData.fields.length-1); + continue; } add(Types.types[type]); } diff --git a/src/runtime.js b/src/runtime.js index 8c2c8f4d..e07d5054 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -212,7 +212,7 @@ var Runtime = { if (field[1] === '0') { // this is [0 x something]. When inside another structure like here, it must be at the end, // and it adds no size - assert(index === type.fields.length); + // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!'); size = 0; alignSize = type.alignSize || QUANTUM_SIZE; } else { diff --git a/src/settings.js b/src/settings.js index b7460cf2..52e4eeb0 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1289,6 +1289,7 @@ var C_DEFINES = {'SI_MESGQ': '5', 'SOCK_STREAM': '200', 'SOCK_DGRAM': '20', 'IPPROTO_TCP': '1', - 'IPPROTO_UDP': '2' + 'IPPROTO_UDP': '2', + 'EOF': '-1' }; diff --git a/src/shell.js b/src/shell.js index 679201d0..2082eeae 100644 --- a/src/shell.js +++ b/src/shell.js @@ -1,9 +1,26 @@ +// The Module object: Our interface to the outside world. We import +// and export values on it, and do the work to get that through +// closure compiler if necessary. There are various ways Module can be used: +// 1. Not defined. We create it here +// 2. A function parameter, function(Module) { ..generated code.. } +// 3. pre-run appended it, var Module = {}; ..generated code.. +// 4. External script tag defines var Module. +// We need to do an eval in order to handle the closure compiler +// case, where this code here is minified but Module was defined +// elsewhere (e.g. case 4 above). We also need to check if Module +// already exists (e.g. case 3 above). +// Note that if you want to run closure, and also to use Module +// after the generated code, you will need to define var Module = {}; +// before the code. Then that object will be used in the code, and you +// can continue to use Module afterwards as well. +var Module; +if (!Module) Module = eval('(function() { try { return {{{ EXPORT_NAME }}} || {} } catch(e) { return {} } })()'); + // Sometimes an existing Module object exists with properties // meant to overwrite the default module functionality. Here // we collect those properties and reapply _after_ we configure // the current environment's defaults to avoid having to be so // defensive during initialization. -var Module = typeof {{{ EXPORT_NAME }}} !== 'undefined' ? {{{ EXPORT_NAME }}} : {}; var moduleOverrides = {}; for (var key in Module) { if (Module.hasOwnProperty(key)) { diff --git a/tests/runner.py b/tests/runner.py index d16472ad..1948ab59 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -7142,6 +7142,10 @@ def process(filename): ''' self.do_run(src, 'written=0') + def test_fgetc_ungetc(self): + src = open(path_from_root('tests', 'stdio', 'test_fgetc_ungetc.c'), 'r').read() + self.do_run(src, 'success', force_c=True) + def test_fgetc_unsigned(self): if self.emcc_args is None: return self.skip('requires emcc') src = r''' @@ -9524,7 +9528,10 @@ def process(filename): c2.virtualFunc2(); Module.print('*ok*'); ''' - src = open(filename, 'a') + code = open(filename).read() + src = open(filename, 'w') + src.write('var Module = {};\n') # name Module + src.write(code) src.write(script_src_2 + '\n') src.close() @@ -11223,6 +11230,22 @@ f.close() self.assertContained('libf1\nlibf2\n', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + def test_stdin(self): + open('main.cpp', 'w').write(r''' +#include <stdio.h> +int main(int argc, char const *argv[]) +{ + char str[10] = {0}; + scanf("%10s", str); + printf("%s\n", str); + return 0; +} +''') + Building.emcc('main.cpp', output_filename='a.out.js') + open('in.txt', 'w').write('abc') + # node's stdin support is broken + self.assertContained('abc', Popen(listify(SPIDERMONKEY_ENGINE) + ['a.out.js'], stdin=open('in.txt'), stdout=PIPE, stderr=PIPE).communicate()[0]) + def test_abspaths(self): # Includes with absolute paths are generally dangerous, things like -I/usr/.. will get to system local headers, not our portable ones. @@ -12228,6 +12251,7 @@ elif 'browser' in str(sys.argv): basename = os.path.basename(expected) shutil.copyfile(expected, os.path.join(self.get_dir(), basename)) open(os.path.join(self.get_dir(), 'reftest.js'), 'w').write(''' + var Module = eval('Module'); function doReftest() { if (doReftest.done) return; doReftest.done = true; diff --git a/tests/stdio/test_fgetc_ungetc.c b/tests/stdio/test_fgetc_ungetc.c new file mode 100644 index 00000000..c69a3d1a --- /dev/null +++ b/tests/stdio/test_fgetc_ungetc.c @@ -0,0 +1,87 @@ +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void create_file(const char *path, const char *buffer, int mode) { + int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode); + assert(fd >= 0); + + int err = write(fd, buffer, sizeof(char) * strlen(buffer)); + assert(err == (sizeof(char) * strlen(buffer))); + + close(fd); +} + +void setup() { + create_file("file.txt", "cd", 0666); +} + +void cleanup() { + unlink("file.txt"); +} + +void test() { + FILE *file; + int err; + char buffer[256]; + + file = fopen("file.txt", "r"); + assert(file); + + // pushing EOF always returns EOF + rewind(file); + err = ungetc(EOF, file); + assert(err == EOF); + + // ungetc should return itself + err = ungetc('a', file); + assert(err == (int)'a'); + + // push two chars and make sure they're read back in + // the correct order (both by fgetc and fread) + rewind(file); + ungetc('b', file); + ungetc('a', file); + err = fgetc(file); + assert(err == (int)'a'); + fread(buffer, sizeof(char), sizeof(buffer), file); + assert(!strcmp(buffer, "bcd")); + + // rewind and fseek should reset anything that's been + // pushed to the stream + ungetc('a', file); + rewind(file); + err = fgetc(file); + assert(err == (int)'c'); + ungetc('a', file); + fseek(file, 0, SEEK_SET); + err = fgetc(file); + assert(err == (int)'c'); + + // fgetc, when nothing is left, should return EOF + fseek(file, 0, SEEK_END); + err = fgetc(file); + assert(err == EOF); + err = feof(file); + assert(err); + + // ungetc should reset the EOF indicator + ungetc('e', file); + err = feof(file); + assert(!err); + + fclose(file); + + puts("success"); +} + +int main() { + atexit(cleanup); + signal(SIGABRT, cleanup); + setup(); + test(); + return EXIT_SUCCESS; +}
\ No newline at end of file |