summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/library.js71
-rw-r--r--src/parseTools.js7
-rw-r--r--src/runtime.js2
-rw-r--r--src/settings.js3
-rw-r--r--src/shell.js19
-rwxr-xr-xtests/runner.py26
-rw-r--r--tests/stdio/test_fgetc_ungetc.c87
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