This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Lupus590's profile picture

[solved - properly this time] Processing Command Line Arguments

Started by Lupus590, 22 November 2015 - 07:26 PM
Lupus590 #1
Posted 22 November 2015 - 08:26 PM
Maybe not so solved…

http://www.computerc...post__p__239950


old postSo I'm working on an update to my quadPipe program and am having a problem interpreting the command line arguments, I have a for loop and am looping through everything in (admittedly) a very bad way. I'm considering replacing the for loop with a while loop, but want to pick your brains first.

If a rewrite is needed then consider this a "how not to write a for loop".

Full Code
Relevant Code
local arg = {...}
--set vaiables to default, we will overide these with the arg later
local quadProgram = defaults.quadProgram
local numOfQuads = defaults.numOfQuads
local delayMult = defaults.delayMult
local ignoreRedstone = defaults.ignoreRedstone
local anyKeyTerminate = defaults.anyKeyTerminate
local bSide = defaults.bSide
local rSide = defaults.rSide

--lower case everything
for i = 1, #arg do
  if tostring(arg[i]) then
	arg[i] = string.lower(arg[i])
  end
end
--process arg
for i = 1, #arg do
  if arg[i] == "-h" then
	printUsage()
  elseif arg[i] == "-f" then --quadProgram
	do --make my editor look clearer
	myError("arg "..i.." Can't load file", 2)
	i = i + 1 --this is definatly really bad practise
	end --make my editor look clearer
  elseif arg[i] == "-n" then --numOfQuads
	do --make my editor look clearer
	local n = tonumber(arg[i+1])
	if n == nil or n < 1 then
	  myError("arg "..i.." -n arg must be followed by a whole number greater than 0 (1 or greater are valid)", 2)
	else
	  local a,b = math.modf(n)
	  if b ~= 0 then
		myError("arg "..i.." -n arg must be followed by a whole number greater than 0 (1 or greater are valid)", 2)
	  end
	end
	if n > 64 then
	  print("arg "..i.." Warning: numOfQuads is larger than one stack(64). Did the max per base change or are you piping them in?")
	end
	numOfQuads = n
	i = i + 1 --this is definatly really bad practise
	end --make my editor look clearer
  elseif arg[i] == "-d" then --delayMult
	do --make my editor look clearer
	local d = tonumber(arg[i+1])
	if d == nil then
	  myError("arg "..i.." -d arg must be followed by a number", 2)
	end
	delayMult = d
	i = i + 1 --this is definatly really bad practise
	end --make my editor look clearer
  elseif arg[i] == "-r" then --redstoneSide
	do --make my editor look clearer
	local r = tostring(arg[i+1])
	if r == nil then
	 myError("arg "..i.." -r arg must be followed by a string representing a side or equal to 'ignore'", 2)
	end
	if r == "ignore" then
	  ignoreRedstone = true
	elseif r == "left" or r == "right" or r == "front" or r == "back" then
	  rSide = r
	  ignoreRedstone  = false
	else
	  myError("arg "..i.." -r arg must be followed by a string representing a side or equal to 'ignore'", 2)
	end
	i = i + 1 --this is definatly really bad practise
	end --make my editor look clearer
  elseif arg[i] == "-b" then --baseSide
	do --make my editor look clearer
	local b = tostring(arg[i+1])
	if b == nil then
	  myError("arg "..i.." -b arg must be followed by a string representing a side", 2)
	end
	if b == "left" or b == "right" or b == "front" or b == "back" then
	  bSide = r
	else
	  myError("arg "..i.." -b arg must be followed by a string representing a side", 2)
	end
	i = i + 1 --this is definatly really bad practise
	end --make my editor look clearer
  elseif arg[i] == "-t" then --anyKeyTerminate
	do --make my editor look clearer
	local t = tostring(arg[i+1])
	if t == nil then
	  nyError("arg "..i.." -t arg must be followed by a string equal to 'true' or 'false'", 2)
	end
	if t == "true" then
	  anyKeyTerminate = true
	elseif t == "false" then
	  anyKeyTerminate = false
	else
	  myError("arg "..i.." -t arg must be followed by a string equal to 'true' or 'false'", 2)
	end
	i = i + 1 --this is definatly really bad practise
	end --make my editor look clearer
  else
	myError("arg "..i.." unprocessed arg",2)
  end
end
Edited on 09 December 2015 - 02:07 PM
Dog #2
Posted 22 November 2015 - 09:45 PM
If I could request a little clarification - what problem are you having interpreting the command line arguments? Are some being skipped? None working?

I noticed a couple of things you may want to take another look at:

- Not sure if you care about this but, unless I'm mistaken, your 'lower case everything' loop will crash if one of the arguments provided is a number

- This may be part of your problem … regarding your use of i = i + 1 in your 'process arg' loop - I'm not exactly sure what you're trying to do, but based on what you've posted, I'm guessing that you're trying to increment the value of 'i' used by the for loop. I may be wrong about this (too), but I don't think that actually modifies the value of i that is defined by the loop. I tried something similar in the past and eventually came to the conclusion that the variable used for the loop can't be 'adjusted' except by the loop itself. Unless I'm mistaken, you're actually creating another variable named i, within the loop, separate from the variable that is holding the current value for the loop. In your particular case, I think this would work…

