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