webmcp
diff libraries/multirand/multirand.c @ 0:9fdfb27f8e67
Version 1.0.0
author | jbe/bsw |
---|---|
date | Sun Oct 25 12:00:00 2009 +0100 (2009-10-25) |
parents | |
children | 3d43a5cf17c1 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libraries/multirand/multirand.c Sun Oct 25 12:00:00 2009 +0100 1.3 @@ -0,0 +1,124 @@ 1.4 +#include <lua.h> 1.5 +#include <lauxlib.h> 1.6 +#include <dirent.h> 1.7 + 1.8 +static FILE *multirand_dev; 1.9 + 1.10 +static lua_Integer multirand_range( 1.11 + lua_State *L, lua_Integer from, lua_Integer to 1.12 +) { 1.13 + lua_Integer range; 1.14 + int bits = 0; 1.15 + lua_Integer bit_mask = 0; 1.16 + if (to < from) return luaL_error(L, "Assertion failed in C."); 1.17 + range = to - from; 1.18 + { 1.19 + lua_Integer tmp; 1.20 + tmp = range; 1.21 + while (tmp) { 1.22 + bits++; 1.23 + bit_mask <<= 1; 1.24 + bit_mask |= 1; 1.25 + tmp >>= 1; 1.26 + } 1.27 + } 1.28 + while (1) { 1.29 + int i; 1.30 + lua_Integer rnd = 0; 1.31 + for (i = 0; i < (bits + 7) / 8; i++) { 1.32 + int b; 1.33 + b = getc(multirand_dev); 1.34 + if (b == EOF) { 1.35 + return luaL_error(L, "I/O error while reading random."); 1.36 + } 1.37 + rnd = (rnd << 8) | (unsigned char)b; 1.38 + } 1.39 + rnd &= bit_mask; 1.40 + if (rnd <= range) return from + rnd; 1.41 + } 1.42 +} 1.43 + 1.44 +static int multirand_integer(lua_State *L) { 1.45 + lua_Integer arg1, arg2; 1.46 + lua_settop(L, 2); 1.47 + arg1 = luaL_checkinteger(L, 1); 1.48 + if (lua_toboolean(L, 2)) { 1.49 + arg2 = luaL_optinteger(L, 2, 0); 1.50 + if (arg1 > arg2) { 1.51 + return luaL_error(L, 1.52 + "Upper boundary is smaller than lower boundary." 1.53 + ); 1.54 + } else if (arg1 == arg2) { 1.55 + lua_pushinteger(L, arg1); 1.56 + } else { 1.57 + lua_pushinteger(L, multirand_range(L, arg1, arg2)); 1.58 + } 1.59 + } else { 1.60 + luaL_argcheck(L, arg1 >= 1, 1, "smaller than 1"); 1.61 + lua_pushinteger(L, multirand_range(L, 1, arg1)); 1.62 + } 1.63 + return 1; 1.64 +} 1.65 + 1.66 +static int multirand_fraction(lua_State *L) { 1.67 + int i, j; 1.68 + lua_settop(L, 0); 1.69 + lua_Number rnd = 0.0; 1.70 + for (i = 0; i < 8; i++) { 1.71 + int b; 1.72 + unsigned char c; 1.73 + b = getc(multirand_dev); 1.74 + if (b == EOF) return luaL_error(L, "I/O error while reading random."); 1.75 + c = (unsigned char) b; 1.76 + for (j = 0; j < 8; j++) { 1.77 + rnd /= 2.0; 1.78 + if (c & 1) rnd += 0.5; 1.79 + c >>= 1; 1.80 + } 1.81 + } 1.82 + lua_pushnumber(L, rnd); 1.83 + return 1; 1.84 +} 1.85 + 1.86 +static int multirand_string(lua_State *L) { 1.87 + int length; 1.88 + const char *charset; 1.89 + size_t charset_size; 1.90 + luaL_Buffer buf; 1.91 + lua_settop(L, 2); 1.92 + length = luaL_checkint(L, 1); 1.93 + charset = luaL_optlstring(L, 2, "abcdefghijklmnopqrstuvwxyz", &charset_size); 1.94 + if (charset_size > 32767) { 1.95 + return luaL_error(L, "Set of chars is too big."); 1.96 + } 1.97 + luaL_buffinit(L, &buf); 1.98 + for (; length > 0; length--) { 1.99 + luaL_addchar(&buf, 1.100 + charset[multirand_range(L, 0, (lua_Integer)charset_size - 1)] 1.101 + ); 1.102 + } 1.103 + luaL_pushresult(&buf); 1.104 + return 1; 1.105 +} 1.106 + 1.107 +static const struct luaL_Reg multirand_module_functions[] = { 1.108 + {"integer", multirand_integer}, 1.109 + {"fraction", multirand_fraction}, 1.110 + {"string", multirand_string}, 1.111 + {NULL, NULL} 1.112 +}; 1.113 + 1.114 +int luaopen_multirand(lua_State *L) { 1.115 + const char *module_name; 1.116 + lua_settop(L, 1); 1.117 + module_name = lua_tostring(L, 1); 1.118 + if (module_name) { 1.119 + luaL_register(L, module_name, multirand_module_functions); 1.120 + } else { 1.121 + luaL_register(L, "multirand", multirand_module_functions); 1.122 + } 1.123 + lua_replace(L, 1); 1.124 + multirand_dev = fopen("/dev/urandom", "r"); 1.125 + if (!multirand_dev) return luaL_error(L, "Could not open /dev/urandom."); 1.126 + return 1; 1.127 +}