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

0 Members and 3 Guests are viewing this topic.

Mike Lobanovsky

  • Guest
Re: Different approach for Commandline arguments
« Reply #30 on: June 10, 2015, 01:21:49 PM »
Hi Aurel,

Your code can't handle space-delimited pathnames either. And you should also be aware that Windows accepts both backslashes and forward slashes in its pathnames.

JRS

  • Guest
Re: Different approach for Commandline arguments
« Reply #31 on: June 10, 2015, 01:33:43 PM »
Quote
And you should also be aware that Windows accepts both backslashes and forward slashes in its pathnames.

I can't thank Microsoft enough for seeing the light with this.

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #32 on: June 10, 2015, 04:20:33 PM »
Hi Mike,

you pointed me to a big mistake in my thinking. I must look for arguments enclosed in quotes or in spaces, not for chars > space. Nice idea and bad realization. But I am in the stage of experimenting.

I modified the procedure splitCommandLine, maybe it is correct now. And with spaces in the filename.exe should work now too.

Roland

Edit:

And I found another bug this morning when using args with unclosed quotes. Although this is only a learning exercise and I consider such behaviour as a user error the program should not freeze. I corrected this too. But it is a little bit frustrating. If I produce already so many errors in such a little piece of code, how will it be when I start to write some hundred or thousand lines?


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. ! GetCommandLine alias "GetCommandLineA" lib "kernel32.dll" () as char*  
  9. ! GetCurrentDirectory alias "GetCurrentDirectoryA" lib "kernel32.dll" (dword nBufferLength, char* lpBuffer) as dword
  10. ! GetModuleFileName alias "GetModuleFileNameA" lib "kernel32.dll" (sys hModule, char* lpFilename, DWORD nSize) as dword
  11.  
  12.  
  13. function current_dir() as string      
  14.    zstring CurDir[1024]
  15.    GetCurrentDirectory( 1024, CurDir)
  16.    return CurDir
  17. end function
  18.  
  19. function exe_name() as string
  20.    zstring fname[1024]
  21.    GetModuleFileName(NULL, fname, 1024)
  22.    return fname
  23. end function
  24.  
  25. function exe_path() as string
  26.    string path=exe_name()
  27.    for x=len(path) to 1 step -1
  28.       if asc(path,x)=47 or asc(path,x)=92 then ' / or \
  29.         path=mid(path,1,x-1)
  30.          exit for
  31.       end if
  32.    next x
  33.    return path
  34. end function
  35.  
  36.  
  37. sub splitCommandLine(sys array, cnt, int limit)
  38.  
  39.    string args at array
  40.    int ix at cnt
  41.  
  42.    string cmdline = GetCommandLine
  43.    int length=len(cmdline)
  44.  
  45.    ix=0
  46.    if limit < 2 then
  47.       print "Error in splitCommandLine: limit < 2 "    
  48.       return
  49.    end if
  50.  
  51.    ' build array of args
  52.   p1=1: p2=p1
  53.  
  54.    do
  55.      'filename can be enclosed with ""
  56.     'arguments are separated with space
  57.     if asc(cmdline,p1) = 34 then  ' quote
  58.        'next match
  59.        p2=p1+1
  60.         do
  61.           if p2>length then exit do        
  62.           if asc(cmdline,p2) = 34 then
  63.              exit do
  64.           else
  65.              p2+=1
  66.           end if
  67.         end do                                
  68.      else  ' look for space
  69.        p2=p1+1
  70.         do
  71.           if p2>length then exit do
  72.           if asc(cmdline,p2) = 32 then
  73.              exit do
  74.           else
  75.              p2+=1
  76.           end if
  77.         end do
  78.      end if
  79.  
  80.      ix+=1            
  81.      args[ix]=mid(cmdline,p1,p2-p1+1)
  82.      if asc(cmdline,p1) = 34 then
  83.         'remove quote
  84.        le=len(args[ix])-1
  85.         args[ix]=mid(args[ix],2,le)
  86.      end if
  87.         if asc(cmdline,p2) = 34 then
  88.         'remove quote        
  89.        le=len(args[ix])-1
  90.         args[ix]=mid(args[ix],1,le)
  91.      end if
  92.  
  93.      if ix=1 then
  94.         args[1]=exe_name()
  95.         if mid(args[1],-8) != "gxo2.exe"  _
  96.              and mid(args[1],-7) != "co2.exe" then
  97.  
  98.            'add placeholder
  99.           args[2]=args[1]
  100.            ix+=1
  101.         end if
  102.      end if
  103.      
  104.      if ix=limit then exit do
  105.  
  106.      'next arg
  107.     p1=p2+1
  108.      do
  109.        if asc(cmdline,p1) = 32 then
  110.           p1+=1
  111.        else
  112.           exit do
  113.        end if
  114.      end do
  115.      if p1 > length then exit do    
  116.  
  117.    end do
  118. end sub
  119.  
  120.  
  121. ' Test
  122. '====='
  123.  
  124. dim as string params[16]=""
  125. int count
  126.  
  127. splitCommandLine(@params, @count, countof(params))
  128.  
  129. if count=2 then
  130.    cls
  131.    print "Usage: SplitCommandline arg1 arg2 arg3 ..." & cr
  132.    print "For Help use: SplitCommandLine -help" & cr      
  133. end if
  134.  
  135. if count=3 and params[3]="-help" then
  136.    cls
  137.    print "SplitCommandline is an approach to arrange arguments in the same order" & cr
  138.    print "no matter if run with gxo2.exe / co2.exe or as a stand-alone application" & cr          
  139. end if
  140.  
  141. if count=3 and params[3]!="-help" or count>3 then
  142.    cls
  143.    print "Commandline arguments:" & cr
  144.    for x=1 to count
  145.       print x ") "params[x] & cr
  146.    next x
  147.    print "count of arguments: " count & cr
  148.    print "name of executable: " exe_name() & cr
  149.    print "path of executable: " exe_path() & cr
  150.    print "current directory: "  current_dir() & cr
  151.    if params[1]=params[2] then
  152.       print params[2] " is an executable" & cr
  153.    else
  154.       print params[2] " is executed with " params[1] & cr
  155.    end if
  156. end if
  157.  
  158. print "Enter..." & cr
  159. waitkey()                
  160.  

