I have the following lua code snippet (that uses cairo)
cairo_set_source_rgba(cr, COLOR_FONT_R, COLOR_FONT_G, COLOR_FONT_B, 1)
cairo_set_font_size(cr, 0.011 * WINDOW_HEIGHT)
local ps_str = conky_parse("${exec ps -Ao comm,pcpu,%mem --sort=-pcpu | head -n 15}")
local processes = {}
for line in string.gmatch(ps_str, '([^\n]+)') do
table.insert(processes, line)
end
for line = 1,table.getn(processes) do
cairo_move_to(cr, 0.213 * WINDOW_WIDTH, 0.443 * WINDOW_HEIGHT + line * 0.014 * WINDOW_HEIGHT)
cairo_show_text(cr, processes[line])
end
cairo_stroke(cr)
However, when I run it through conky, I get the following error (this is in the line, 5 lines from the end).
I get the error: attempt to call a nil value (field 'getn')
I have tried a few things suggested here, but I am not sure how to fix this so was wondering if there is an easy fix.
The suggested solution in the comments works beautifully for the above but not for the following:
function conky_geo_dotspiral(cx_str, cy_str, ...)
local cx = conky_to_num(cx_str)
local cy = conky_to_num(cy_str)
local arms = math.ceil(24 / table.getn(arg)) * table.getn(arg)
local rows = 10
local radius0, radius1 = 50, 140
local dotradius = 4
for i,v_str in ipairs(arg) do
v = conky_to_num(conky_parse(v_str))
for j = i-1, arms - 1, table.getn(arg) do
local p = j / arms
for k = 0, v / rows do
local dx = cx + (radius0 + (radius1-radius0) * k/rows) * math.cos(p * 2*math.pi + k * math.pi/arms)
local dy = cy + (radius0 + (radius1-radius0) * k/rows) * math.sin(p * 2*math.pi + k * math.pi/arms)
cairo_arc (cr, dx, dy, dotradius, 0, 2 * math.pi)
cairo_fill(cr)
end
end
end
end
I get the error:
attempt to call a nil value (field 'getn')
I tried replacing table.getn(arg) with #arg but still get the error.
conky: llua_do_call: function conky_geo_dotspiral execution failed: conky_geometry.lua:155: attempt to get length of a nil value (global 'arg')
Here is the code snippet, fixed:
cairo_set_source_rgba(cr, COLOR_FONT_R, COLOR_FONT_G, COLOR_FONT_B, 1)
cairo_set_font_size(cr, 0.011 * WINDOW_HEIGHT)
local ps_str = conky_parse("${exec ps -Ao comm,pcpu,%mem --sort=-pcpu | head -n 15}")
local processes = {}
for line in string.gmatch(ps_str, '([^\n]+)') do
table.insert(processes, line)
end
for line = 1,#processes do
cairo_move_to(cr, 0.213 * WINDOW_WIDTH, 0.443 * WINDOW_HEIGHT + line * 0.014 * WINDOW_HEIGHT)
cairo_show_text(cr, processes[line])
end
cairo_stroke(cr)
And the code snippet, fixed for the second question is:
function conky_geo_dotspiral(cx_str, cy_str, ...)
local cx = conky_to_num(cx_str)
local cy = conky_to_num(cy_str)
local arms = math.ceil(24 / #arg) * #arg
local rows = 10
local radius0, radius1 = 50, 140
local dotradius = 4
for i,v_str in ipairs(arg) do
v = conky_to_num(conky_parse(v_str))
for j = i-1, arms - 1, #arg do
local p = j / arms
for k = 0, v / rows do
local dx = cx + (radius0 + (radius1-radius0) * k/rows) * math.cos(p * 2*math.pi + k * math.pi/arms)
local dy = cy + (radius0 + (radius1-radius0) * k/rows) * math.sin(p * 2*math.pi + k * math.pi/arms)
cairo_arc (cr, dx, dy, dotradius, 0, 2 * math.pi)
cairo_fill(cr)
end
end
end
return ''
end
Thanks for all the suggestions that went into fixing this code.
i am working on a calculator running in pure lua but i need help with making the out put decimals in to fractions
This solution uses continued fraction to exactly restore fractions with denominator up to 107
local function to_frac(num)
local W = math.floor(num)
local F = num - W
local pn, n, N = 0, 1
local pd, d, D = 1, 0
local x, err, q, Q
repeat
x = x and 1 / (x - q) or F
q, Q = math.floor(x), math.floor(x + 0.5)
pn, n, N = n, q*n + pn, Q*n + pn
pd, d, D = d, q*d + pd, Q*d + pd
err = F - N/D
until math.abs(err) < 1e-15
return N + D*W, D, err
end
local function print_frac(numer,denom)
print(string.format("%.14g/%d = %d/%d + %g", numer, denom, to_frac(numer/denom)))
end
print_frac(1, 4) --> 1/4 = 1/4 + 0
print_frac(12, 8) --> 12/8 = 3/2 + 0
print_frac(4, 2) --> 4/2 = 2/1 + 0
print_frac(16, 11) --> 16/11 = 16/11 + 5.55112e-17
print_frac(1, 13) --> 1/13 = 1/13 + 0
print_frac(math.sqrt(3), 1) --> 1.7320508075689/1 = 50843527/29354524 + -4.44089e-16
print_frac(math.pi, 1) --> 3.1415926535898/1 = 80143857/25510582 + 4.44089e-16
print_frac(0, 3) --> 0/3 = 0/1 + 0
print_frac(-10, 3) --> -10/3 = -10/3 + -1.11022e-16
This is not possible. You need a class which stores fractions for that.
You can achieve an approximate solution. It works nicely for things that can be expressed as fraction and blows up for everything else
local function gcd(a, b)
while a ~= 0 do
a, b = b%a, a;
end
return b;
end
local function round(a)
return math.floor(a+.5)
end
function to_frac(num)
local integer = math.floor(num)
local decimal = num - integer
if decimal == 0 then
return num, 1.0, 0.0
end
local prec = 1000000000
local gcd_ = gcd(round(decimal*prec), prec)
local numer = math.floor((integer*prec + round(decimal*prec))/gcd_)
local denom = math.floor(prec/gcd_)
local err = numer/denom - num
return numer, denom, err
end
function print_frac(numer,denom)
print(string.format("%d/%d = %d/%d + %g", numer, denom, to_frac(numer/denom)))
end
print_frac(1,4)
print_frac(12,8)
print_frac(4,2)
print_frac(16,11)
print_frac(1,13)
Output:
1/4 = 1/4 + 0
12/8 = 3/2 + 0
4/2 = 2/1 + 0
16/11 = 290909091/200000000 + 4.54546e-10
1/13 = 76923077/1000000000 + 7.69231e-11
I've been using lunadry to reformat my code for me, but I've run into errors, namely, this happens when I try it:
lua: ./lunadry.lua:322: assertion failed!
stack traceback:
[C]: in function 'assert'
./lunadry.lua:322: in main chunk
[C]: in ?
Now I've gone through a large chunk of code I had and tracked down the source of this error to this specific function...
function e.insertvalues(e,...)g(1,e,'table')local n,t
if y('#',...)==1 then
n,t=#e+1,...else
n,t=...end
if#t>0 then
for n=#e,n,-1 do
e[n+#t]=e[n]end
local i=1-n
for n=n,n+#t-1 do
e[n]=t[n+i]end
end
return e
end
(yes, it's supposed to look ugly formatted like that).
And even more specifically, taking out this bit of code makes it work again:
if y('#',...)==1 then
n,t=#e+1,...else
n,t=...end
It is the ...else and ...end bits that cause it to mess up.
I've been trying to get it to reformat that code so it looks pretty but it causes the error. For all I know that could simply have one replication of a sea of errors in the author's code, but I hope not. Here is the source of the file which does the magic: click me.
Could someone take a look at this and tell me what needs to be changed, to solve this very annoying bug? Thank you!
This is caused by matching ... as a keyword. For example, instances of lunadry.lua:
K "..."
should instead be
C "..."
Use this patch:
diff --git a/lunadry.lua b/lunadry.lua
index e056140..19d714b 100755
--- a/lunadry.lua
+++ b/lunadry.lua
## -201,7 +201,7 ## local lua = lpeg.locale {
K "true" +
V "Number" +
V "String" +
- K "..." +
+ C "..." +
V "function" +
V "tableconstructor" +
V "functioncall" +
## -251,8 +251,8 ## local lua = lpeg.locale {
funcbody = C "(" * V "whitespace" * (V "parlist" * V "whitespace")^-1 * C ")" * INDENT_INCREASE(V "block" * V "whitespace") * INDENT * K "end";
- parlist = V "namelist" * (V "whitespace" * C "," * SPACE * V "whitespace" * K "...")^-1 +
- K "...";
+ parlist = V "namelist" * (V "whitespace" * C "," * SPACE * V "whitespace" * C "...")^-1 +
+ C "...";
tableconstructor = FLATTEN(C "{" * (INDENT_INCREASE(V "filler" * V "fieldlist" * V "filler") * INDENT + V "filler") * C "}");
I will commit the fix later today.
This has been bothering be for a while now, I cannot seem to find a pure Lua implementation of a popular hashing method like SHA256, SHA512, or Whirlpool. I need it as I will be hashing the password client side before sending it of to a server. Speed isn't a worry here, I don't care if it takes 10 or so seconds to hash 10,000 times, I will be running it on a thread.
I have tried a couple before, which seemed like they worked perfectly fine at first, but when I tried a different input strings (usually longer ones), the hash comes out as a totally incorrect hash output.
I am using the LuaJIT version of Love2D, so it already has the BitOp library implemented. If any of you know any good implementations of these hashing methods or any similar secure ones then please let me know!
Thank you!
UPDATE: Here are some results!
Firstly this is the test code I am using.
https://github.com/JustAPerson/LuaCrypt
INPUT: Test string
OUTPUT: a3e49d843df13c2e2a7786f6ecd7e0d184f45d718d1ac1a8a63e570466e489dd
EXPECTED: a3e49d843df13c2e2a7786f6ecd7e0d184f45d718d1ac1a8a63e570466e489dd
INPUT: This is a test string to hash
OUTPUT: 05b4ac920d4130cb9d9bb046cac7476f35d7404cf116dc8d6d4a113c3c79d904
EXPECTED: f70b476ff948472f8e4e52793a5a2779e636c20dd5336d3a8a4455374318db35
https://bitbucket.org/Boolsheet/sil/raw/tip/hash.lua
INPUT: Test string
OUTPUT: 8f1a5b37fbe986953c343d5b839b14843c6c29d47a6a7e52f263cd82ad6141a3
EXPECTED: a3e49d843df13c2e2a7786f6ecd7e0d184f45d718d1ac1a8a63e570466e489dd
INPUT: This is a test string to hash
OUTPUT: 167bf7b9000442419b3016a6e1edfcc7c8d40b5f0b80518a31ddb0bbd388e87ac
EXPECTED: f70b476ff948472f8e4e52793a5a2779e636c20dd5336d3a8a4455374318db35
I would recommend against using SHA256 for passwords. They are easy to bruteforce nowadays, and the way you are using them is vulnerable to replay attacks.
Also if you must use SHA256, use the version from OpenSSL if possible (especially if your program already depends on OpenSSL.)
But if you must use it (and cannot link with OpenSSL, but can use FFI) here is a LuaJIT version of SHA256 (only) that I am using in one of my projects.
local bit = require 'bit'
local ffi = require 'ffi'
local type = type
local band, bnot, bswap, bxor, rol, ror, rshift, tobit =
bit.band, bit.bnot, bit.bswap, bit.bxor, bit.rol, bit.ror, bit.rshift, bit.tobit
local min, max = math.min, math.max
local C = ffi.C
local istype, new, fill, copy, cast, sizeof, ffi_string =
ffi.istype, ffi.new, ffi.fill, ffi.copy, ffi.cast, ffi.sizeof, ffi.string
local sha256 = {}
ffi.cdef [[
void *malloc(size_t size);
void free(void *ptr);
]]
local ctHashState = ffi.typeof 'uint32_t[8]'
local cbHashState = ffi.sizeof(ctHashState)
local ctBlock = ffi.typeof 'uint32_t[64]'
local cbBlock = ffi.sizeof(ctBlock)
local ctpu8 = ffi.typeof 'uint8_t *'
local ctpcu8 = ffi.typeof 'const uint8_t *'
local ctpu32 = ffi.typeof 'uint32_t *'
local ctpu64 = ffi.typeof 'uint64_t *'
-- This struct is used by the 'preprocess' iterator function. It keeps track
-- of the end of the input string + the total input length in bits + a pointer
-- to the block buffer (where expansion takes place.)
local ctBlockIter
local cmtBlockIter = {}
function cmtBlockIter.__sub(a, b)
if istype(ctBlockIter, a) then a = a.limit end
if istype(ctBlockIter, b) then b = b.limit end
return a - b
end
function cmtBlockIter:__tostring()
return string.format("<ctBlockIter: limit=%s; keyLength=%s>",
tostring(self.base), tostring(self.keyLength))
end
ctBlockIter = ffi.metatype([[
struct {
const uint8_t *limit;
uint32_t *blockBuffer;
uint64_t keyLength;
}
]], cmtBlockIter)
-- Initial state of the hash
local init_h = new('const uint32_t[8]', {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
})
-- Constants used in the add step of the compression function
local k = new('const uint32_t[64]', {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
})
-- Expand block from 512 to 2048 bits
local function expand(w)
for i = 16, 63 do
local s0 = bxor(ror(w[i-15], 7), ror(w[i-15], 18), rshift(w[i-15], 3))
local s1 = bxor(ror(w[i-2], 17), ror(w[i-2], 19), rshift(w[i-2], 10))
w[i] = w[i-16] + s0 + w[i-7] + s1
end
end
-- Process one expanded block and update the hash state
local function compress(hh, w)
local a, b, c, d, e, f, g, h =
hh[0],hh[1],hh[2],hh[3],hh[4],hh[5],hh[6],hh[7]
for i = 0, 63 do
local S1 = bxor(ror(e, 6), ror(e, 11), ror(e, 25))
local ch = bxor(band(e, f), band(bnot(e), g))
local t = tobit(h + S1 + ch + k[i] + w[i])
local S0 = bxor(ror(a, 2), ror(a, 13), ror(a, 22))
local maj = bxor(band(a, bxor(b, c)), band(b, c))
a, b, c, d, e, f, g, h =
tobit(t + S0 + maj),
a, b, c,
tobit(d + t),
e, f, g
end
hh[0],hh[1],hh[2],hh[3],hh[4],hh[5],hh[6],hh[7] =
hh[0]+a, hh[1]+b, hh[2]+c, hh[3]+d,
hh[4]+e, hh[5]+f, hh[6]+g, hh[7]+h
end
-- Take a 512-bit chunk from the input.
-- If it is the final chunk, also add padding
local keyLengthOfs = ffi.offsetof(ctBlockIter, 'keyLength')
local function nextBlock(state, input)
local w = state.blockBuffer
local cLen = min(state - input, 64)
if cLen < -8 then return nil end
fill(w, 256, 0)
copy(w, input, max(0, cLen))
if 0 <= cLen and cLen < 64 then
copy(cast(ctpu8, w)+cLen, '\128', 1)
end
for i = 0, 15 do w[i] = bswap(w[i]) end
if cLen <= (64-8-1) then
copy(cast(ctpu64, w) + 7, cast(ctpu8, state) + keyLengthOfs, 8)
w[14], w[15] = w[15], w[14]
end
input = input + 64
return input
end
-- Iterator that yields one block (possibly padded) at a time from the input
local function preprocess(input, len, w)
len = len or (type(input) == 'string' and #input or sizeof(input))
input = cast(ctpu8, input)
local it = new(ctBlockIter)
it.blockBuffer = w
it.limit = input+len
it.keyLength = len*8
return nextBlock, it, input
end
-- Compute a binary hash (32-byte binary string) from the input
function sha256.binFromBin(input, len)
local h = new(ctHashState)
local w = cast(ctpu32, C.malloc(cbBlock))
copy(h, init_h, cbHashState)
for _ in preprocess(input, len, w) do
expand(w)
compress(h, w)
end
for i = 0, 7 do h[i] = bswap(h[i]) end
C.free(w)
return ffi_string(h, 32)
end
local hexDigits = new('char[16]', "0123456789abcdef")
local hexOut = new('char[65]')
-- Compute the hash and convert to hexadecimal
function sha256.hexFromBin(input, len)
local h = new(ctHashState)
local w = cast(ctpu32, C.malloc(cbBlock))
copy(h, init_h, cbHashState)
for _ in preprocess(input, len, w) do
expand(w)
compress(h, w)
end
for i = 0, 7 do
local w = h[i]
for j = 0, 3 do
w = rol(w, 8)
hexOut[i*8 + j*2] = hexDigits[band(rshift(w, 4), 15)]
hexOut[i*8 + j*2 + 1] = hexDigits[band(w, 15)]
end
end
C.free(w)
return ffi_string(hexOut, 64)
end
return sha256
There is an implementation of SHA256 at the Lua User's Wiki. The page observes it is Lua 5.2. I would imagine that it would be practical to make that work in LuaJIT without too much trouble.
Do pay attention to the larger security issues surrounding passwords and authentication. The usual advice applies; rolling your own security rather than using an existing tested and supported implementation is not something to be done lightly.
Since you are using LuaJIT, you should be able to leverage its very powerful FFI capabilities to use crypto supplied on your native platform. That will likely require writing some FFI-flavored Lua that is platform specific to each platform on which your client expects to run, but from what I've seen by lurking in the LuaJIT mailing list that shouldn't be too painful.
The following Lua 4.0 script fails due to some of the variables being in an 'outer' scope. What are the different ways I can fix this? I would like to avoid putting things in the global scope completely if possible. Thanks.
function flokalAdd(iNx, iNy, iXmin, iSym, fEcc, bInside, fScale)
TWO_PI = 2 * PI;
iSx = 4;
iSy = 4;
function pow(fA, fB)
return fA^fB
end
function mag(fX, fY)
return dist(fX, fY, 0, 0)
end
function dist(fX1, fY1, fX2, fY2)
return sqrt(pow(fX2 - fX1, 2) + pow(fY2 - fY1, 2))
end
function norm()
local fY1 = 0;
local fX1 = 0;
local fX2 = exp(fX1) * cos(deg(fY1));
local fY2 = exp(fX1) * sin(deg(fY1)) + fEcc;
local fD = 0;
if (bInside == 1) then
fD = pow(mag(fX2, fY2), 1/iSym);
else
fD = pow(mag(fX2, fY2), -1/iSym);
end
local fArg = rad(atan2(fX2, fY2)) * -1/iSym;
local fX3 = fD * cos(deg(fArg))/TWO_PI;
local fY3 = fD * sin(deg(fArg))/TWO_PI;
return mag(fX3, fY3)
end
function fn(fX, fY)
local aP = {};
local fX1 = exp(fX) * cos(deg(fY));
local fY1 = exp(fX) * sin(deg(fY)) + fEcc;
local fD = 0;
if (bInside == 1) then
fD = pow(mag(fX1, fY1), 1/iSym);
else
fD = pow(mag(fX1, fY1), -1/iSym);
end
local fArg = rad(atan2(fX1, fY1)) * -1/iSym;
for i = 0, iSym - 1 do
local fX2 = fD * cos(deg(fArg + i * TWO_PI/iSym))/TWO_PI;
local fY2 = fD * sin(deg(fArg + i * TWO_PI/iSym))/TWO_PI;
aP[i + 1] = {fX2, fY2};
end
return aP
end
function lines(aP1, aP2)
for i = 0, iSym - 1 do
local fX1 = aP1[i + 1][0 + 1];
local fY1 = aP1[i + 1][1 + 1];
local fX2 = aP2[i + 1][0 + 1];
local fY2 = aP2[i + 1][1 + 1];
--addPebble(<sPebbleType>, <tPosition>, ?, ?, ?)
--addPebble("Pebble_2", {fX1 * fScale/fNorm, 0 * fScale/fNorm, fY1 * fScale/fNorm,}, 0, 0, 0)
-----------------------
-- DO SOMETHING HERE --
-----------------------
end
end
-- calculate the distance from the origin to the center of each eye, then use it to normalize the shape to within 1 unit of the center
fNorm = norm();
for i = 0, iNy - 1 do
local fY = i * TWO_PI/iNy;
for j = iXmin * iSx, iNx * iSx - 1 do
local fX1 = j * TWO_PI/iNx/iSx;
local fX2 = (j + 1) * TWO_PI/iNx/iSx;
lines(fn(fX1, fY), fn(fX2, fY))
end
end
for i = iXmin, iNx do
local fX = i * TWO_PI/iNx;
for j = 0, iNy * iSy - 1 do
local fY1 = j * TWO_PI/iNy/iSy;
local fY2 = (j + 1) * TWO_PI/iNy/iSy;
lines(fn(fX, fY1), fn(fX, fY2))
end
end
end
flokalAdd(16, 16, 12, 5, 256, false, 20000)
This happens due to Lua 4.0 scoping rules:
Function scopes have a special limitation in that outer scopes (other than the global scope) may not be accessed. This applies to any function, but is most noticeable in the case of nested functions where you may want to access locals of the enclosing scope.
In your code fEcc is defined in the scope of function flokalAdd, so it can't be accessed from the inner norm function.
You can fix this using upvalues:
Upvalues were added to work around the function scope limitation. Prefixing an outer-scope variable reference with % produces a copy of that variable as of the function's instantiation. Only the immediate scope containing the function and the global scope may be accessed in this manner.
Looking at the code, it seems that copying by value is OK. Here is the fixed version.