Author Topic: Different approach for Commandline arguments  (Read 19720 times)

0 Members and 3 Guests are viewing this topic.

Arnold

  • Guest
Different approach for Commandline arguments
« on: June 05, 2015, 10:27:46 AM »
Hi Charles,

in examples\system I found cmdlinesplitter.o2bas. I would like to apply another approach which I think is useful (not my idea but I like it).

If run by gxo2 or co2 the arguments are:

1) gxo2.exe or co2.exe
2) application (.o2bas, .bas)
3) arg1
4) arg2
...

if run as a stand-alone application:

1) app.exe
2) app.exe (placeholder)
3) arg1
4) arg2
...

This way the parameters for the application would always start at index 3. I managed to create a procedure which extracts an ordered array of arguments and the count of the array. This is the code of the first draft:

Edit: deleted

This code works fine, but I am not sure if I must pay attention because of GetCommandLine? E.g. GetCommandLine is used in minwin.inc. Will there be any conflict if I use GetCommandLine in the splitCommandLine procedure too?

And I wonder if the code could be improved a little bit more to get rid of some superfluous statements? Is it possible to determine the mandatory value of 'countof(params)' inside the sub splitCommandLine?

Roland
« Last Edit: June 07, 2015, 02:21:31 AM by Arnold »

Charles Pegge

  • Guest
Re: Different approach for Commandline arguments
« Reply #1 on: June 05, 2015, 11:14:22 PM »
Hi Roland,

I don't think duplicating ! GetCommandLine will cause problems.



You can read ascii in a string directly, instead of creating a substring for it asc(mid(s,i))
asc(s,i)


You can also perform an exclusion check in one go:

if instr(" gxo2 gxo2.exe co2 co2.exe "," "+lcase(args[1])+" ")=0 then ..



countof(params) .. is a fixed value determined at compile-time, so it has to be passed explicitly.
« Last Edit: June 05, 2015, 11:27:25 PM by Charles Pegge »

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #2 on: June 07, 2015, 02:18:38 AM »
Hi Charles,

my questions reveal that I am not a real programmer. But each time I learn a little bit more about Oxygenbasic. And I learned that I as a programmer should at least take responsibility to use the correct values.
I experimented a little bit with dynamic.inc library, but I think the splitcommandline sub works ok as it is. Using instr does not work in this case, because args(x) can point to the full path of gxo2.exe / co2.exe.

With help of this little project it should be possible to see if a program is run with gxo2.exe or as a stand-alone application. With arg[1] it should be possible to get the full path of gxo2.exe / co2.exe if they are used, with arg[2] it should be possible to get the current path of the application if run with gxo2.exe. These will be my next steps and I found that you already provided some demos in folder examples.

There is a problem: if I set the path of OxygenBasic in the environment and call gxo2.exe application then there is an include error. I must always use e.g. c:\oxygenbascic\gxo2.exe app. It seems that includepath "$/inc/" will not recognize the full path of oxygenbasic if I  only use gxo2.exe?

Roland