.
« Last Edit: June 11, 2015, 08:17:24 AM by Arnold »

Mike Lobanovsky

  • Guest
Re: Different approach for Commandline arguments
« Reply #33 on: June 11, 2015, 05:05:19 AM »
Hi Roland,

Yes, now it seems to work correctly and I'm glad that my notes pointed you in the right direction.

Quote
... how will it be when I start to write some hundred or thousand lines?

Do not let such thoughts annoy you before the trouble actually comes. The Russians have a wise and popular maxim "Дорогу осилит идущий", which roughly translates to "Walk and ye shall come".

One method to make you feel less lost in the debris of your trials and failures is to split you scripts into a set of include files, each of which would deal with just one of the major tasks of your application at a time. This would keep you concentrated on a particular job at hand, and it would also keep your code well structured by application tasks and helper functions that you provide to resolve them. A multi-tabbed code editor can assist you in that greately.

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #34 on: June 11, 2015, 08:16:11 AM »
Hi Mike,

yes, this is true. If I do not try I will make no errors. And I will not enhance my knowledge.

I noticed that it could be useful to have a function to retrieve the application folder. This can be different from the current folder, if gxo2 with path set runs an oxygen.o2bas file in a different directory.

But now I should have all the tools to get the necessary information from a commandline to use in a small Oxygen project. Of course this is only one possibilty to do it. And probably not the most effective way.

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. ! GetCommandLine alias "GetCommandLineA" lib "kernel32.dll" () as char*  
  9. ! GetCurrentDirectory alias "GetCurrentDirectoryA" lib "kernel32.dll" (dword nBufferLength, char* lpBuffer) as dword
  10. ! GetFullPathName alias "GetFullPathNameA" lib "kernel32.dll" (char* lpFileName, dword nBufferLength, char* lpBuffer, sys lpFilePart) as dword
  11. ! GetModuleFileName alias "GetModuleFileNameA" lib "kernel32.dll" (sys hModule, char* lpFilename, DWORD nSize) as dword
  12.          
  13.  
  14. function current_dir() as string      
  15.    zstring CurDir[1024]
  16.    GetCurrentDirectory( 1024, CurDir)
  17.    return CurDir
  18. end function
  19.  
  20. function exe_name() as string
  21.    zstring fname[1024]
  22.    GetModuleFileName(NULL, fname, 1024)
  23.    return fname
  24. end function
  25.  
  26. function exe_path() as string
  27.    string path=exe_name()
  28.    for x=len(path) to 1 step -1
  29.       if asc(path,x)=47 or asc(path,x)=92 then ' / or \
  30.         path=mid(path,1,x-1)
  31.          exit for
  32.       end if
  33.    next x
  34.    return path
  35. end function
  36.  
  37. function app_path(string name) as string
  38.    zstring path[1024]
  39.    sys fp
  40.    GetFullPathName(name, 1024, path, @fp)
  41.    for x=len(path) to 1 step -1
  42.       if asc(path,x)=47 or asc(path,x)=92 then ' / or \
  43.         path=mid(path,1,x-1)
  44.          exit for
  45.       end if
  46.    next x
  47.    if x=0 then
  48.       path=current_dir()
  49.    end if
  50.    return path
  51. end function
  52.  
  53.  
  54. sub splitCommandLine(sys array, cnt, int limit)
  55.  
  56.    string args at array
  57.    int ix at cnt
  58.  
  59.    string cmdline = GetCommandLine
  60.    int length=len(cmdline)
  61.  
  62.    ix=0
  63.    if limit < 2 then
  64.       print "Error in splitCommandLine: limit < 2 "    
  65.       return
  66.    end if
  67.  
  68.    ' build array of args
  69.   p1=1: p2=p1
  70.  
  71.    do
  72.      'filename can be enclosed with ""
  73.     'arguments are separated with space
  74.     if asc(cmdline,p1) = 34 then  ' quote
  75.        'next match
  76.        p2=p1+1
  77.         do
  78.           if p2>length then exit do        
  79.           if asc(cmdline,p2) = 34 then
  80.              exit do
  81.           else
  82.              p2+=1
  83.           end if
  84.         end do                                
  85.      else  
  86.         ' look for space
  87.        p2=p1+1
  88.         do
  89.           if p2>length then exit do
  90.           if asc(cmdline,p2) = 32 then
  91.              exit do
  92.           else
  93.              p2+=1
  94.           end if
  95.         end do
  96.      end if
  97.  
  98.      ix+=1            
  99.      args[ix]=mid(cmdline,p1,p2-p1+1)
  100.      if asc(cmdline,p1) = 34 then
  101.         'remove quote
  102.        le=len(args[ix])-1
  103.         args[ix]=mid(args[ix],2,le)
  104.      end if
  105.         if asc(cmdline,p2) = 34 then
  106.         'remove quote        
  107.        le=len(args[ix])-1
  108.         args[ix]=mid(args[ix],1,le)
  109.      end if
  110.  
  111.      if ix=1 then
  112.         args[1]=exe_name()
  113.         if mid(args[1],-8) != "gxo2.exe"  _
  114.              and mid(args[1],-7) != "co2.exe" then
  115.  
  116.            'add placeholder
  117.           args[2]=args[1]
  118.            ix+=1
  119.         end if
  120.      end if
  121.      
  122.      if ix=limit then exit do
  123.  
  124.      'next arg
  125.     p1=p2+1
  126.      do
  127.        if asc(cmdline,p1) = 32 then
  128.           p1+=1
  129.        else
  130.           exit do
  131.        end if
  132.      end do
  133.      if p1 > length then exit do    
  134.  
  135.    end do
  136. end sub
  137.  
  138.  
  139. ' Test
  140. '====='
  141.  
  142. dim as string params[16]=""
  143. int count
  144.  
  145. splitCommandLine(@params, @count, countof(params))
  146.  
  147. if count=2 then
  148.    cls
  149.    print "Usage: SplitCommandline arg1 arg2 arg3 ..." & cr
  150.    print "For Help use: SplitCommandLine -help" & cr      
  151. end if
  152.  
  153. if count=3 and params[3]="-help" then
  154.    cls
  155.    print "SplitCommandline is an approach to arrange arguments in the same order" & cr
  156.    print "no matter if run with gxo2.exe / co2.exe or as a stand-alone application" & cr          
  157. end if
  158.  
  159. if count=3 and params[3]!="-help" or count>3 then
  160.    cls
  161.    print "Commandline arguments:" & cr
  162.    for x=1 to count
  163.       print x ") "params[x] & cr
  164.    next x
  165.    print "count of arguments: " count & cr
  166.    print "name of executable: " exe_name() & cr
  167.    print "path of executable: " exe_path() & cr
  168.    print "path of application: " app_path(params[2]) & cr
  169.    print "current directory: "  current_dir() & cr & cr
  170.    if params[1]=params[2] then
  171.       print params[2] " is an executable" & cr
  172.    else
  173.       print params[2] " is executed with " params[1] & cr
  174.    end if
  175. end if
  176.  
  177. print "Enter..." & cr
  178. waitkey()                
  179.  

