diff options
author | kripken <alonzakai@gmail.com> | 2011-07-03 22:16:19 -0700 |
---|---|---|
committer | kripken <alonzakai@gmail.com> | 2011-07-03 22:16:19 -0700 |
commit | 39b1dca3a0263549a259e1da88c10b9b3ea4ce13 (patch) | |
tree | 7eb9779fc610c0b76d14ea4dc68408a771b5a68e | |
parent | 4e9d7978c6cdcc6eba29e372b763343f1bb4a1ff (diff) | |
parent | 6390aaff2001afd7cdabd84cdaa141a4fba96b4d (diff) |
Merge pull request #43 from max99x/master
More library functions
-rw-r--r-- | src/library.js | 264 | ||||
-rw-r--r-- | tests/runner.py | 14 | ||||
-rw-r--r-- | tests/time/output.txt | 38 | ||||
-rw-r--r-- | tests/time/src.c | 106 |
4 files changed, 401 insertions, 21 deletions
diff --git a/src/library.js b/src/library.js index bd17e2dd..d87fea6d 100644 --- a/src/library.js +++ b/src/library.js @@ -210,19 +210,9 @@ var Library = { var currArg = getNextArg(false, argSize); // Truncate to requested size. argSize = argSize || 4; - var limit = undefined; - if (argSize == 4) { - limit = 0xFFFFFFFF; - } else if (argSize == 2) { - limit = 0xFFFF; - } else if (argSize == 1) { - limit = 0xFF; - } - if (limit !== undefined) { - currArg = currArg & limit; - if (!signed && currArg < 0 || signed && currArg > (limit - 1) / 2) { - currArg = ~(limit - currArg); - } + if (argSize <= 4) { + var limit = Math.pow(256, argSize) - 1; + currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8); } // Format the number. var currAbsArg = Math.abs(currArg); @@ -794,15 +784,33 @@ var Library = { fstat: function(stream, ptr) { var info = STDIO.streams[stream]; if (!info) return -1; + // XXX: hardcoded indexes into the structure. try { - {{{ makeSetValue('ptr', '$struct_stat___FLATTENER[9]', 'info.data.length', 'i32') }}} // st_size. XXX: hardcoded index 9 into the structure. + {{{ makeSetValue('ptr', '$struct_stat___FLATTENER[0]', '1', 'i32') }}} // st_dev + {{{ makeSetValue('ptr', '$struct_stat___FLATTENER[15]', 'stream', 'i32') }}} // st_ino + {{{ makeSetValue('ptr', '$struct_stat___FLATTENER[9]', 'info.data.length', 'i32') }}} // st_size } catch(e) { - {{{ makeSetValue('ptr', '9', 'info.data.length', 'i32') }}} // no FLATTENER + // no FLATTENER + {{{ makeSetValue('ptr', '0', '1', 'i32') }}} + {{{ makeSetValue('ptr', '15', 'stream', 'i32') }}} + {{{ makeSetValue('ptr', '9', 'info.data.length', 'i32') }}} } // TODO: other fields return 0; }, + stat__deps: ['open', 'fstat'], + stat: function(filename, ptr) { + if (typeof window === 'undefined') { + // d8 hangs if you try to read a folder. + // http://code.google.com/p/v8/issues/detail?id=1533 + return 0; + } + // TODO: Handle symbolic links. + var stream = _open(filename, 0, 256); // RDONLY, 0400. + return _fstat(stream, ptr); + }, + mmap: function(start, num, prot, flags, stream, offset) { // Leaky and non-shared... FIXME var info = STDIO.streams[stream]; @@ -1501,7 +1509,6 @@ var Library = { dlopen: function(filename, flag) { // TODO: Add support for LD_LIBRARY_PATH. filename = Pointer_stringify(filename); - filename += '.js'; if (DLFCN_DATA.loadedLibNames[filename]) { // Already loaded; increment ref count and return. @@ -1611,10 +1618,28 @@ var Library = { // unistd.h // ========================================================================== + getcwd__deps: ['malloc'], + getcwd: function(buf, size) { + // TODO: Implement for real once we have a file system. + var path = window ? window.location.pathname.replace(/\/[^/]*$/, '') : '/'; + if (buf === 0) { + // Null. Allocate manually. + buf = _malloc(path.length); + } else if (size < path.length) { + return 0; + // TODO: Set errno. + } + for (var i = 0; i < path.length; i++) { + {{{ makeSetValue('buf', 'i', 'path[i].charCodeAt(0)', 'i8') }}} + } + return buf; + }, + sysconf: function(name_) { // XXX we only handle _SC_PAGE_SIZE/PAGESIZE for now, 30 on linux, 29 on OS X... be careful here! switch(name_) { case 29: case 30: return PAGE_SIZE; + case 2: return 1000000; // _SC_CLK_TCK default: throw 'unknown sysconf param: ' + name_; } }, @@ -1659,16 +1684,25 @@ var Library = { getuid: function() { return 100; }, + geteuid: 'getuid', getgid: function() { return 100; }, + getegid: 'getgid', getpwuid: function(uid) { return 0; // NULL }, + // ========================================================================== // time.h + // ========================================================================== + + clock: function() { + if (_clock.start === undefined) _clock.start = new Date(); + return (_clock.start.getTime() - Date.now())*1000; + }, time: function(ptr) { var ret = Math.floor(Date.now()/1000); @@ -1678,6 +1712,197 @@ var Library = { return ret; }, + difftime: function(time1, time0) { + return time1 - time0; + }, + + __tm_struct_layout: Runtime.generateStructInfo([ + ['i32', 'tm_sec'], + ['i32', 'tm_min'], + ['i32', 'tm_hour'], + ['i32', 'tm_mday'], + ['i32', 'tm_mon'], + ['i32', 'tm_year'], + ['i32', 'tm_wday'], + ['i32', 'tm_yday'], + ['i32', 'tm_isdst'], + ['i32', 'tm_gmtoff'], + ['i8*', 'tm_zone'], + ]), + // Statically allocated time struct. + __tm_current: 0, + // Statically allocated timezone strings. + __tm_timezones: {}, + // Statically allocated time strings. + __tm_formatted: 0, + + mktime__deps: ['__tm_struct_layout', 'tzset'], + mktime: function(tmPtr) { + _tzset(); + var year = {{{ makeGetValue('tmPtr', '___tm_struct_layout.tm_year', 'i32') }}}; + var timestamp = new Date(year >= 1900 ? year : year + 1900, + {{{ makeGetValue('tmPtr', '___tm_struct_layout.tm_mon', 'i32') }}}, + {{{ makeGetValue('tmPtr', '___tm_struct_layout.tm_mday', 'i32') }}}, + {{{ makeGetValue('tmPtr', '___tm_struct_layout.tm_hour', 'i32') }}}, + {{{ makeGetValue('tmPtr', '___tm_struct_layout.tm_min', 'i32') }}}, + {{{ makeGetValue('tmPtr', '___tm_struct_layout.tm_sec', 'i32') }}}, + 0).getTime() / 1000; + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_wday', 'new Date(timestamp).getDay()', 'i32') }}} + var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24)); + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_yday', 'yday', 'i32') }}} + return timestamp; + }, + timelocal: 'mktime', + + gmtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'gmtime_r'], + gmtime: function(time) { + if (!___tm_current) ___tm_current = _malloc(___tm_struct_layout.__size__); + return _gmtime_r(time, ___tm_current); + }, + + gmtime_r__deps: ['__tm_struct_layout', '__tm_timezones'], + gmtime_r: function(time, tmPtr) { + var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000); + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_sec', 'date.getUTCSeconds()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_min', 'date.getUTCMinutes()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_hour', 'date.getUTCHours()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_mday', 'date.getUTCDate()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_mon', 'date.getUTCMonth()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_year', 'date.getUTCFullYear()-1900', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_wday', 'date.getUTCDay()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_gmtoff', '0', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_isdst', '0', 'i32') }}} + + var start = new Date(date.getFullYear(), 0, 1); + var yday = Math.round((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_yday', 'yday', 'i32') }}} + + var timezone = "GMT"; + if (!(timezone in ___tm_timezones)) { + ___tm_timezones[timezone] = Pointer_make(intArrayFromString(timezone), null, ALLOC_NORMAL, 'i8'); + } + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_zone', '___tm_timezones[timezone]', 'i32') }}} + + return tmPtr; + }, + + timegm__deps: ['__tm_struct_layout', 'mktime'], + timegm: function(tmPtr) { + _tzset(); + var offset = {{{ makeGetValue('_timezone', 0, 'i32') }}}; + var daylight = {{{ makeGetValue('_daylight', 0, 'i32') }}}; + daylight = (daylight == 1) ? 60 * 60 : 0; + var ret = _mktime(tmPtr) - (offset + daylight); + return ret; + }, + + localtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'localtime_r'], + localtime: function(time) { + if (!___tm_current) ___tm_current = _malloc(___tm_struct_layout.__size__); + return _localtime_r(time, ___tm_current); + }, + + localtime_r__deps: ['__tm_struct_layout', '__tm_timezones', 'tzset'], + localtime_r: function(time, tmPtr) { + _tzset(); + var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000); + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_sec', 'date.getSeconds()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_min', 'date.getMinutes()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_hour', 'date.getHours()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_mday', 'date.getDate()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_mon', 'date.getMonth()', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_year', 'date.getFullYear()-1900', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_wday', 'date.getDay()', 'i32') }}} + + var start = new Date(date.getFullYear(), 0, 1); + var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_yday', 'yday', 'i32') }}} + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_gmtoff', '-start.getTimezoneOffset() * 60', 'i32') }}} + + var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset()); + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_isdst', 'dst', 'i32') }}} + + var timezone = date.toString().match(/\(([A-Z]+)\)/)[1]; + if (!(timezone in ___tm_timezones)) { + ___tm_timezones[timezone] = Pointer_make(intArrayFromString(timezone), null, ALLOC_NORMAL, 'i8'); + } + {{{ makeSetValue('tmPtr', '___tm_struct_layout.tm_zone', '___tm_timezones[timezone]', 'i32') }}} + + return tmPtr; + }, + + asctime__deps: ['malloc', '__tm_formatted', 'asctime_r'], + asctime: function(tmPtr) { + if (!___tm_formatted) ___tm_formatted = _malloc(26); + return _asctime_r(tmPtr, ___tm_formatted); + }, + + asctime_r__deps: ['__tm_formatted', 'mktime'], + asctime_r: function(tmPtr, buf) { + var date = new Date(_mktime(tmPtr)*1000); + var formatted = date.toString(); + var datePart = formatted.replace(/\d{4}.*/, '').replace(/ 0/, ' '); + var timePart = formatted.match(/\d{2}:\d{2}:\d{2}/)[0]; + formatted = datePart + timePart + ' ' + date.getFullYear() + '\n'; + formatted.split('').forEach(function(chr, index) { + {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}} + }); + {{{ makeSetValue('buf', '25', '0', 'i8') }}} + return buf; + }, + + ctime__deps: ['localtime', 'asctime'], + ctime: function(timer) { + return _asctime(_localtime(timer)); + }, + + ctime_r__deps: ['localtime', 'asctime'], + ctime_r: function(timer, buf) { + return _asctime_r(_localtime_r(timer, ___tm_current), buf); + }, + + dysize: function(year) { + var leap = ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))); + return leap ? 366 : 365; + }, + + // TODO: Initialize these to defaults on startup from system settings. + tzname: null, + daylight: null, + timezone: null, + tzset__deps: ['malloc', 'tzname', 'daylight', 'timezone'], + tzset: function() { + // TODO: Use (malleable) environment variables instead of system settings. + if (_tzname !== null) return; + + _timezone = _malloc(QUANTUM_SIZE); + {{{ makeSetValue('_timezone', '0', '(new Date()).getTimezoneOffset() * 60', 'i32') }}} + + _daylight = _malloc(QUANTUM_SIZE); + var winter = new Date(2000, 0, 1); + var summer = new Date(2000, 6, 1); + {{{ makeSetValue('_daylight', '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}} + + var winterName = winter.toString().match(/\(([A-Z]+)\)/)[1]; + var summerName = summer.toString().match(/\(([A-Z]+)\)/)[1]; + var winterNamePtr = Pointer_make(intArrayFromString(winterName), null, ALLOC_NORMAL, 'i8'); + var summerNamePtr = Pointer_make(intArrayFromString(summerName), null, ALLOC_NORMAL, 'i8'); + _tzname = _malloc(2 * QUANTUM_SIZE); + {{{ makeSetValue('_tzname', '0', 'winterNamePtr', 'i32') }}} + {{{ makeSetValue('_tzname', QUANTUM_SIZE, 'summerNamePtr', 'i32') }}} + }, + + stime: function(when) { + // TODO: Set errno. + return -1; + }, + + // TODO: Implement strftime(), strptime() and getdate(). + + // ========================================================================== + // sys/time.h + // ========================================================================== + gettimeofday: function(ptr) { // %struct.timeval = type { i32, i32 } var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] }); @@ -1717,12 +1942,17 @@ var Library = { return 0; }, + // ========================================================================== // stat.h + // ========================================================================== - __01stat64_: 'fstat', __01fstat64_: 'fstat', + __01stat64_: 'stat', + __01lstat64_: 'stat', + // ========================================================================== // locale.h + // ========================================================================== setlocale: function(category, locale) { return 0; diff --git a/tests/runner.py b/tests/runner.py index 85a27a32..88a79c73 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -1640,6 +1640,12 @@ if 'benchmark' not in sys.argv: ''' self.do_test(src, '*1,2,3,5,5,6*\n*stdin==0:0*\n*%*\n*5*\n*66.0*\n*cleaned*') + def test_time(self): + src = open(path_from_root('tests', 'time', 'src.c'), 'r').read() + expected = open(path_from_root('tests', 'time', 'output.txt'), 'r').read() + self.do_test(src, expected) + + def test_statics(self): # static initializers save i16 but load i8 for some reason global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = ['-g'] @@ -1825,7 +1831,7 @@ if 'benchmark' not in sys.argv: filename = os.path.join(dirname, 'liblib.cpp') BUILD_AS_SHARED_LIB = 1 self.build(lib_src, dirname, filename) - shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so.js')) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) src = ''' #include <cstdio> @@ -1870,7 +1876,7 @@ if 'benchmark' not in sys.argv: BUILD_AS_SHARED_LIB = 1 EXPORTED_FUNCTIONS = ['__Z7get_cmpv'] self.build(lib_src, dirname, filename) - shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so.js')) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) src = ''' #include <stdio.h> @@ -1960,7 +1966,7 @@ if 'benchmark' not in sys.argv: EXPORTED_FUNCTIONS = ['__Z4funciPFvvE'] EXPORTED_GLOBALS = ['_global'] self.build(lib_src, dirname, filename) - shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so.js')) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) src = ''' #include <stdio.h> @@ -2477,7 +2483,7 @@ if 'benchmark' not in sys.argv: global EXPORTED_FUNCTIONS; EXPORTED_FUNCTIONS = ['_main', '_PyRun_SimpleStringFlags'] # for the demo self.do_ll_test(path_from_root('tests', 'python', 'python.ll'), - 'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470', + 'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000', args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47''']) ### Test cases in separate files diff --git a/tests/time/output.txt b/tests/time/output.txt new file mode 100644 index 00000000..c8f31001 --- /dev/null +++ b/tests/time/output.txt @@ -0,0 +1,38 @@ +stime: -1 +tzname[0] set: 1 +tzname[1] set: 1 +sec: 43 +min: 22 +hour: 3 +day: 25 +mon: 11 +year: 102 +wday: 3 +yday: 358 +dst: 0 +off: 0 +zone: GMT +timegm <-> gmtime: 1 +old year: 102 +new year: 70 +old year again: 102 +localtime timezone: 1 +localtime daylight: 1 +localtime tzname: 1 +localtime <-> mktime: 1 +old year: 102 +new year: 70 +old year again: 102 +time: 1 +difftime+: 268848637.000000 +difftime-: -268848637.000000 +1854 days: 365 +2000 days: 366 +2001 days: 365 +2004 days: 366 +asctime: Wed Dec 25 05:22:43 2002 +old asctime: Wed Dec 25 05:22:43 2002 +new asctime_r: Sat Jul 2 22:33:20 2011 +old asctime again: Wed Dec 25 05:22:43 2002 +clock: 0 +ctime: 0 diff --git a/tests/time/src.c b/tests/time/src.c new file mode 100644 index 00000000..df9ad264 --- /dev/null +++ b/tests/time/src.c @@ -0,0 +1,106 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> + +int main() { + time_t xmas2002 = 1040786563ll; + struct tm* tm_ptr; + + // Make sure stime() always fails. + printf("stime: %d\n", stime(&xmas2002)); + + // Verify that tzname sets *something*. + tzset(); + printf("tzname[0] set: %d\n", strlen(tzname[0]) >= 3); + printf("tzname[1] set: %d\n", strlen(tzname[1]) >= 3); + + // Verify gmtime() creates correct struct. + tm_ptr = gmtime(&xmas2002); + printf("sec: %d\n", tm_ptr->tm_sec); + printf("min: %d\n", tm_ptr->tm_min); + printf("hour: %d\n", tm_ptr->tm_hour); + printf("day: %d\n", tm_ptr->tm_mday); + printf("mon: %d\n", tm_ptr->tm_mon); + printf("year: %d\n", tm_ptr->tm_year); + printf("wday: %d\n", tm_ptr->tm_wday); + printf("yday: %d\n", tm_ptr->tm_yday); + printf("dst: %d\n", tm_ptr->tm_isdst); + printf("off: %d\n", tm_ptr->tm_gmtoff); + printf("zone: %s\n", tm_ptr->tm_zone); + + // Verify timegm() reverses gmtime. + printf("timegm <-> gmtime: %d\n", timegm(tm_ptr) == xmas2002); + + // Verify gmtime_r() doesn't clobber static data. + time_t t1 = 0; + struct tm tm1; + gmtime_r(&t1, &tm1); + printf("old year: %d\n", tm_ptr->tm_year); + printf("new year: %d\n", tm1.tm_year); + gmtime(&xmas2002); + printf("old year again: %d\n", tm_ptr->tm_year); + + // Verify localtime() picks up timezone data. + time_t t2 = xmas2002 - 60 * 60 * 24 * 30 * 6; + tm_ptr = localtime(&t2); + printf("localtime timezone: %d\n", (timezone + tm_ptr->tm_isdst * 60 * 60 == + -tm_ptr->tm_gmtoff)); + printf("localtime daylight: %d\n", daylight == tm_ptr->tm_isdst); + printf("localtime tzname: %d\n", (!strcmp(tzname[0], tm_ptr->tm_zone) || + !strcmp(tzname[1], tm_ptr->tm_zone))); + + // Verify localtime() and mktime() reverse each other. + printf("localtime <-> mktime: %d\n", mktime(localtime(&xmas2002)) == xmas2002); + + // Verify localtime_r() doesn't clobber static data. + time_t t3 = 0; + struct tm tm2; + localtime_r(&t3, &tm2); + printf("old year: %d\n", tm_ptr->tm_year); + printf("new year: %d\n", tm2.tm_year); + localtime(&xmas2002); + printf("old year again: %d\n", tm_ptr->tm_year); + + // Verify time() returns reasonable value (between 2011 and 2030). + time_t t4 = 0; + time(&t4); + printf("time: %d\n", t4 > 1309635200ll && t4 < 1893362400ll); + + // Verify difftime() calculates accurate time difference. + time_t t5 = 1309635200ll; + printf("difftime+: %lf\n", difftime(t5, xmas2002)); + printf("difftime-: %lf\n", difftime(xmas2002, t5)); + + // Verify dysize() knows its leap years. + printf("1854 days: %d\n", dysize(1854)); + printf("2000 days: %d\n", dysize(2000)); + printf("2001 days: %d\n", dysize(2001)); + printf("2004 days: %d\n", dysize(2004)); + + // Verify asctime() formatting(). + printf("asctime: %s", asctime(localtime(&xmas2002))); + + // Verify asctime_r() doesn't clobber static data. + time_t t6 = 1309635200ll; + tm_ptr = localtime(&xmas2002); + char* formatted = asctime(tm_ptr); + char buffer[32]; + asctime_r(localtime(&t6), buffer); + printf("old asctime: %s", formatted); + printf("new asctime_r: %s", buffer); + asctime_r(tm_ptr, buffer); + printf("old asctime again: %s", formatted); + + // Verify that clock() is initially 0 and doesn't crash. + printf("clock: %d\n", clock()); + + // Verify that ctime_r(x, buf) is equivalent to asctime_r(localtime(x), buf2). + time_t t7 = time(0); + char buffer2[30]; + char buffer3[30]; + printf("ctime: %d\n", strcmp(ctime_r(&t7, buffer2), + asctime_r(localtime(&t7), buffer3))); + + return 0; +} |