for i = 1, #arg, 2 do
since you're parsing every other variable and using arg[i+1] to get the ones in between.
Edited on 22 November 2015 - 08:50 PM
Lupus590 #3
Posted 22 November 2015 - 10:12 PM
your code snippet will not work at -h is a single argument

as for the actual problem, my unprocessed arg error goes off (complaining about the second arg) when I pass these as arguments
 quadPipe -t true 
to me that means that
 i = i+1 
doesn't work

the lowercase everything loop checks if the arg is a string before lowering, not tried it yet on numbers though, I can always add an escape condition

while loop with my own loop counter will have to do then, as messy as that will end up being


To clarify I'm replacing the problem for loop with a while loop, it may be a bit more messy but it should work.
Edited on 22 November 2015 - 09:34 PM
Dog #4
Posted 22 November 2015 - 10:32 PM
your code snippet will not work at -h is a single argument

the lowercase everything loop checks if the arg is a string before lowering, not tried it yet on numbers though
Uggg - I missed the -h - apologies for a useless suggestion.

I may be incorrect (again), but I believe your lowercase everything loop isn't actually checking if arg is a string, it's just applying tostring to arg without capturing the output. You can successfully tostring(nil) as far as I know - which would pass your if tostring(arg) check if I'm not mistaken. To check if it's a string, I think you probably want/need to use something like this…

if type(arg[i]) == "string" then
Edited on 22 November 2015 - 09:34 PM
KingofGamesYami #5
Posted 22 November 2015 - 10:36 PM
Since it's a command line argument, it will always be a string. So checking whether or not you have a string is redundant.

Why not use patterns and string manipulation to make life easy?


local args = {...}

for a, b in table.concat( args, " " ):gmatch( "%-(%a)%s(%a+)" ) do
  ...
end

In your example

quadPipe -t true

This would make a equal to "t", and b equal to "true".
Edited on 22 November 2015 - 09:39 PM
Lupus590 #6
Posted 22 November 2015 - 10:40 PM
I've replaced it with a while loop now, I'll check if that fixed it
Dog #7
Posted 22 November 2015 - 10:42 PM
Since it's a command line argument, it will always be a string. So checking whether or not you have a string is redundant.
That makes perfect sense, thank you.

Apologies for the bad advice, Lupus590 :/
Edited on 22 November 2015 - 09:42 PM
Lupus590 #8
Posted 22 November 2015 - 10:49 PM
Well, it's stopped crashing… which means that the problem is harder to trace.

I'll bash my head on the keyboard a bit, and maybe sleep on it.

The new bug is that any arg is valid now and they don't change the variables/trigger the if statements (but do the while loop).

new code (under new paste)
Edited on 22 November 2015 - 09:51 PM
Dog #9
Posted 22 November 2015 - 11:10 PM
I did notice a couple of things:

On line 125 you nyError instead of myError.

Second thing - if you only pass a single argument (e.g. -h), this

while i < #arg do
will skip the loop if #arg == 1 since 1 isn't less than 1. I think you want…

while i <= #arg do
Edited on 22 November 2015 - 10:14 PM
H4X0RZ #10
Posted 23 November 2015 - 12:33 AM
You could also use my (old) code I made exactly for this Kind of work.

http://pastebin.com/zb5JMzbb


local cli = dofile "path to cli"
local args = cli.new{...}
args:setDefault("someValue",true)
args:parse()

--now handle the data
if not args:getBoolean "someValue" then 
  --do stuff
end
Lupus590 #11
Posted 23 November 2015 - 01:00 PM
I did notice a couple of things:

On line 125 you nyError instead of myError.

Second thing - if you only pass a single argument (e.g. -h), this

while i < #arg do
will skip the loop if #arg == 1 since 1 isn't less than 1. I think you want…

while i <= #arg do

lets hope that those are the last of the bugs.

You could also use my (old) code I made exactly for this Kind of work.

http://pastebin.com/zb5JMzbb


local cli = dofile "path to cli"
local args = cli.new{...}
args:setDefault("someValue",true)
args:parse()

--now handle the data
if not args:getBoolean "someValue" then
  --do stuff
end

I do remember finding your post for that, but I couldn't find it again when I wanted to use it (have now, got it bookmarked in a more logical place now)
I've gotten this far without it, so I'd like to continue. It's part of the fun.
Lupus590 #12
Posted 23 November 2015 - 01:24 PM
I think that everything is working now (except the file part, but that's because I haven't written that yet.)

Thanks for all the help guys!

Fixed version of the code (file loading still WIP)
Edited on 23 November 2015 - 12:26 PM
Lupus590 #13
Posted 09 December 2015 - 01:10 PM
You may have noticed a lack of an update on the quadPipe thread, I've had another bug and (until recently) not had the time/energy to look into it.

the test file is this (and is named test)

{"up","down"}

the current code: http://pastebin.com/mkN2XJRJ

the error: quadpipe:63: attempt to index ? (a nil value)

what I typed to get the error: quadpipe -f test
Edited on 09 December 2015 - 12:12 PM
Wojbie #14
Posted 09 December 2015 - 01:19 PM
You appear to be using "args" instead of "arg" in few lines.
Lupus590 #15
Posted 09 December 2015 - 02:36 PM
that would do it

all bugs fixed, time for cleanup and more testing
Edited on 09 December 2015 - 02:06 PM