.

Mike Lobanovsky

  • Guest
Re: Different approach for Commandline arguments
« Reply #35 on: June 11, 2015, 08:34:43 AM »
Quote
I noticed that it could be useful to have a function to retrieve the application folder. This can be different from the current folder ...

Exactly! Very often the GetOpenFileName/GetSaveFileName APIs that spawn the respective common dialogs can also change the current directory setting transparently to the user. Under such circumstances, it seems only reasonable to have some reference that you can always use to immediately return to your "point of origin" or reconstruct on the fly the other pathnames that may have been possibly specified relative to your binary. This is exactly what the built-in APPEXEPATH constant is for in FBSL. Its actual value is set automatically at app start.

JRS

  • Guest
Re: Different approach for Commandline arguments
« Reply #36 on: June 11, 2015, 09:50:55 AM »
One should embrace their environment (variables) or create their own before starting their journey.

Charles Pegge

  • Guest
Re: Different approach for Commandline arguments
« Reply #37 on: June 11, 2015, 11:55:29 AM »
Hi Roland and Mike,

I've been following your work closely, and thus prompted to make a few additions to OxygenBasic.

I've updated gxo2, co2 and oxide to support spaces in both file-paths and file-names, and to add .o2bas as the default exension

examples:
co2 t.o2bas
co2 t
co2 ..\t
co2 "t t"
co2 "..\t t"


