Oxygen Basic
Programming => Problems & Solutions => Topic started by: Mike Lobanovsky on September 18, 2014, 08:07:18 AM
-
Hello community,
Does anyone have a ready made command line splitter function, please?
Thanks!
-
what's the meaning of it? "command line splitter function" ? never heard before..
-
That's the function that would split the command line that the OS supplies an executable with when the executable is loaded in system memory for running. That's where the program options would normally be passed.
The Oxygen console uses the GetCommandLine() WinAPI to fetch the command line into an Oxygen program but it fetches it in its entirety (its raw form) whereas I need the command line to be split into its constituent parts delimited in the raw command line with spaces.
Having split the command line into individual tokens, I will be able to safely examine them for program parameters. If I simply use an unsafe Instr() to search for options in the raw command line, I'm going to be in trouble with e.g. -h (a conventional option for "show help") if the line doesn't actually contain such an option but instead contains e.g. a "no-help-available" token. :)
-
Mike,
Do you want all your args together in a single string, or should they be split into a string array?
-
A string array would be perfect, and if such a function is developed, I vote for including it into the Console.inc file.
Command(0) (or [ 0 ] for that matter) can contain the entire command line but that isn't strictly necessary due to the availability of basic GetCommanLine().
Command(1) would store its 1st token.
Command(2), its 2nd token.
.......
Command(n), its n-th token.
.......
.......
Profit!
A CommandCount() function would also be very handy for iterating through the members available in the array.
:D
-
And on a side note, I would also vote for an Oxygen system constant that would tell the program code if it's currently running in a JIT compiled mode or as a standalone executable. FBSL has such a constant -- STANDALONE. It evaluates to TRUE when the program is precompiled and runs as an executable, and to FALSE otherwise.
For instance, the contents of Command() array (or function, as in FBSL) would differ when the script runs interpreted (or JIT compiled) and when it runs as a standalone executable.
It can also be very handy to differentiate where to load resources from -- a disk resource directory when interpreted/JIT compiled or the executable's own resource section when precompiled standalone.
What would you say to that?
-
Hmmm... There are 5 modes to consider:
JIT
Dynamic JIT
Dependent
32 bit independent RTL
64 bit independent RTL
the last two have metaflags set by the RTLs: mode32bit mode64bit
#ifdef mode32bit
...
#endif
-
This will cope with command-lines with or without quotey bits
includepath "$/inc/"
% filename "t.exe"
'include "RTL32.inc"
include "console.inc"
string cla[4],clp[64]
sys cln
function CommandLineSplit()
===========================
char* s
@s= (sys) getCommandline
printl s
byte *b=strptr s
sys i,j,k,le
sys bb=@b,bs=@b,mm=0,ms=0
do
select case b
case 0 : exit do
case 32 : if mm=0 then exit do ' space (no quote at start)
case 34 : if mm then exit do ' " double quote
mm=@b
bs=@b+1
case 47 : ms=@b ' / fwd slash
case 92 : ms=@b ' \ back slash
end select
@b++
end do
cla[1]=s
if ms then
cla[2]=mid(s,bs-bb+1,ms-bs+1) 'path
else
ms=bb-1
end if
cla[3]=mid(s,ms-bb+2,@b-ms-1) 'filename
@b++
i=@b-bb+1
le=len s
cln=0
if mm then
do 'look for first arg
@b++ : i++
select b
case 0 : exit do 'no args
case 34 : @b++ : i++ : exit do 'skip quote
case 33 to 255 : exit do
end select
@b++ : i++
end do
cla[4]=mid(s,i,le-i) 'remainder as args without quotes
else
cla[4]=mid(s,i) 'remainder as args. no quotes expected
end if
le=len cla[3]
if le=0 then return
i=1
j=1
k=0
@b=strptr cla[4]
do 'capture all args
do 'skip leading spaces
select b
case 0 : jmp fwd done
case 33 to 255 : exit do
end select
i++ : j++ : @b++
end do
if b=0 then jmp fwd done
do 'capture each arg
select case b
case 0 to 32
k++ : cln++
clp[k]=mid cla[4],j,i-j
if b=0 then jmp fwd done
j=i
@b++ : i++ : j++
exit do
end select
@b++ : i++
end do
end do
done:
end function
'TEST
CommandLineSplit()
printl "raw" tab cla[1]
printl "path" tab cla[2]
printl "file" tab cla[3]
printl "Args" tab cla[4]
printl "Arg count: " cln
for i=1 to cln
printl i tab clp[i]
next
waitkey
-
No, I am not talking about preprocessor macros. I'm talking about a live, vibrant, run time constant that would help the executable code to make intelligent choices based on its environment. I have supplied at least two examples where it might be helpful: i) how to interpret the command line tokens in the Command() array, and ii) where to load resources from.
If the script runs JIT compiled, Command(1) will be gxo2.exe, Command(2) will be scriptname.o2bas, and Command(3) will be the script's parameter, say, -h. If it runs compiled, Command(1) will be scriptname.exe, Command(2) will be -h, and there won't be any Command(3) at all. Hence, i) we can't rely on -h always being in the Command(3) position, and ii) we are running the risk of a crash if we don't know CommandCount(), or the UBound of our Command() array. (see my griefs in a similar topic named Why Don't We?)
If the script runs JIT compiled, it is natural to expect its media resources to be grouped in a temporary folder alonside the script. But it is unnatural to expect this folder to be deployed together with the executable compiled from that script. That's OK for a Mac app, but it is not becoming to a Windows application.
You can invent a dozen other similar situations where STANDALONE is coming in very handy.
As for other run time constants, say, to differentiate JIT from dynamic JIT, they may be introduced if you find some common enough reasons like those above to justify their existance.
-
This will cope with command-lines with or without quotey bits
Wonderful!
But I think I'll boil down with my modest OxyLISP needs to something much simpler based on msvcrt.dll's strtok(). Lightning fast in a 4-line While/Wend block.
Thanks for your help anyway. :)