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