Oxygen has also been tweaked to prevent jit execution of code that has been compiled to a PE file. This is to prevent recursion hazards such as compiling compilers  :o

There is a new include file inc\sysutil.inc, which provides parsing services, and a few additional functions, such as extracting command args, and filepaths.

inc\sysutil.inc
Code: OxygenBasic
  1.  
  2.  'Charles Pegge
  3. '12:49 11/06/2015
  4.  
  5.   include once "minwin.inc"
  6.   include      "ParseUtil.inc"
  7.  
  8.   extern lib "$\oxygen.dll"
  9.   ! o2_mode  (long m)
  10.   ! o2_abst  (string s) as string
  11.   ! o2_asmo  (string s) as string
  12.   ! o2_basic (string s) as sys
  13.   ! o2_exec  (sys p)    as sys
  14.   ! o2_buf   (sys n)    as sys
  15.   ! o2_errno ()         as sys
  16.   ! o2_error ()         as string
  17.   ! o2_get   ()         as string
  18.   ! o2_len   ()         as sys
  19.   ! o2_prep  (string s) as string
  20.   ! o2_put   (string s)
  21.   ! o2_view  (string s) as string
  22.   end extern
  23.  
  24.  
  25.   function DOS(string s)
  26.   ======================
  27.   string c
  28.   static STARTUPINFO         infs
  29.   static PROCESS_INFORMATION infp
  30.   if s then c="cmd.exe /c " else c="cmd.exe "
  31.   CreateProcess null,c+s,0,0,0,0,0,0,@infs,@infp
  32.   WaitForMultipleObjects 1,@infp.hthread,1,-1
  33.   CloseHandle infp.hProcess
  34.   CloseHandle infp.hThread
  35.   end function
  36.  
  37.  
  38.   function CommandLineArgs() as string
  39.   ====================================
  40.   string s,command
  41.   sys i=1
  42.   Command = (char) GetCommandLine
  43.   s=GetWord command,i 'step over filepath\file
  44.  SkipSpace command,i
  45.   return mid Command, i
  46.   end function
  47.  
  48.  
  49.   function ParseFileName(string src, sys *ii, string *mnm, *xnm) as string
  50.   ========================================================================
  51.   sys    i=1, dt
  52.   string s
  53.   s=unquote getword src,ii
  54.   skipspace(src,ii)
  55.   do
  56.     i++
  57.     select asc s,i
  58.     case 46        : dt=i 'position of latest dot
  59.    case 47,92     : dt=0 'exclude .\ ..\
  60.    case 0         : exit do
  61.     end select
  62.   end do
  63.   '
  64.  if dt then
  65.     mnm=left s,dt-1
  66.     xnm=mid s,dt
  67.   else
  68.     mnm=left(s,i-1)
  69.   end if
  70.   return mnm+xnm
  71.   end sub
  72.  
  73.  
  74.   function ExeDir() as string
  75.   ===========================
  76.   char s[256]
  77.   byte b at strptr s
  78.   GetModuleFileName 0,s,256
  79.   sys i
  80.   do
  81.     select b
  82.     case 0  : exit do
  83.     case 92 : i=@b
  84.     end select
  85.     @b++
  86.   end do
  87.   return left s,i-strptr s
  88.   end function
  89.  
  90.  
  91.   function CurDir() as string
  92.   ===========================
  93.   char s[256]
  94.   GetCurrentDirectory 256, s
  95.   return s
  96.   end function
  97.  
  98.   macro CreateArgv
  99.   ================
  100.   sys    argv[64], argc
  101.   string arga[64]
  102.   string args=GetCommandLine
  103.   scope
  104.     indexbase 0
  105.     sys i=1
  106.     do
  107.       arga[argc]=unquote getword args,i
  108.       if not arga[argc] then exit do
  109.       argv[argc]=strptr arga[argc]
  110.       argc++
  111.     end do
  112.   end scope
  113.   end macro
  114.  
  115.  
  116.   string prs
  117.   string cr  = chr(13,10)
  118.  
  119.   sub pri(string s)
  120.   =================
  121.   prs+=s+cr
  122.   end sub
  123.  


