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