I'm working on a Windows 8 mock-up OS for Computercraft, and my log in system isn't working. I have been trying to figure it out for the past hour or so and it's really frustrating.
Here's the log in code:
-- Log-in and User Definition Service
--- Variables
userExists = fs.exists("/Users/.config/userConfig.cfg")
termx, termy = term.getSize()
halfx = math.floor(termx*0.5)
halfy = math.floor(termy*0.5)
prompt = "Welcome"
uprompt = "Username: "
pprompt = "Password: "
userConfig = fs.open("/Users/.config/userConfig.cfg", "r")
edituserConfig = fs.open("/Users/.config/userConfig.cfg", "w")
--- Functions
function login(user)
if user == "admin" then
term.setCursorPos(1,1)
term.setTextColor(256)
print (user)
elseif user == "guest" then
print (user)
else
print ("nil")
end
end
function userCheck()
if userExists == true then
term.clear()
term.setBackgroundColor(8)
term.setCursorPos(halfx-0.5*#prompt, halfy - 4)
term.clear()
print (prompt)
term.setCursorPos((halfx-#uprompt), (halfy - 2))
write (uprompt)
term.setCursorPos((halfx-#uprompt), (halfy - 1))
write (pprompt)
term.setCursorPos((halfx), (halfy - 2))
upin = read()
term.setCursorPos((halfx), (halfy - 1))
ppin = read("*")
if upin == userConfig.readLine(21) and ppin == userConfig.readLine(24) then
print ("ADMIN")
elseif upin == userConfig.readLine(33) and ppin == userConfig.readLine(36) then
login("guest")
end
elseif userExists == false then
elseif userExists == nil then
end
end
--- Main
userCheck()
userConfig.cfg:
-- Format as follows:
--
-- (name):
--
-- (prop):
-- "(value)"
--
-- (prop):
-- "(value)"
--
-- (prop):
-- "(value)"
--
--
-- (name):
-- [etc.]
Admin:
user:
"Admin"
pass:
"admin"
auth:
"1"
Guest:
user:
"Admin"
pass:
nil
auth:
"0"
Root:
user:
nil
pass:
nil
auth:
"2"
readLine does not accept arguments and only reads the next line. Your best bet would be to use tables and textutils.serialize to write it all to a file and then when reading use textutils.unserialize to have it inside a table.
Admin:
user:
"Admin"
pass:
"admin"
auth:
"1"
Can be written inside a table such as
{
Admin = {
user = "Admin"
pass = "admin"
auth = "1"
}
Guest = {
user = "Admin"
pass = nil
auth = "0"
}
}
This would work much in the way that you want, and allows for more variability as well as expansion. Of course to read from it is a different story, and i would use a function to find and send either the auth code back, or nil if it didn't work.
Such as
local function findUsers(username,password)
--This will read the file and put all it's data inside a table, and then close it.
local file = fs.open("userConfig.cfg","r")
local userRanks = textutils.unserialize(file.readAll())
file.close()
--To read all the data in a table, i'm going to do this.
for a,v in pairs(userRanks) do
if type(v) == "table" then
if userRanks[a].user == username and userRanks[a].pass == password then
return userRanks[a].auth
end
end
end
--[[If we look through the entire file table, and the username and password aren't the same
as on file, then we say we couldn't find it by returning nil]]--
return nil
end
Now for your input area all you have to do is when they input the username and password just call this afterwards, also if allows you to have the auth code
local auth = findUsers(upin,ppin)
--If they inputted an actual username and password
if auth ~= nil then
--If the auth code from the rank is "1"
if auth == "1" then
--Do whatever stuff you want
elseif auth == "2" then
--Do whatever other stuff for this auth code
end
elseif auth == nil then
print("Oh no you inputted an invalid username and/or password, please try again!"
end
To expand on Dragon53535's answer:
Here's a quick routine I threw together that reads a file into a table:
local function fileToTable(path)
-- first we make sure that the path can be opened
assert(fs.exists(path), path..' does not exist!')
assert(not fs.isDir(path), path..' is a directory!')
local tSrc = {}
local inFile = fs.open(path, 'r')
-- we set line to a non-nil value
local line = ''
-- we continue the loop until line is nil
while line do
-- we read a line from the file
line = inFile.readLine()
-- now we save the value of line to our table
-- line will be nil at EOF
tSrc[#tSrc+1] = line
end
inFile.close()
return tSrc
end
After running userConfig = fileToTable('/Users/.config/userConfig.cfg'), you'd replace something like userConfig.readLine(24) with userConfig[24].
Alternatively, you could check out CC's implementation of the io library. It's a standard Lua library (though in CC it's an fs wrapper), so code can be moved more easily out of CC.
In particular, io.lines() would be helpful here.
The above code rewritten to use io.lines:
local function fileToTable(path)
-- first we make sure that the path can be opened
assert(fs.exists(path), path..' does not exist!')
assert(not fs.isDir(path), path..' is a directory!')
local tSrc = {}
-- iterate over file
-- io.lines is neat, since it opens and closes the file automatically
for line in io.lines(path) do
tSrc[#tSrc+1] = line
end
return tSrc
end
As you can see, this is much smaller (only 9 lines of code!) and more manageable. The reason it's not my preferred solution in CC is that io sits on top of fs, so it's probably better to remove the middleman.
Hope this helps.
Related
Please I'm in need of a lift right now. I want the user to be able to have the option of re-entering his numerical input if perhaps, he/she entered an alphabet by mistake.
Right now it just loops infinitely on the "Please select a valid option" and "Try again" outputs.
print("\n-----Factorial Calculator------\n")
def option():
opt = (input('Try again? y/n: '))
if option == 'y':
facto(num)
elif option == 'n':
exit()
else:
print("Please select a valid option")
option()
def facto(factorial):
fact = 1
for nums in range(1, num+1):
fact = fact * nums
return fact
try:
num = int(input("Number(Just input the number): "))
except ValueError:
print("Invalid input")
option()
print(f" {num}! = {facto(num)}")
First, rather than calling option recursively, simply put a loop inside it.
Second, when the user enters y into the "Try again?" input, it should not calculate the factorial there, but return the user back to the original input, by breaking out of the loop within the option call.
Putting these two together will fix option:
def option():
while True:
retry = input('Try again? y/n: ')
if retry == 'y':
break
elif retry == 'n':
exit()
else:
print("Please select a valid option")
Third, you need some kind of loop around your initial input, otherwise how will they enter the number again after indicating they want to try again?
Fix this by sticking the initial num assignment and option call in a while loop, with the same try; except statement you had before:
while True:
try:
num = int(input("Number(Just input the number): "))
break
except ValueError:
print("Invalid input")
option()
continue
I see someone else got an answer in ahead of me which identified the bug in option() and the bug which prevents user re-entering the number but I'll post this anyway because there are other ways your code can be restructured.
print("\n-----Factorial Calculator------\n")
# Each function should handle just one thing
# Eg, option() should just handle whether user wants to continue, not try to handle factorial calc
# Also it's best to let the mainline logic decide whether to exit() or not
# This function should just return 'y' or 'n'
# Note that the original code captured the user's option in variable `opt` but then checked variable `option`.
# That's why it looped endlessly
def option():
opt = ' '
while ( opt != 'y' and opt != 'n' ):
opt = (input('Try again? y/n: '))
if opt == 'y':
return opt
elif opt == 'n':
return opt
else:
print("Please select a valid option")
# You specified argument `factorial` in original code but then did not use it.
# It still worked because the variable `num` was defined at the top level in the mainline
# Functions should be self-contained and rely only on the arguments that are passed into them
def facto(n):
fact = 1
for nums in range(1, n+1):
fact = fact * nums
return fact
opt = 'y'
is_print = False
while ( opt == 'y' ):
try:
num = int(input("Number(Just input the number): "))
opt = 'n'
is_print = True
except ValueError:
print("Invalid input")
opt = option()
if ( is_print ):
print(f" {num}! = {facto(num)}")
Thanks everyone for the help, but after struggling with it for a couple of days and taking few days off due to illness, I somehow did it. Eureka!
def facto(n):
fact = 1
for i in range(1, n + 1):
fact = fact * i
return fact
def opt():
option = (input("Do you want to try again? y/n: "))
if option == 'y':
number()
elif option == 'n':
exit()
else:
print("\nPlease select a valid option.")
opt()
def number():
try:
num = int(input("Number: "))
print(f"{num}! = {facto(num)}")
except ValueError:
print("Invalid input! Please input integers only")
opt()
number()
I am using this script as a template to rename a file in VLC: https://github.com/surrim/vlc-delete/
The Script works as intended.
My code looks like this:
function descriptor()
return {
title = "VLC Rename";
version = "0.1";
author = "I";
shortdesc = "Rename current file";
description = [[
<h1>vlc-rename</h1>"
When you're playing a file, use VLC Rename
to rename the current file]];
}
end
function removeItem()
local id = vlc.playlist.current()
vlc.playlist.delete(id)
vlc.playlist.gotoitem(id + 1)
vlc.deactivate()
end
function activate()
local item = vlc.input.item()
local uri = item:uri()
oldFile = vlc.strings.decode_uri(string.gsub(uri, "^file:///", ""))
d = vlc.dialog( "Rename Dialog" )
d:add_label("Filename")
w = d:add_text_input(oldFile, 1, 5,200 ,30)
d:add_button("OK", click_ok)
d:show()
end
function click_ok()
local newFile = w:get_text()
vlc.msg.info("[vlc-rename] renaming: " .. oldFile .. " with " .. newFile)
if newFile ~= oldFile then
removeItem()
retval, err = os.rename(oldFile,newFile)
vlc.msg.info("[vlc-rename] end rename")
if (retval == nil) then
vlc.msg.err("[vlc-rename] fail: " .. err)
end
end
d:delete()
vlc.deactivate()
end
function deactivate()
vlc.deactivate()
end
function close()
deactivate()
end
function meta_changed()
end
This code outputs an error from the os.rename() function:
lua error: [vlc-rename] fail: [my filename] Permission denied
Regardless of elevation level.
I am using windows 10 64bit and VLC 3.03.
Since this is my first lua script I welcome any input.
I might be wrong, but maybe the file you are trying to rename is already opened elsewhere or by VLC (you said you want to rename the "current file").
I am converting Markdown to HTML with Pandoc. With --toc, Pandoc generates a table of contents and inserts it under the first H1 heading (of which there is only one).
I would like it to have a separate, additional table of contents for each subheading. More specifically, I would like a small local table of contents under each H3.
Can Pandoc do that, and if yes, how?
I received an answer on the pandoc-discuss mailing list in the form of a Lua filter.
Quoting from the author of the solution:
Warning: Assumes that all chapters are heading level 2 — change the chapter_level and toc_level variables to match!
Warning: Assumes that each section/chapter has a unique identifier!
local chapter_level = 2
local toc_level = 3
local headings = {}
local current_chapter = nil
local function collect_headings (head)
if head.level == chapter_level then
local id = head.identifier
current_chapter = {
chapter = id,
toc = {},
}
headings[id] = current_chapter
elseif head.level == toc_level then
if current_chapter then
local toc = current_chapter.toc
toc[#toc+1] = head
end
end
return nil
end
local function build_toc (heads)
local toc = {}
for _,head in ipairs(heads) do
local entry = {
pandoc.Plain{
pandoc.Link(
head.content:clone(), -- text
'#' .. head.identifier, -- target
"", -- empty title
pandoc.Attr(
"", -- empty identifier
{'local-toc-link'} -- class
)
)
}
}
toc[#toc+1] = entry
end
return pandoc.Div(
{ pandoc.BulletList(toc) },
pandoc.Attr( "", {'local-toc'} )
)
end
local function insert_toc (head)
if head.level == chapter_level then
local id = head.identifier
if headings[id] then
local toc = build_toc(
headings[id].toc
)
return {head,toc}
end
end
return nil
end
return {
{ Header = collect_headings },
{ Header = insert_toc },
}
Here is my code (and below it is my issue):
require "socket"
server = TCPServer.open("localhost", 2000)
loop {
thread.start(server.accept) do |nodervcr|
msg = nodervcr.gets
puts(msg)
if msg = "codeword"
puts("codeword!")
else
puts("not codeword")
# Note this part works: it sends the server a message and it displays it
# You would think a simple if then else statement could redirect it according to the imcoming message from the client; which is my issue.
end
}
So I tried:
if msg == code
# then do this
elsif msg == code2
# then do this
# etc
But it's not working.
I've tried replacing msg with nodervcr, still nothing.
The strange part is that it's obviously getting the message, and msg does = what the client sends.. but it acts as if that variable dies immediately. I'm new to ruby. please help thanks.
You have a few problems in your code. But the main problem is that when you use something like Telnet, you probally are giving a enter.
So your sending "codeword" + CRLF (codeword\r\n). Thats not the same as your check: msg == "codeword"
What you should do is strip the input from these chars (strip). It removes the CRLF and it then works
Remember. Variable Assignments are = (single) comparing is double ==
Below the working code:
require "socket"
server = TCPServer.open("127.0.0.1", 2000)
loop {
Thread.start(server.accept) do |nodervcr| # Thread, not thread
msg = nodervcr.gets
# puts(msg)
p msg # use this so see all the invisiable chars
if msg.strip == "codeword" # stip the input
puts("codeword!")
else
puts("not codeword")
end
# Note this part works: it sends the server a message and it displays it
# You would think a simple if then else statement could redirect it according to the imcoming message from the client; which is my issue.
end
}
Whenever an error occurs in a Lua script, I'd like it to write the values of all local and global variables to the screen/optionally to a file - in addition to the usual stack trace.
How could I get this to be the default behavior for all errors?
If you're using the standard Lua interpreter, replace debug.traceback with your own function. If you're embedding Lua in your program, use your traceback function in lua_pcall.
The StackTracePlus module does what you want, displaying local variables at each level of the stack trace. It doesn't dump the entire globals table, but that is probably overkill.
To install it with LuaRocks, use
luarocks install stacktraceplus
Then in your code, do:
local STP = require "StackTracePlus"
debug.traceback = STP.stacktrace
In Lua 5.1 this will automatically convert all stack traces; for Lua 5.2 code you need to wrap your code with an xpcall as suggested in other answers.
A more proper solution would be to use xpcall around your whole code.
local function myerrhandler ( errobj )
print(debug.traceback())
for k,v in pairs(_G) do print("GLOBAL:" , k,v) end
return false
end
xpcall( function ()
--Your code here
end , myerrhandler )
Your error handler may be overwritten. If you're calling Lua from C, to always print the stack you can hook in to the luaG_errormsg function.
In lua, write :
local _HandlingError = 0
function _ErrorHandler ( errobj )
if( _HandlingError == 0 ) then
_HandlingError = 1
local errStr = tostring(errobj) or ""
if( type(errobj)=='table' ) then
errStr = "Table: {" .. table.concat(errobj, ',') .. "}"
end
print("Error: \"" .. errStr .. "\"")
--for k,v in pairs(_G) do print("GLOBAL:" , k,v) end
if( type(errobj)=='thread' ) then
print(debug.traceback(errobj))
else
print(debug.traceback('',2))
end
_HandlingError = 0
end
return false
end
Then in ldebug.c, add to luaG_errormsg after if(L->errfunc != 0)
else
{
lua_getfield(L, LUA_GLOBALSINDEX, "_ErrorHandler");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 1);
}
else {
lua_pushvalue(L, 1);
lua_call(L, 2, 1);
lua_pop(L, 1);
}
}