This substantially cleans up the source code for co2.exe
Code: OxygenBasic
  1.  
  2.  'Compiler for OxygenBasic
  3. '========================
  4.  
  5.  'Charles Pegge
  6. '12:53 11/06/2015
  7.  
  8.   #compact
  9.   #file       "co2.exe" 'Oxygen dependent compiling
  10.  %NoConsole
  11.   includepath "$\inc\"
  12.   include     "SysUtil.inc"
  13.   include     "console.inc"
  14.  
  15.   sys    a,i
  16.   string s,t,u
  17.   sys    swa,swc,swm       'COMPILER SWITCHES
  18.  string fname,mname,xname 'FILE NAME COMPONENTS
  19.  string er                'ERROR MESSAGES
  20.  '
  21.  s=lcase CommandLineArgs()
  22.   if not s then goto nofile
  23.   '
  24.  'SWITCHES
  25.  '========
  26.  i=0
  27.   do
  28.     i++ : skiplspace s,i
  29.     if ascb<>45 then exit do
  30.     i++ : skiplspace s,i
  31.     select ascb
  32.     case "i" : swa=ascb '-i intermediate output
  33.    case "a" : swa=ascb '-a asm output
  34.    case "b" : swa=ascb '-b o2 output
  35.    case "c" : swc=ascb '-c compile
  36.    case "m" : swm=ascb '-m do not show messagebox
  37.    end select
  38.   end do
  39.   '
  40.  s=mid s,i
  41.   '
  42.  nofile: 'check
  43.  '=============
  44.  '
  45.  if not s then
  46.   pri "
  47.   compiler options:
  48.   <filename>       compile and execute directly in memory
  49.   -a <filename>    list assembly code
  50.   -b <filename>    list o2 machine script
  51.   -c <filename>    compile to an executable file
  52.   -i <filename>    list intermediate code
  53.   -m               output to console
  54.   "
  55.   jmp fwd done
  56.   end if
  57.  
  58.   i=1 : xname=".o2bas" 'DEFAULT EXTENSION NAME
  59.  fname=ParseFileName(s,i,mname,xname)
  60.   '
  61.  '
  62.  'ATTEMPT TO GET FILE
  63.  '===================
  64.  '
  65.  t=getfile fname
  66.   if not t then
  67.     pri "error 3: file empty or not found: "+fname
  68.     jmp fwd done
  69.   end if
  70.   '
  71.  u="#basic"+cr
  72.   '
  73.  if swc then
  74.     u+="#file "+qu+mname+".exe"+qu+cr
  75.   end if
  76.   '
  77.  t=u+chr(12)+t
  78.   '
  79.  '
  80.  'NORMAL COMPILE
  81.  '==============
  82.  
  83.  'o2_mode 0  'read/return null terminated ascii strings
  84.  o2_mode 9   'ascii string (1: byte characters) (8: o2 string)
  85.  '
  86.  select swa
  87.   case "a"  : prs = o2_prep  t
  88.   case "i"  : prs = o2_abst  t
  89.   case "b"  : prs = o2_view  t
  90.   case else :       o2_basic t
  91.   end select
  92.   '
  93.  er=o2_error
  94.   '
  95.  if er then
  96.     pri cr+ er
  97.     jmp fwd done
  98.   else
  99.     if swc=0 then
  100.       o2_exec 0
  101.     else
  102.       pri cr+"Okay"
  103.     end if
  104.   end if
  105.  
  106.   done:
  107.  
  108.   sys ho,lew
  109.   if len(prs) then
  110.     if swm=0 then
  111.       mbox prs
  112.     else
  113.       ho=GetStdHandle( STD_OUTPUT_HANDLE ) 'do this before AttachConsole
  114.      AttachConsole(-1) 'attach to console of parent process
  115.      WriteFile( ho, strptr prs, len(prs)+1, lew, null ) 'accepts redirected STDOUT
  116.      FreeConsole
  117.     end if
  118.   end if
  119.  




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