Code: OxygenBasic
  1. $ filename "SplitCommandline.exe"
  2. includepath "$/inc/"
  3. '#include "RTL32.inc"
  4. '#include "RTL64.inc"
  5. include "Console.inc"
  6. '#include "MinWin.inc"
  7.  
  8.  
  9. sub splitCommandLine(sys array, cnt, int limit)
  10.  
  11.    string args at array
  12.    int ix at cnt
  13.  
  14.    ! GetCommandLine alias "GetCommandLineA" lib "kernel32.dll" () as char*
  15.  
  16.    string cmdline = GetCommandLine
  17.    int length=len(cmdline)
  18.  
  19.    ix=0
  20.    if limit < 2 then
  21.       print "Error in splitCommandLine: limit < 2 "    
  22.       return
  23.    end if
  24.  
  25.    ' build array of args
  26.   p1=1: p2=p1
  27.  
  28.    do
  29.      'must start with value higher than space
  30.     if asc(cmdline,p1) > 32 then
  31.         'next match
  32.        p2=p1+1
  33.         do
  34.           if asc(cmdline,p2) > 32 then
  35.              p2+=1
  36.           else
  37.              p2-=1
  38.              exit do
  39.           end if
  40.         end do
  41.  
  42.         ix+=1            
  43.         args[ix]=mid(cmdline,p1,p2-p1+1)
  44.         if asc(cmdline,p1) = 34 then
  45.            'remove quote
  46.           le=len(args[ix])-2
  47.            args[ix]=mid(args[ix],2,le)
  48.         end if
  49.  
  50.         if ix=1 then
  51.            if mid(args[1],-8) != "gxo2.exe"  _
  52.                 and mid(args[1],-4) != "gxo2"  _
  53.                 and mid(args[1],-7) != "co2.exe" _
  54.                 and mid(args[1],-3) != "co2" then
  55.  
  56.               'add placeholder
  57.              args[2]=args[1]
  58.               ix+=1
  59.            end if
  60.         end if
  61.      
  62.      end if
  63.      
  64.      if ix=limit then exit do
  65.  
  66.      'next arg
  67.     p1=p2+1
  68.      do
  69.        if asc(cmdline,p1) > 32 then
  70.           exit do
  71.        else
  72.           p1+=1
  73.           if p1>length then exit do
  74.        end if
  75.      end do
  76.      if p1 > length then exit do    
  77.  
  78.    end do
  79. end sub
  80.  
  81.  
  82. ' Test
  83. '====='
  84.  
  85. dim as string params[16]=""
  86. int count
  87.  
  88. splitCommandLine(@params, @count, countof(params))
  89.  
  90. if count=2 then
  91.    cls
  92.    print "Usage: SplitCommandline arg1 arg2 arg3 ..." & cr
  93.    print "For Help use: SplitCommandLine -help" & cr      
  94. end if
  95.  
  96. if count=3 and params[3]="-help" then
  97.    cls
  98.    print "SplitCommandline is an approach to arrange arguments in the same order" & cr
  99.    print "no matter if run with gxo2.exe / co2.exe or as a stand-alone application" & cr          
  100. end if
  101.  
  102. if count=3 and params[3]!="-help" then
  103.    cls
  104.    print "Commandline arguments:" & cr
  105.    for x=1 to count
  106.       print x ") "params[x] & cr
  107.    next x
  108.    print "count of arguments: " count & cr
  109. end if
  110.  
  111. if count>3 then
  112.    cls
  113.    print "Commandline arguments:" & cr
  114.    for x=1 to count
  115.       print x ") "params[x] & cr
  116.    next x
  117.    print "count of arguments: " count & cr
  118. end if
  119.  
  120. print "Enter..." & cr
  121. waitkey()                
  122.  


.
« Last Edit: June 10, 2015, 09:50:47 AM by Arnold »

Aurel

  • Guest
Re: Different approach for Commandline arguments
« Reply #3 on: June 07, 2015, 09:28:01 AM »
Arnold
i really don't know why you use char* pointer as result of CommandLine
Declare Function GetCommandLine Lib "kernel32.dll" Alias "GetCommandLineA" () as String
also windows require full path

JRS

  • Guest
Re: Different approach for Commandline arguments
« Reply #4 on: June 07, 2015, 10:37:02 AM »
Quote from: SB Docs
COMMAND()

This function returns the command line arguments of the program in a single string. This does not include the name of the interpreter and the name of the BASIC program, only the arguments that are to be passed to the BASIC program. For example the program started as

# scriba test_command.sb arg1 arg2  arg3

will see "arg1 arg2 arg3" string as the return value of the function COMMAND().

Keeping it simple requires only a split and serve.

FYI: Script BASIC also allows passing command line arguments to embedded instances of SB and threads.

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #5 on: June 07, 2015, 10:45:29 AM »
 Hi Aurel,

Declare Function GetCommandLine Lib "kernel32.dll" Alias "GetCommandLineA" () as String
will not work with this project. I could use:

Declare Function GetCommandLine Lib "kernel32.dll" Alias "GetCommandLineA" () as zstring (ptr)
Declare Function GetCommandLine Lib "kernel32.dll" Alias "GetCommandLineA" () as asciiz (ptr)

but
Declare Function GetCommandLine Lib "kernel32.dll" Alias "GetCommandLineA" () as char*
looks nice.

Windows requires full path in every case? If you are in a command window, how do you start notepad?

Roland

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #6 on: June 07, 2015, 10:50:40 AM »
Hi John,

there are certainly different possibilites to get the arguments of the commandline. But one purpose of this little project is to decide if the app is compiled or run with gxo2.exe or co2.exe.

Roland

JRS

  • Guest
Re: Different approach for Commandline arguments
« Reply #7 on: June 07, 2015, 11:15:43 AM »
The JIT factor.  8)

Aurel

  • Guest
Re: Different approach for Commandline arguments
« Reply #8 on: June 07, 2015, 01:00:00 PM »
Quote
Declare Function GetCommandLine Lib "kernel32.dll" Alias "GetCommandLineA" () as String
will not work with this project
...and do you know why not ?
i guess...because is declared inside subroutine then returned char pointer become global
or i am completelly wrong  ::)

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #9 on: June 07, 2015, 11:07:35 PM »
Hi Aurel,

I looked in the demos of Oxygenbasic and only awinh.inc tries to get string as a return value of of the low level function GetCommandLine.

In the win32 help file there is the definition:

LPTSTR GetCommandLine(VOID)

In Internet I searched for LPTSTR and found this link with the Datatypes:

