webmcp
annotate libraries/multirand/multirand.c @ 110:0c4841af07a5
String truncating by counting Unicode codepoints in format.string(...)
(grapheme cluster boundary detection not implemented)
(grapheme cluster boundary detection not implemented)
| author | jbe | 
|---|---|
| date | Sun Jan 12 03:57:47 2014 +0100 (2014-01-12) | 
| parents | 593413f317f4 | 
| children | 9d15451c340a | 
| 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@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 } |