OxyMin Update (800k)
http://www.oxygenbasic.org/o2zips/OxyMin.zip

OxygenBasic Full Update (4700k)
http://www.oxygenbasic.org/o2zips/OxygenBasic.zip

« Last Edit: June 11, 2015, 12:13:01 PM by Charles Pegge »

Mike Lobanovsky

  • Guest
Re: Different approach for Commandline arguments
« Reply #38 on: June 11, 2015, 01:27:04 PM »
Hi Charles,

Quote
I've been following your work closely ...

Thank you; I think it was what both Roland and I were secretly hoping for...

Quote
... and thus prompted to make a few additions to OxygenBasic. I've updated gxo2, co2 and oxide to support spaces in both file-paths and file-names ...

Excellentissimo! I always can't help admiring how laconic, exact and elegant your OxygenBasic code is. :)

Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #39 on: June 12, 2015, 03:35:19 AM »
Hi Charles,

it is good to know that Oxygen is now able to compile path\filename with spaces in it. I omit using spaces. I could save and run OxygenBasic in folder "program files" but I would always need  administrator privileges. Nevertheless sometimes it could be necessary to use these namings.

There was a small problem with using co2.exe because it contains a path "c:\cevp\..." . But after compiling co2.o2bas with gxo2.exe and then compiling co2.o2bas with the new co2.exe everything works ok. I also did a full Compile and Run test with gxo2.exe (without the tests folder). Everything seems to work like before. There were some messages (e.g. in examples\OpenGL\glMathTest) but I think this is because of changing to a newer version of OpenGL?

Roland


Charles Pegge

  • Guest
Re: Different approach for Commandline arguments
« Reply #40 on: June 12, 2015, 07:31:19 PM »
Mike,

One of my original intentions in creating OxygenBasic was to facilitate clearer code by reducing syntax 'noise' - making the compiler work a bit harder behind the scenes. Organizing compact, useful libraries takes a little longer, but I think we are making progress.

I am intrigued that FBSL reads all the core Windows calls from Kernel32.dll etc. How long does this take? Presumably faster than reading a full set of API declarations.

Thanks for testing, Roland.

Some of the pieces in examples/Opengl/glmath use GLSL 3.3 and geometry shaders, which may not work on older graphics cards. (mine is 2009 nvidia).


Arnold

  • Guest
Re: Different approach for Commandline arguments
« Reply #41 on: June 13, 2015, 03:43:54 AM »
Hi Charles,

maybe you will not notice this within your development system, so I would like to mention this:

if I run co2.exe I get the message:  c:\cevp\code\oxygenbasic\oxygen.dll
Using my Textcrawler program I find this path included in co2.exe. I do not find it anywhere else in the files of the Oxygenbasic folder. Anyway if I compile co2.o2bas with gxo2.exe and make a copy in Oxygenbasic and then compile co2.o2bas again with co2.exe everything works ok.

I am trying to rebuild my little project with sysutil.inc. It seems that I use CreateArgV the wrong way. Do I need some parameters with CreateArgV?

Roland

Code: OxygenBasic
  1. $ filename "TestArg Prog.exe"
  2. includepath "$/inc/"
  3. '#include "RTL32.inc"
  4. '#include "RTL64.inc"
  5.  
  6. include "sysutil.inc"
  7. include "console.inc"
  8.  
  9. string fname,mname,xname 'FILE NAME COMPONENTS
  10.  
  11. print "This will only work with version A41 12/06/2015 and later" & cr
  12.  
  13. string cmd_args=lcase CommandLineArgs() : printl "Commandline Args: " cmd_args
  14.  
  15. i=1 : xname=".o2bas" 'DEFAULT EXTENSION NAME
  16. fname=ParseFileName(cmd_args,i,mname,xname) : printl "Filename: " fname
  17.  
  18. string exe_path = ExeDir(): printl "ExeDir = " exe_path
  19. string current_dir = CurDir(): printl "Current directory = " current_dir
  20.  
  21. waitkey()
  22.  
  23. CreateArgV
  24.  
  25.  
  26. printl"Enter ... ": waitkey()
  27.  

