diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 4 | ||||
-rw-r--r-- | src/embind/embind.js | 620 | ||||
-rw-r--r-- | src/embind/emval.js | 111 | ||||
-rw-r--r-- | src/jsifier.js | 14 | ||||
-rw-r--r-- | src/library.js | 271 | ||||
-rw-r--r-- | src/library_browser.js | 66 | ||||
-rw-r--r-- | src/library_egl.js | 421 | ||||
-rw-r--r-- | src/library_gl.js | 11 | ||||
-rw-r--r-- | src/library_jansson.js | 225 | ||||
-rw-r--r-- | src/library_sdl.js | 37 | ||||
-rw-r--r-- | src/modules.js | 2 | ||||
-rw-r--r-- | src/parseTools.js | 8 | ||||
-rw-r--r-- | src/preamble.js | 8 | ||||
-rw-r--r-- | src/runtime.js | 2 | ||||
-rw-r--r-- | src/settings.js | 9 |
15 files changed, 1762 insertions, 47 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 69b811f0..9d060a2c 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1237,7 +1237,7 @@ function analyzer(data, sidePass) { if (phi.intertype == 'phi') { for (var i = 0; i < phi.params.length; i++) { phi.params[i].label = func.labelIds[phi.params[i].label]; - if (!phi.params[i].label) warn('phi refers to nonexistent label on line ' + phi.lineNum); + if (VERBOSE && !phi.params[i].label) warn('phi refers to nonexistent label on line ' + phi.lineNum); } } }); @@ -1316,7 +1316,7 @@ function analyzer(data, sidePass) { if (phi.intertype == 'phi') { for (var i = 0; i < phi.params.length; i++) { var param = phi.params[i]; - if (!param.label) warn('phi refers to nonexistent label on line ' + phi.lineNum); + if (VERBOSE && !param.label) warn('phi refers to nonexistent label on line ' + phi.lineNum); var sourceLabelId = getActualLabelId(param.label); if (sourceLabelId) { var sourceLabel = func.labelsDict[sourceLabelId]; diff --git a/src/embind/embind.js b/src/embind/embind.js new file mode 100644 index 00000000..d40d6ca2 --- /dev/null +++ b/src/embind/embind.js @@ -0,0 +1,620 @@ +/*global Module*/ +/*global _malloc, _free, _memcpy*/ +/*global FUNCTION_TABLE, HEAP32*/ +/*global Pointer_stringify, writeStringToMemory*/ +/*global __emval_register, _emval_handle_array, __emval_decref*/ + +function createNamedFunction(name, body) { + /*jshint evil:true*/ + return new Function( + "body", + "return function " + name + "() {\n" + + " return body.apply(this, arguments);\n" + + "};\n" + )(body); +} + +function _embind_repr(v) { + var t = typeof v; + if (t === 'object' || t === 'array' || t === 'function') { + return v.toString(); + } else { + return '' + v; + } +} + +var typeRegistry = {}; + +function validateType(type, name) { + if (!type) { + throw new BindingError('type "' + name + '" must have a positive integer typeid pointer'); + } + if (undefined !== typeRegistry[type]) { + throw new BindingError('cannot register type "' + name + '" twice'); + } +} + +function __embind_register_void(voidType, name) { + name = Pointer_stringify(name); + validateType(voidType, name); + typeRegistry[voidType] = { + name: name, + fromWireType: function() { + return undefined; + } + }; +} + +function __embind_register_bool(boolType, name, trueValue, falseValue) { + name = Pointer_stringify(name); + validateType(boolType, name); + typeRegistry[boolType] = { + name: name, + toWireType: function(destructors, o) { + return o ? trueValue : falseValue; + }, + fromWireType: function(wt) { + return wt === trueValue; + }, + }; +} + +function __embind_register_integer(primitiveType, name) { + name = Pointer_stringify(name); + validateType(primitiveType, name); + typeRegistry[primitiveType] = { + name: name, + toWireType: function(destructors, value) { + if (typeof value !== "number") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + name); + } + return value | 0; + }, + fromWireType: function(value) { + return value; + } + }; +} + +function __embind_register_float(primitiveType, name) { + name = Pointer_stringify(name); + validateType(primitiveType, name); + typeRegistry[primitiveType] = { + name: name, + toWireType: function(destructors, value) { + if (typeof value !== "number") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + name); + } + return value; + }, + fromWireType: function(value) { + return value; + } + }; +} + +function __embind_register_cstring(stringType, name) { + name = Pointer_stringify(name); + validateType(stringType, name); + typeRegistry[stringType] = { + name: name, + toWireType: function(destructors, value) { + var ptr = _malloc(value.length + 1); + writeStringToMemory(value, ptr); + destructors.push(_free); + destructors.push(ptr); + return ptr; + }, + fromWireType: function(value) { + var rv = Pointer_stringify(value); + _free(value); + return rv; + } + }; +} + +function __embind_register_emval(emvalType, name) { + name = Pointer_stringify(name); + validateType(emvalType, name); + typeRegistry[emvalType] = { + name: name, + toWireType: function(destructors, value) { + return __emval_register(value); + }, + fromWireType: function(handle) { + var rv = _emval_handle_array[handle].value; + __emval_decref(handle); + return rv; + } + }; +} + +var BindingError = Error; +/** @expose */ +Module.BindingError = BindingError; + +function typeName(typeID) { + // could use our carnal knowledge of RTTI but for now just return the pointer... + return typeID; +} + +function requireRegisteredType(type, humanName) { + var impl = typeRegistry[type]; + if (undefined === impl) { + throw new BindingError(humanName + " has unknown type: " + typeName(type)); + } + return impl; +} + +function requireArgumentTypes(argCount, argTypes, name) { + var argTypeImpls = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var argType = HEAP32[(argTypes >> 2) + i]; + argTypeImpls[i] = requireRegisteredType(argType, name + " parameter " + i); + } + return argTypeImpls; +} + +function runDestructors(destructors) { + while (destructors.length) { + var ptr = destructors.pop(); + var del = destructors.pop(); + del(ptr); + } +} + +function __embind_register_function(name, returnType, argCount, argTypes, invoker, fn) { + name = Pointer_stringify(name); + returnType = requireRegisteredType(returnType, "Function " + name + " return value"); + invoker = FUNCTION_TABLE[invoker]; + argTypes = requireArgumentTypes(argCount, argTypes, name); + + Module[name] = function() { + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + var destructors = []; + var args = new Array(argCount + 1); + args[0] = fn; + for (var i = 0; i < argCount; ++i) { + args[i + 1] = argTypes[i].toWireType(destructors, arguments[i]); + } + var rv = returnType.fromWireType(invoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; +} + +function __embind_register_tuple(tupleType, name, constructor, destructor) { + name = Pointer_stringify(name); + constructor = FUNCTION_TABLE[constructor]; + destructor = FUNCTION_TABLE[destructor]; + + var elements = []; + + typeRegistry[tupleType] = { + name: name, + elements: elements, + fromWireType: function(ptr) { + var len = elements.length; + var rv = new Array(len); + for (var i = 0; i < len; ++i) { + rv[i] = elements[i].read(ptr); + } + destructor(ptr); + return rv; + }, + toWireType: function(destructors, o) { + var len = elements.length; + if (len !== o.length) { + throw new TypeError("Incorrect number of tuple elements"); + } + var ptr = constructor(); + for (var i = 0; i < len; ++i) { + elements[i].write(ptr, o[i]); + } + destructors.push(destructor); + destructors.push(ptr); + return ptr; + } + }; +} + +function copyMemberPointer(memberPointer, memberPointerSize) { + var copy = _malloc(memberPointerSize); + if (!copy) { + throw new Error('Failed to allocate member pointer copy'); + } + _memcpy(copy, memberPointer, memberPointerSize); + return copy; +} + +function __embind_register_tuple_element( + tupleType, + elementType, + getter, + setter, + memberPointerSize, + memberPointer +) { + tupleType = requireRegisteredType(tupleType, 'tuple'); + elementType = requireRegisteredType(elementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; + memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + + tupleType.elements.push({ + read: function(ptr) { + return elementType.fromWireType(getter(ptr, memberPointer)); + }, + write: function(ptr, o) { + var destructors = []; + setter(ptr, memberPointer, elementType.toWireType(destructors, o)); + runDestructors(destructors); + } + }); +} + +function __embind_register_tuple_element_accessor( + tupleType, + elementType, + staticGetter, + getterSize, + getter, + staticSetter, + setterSize, + setter +) { + tupleType = requireRegisteredType(tupleType, 'tuple'); + elementType = requireRegisteredType(elementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]"); + staticGetter = FUNCTION_TABLE[staticGetter]; + getter = copyMemberPointer(getter, getterSize); + staticSetter = FUNCTION_TABLE[staticSetter]; + setter = copyMemberPointer(setter, setterSize); + + tupleType.elements.push({ + read: function(ptr) { + return elementType.fromWireType(staticGetter(ptr, HEAP32[getter >> 2])); + }, + write: function(ptr, o) { + var destructors = []; + staticSetter( + ptr, + HEAP32[setter >> 2], + elementType.toWireType(destructors, o)); + runDestructors(destructors); + } + }); +} + +function __embind_register_struct( + structType, + name, + constructor, + destructor +) { + name = Pointer_stringify(name); + constructor = FUNCTION_TABLE[constructor]; + destructor = FUNCTION_TABLE[destructor]; + + typeRegistry[structType] = { + fields: {}, + fromWireType: function(ptr) { + var fields = this.fields; + var rv = {}; + for (var i in fields) { + rv[i] = fields[i].read(ptr); + } + destructor(ptr); + return rv; + }, + toWireType: function(destructors, o) { + var fields = this.fields; + for (var fieldName in fields) { + if (!(fieldName in o)) { + throw new TypeError('Missing field'); + } + } + var ptr = constructor(); + for (var fieldName in fields) { + fields[fieldName].write(ptr, o[fieldName]); + } + destructors.push(destructor); + destructors.push(ptr); + return ptr; + } + }; +} + +function __embind_register_struct_field( + structType, + fieldName, + fieldType, + getter, + setter, + memberPointerSize, + memberPointer +) { + structType = requireRegisteredType(structType, 'struct'); + fieldName = Pointer_stringify(fieldName); + fieldType = requireRegisteredType(fieldType, 'field "' + structType.name + '.' + fieldName + '"'); + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; + memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + + structType.fields[fieldName] = { + read: function(ptr) { + return fieldType.fromWireType(getter(ptr, memberPointer)); + }, + write: function(ptr, o) { + var destructors = []; + setter(ptr, memberPointer, fieldType.toWireType(destructors, o)); + runDestructors(destructors); + } + }; +} + +function __embind_register_class( + classType, + name, + destructor +) { + name = Pointer_stringify(name); + destructor = FUNCTION_TABLE[destructor]; + + var Handle = createNamedFunction(name, function(ptr) { + this.count = {value: 1}; + this.ptr = ptr; + }); + + Handle.prototype.clone = function() { + if (!this.ptr) { + throw new BindingError(classType.name + ' instance already deleted'); + } + + var clone = Object.create(Handle.prototype); + clone.count = this.count; + clone.ptr = this.ptr; + + clone.count.value += 1; + return clone; + }; + + Handle.prototype.move = function() { + var rv = this.clone(); + this.delete(); + return rv; + }; + + Handle.prototype['delete'] = function() { + if (!this.ptr) { + throw new BindingError(classType.name + ' instance already deleted'); + } + + this.count.value -= 1; + if (0 === this.count.value) { + destructor(this.ptr); + } + this.ptr = undefined; + }; + + var constructor = createNamedFunction(name, function() { + var body = constructor.body; + body.apply(this, arguments); + }); + constructor.prototype = Object.create(Handle.prototype); + + typeRegistry[classType] = { + name: name, + constructor: constructor, + Handle: Handle, + fromWireType: function(ptr) { + return new Handle(ptr); + }, + toWireType: function(destructors, o) { + return o.ptr; + } + }; + + Module[name] = constructor; +} + +function __embind_register_class_constructor( + classType, + argCount, + argTypes, + constructor +) { + classType = requireRegisteredType(classType, 'class'); + var humanName = 'constructor ' + classType.name; + argTypes = requireArgumentTypes(argCount, argTypes, humanName); + constructor = FUNCTION_TABLE[constructor]; + + classType.constructor.body = function() { + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + var destructors = []; + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i]); + } + + var ptr = constructor.apply(null, args); + runDestructors(destructors); + classType.Handle.call(this, ptr); + }; +} + +function __embind_register_class_method( + classType, + methodName, + returnType, + argCount, + argTypes, + invoker, + memberFunctionSize, + memberFunction +) { + classType = requireRegisteredType(classType, 'class'); + methodName = Pointer_stringify(methodName); + var humanName = classType.name + '.' + methodName; + returnType = requireRegisteredType(returnType, 'method ' + humanName + ' return value'); + argTypes = requireArgumentTypes(argCount, argTypes, 'method ' + humanName); + invoker = FUNCTION_TABLE[invoker]; + memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); + + classType.Handle.prototype[methodName] = function() { + if (!this.ptr) { + throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + } + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + + var destructors = []; + var args = new Array(argCount + 2); + args[0] = this.ptr; + args[1] = memberFunction; + for (var i = 0; i < argCount; ++i) { + args[i + 2] = argTypes[i].toWireType(destructors, arguments[i]); + } + + var rv = returnType.fromWireType(invoker.apply(null, args)); + runDestructors(destructors); + return rv; + }; +} + +function __embind_register_class_classmethod( + classType, + methodName, + returnType, + argCount, + argTypes, + method +) { + classType = requireRegisteredType(classType, 'class'); + methodName = Pointer_stringify(methodName); + var humanName = classType.name + '.' + methodName; + returnType = requireRegisteredType(returnType, 'classmethod ' + humanName + ' return value'); + argTypes = requireArgumentTypes(argCount, argTypes, 'classmethod ' + humanName); + method = FUNCTION_TABLE[method]; + + classType.constructor[methodName] = function() { + if (arguments.length !== argCount) { + throw new BindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + argCount); + } + + var destructors = []; + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + args[i] = argTypes[i].toWireType(destructors, arguments[i]); + } + + var rv = returnType.fromWireType(method.apply(null, args)); + runDestructors(destructors); + return rv; + }; +} + +function __embind_register_class_field( + classType, + fieldName, + fieldType, + getter, + setter, + memberPointerSize, + memberPointer +) { + classType = requireRegisteredType(classType, 'class'); + fieldName = Pointer_stringify(fieldName); + var humanName = classType.name + '.' + fieldName; + fieldType = requireRegisteredType(fieldType, 'field ' + humanName); + getter = FUNCTION_TABLE[getter]; + setter = FUNCTION_TABLE[setter]; + memberPointer = copyMemberPointer(memberPointer, memberPointerSize); + + Object.defineProperty(classType.Handle.prototype, fieldName, { + get: function() { + if (!this.ptr) { + throw new BindingError('cannot access emscripten binding field ' + humanName + ' on deleted object'); + } + return fieldType.fromWireType(getter(this.ptr, memberPointer)); + }, + set: function(v) { + if (!this.ptr) { + throw new BindingError('cannot modify emscripten binding field ' + humanName + ' on deleted object'); + } + var destructors = []; + setter(this.ptr, memberPointer, fieldType.toWireType(destructors, v)); + runDestructors(destructors); + }, + enumerable: true + }); +} + +function __embind_register_enum( + enumType, + name +) { + name = Pointer_stringify(name); + + function Enum() { + } + Enum.values = {}; + + typeRegistry[enumType] = { + name: name, + constructor: Enum, + toWireType: function(destructors, c) { + return c.value; + }, + fromWireType: function(c) { + return Enum.values[c]; + }, + }; + + Module[name] = Enum; +} + +function __embind_register_enum_value( + enumType, + name, + enumValue +) { + enumType = requireRegisteredType(enumType, 'enum'); + name = Pointer_stringify(name); + + var Enum = enumType.constructor; + + var Value = Object.create(enumType.constructor.prototype, { + value: {value: enumValue}, + constructor: {value: createNamedFunction(enumType.name + '_' + name, function() {})}, + }); + Enum.values[enumValue] = Value; + Enum[name] = Value; +} + +function __embind_register_interface( + interfaceType, + name, + constructor, + destructor +) { + name = Pointer_stringify(name); + constructor = FUNCTION_TABLE[constructor]; + destructor = FUNCTION_TABLE[destructor]; + + typeRegistry[interfaceType] = { + name: name, + toWireType: function(destructors, o) { + var handle = __emval_register(o); + var ptr = constructor(handle); + destructors.push(destructor); + destructors.push(ptr); + return ptr; + }, + }; +} + diff --git a/src/embind/emval.js b/src/embind/emval.js new file mode 100644 index 00000000..9574ab37 --- /dev/null +++ b/src/embind/emval.js @@ -0,0 +1,111 @@ +/*global Module*/ +/*global HEAP32*/ +/*global Pointer_stringify, writeStringToMemory*/ +/*global requireRegisteredType*/ + +var _emval_handle_array = []; +var _emval_free_list = []; + +// Public JS API + +/** @expose */ +Module.count_emval_handles = function() { + return _emval_handle_array.length; +}; + +// Private C++ API + +function __emval_register(value) { + var handle = _emval_free_list.length ? + _emval_free_list.pop() : + _emval_handle_array.length; + _emval_handle_array[handle] = {refcount: 1, value: value}; + return handle; +} + +function __emval_incref(handle) { + _emval_handle_array[handle].refcount += 1; +} + +function __emval_decref(handle) { + if (0 === --_emval_handle_array[handle].refcount) { + delete _emval_handle_array[handle]; + _emval_free_list.push(handle); + + var actual_length = _emval_handle_array.length; + while (actual_length > 0 && _emval_handle_array[actual_length - 1] === undefined) { + --actual_length; + } + _emval_handle_array.length = actual_length; + } +} + +function __emval_new_object() { + return __emval_register({}); +} + +function __emval_new_long(value) { + return __emval_register(value); +} + +function __emval_new_cstring(str) { + return __emval_register(Pointer_stringify(str)); +} + +function __emval_get_property(handle, k) { + k = Pointer_stringify(k); + return __emval_register(_emval_handle_array[handle].value[k]); +} + +function __emval_get_property_by_long(handle, k) { + return __emval_register(_emval_handle_array[handle].value[k]); +} + +function __emval_get_property_by_unsigned_long(handle, k) { + return __emval_register(_emval_handle_array[handle].value[k]); +} + +function __emval_set_property(handle, k, value) { + k = Pointer_stringify(k); + _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; +} + +function __emval_set_property_by_int(handle, k, value) { + _emval_handle_array[handle].value[k] = _emval_handle_array[value].value; +} + +function __emval_as(handle, returnType) { + returnType = requireRegisteredType(returnType, 'emval::as'); + var destructors = []; + // caller owns destructing + return returnType.toWireType(destructors, _emval_handle_array[handle].value); +} + +function __emval_call(handle, argCount, argTypes) { + var args = Array.prototype.slice.call(arguments, 3); + var fn = _emval_handle_array[handle].value; + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var argType = requireRegisteredType( + HEAP32[(argTypes >> 2) + i], + "parameter " + i); + a[i] = argType.fromWireType(args[i]); + } + var rv = fn.apply(undefined, a); + return __emval_register(rv); +} + +function __emval_call_method(handle, name, argCount, argTypes) { + name = Pointer_stringify(name); + var args = Array.prototype.slice.call(arguments, 4); + var obj = _emval_handle_array[handle].value; + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var argType = requireRegisteredType( + HEAP32[(argTypes >> 2) + i], + "parameter " + i); + a[i] = argType.fromWireType(args[i]); + } + var rv = obj[name].apply(obj, a); + return __emval_register(rv); +} diff --git a/src/jsifier.js b/src/jsifier.js index 8021f8a1..02459193 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -358,11 +358,21 @@ function JSify(data, functionsOnly, givenFunctions) { item.JS = 'var ' + item.ident + ';'; // Set the actual value in a postset, since it may be a global variable. We also order by dependencies there var value = Variables.globals[item.ident].resolvedAlias = finalizeLLVMParameter(item.value); + var fix = ''; + if (BUILD_AS_SHARED_LIB == 2 && !item.private_) { + var target = item.ident; + if (isFunctionType(item.type)) { + target = item.value.ident; // the other side does not know this is an alias/function table index. So make it the alias target. + var varData = Variables.globals[target]; + assert(!varData, 'multi-level aliasing does not work yet in shared lib 2 exports'); + } + fix = '\nif (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + target + ' }' + } ret.push({ intertype: 'GlobalVariablePostSet', ident: item.ident, dependencies: set([value]), - JS: item.ident + ' = ' + value + ';' + JS: item.ident + ' = ' + value + ';' + fix }); return ret; } @@ -1243,7 +1253,7 @@ function JSify(data, functionsOnly, givenFunctions) { // Load runtime-linked libraries RUNTIME_LINKED_LIBS.forEach(function(lib) { - print('eval(read("' + lib + '"))(FUNCTION_TABLE.length, this);'); + print('eval(Module["read"]("' + lib + '"))(FUNCTION_TABLE.length, this);'); }); print(postParts[1]); diff --git a/src/library.js b/src/library.js index 594ba931..69642151 100644 --- a/src/library.js +++ b/src/library.js @@ -382,12 +382,14 @@ LibraryManager.library = { // You can also call this with a typed array instead of a url. It will then // do preloading for the Image/Audio part, as if the typed array were the // result of an XHR that you did manually. - createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror) { + createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile) { Browser.ensureObjects(); var fullname = FS.joinPath([parent, name], true); function processData(byteArray) { function finish(byteArray) { - FS.createDataFile(parent, name, byteArray, canRead, canWrite); + if (!dontCreateFile) { + FS.createDataFile(parent, name, byteArray, canRead, canWrite); + } if (onload) onload(); removeRunDependency('cp ' + fullname); } @@ -1286,7 +1288,7 @@ LibraryManager.library = { return 0; case {{{ cDefine('F_SETOWN') }}}: case {{{ cDefine('F_GETOWN') }}}: - // These are for sockets. We don't have them implemented (yet?). + // These are for sockets. We don't have them fully implemented yet. ___setErrNo(ERRNO_CODES.EINVAL); return -1; default: @@ -2498,8 +2500,8 @@ LibraryManager.library = { while ((curr < max_ || isNaN(max_)) && next > 0) { if (!(next in __scanString.whiteSpace) && // stop on whitespace (type == 's' || - ((type === 'd' || type == 'u') && ((next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) || - (first && next == '-'.charCodeAt(0)))) || + ((type === 'd' || type == 'u' || type == 'i') && ((next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) || + (first && next == '-'.charCodeAt(0)))) || (type === 'x' && (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0) || next >= 'a'.charCodeAt(0) && next <= 'f'.charCodeAt(0) || next >= 'A'.charCodeAt(0) && next <= 'F'.charCodeAt(0)))) && @@ -2518,7 +2520,7 @@ LibraryManager.library = { var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; argIndex += Runtime.getNativeFieldSize('void*'); switch (type) { - case 'd': case 'u': + case 'd': case 'u': case 'i': if (half) { {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i16') }}}; } else { @@ -6398,14 +6400,18 @@ LibraryManager.library = { ntohl: 'htonl', ntohs: 'htons', - inet_pton__deps: ['__setErrNo', '$ERRNO_CODES'], + inet_addr: function(ptr) { + var b = Pointer_stringify(ptr).split("."); + if (b.length !== 4) return -1; // we return -1 for error, and otherwise a uint32. this helps inet_pton differentiate + return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0; + }, + + inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_addr'], inet_pton: function(af, src, dst) { // int af, const char *src, void *dst if ((af ^ {{{ cDefine("AF_INET") }}}) !== 0) { ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); return -1; } - var b = Pointer_stringify(src).split("."); - if (b.length !== 4) return 0; - var ret = Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24); - if (isNaN(ret)) return 0; + var ret = _inet_addr(src); + if (ret == -1 || isNaN(ret)) return 0; setValue(dst, ret, 'i32'); return 1; }, @@ -6423,7 +6429,62 @@ LibraryManager.library = { }, // ========================================================================== - // sockets + // netdb.h + // ========================================================================== + + // All we can do is alias names to ips. you give this a name, it returns an + // "ip" that we later know to use as a name. There is no way to do actual + // name resolving clientside in a browser. + // we do the aliasing in 172.29.*.*, giving us 65536 possibilities + // note: lots of leaking here! + __hostent_struct_layout: Runtime.generateStructInfo([ + ['i8*', 'h_name'], + ['i8**', 'h_aliases'], + ['i32', 'h_addrtype'], + ['i32', 'h_length'], + ['i8**', 'h_addr_list'], + ]), + gethostbyname__deps: ['__hostent_struct_layout'], + gethostbyname: function(name) { + name = Pointer_stringify(name); + if (!_gethostbyname.id) { + _gethostbyname.id = 1; + _gethostbyname.table = {}; + } + var id = _gethostbyname.id++; + assert(id < 65535); + var fakeAddr = 172 | (29 << 8) | ((id & 0xff) << 16) | ((id & 0xff00) << 24); + _gethostbyname.table[id] = name; + // generate hostent + var ret = _malloc(___hostent_struct_layout.__size__); + var nameBuf = _malloc(name.length+1); + writeStringToMemory(name, nameBuf); + setValue(ret+___hostent_struct_layout.h_name, nameBuf, 'i8*'); + var aliasesBuf = _malloc(4); + setValue(aliasesBuf, 0, 'i8*'); + setValue(ret+___hostent_struct_layout.h_aliases, aliasesBuf, 'i8**'); + setValue(ret+___hostent_struct_layout.h_addrtype, {{{ cDefine("AF_INET") }}}, 'i32'); + setValue(ret+___hostent_struct_layout.h_length, 4, 'i32'); + var addrListBuf = _malloc(12); + setValue(addrListBuf, addrListBuf+8, 'i32*'); + setValue(addrListBuf+4, 0, 'i32*'); + setValue(addrListBuf+8, fakeAddr, 'i32'); + setValue(ret+___hostent_struct_layout.h_addr_list, addrListBuf, 'i8**'); + return ret; + }, + + gethostbyname_r__deps: ['gethostbyname'], + gethostbyname_r: function(name, hostData, buffer, bufferSize, hostEntry, errnum) { + var data = _gethostbyname(name); + _memcpy(hostData, data, ___hostent_struct_layout.__size__); + _free(data); + setValue(errnum, 0, 'i32'); + return 0; + }, + + // ========================================================================== + // sockets. Note that the implementation assumes all sockets are always + // nonblocking // ============================================================= |