#ifdef UNICODE
 typedef LPWSTR LPTSTR;
#else
 typedef LPSTR LPTSTR;
#endif

LPSTR:
A pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.

Therefore GetCommandLine in the ansi world returns a zstring or asciiz (ptr) which makes sense to me. I think string in OxygenBasic serves for higher level purposes. And I think as string has automatic garbage collection it is maybe not a good idea to use a string pointer as a return value in low level functions.

Roland


Charles Pegge

  • Guest
Re: Different approach for Commandline arguments
« Reply #10 on: June 08, 2015, 01:50:23 AM »

Hi Roland,

Oxygen will now derive the '$' exe path from GetModuleFileName instead of GetCommandLine.

This guarantees that  '$' always contains the fully qualified exe path.

Does this resolve the environment path problem?



Oxygen DLL Update (200k)
http://www.oxygenbasic.org/o2zips/Oxygen.zip


Mike Lobanovsky

  • Guest
Re: Different approach for Commandline arguments
« Reply #11 on: June 08, 2015, 02:11:31 AM »
Hi everybody,

I think that ready access to a program's environment variables and command line parameters is not a high-level language privilege but rather a must.

Even (comparatively) low-level C provides the programmer with those through the argv[] (param array), argc (param count) arguments to the C program's conventional main entry point defined by the program's main() function. Actually, this isn't the first function that the program would execute at its start time. The C linker would pre-link a lot more functions into the program binary preceding the point at which main() is executed, one of which would always be supposed to provide the main() function with the argv[] command line parameter array and its associated argc count. The exact list and tasks of those extra prologue functions would be compiler and platform dependent but in any case, the programmer would be provided with equal functionality of main() transparently regardless of what compiler they use and on what platform they currently are.

It is only in GUI programs that the C programmer is supposed to call GetCommandLine() under Windows themselves and parse its return string manually but I really do not see any reason why a higher-level language such as OxygenBasic shouldn't ensure that its users can access the command line parameters through a convenient function of the language itself.

FBSL provides the programmer with a STANDALONE environment constant that's TRUE if the program runs precompiled from a stand-alone binary, and FALSE otherwise if interpreted or JIT compiled depending on its content. Access to command line arguments is ensured in both console and GUI scripts via uniform Command() and CommandCount() functions, whereby:
  • Command(0) always returns the name of the binary that's currently running: fbsl.exe/fbsl_tiny.exe if STANDALONE = FALSE or the actual name of the binary otherwise;
  • Command(1 ... n) returns a pre-split CommandCount()-dependent string value of the respective parameter or empty strings if n exceeds the actual command count;
  • a special Command(-1) call returns the entire command line exactly as a GetCommandLine() call would.


[EDIT] Additionally, FBSL provides an APPEXEPATH environment constant that always returns a fully qualified path to the binary that is currently running. This would evaluate to the location where Fbsl.exe and/or Fbsl_Tiny.exe is/are installed if the program runs in the interpretative/JIT compiled mode and the respective STANDALONE value is FALSE, or to the fully qualified path to the precompiled program executable if it is running from its own binary and the respective STANDALONE value is TRUE.

Once an FBSL standalone program is started, its current directory path is always changed to where its binary is located, and the programmer can always resolve any extra relative path dependencies using a CurDir() function call and point the program's current path focus to other disk locations using a CD pathname (= chdir, change current directory) command.
« Last Edit: June 08, 2015, 02:56:33 AM by Mike Lobanovsky »

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #12 on: June 08, 2015, 09:46:03 AM »
Hi Charles,

using the lastest update of Oxygen.dll I had no problems with the include statements when running gxo2 in the path environement. And everything else on my system works as expected.

Roland

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #13 on: June 08, 2015, 09:47:37 AM »
Hi Mike,

I agree that a builtin for getting the commandline args, appexe path / current directory would be helpful (no need for argv, argc). I assume this would not add much overhead to Oxygen.dll. I do not know what should be the case if Oxygenbasic is used with other programming languages but at least Scriptbasic has it's own way to retrieve the commandline, so there should be no problem. But Charles must decide if it is worthwile to add this functionality. In the meantime my little project (which is almost finished) could help in these cases. At least it will be of some help for me. (smiley)

Roland

Aurel

  • Guest
Re: Different approach for Commandline arguments
« Reply #14 on: June 08, 2015, 01:46:59 PM »
Arnold
again..don't get me wrong but this is from vBcode forum:
Quote
I have used following API's

Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hWnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Private Declare Function GetCommandLine Lib "kernel32.dll" Alias "GetCommandLineA" () As String

Private Const SW_MAXIMIZE = 3

Private Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

so if there is used As String  then must work
and from i know and from my experience  in Api declarations most proper way is to use VB way.
so nothing special... ;)