Charles Pegge

  • Guest
Re: Different approach for Commandline arguments
« Reply #42 on: June 13, 2015, 03:58:15 AM »
Hi Roland,

Yes, I see the problem now. The file path to Oxygen.dll got baked at compiletime.

inc\sysutil.inc

  extern lib "$\oxygen.dll"

  extern lib "oxygen.dll"

Also fixed looping problem in CreateArgv.

'Argc is the count
'Arga[ ] is an array of arguments as strings
'Argv[ ] as a block of string pointers
CreateArgv
for i=1 to argc
printl arga[ i ] 'strings
next
waitkey


Sysutil.inc
Code: OxygenBasic
  1.  
  2.  'Charles Pegge
  3. '12:57 13/06/2015
  4.  
  5.   include once "minwin.inc"
  6.   include      "ParseUtil.inc"
  7.  
  8.   extern lib "oxygen.dll"
  9.   ! o2_abst      (string s) as string
  10.   ! o2_asmo      (string s) as sys
  11.   ! o2_assemble  (string s) as sys
  12.   ! o2_basic     (string s) as sys
  13.   ! o2_exec      (sys p)    as sys
  14.   ! o2_buf       (sys n)    as sys
  15.   ! o2_errno     ()         as sys
  16.   ! o2_error     ()         as string
  17.   ! o2_get       ()         as string
  18.   ! o2_len       ()         as sys
  19.   ! o2_link      ()         as sys
  20.   ! o2_mode      (sys m)
  21.   ! o2_pathcall  (sys m)
  22.   ! o2_prep      (string s) as string
  23.   ! o2_put       (string s)
  24.   ! o2_varcall   (sys m)
  25.   ! o2_view      (string s) as string
  26.   end extern
  27.  
  28.  
  29.   function Exec(string c, sys wait=0)
  30.   ===================================
  31.   STARTUPINFO infs
  32.   PROCESS_INFORMATION infp
  33.   CreateProcess null,c,0,0,0,0,0,0,@infs,@infp
  34.   if wait
  35.     WaitForMultipleObjects 1,@infp.hthread,1,-1
  36.   end if
  37.   CloseHandle infp.hProcess
  38.   CloseHandle infp.hThread
  39.   end function
  40.  
  41.  
  42.   function DOS(string s, sys wait=0)
  43.   ==================================
  44.   string c
  45.   if s then
  46.     c="cmd.exe /c "+s
  47.   else
  48.     c="cmd.exe"
  49.   end if
  50.   Exec c, wait
  51.   end function
  52.  
  53.  
  54.   function CommandLineArgs() as string
  55.   ====================================
  56.   string s,command
  57.   sys i=1
  58.   Command = (char) GetCommandLine
  59.   s=GetWord command,i 'step over command filepath\file
  60.  SkipSpace command,i
  61.   return mid Command, i
  62.   end function
  63.  
  64.  
  65.   function ParseFileName(string src, sys *ii, string *mnm, *xnm) as string
  66.   ========================================================================
  67.   sys    i=1, dt
  68.   string s
  69.   s=unquote getword src,ii
  70.   skipspace(src,ii)
  71.   do
  72.     i++
  73.     select asc s,i
  74.     case 46        : dt=i 'position of latest dot
  75.    case 47,92     : dt=0 'exclude .\ ..\
  76.    case 0         : exit do
  77.     end select
  78.   end do
  79.   '
  80.  if dt then
  81.     mnm=left s,dt-1
  82.     xnm=mid s,dt
  83.   else
  84.     mnm=left(s,i-1)
  85.   end if
  86.   return mnm+xnm
  87.   end sub
  88.  
  89.  
  90.   function ExeDir() as string
  91.   ===========================
  92.   char s[256]
  93.   byte b at strptr s
  94.   GetModuleFileName 0,s,256
  95.   sys i
  96.   do
  97.     select b
  98.     case 0  : exit do
  99.     case 92 : i=@b
  100.     end select
  101.     @b++
  102.   end do
  103.   return left s,i-strptr s
  104.   end function
  105.  
  106.  
  107.   function CurDir() as string
  108.   ===========================
  109.   char s[256]
  110.   GetCurrentDirectory 256, s
  111.   return s
  112.   end function
  113.  
  114.   macro CreateArgv
  115.   ================
  116.   sys    argv[64], argc
  117.   string arga[64]
  118.   string args=GetCommandLine
  119.   scope
  120.     indexbase 0
  121.     sys i=1
  122.     do
  123.       arga[argc]=unquote getword args,i
  124.       if ascb=0 then exit do
  125.       argv[argc]=strptr arga[argc]
  126.       argc++
  127.     end do
  128.   end scope
  129.   end macro
  130.  
  131.  
  132.   string prs
  133.   string cr  = chr(13,10)
  134.  
  135.   sub pri(string s)
  136.   =================
  137.   prs+=s+cr
  138.   end sub
  139.  



