| 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 }
 |