| rev | line source | 
| jbe/bsw@0 | 1 #include <lua.h> | 
| jbe/bsw@0 | 2 #include <lauxlib.h> | 
| jbe/bsw@0 | 3 #include <dirent.h> | 
| jbe/bsw@0 | 4 | 
| jbe/bsw@0 | 5 static FILE *multirand_dev; | 
| jbe/bsw@0 | 6 | 
| jbe/bsw@0 | 7 static lua_Integer multirand_range( | 
| jbe/bsw@0 | 8   lua_State *L, lua_Integer from, lua_Integer to | 
| jbe/bsw@0 | 9 ) { | 
| jbe/bsw@0 | 10   lua_Integer range; | 
| jbe/bsw@0 | 11   int bits = 0; | 
| jbe/bsw@0 | 12   lua_Integer bit_mask = 0; | 
| jbe/bsw@0 | 13   if (to < from) return luaL_error(L, "Assertion failed in C."); | 
| jbe/bsw@0 | 14   range = to - from; | 
| jbe/bsw@0 | 15   { | 
| jbe/bsw@0 | 16     lua_Integer tmp; | 
| jbe/bsw@0 | 17     tmp = range; | 
| jbe/bsw@0 | 18     while (tmp) { | 
| jbe/bsw@0 | 19       bits++; | 
| jbe/bsw@0 | 20       bit_mask <<= 1; | 
| jbe/bsw@0 | 21       bit_mask |= 1; | 
| jbe/bsw@0 | 22       tmp >>= 1; | 
| jbe/bsw@0 | 23     } | 
| jbe/bsw@0 | 24   } | 
| jbe/bsw@0 | 25   while (1) { | 
| jbe/bsw@0 | 26     int i; | 
| jbe/bsw@0 | 27     lua_Integer rnd = 0; | 
| jbe/bsw@0 | 28     for (i = 0; i < (bits + 7) / 8; i++) { | 
| jbe/bsw@0 | 29       int b; | 
| jbe/bsw@0 | 30       b = getc(multirand_dev); | 
| jbe/bsw@0 | 31       if (b == EOF) { | 
| jbe/bsw@0 | 32         return luaL_error(L, "I/O error while reading random."); | 
| jbe/bsw@0 | 33       } | 
| jbe/bsw@0 | 34       rnd = (rnd << 8) | (unsigned char)b; | 
| jbe/bsw@0 | 35     } | 
| jbe/bsw@0 | 36     rnd &= bit_mask; | 
| jbe/bsw@0 | 37     if (rnd <= range) return from + rnd; | 
| jbe/bsw@0 | 38   } | 
| jbe/bsw@0 | 39 } | 
| jbe/bsw@0 | 40 | 
| jbe/bsw@0 | 41 static int multirand_integer(lua_State *L) { | 
| jbe/bsw@0 | 42   lua_Integer arg1, arg2; | 
| jbe/bsw@0 | 43   lua_settop(L, 2); | 
| jbe/bsw@0 | 44   arg1 = luaL_checkinteger(L, 1); | 
| jbe/bsw@0 | 45   if (lua_toboolean(L, 2)) { | 
| jbe/bsw@0 | 46     arg2 = luaL_optinteger(L, 2, 0); | 
| jbe/bsw@0 | 47     if (arg1 > arg2) { | 
| jbe/bsw@0 | 48       return luaL_error(L, | 
| jbe/bsw@0 | 49         "Upper boundary is smaller than lower boundary." | 
| jbe/bsw@0 | 50       ); | 
| jbe/bsw@0 | 51     } else if (arg1 == arg2) { | 
| jbe/bsw@0 | 52       lua_pushinteger(L, arg1); | 
| jbe/bsw@0 | 53     } else { | 
| jbe/bsw@0 | 54       lua_pushinteger(L, multirand_range(L, arg1, arg2)); | 
| jbe/bsw@0 | 55     } | 
| jbe/bsw@0 | 56   } else { | 
| jbe/bsw@0 | 57     luaL_argcheck(L, arg1 >= 1, 1, "smaller than 1"); | 
| jbe/bsw@0 | 58     lua_pushinteger(L, multirand_range(L, 1, arg1)); | 
| jbe/bsw@0 | 59   } | 
| jbe/bsw@0 | 60   return 1; | 
| jbe/bsw@0 | 61 } | 
| jbe/bsw@0 | 62 | 
| jbe/bsw@0 | 63 static int multirand_fraction(lua_State *L) { | 
| jbe/bsw@0 | 64   int i, j; | 
| jbe/bsw@0 | 65   lua_settop(L, 0); | 
| jbe/bsw@0 | 66   lua_Number rnd = 0.0; | 
| jbe/bsw@0 | 67   for (i = 0; i < 8; i++) { | 
| jbe/bsw@0 | 68     int b; | 
| jbe/bsw@0 | 69     unsigned char c; | 
| jbe/bsw@0 | 70     b = getc(multirand_dev); | 
| jbe/bsw@0 | 71     if (b == EOF) return luaL_error(L, "I/O error while reading random."); | 
| jbe/bsw@0 | 72     c = (unsigned char) b; | 
| jbe/bsw@0 | 73     for (j = 0; j < 8; j++) { | 
| jbe/bsw@0 | 74       rnd /= 2.0; | 
| jbe/bsw@0 | 75       if (c & 1) rnd += 0.5; | 
| jbe/bsw@0 | 76       c >>= 1; | 
| jbe/bsw@0 | 77     } | 
| jbe/bsw@0 | 78   } | 
| jbe/bsw@0 | 79   lua_pushnumber(L, rnd); | 
| jbe/bsw@0 | 80   return 1; | 
| jbe/bsw@0 | 81 } | 
| jbe/bsw@0 | 82 | 
| jbe/bsw@0 | 83 static int multirand_string(lua_State *L) { | 
| jbe/bsw@0 | 84   int length; | 
| jbe/bsw@0 | 85   const char *charset; | 
| jbe/bsw@0 | 86   size_t charset_size; | 
| jbe/bsw@0 | 87   luaL_Buffer buf; | 
| jbe/bsw@0 | 88   lua_settop(L, 2); | 
| jbe/bsw@0 | 89   length = luaL_checkint(L, 1); | 
| jbe/bsw@0 | 90   charset = luaL_optlstring(L, 2, "abcdefghijklmnopqrstuvwxyz", &charset_size); | 
| jbe/bsw@0 | 91   if (charset_size > 32767) { | 
| jbe/bsw@0 | 92     return luaL_error(L, "Set of chars is too big."); | 
| jbe/bsw@0 | 93   } | 
| jbe/bsw@0 | 94   luaL_buffinit(L, &buf); | 
| jbe/bsw@0 | 95   for (; length > 0; length--) { | 
| jbe/bsw@0 | 96     luaL_addchar(&buf, | 
| jbe/bsw@0 | 97       charset[multirand_range(L, 0, (lua_Integer)charset_size - 1)] | 
| jbe/bsw@0 | 98     ); | 
| jbe/bsw@0 | 99   } | 
| jbe/bsw@0 | 100   luaL_pushresult(&buf); | 
| jbe/bsw@0 | 101   return 1; | 
| jbe/bsw@0 | 102 } | 
| jbe/bsw@0 | 103 | 
| jbe/bsw@0 | 104 static const struct luaL_Reg multirand_module_functions[] = { | 
| jbe/bsw@0 | 105   {"integer",  multirand_integer}, | 
| jbe/bsw@0 | 106   {"fraction", multirand_fraction}, | 
| jbe/bsw@0 | 107   {"string",   multirand_string}, | 
| jbe/bsw@0 | 108   {NULL, NULL} | 
| jbe/bsw@0 | 109 }; | 
| jbe/bsw@0 | 110 | 
| jbe/bsw@0 | 111 int luaopen_multirand(lua_State *L) { | 
| jbe/bsw@0 | 112   const char *module_name; | 
| jbe/bsw@0 | 113   lua_settop(L, 1); | 
| jbe/bsw@0 | 114   module_name = lua_tostring(L, 1); | 
| jbe/bsw@0 | 115   if (module_name) { | 
| jbe/bsw@0 | 116     luaL_register(L, module_name, multirand_module_functions); | 
| jbe/bsw@0 | 117   } else { | 
| jbe/bsw@0 | 118     luaL_register(L, "multirand", multirand_module_functions); | 
| jbe/bsw@0 | 119   } | 
| jbe/bsw@0 | 120   lua_replace(L, 1); | 
| jbe/bsw@0 | 121   multirand_dev = fopen("/dev/urandom", "r"); | 
| jbe/bsw@0 | 122   if (!multirand_dev) return luaL_error(L, "Could not open /dev/urandom."); | 
| jbe/bsw@0 | 123   return 1; | 
| jbe/bsw@0 | 124 } |