« Last Edit: June 13, 2015, 04:33:01 AM by Charles Pegge »

Mike Lobanovsky

  • Guest
Re: Different approach for Commandline arguments
« Reply #43 on: June 13, 2015, 11:27:31 AM »
Hi Charles,

I swear in all honesty that everything I'm telling you is true to the last word.

The FBSL binaries currently carry about 50KB of tightly zipped data (mainly keyword and message tables, and a few auxiliary hash tables such as are usually used for cyclic redundancy checks, password creation and script obfuscation) that are the first to get decompressed and mapped into the process memory once the process starts. Then FBSL's built-in constants are created and the internal functions that are supposed to execute FBSL's high-level BASIC bytecode are mapped into the respective hash tables. All in all, it takes up to 20 milliseconds to launch FBSL proper including the time it takes the OS to connect all the relevant system libraries to the FBSL process.

It takes another 30 to 60 milliseconds to parse, precompile to bytecode and/or JIT machine code, and launch a medium sized BASIC+DynC+DynAsm scripted project of about 10 to 15 thousand code lines (that's my favorite size :) ) for execution. Anything less than a thousand code lines can hardly be benchmarked. It may take yet a couple milliseconds more to decompress and deobfuscate the same script if it is embedded in a precompiled executable in the form of an LZMA-compressed payload. Decompression/deobfuscation runs at about 15MB of scripted code per second. Then, code parsing and precompilation proper begins.

First, the four DLLs I told you about are scanned for the constituent API names and entry points, and an approx. 200KB large Windows.inc file for the BASIC preprocessor is scanned (that's roughly a WINDOWS_LEAN_AND_MEAN equivalent), and the respective hash tables are created.

Next, the BASIC compiler starts its work. It's a three-pass compiler with a multiply reentrant recursive descent parser. The first pass is used to tokenize the entire script including BASIC, C, and asm vocabulary. The second pass creates the actual binary bytecode tree and resolves cross-references between BASIC, C, asm, and external procedures. That's the heaviest pass of all the three, and it takes GCC almost a minute to compile that file alone on my 3.2GHz PC. The third pass is used for some simple optimization of BASIC bytecode like macro expansion and constant propagation.

At pass 2 of BASIC bytecode compiler, Dynamic C and Dynamic Asm jitters also compile their respective code blocks from the tokens prepared by the BASIC compiler during its pass 1. The Dynamic C JIT compiler is a deeply nested one-pass recursive descent compiler based on Fabrice Bellard's Tiny C Compiler v0.9.25. Its compilation speed on my PC is on the order of 50MB of raw C code per second; it's simply lightning fast. The Dynamic Asm compiler is my own "1.5-pass" recursive descent compiler that does only one level deep recursion when resolving a label, and runs only one pass unless assembly contains forward references, in which case it runs a brief additional half-pass to fill in the blanks with i) actual addresses of forward references it didn't know how to resolve on its first pass, and ii) 1-clock variable-length NOP padding dummies like mov eax, eax etc. where necessary. I've worked out a habit of avoiding forward references in my asm code altogether to make the compiler do everything in one pass, if possible, and to also make my asm code run a few clocks faster avoiding NOPs associated with forward references. :) The DynAsm jitter works at about 10MB of asm code per second if not monitored via the Asm Logger window that's available in a special build of Fbsl.exe binary, in which case the speed would drop to some 4 or 5K lines of asm code per second.

I have never seen any script that would take FBSL more than 80 milliseconds to start executing. Actually, the OpenGL render context initialization routine alone written in FBSL BASIC in my current Objector project takes two or three times longer to execute than it takes FBSL to parse, compile, and start to execute this entire project with its main script plus 19 include files of BASIC, C, and assembly code. :)

JRS

  • Guest
Re: Different approach for Commandline arguments
« Reply #44 on: June 13, 2015, 11:45:41 AM »
I'm confused. I thought FBSL (Freestyle BASIC Scripting Language) was an interpreter. Based on the above description, it's a high performance BASIC compiler.