jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: #include jbe/bsw@0: jbe/bsw@0: static FILE *multirand_dev; jbe/bsw@0: jbe/bsw@0: static lua_Integer multirand_range( jbe/bsw@0: lua_State *L, lua_Integer from, lua_Integer to jbe/bsw@0: ) { jbe/bsw@0: lua_Integer range; jbe/bsw@0: int bits = 0; jbe/bsw@0: lua_Integer bit_mask = 0; jbe/bsw@0: if (to < from) return luaL_error(L, "Assertion failed in C."); jbe/bsw@0: range = to - from; jbe/bsw@0: { jbe/bsw@0: lua_Integer tmp; jbe/bsw@0: tmp = range; jbe/bsw@0: while (tmp) { jbe/bsw@0: bits++; jbe/bsw@0: bit_mask <<= 1; jbe/bsw@0: bit_mask |= 1; jbe/bsw@0: tmp >>= 1; jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: while (1) { jbe/bsw@0: int i; jbe/bsw@0: lua_Integer rnd = 0; jbe/bsw@0: for (i = 0; i < (bits + 7) / 8; i++) { jbe/bsw@0: int b; jbe/bsw@0: b = getc(multirand_dev); jbe/bsw@0: if (b == EOF) { jbe/bsw@0: return luaL_error(L, "I/O error while reading random."); jbe/bsw@0: } jbe/bsw@0: rnd = (rnd << 8) | (unsigned char)b; jbe/bsw@0: } jbe/bsw@0: rnd &= bit_mask; jbe/bsw@0: if (rnd <= range) return from + rnd; jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: static int multirand_integer(lua_State *L) { jbe/bsw@0: lua_Integer arg1, arg2; jbe/bsw@0: lua_settop(L, 2); jbe/bsw@0: arg1 = luaL_checkinteger(L, 1); jbe/bsw@0: if (lua_toboolean(L, 2)) { jbe/bsw@0: arg2 = luaL_optinteger(L, 2, 0); jbe/bsw@0: if (arg1 > arg2) { jbe/bsw@0: return luaL_error(L, jbe/bsw@0: "Upper boundary is smaller than lower boundary." jbe/bsw@0: ); jbe/bsw@0: } else if (arg1 == arg2) { jbe/bsw@0: lua_pushinteger(L, arg1); jbe/bsw@0: } else { jbe/bsw@0: lua_pushinteger(L, multirand_range(L, arg1, arg2)); jbe/bsw@0: } jbe/bsw@0: } else { jbe/bsw@0: luaL_argcheck(L, arg1 >= 1, 1, "smaller than 1"); jbe/bsw@0: lua_pushinteger(L, multirand_range(L, 1, arg1)); jbe/bsw@0: } jbe/bsw@0: return 1; jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: static int multirand_fraction(lua_State *L) { jbe/bsw@0: int i, j; jbe/bsw@0: lua_settop(L, 0); jbe/bsw@0: lua_Number rnd = 0.0; jbe/bsw@0: for (i = 0; i < 8; i++) { jbe/bsw@0: int b; jbe/bsw@0: unsigned char c; jbe/bsw@0: b = getc(multirand_dev); jbe/bsw@0: if (b == EOF) return luaL_error(L, "I/O error while reading random."); jbe/bsw@0: c = (unsigned char) b; jbe/bsw@0: for (j = 0; j < 8; j++) { jbe/bsw@0: rnd /= 2.0; jbe/bsw@0: if (c & 1) rnd += 0.5; jbe/bsw@0: c >>= 1; jbe/bsw@0: } jbe/bsw@0: } jbe/bsw@0: lua_pushnumber(L, rnd); jbe/bsw@0: return 1; jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: static int multirand_string(lua_State *L) { jbe/bsw@0: int length; jbe/bsw@0: const char *charset; jbe/bsw@0: size_t charset_size; jbe/bsw@0: luaL_Buffer buf; jbe/bsw@0: lua_settop(L, 2); jbe/bsw@0: length = luaL_checkint(L, 1); jbe/bsw@0: charset = luaL_optlstring(L, 2, "abcdefghijklmnopqrstuvwxyz", &charset_size); jbe/bsw@0: if (charset_size > 32767) { jbe/bsw@0: return luaL_error(L, "Set of chars is too big."); jbe/bsw@0: } jbe/bsw@0: luaL_buffinit(L, &buf); jbe/bsw@0: for (; length > 0; length--) { jbe/bsw@0: luaL_addchar(&buf, jbe/bsw@0: charset[multirand_range(L, 0, (lua_Integer)charset_size - 1)] jbe/bsw@0: ); jbe/bsw@0: } jbe/bsw@0: luaL_pushresult(&buf); jbe/bsw@0: return 1; jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: static const struct luaL_Reg multirand_module_functions[] = { jbe/bsw@0: {"integer", multirand_integer}, jbe/bsw@0: {"fraction", multirand_fraction}, jbe/bsw@0: {"string", multirand_string}, jbe/bsw@0: {NULL, NULL} jbe/bsw@0: }; jbe/bsw@0: jbe/bsw@0: int luaopen_multirand(lua_State *L) { jbe/bsw@0: const char *module_name; jbe/bsw@0: lua_settop(L, 1); jbe/bsw@0: module_name = lua_tostring(L, 1); jbe/bsw@0: if (module_name) { jbe/bsw@0: luaL_register(L, module_name, multirand_module_functions); jbe/bsw@0: } else { jbe/bsw@0: luaL_register(L, "multirand", multirand_module_functions); jbe/bsw@0: } jbe/bsw@0: lua_replace(L, 1); jbe/bsw@0: multirand_dev = fopen("/dev/urandom", "r"); jbe/bsw@0: if (!multirand_dev) return luaL_error(L, "Could not open /dev/urandom."); jbe/bsw@0: return 1; jbe/bsw@0: }