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/bsw@0
|
83 int 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/bsw@0
|
88 length = luaL_checkint(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@64
|
117 luaL_register(L, lua_tostring(L, 1) || "multirand", multirand_module_functions);
|
jbe@64
|
118 #endif
|
jbe/bsw@0
|
119 return 1;
|
jbe/bsw@0
|
120 }
|