Entire Unparsed A_Args? Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Entire Unparsed A_Args?

29 Dec 2023, 07:43

I was trying to find if anyone has found a tested way to get the entire script parameter argument string that was used to run the current script (like %* in batch files). Here are the constraints I have:
  • I can't wrap the script call in a batch file to preprocess things. I need to handle it in AHK.
  • I can't enclose the entire parameter list in quotes and then get A_Args[1]. (This will be my fallback but will take extra work across many callers.)
  • I've tried with a DLL call to GetCommandLineW, but that's the entire command line. It would require reparsing to handle the AHK exe and script name (or an alternative if compiled) plus all the possible switches that might have come before the intended parameter list. I just want the script parameter portion after everything else has been consumed.
  • I've tried rejoining A_Args, but many of the parser's effects cannot be precisely reversed (multiple spaces, terminal \", etc.) without quite a bit of processing that seems like it shouldn't be necessary.
I guess I could violate any of those constraints with more work to all the callers, or some middleware, and/or reparsing everything to undo the parsing. I was just certain this must have dealt with before. I found a lot of threads that danced around the edges of it, but none that really solved this issue. It seems like there might be an A_ArgLine or A_ArgStr or A_AllArgs variable (or something like that) that contains the unparsed string. Is there such a thing, even if undocumented? Many thanks in advance for the help.
User avatar
mikeyww
Posts: 26998
Joined: 09 Sep 2014, 18:38

Re: Entire Unparsed A_Args?

29 Dec 2023, 08:59

If you don't want to reassemble the individual arguments, you can use the command line and just strip the switches from it. Why rejoin anyway? What are you trying to achieve? What parser problem exists, specifically?
sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Re: Entire Unparsed A_Args?

29 Dec 2023, 09:34

I have a caller that sends inconsistenly quoted arguments that may or may not contain spaces. Basically, it requires much more complicated parsing of the script args than AHK does by default. I could just make the caller enclose the whole thing in quotes, but it happens in a lot of places and causes other weirdness in the way it then applies quotes. I could make some middle batch file, but that seemed silly. I just figured there must be a way, even if undocumented. If batch files can easily do something (with %*) that AHK can't, that would be a first for me. It just seemed like a miss, especially since the data is there to start with. I wonder if @lexikos has considered this? I'm guessing he probably has and the use case isn't strong enough.

I could write a regex to strip all the switches, plus handle compiled vs uncompiled calls, but it seemed like a lot of trial and error and testing for something that I thought might already be there behind the scenes. As I mentioned, quoting all the args as a group may be my fallback, but I need to see how intelligent the sender (and the AHK parser) are about the nested quotes. Like you said, stripping the switches may be easier. But even there, my regex needs to strip quoted and unquoted path possibilities (potentially 4 of them, including exe/script/lib/include) and 10 switches, and it will be fragile re potential new switches in future versions.

I guess it's doable, but it was one of those things where I was saying to myself that there must be an easier way. You guys are very knowledgeable though, so I trust that if you don't know of an easier way, it probably doesn't exist. Thanks for the quick reply!
User avatar
mikeyww
Posts: 26998
Joined: 09 Sep 2014, 18:38

Re: Entire Unparsed A_Args?

29 Dec 2023, 09:39

OK. I can't claim all knowledge, but I think that the options are to use the command line or to use A_Args.
sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Re: Entire Unparsed A_Args?

29 Dec 2023, 09:42

Your 25K post count (vs my pathetic 200) tells me you've probably forgotten more about AHK than I'll ever know. :) Thanks again!
coffee
Posts: 133
Joined: 01 Apr 2017, 07:55

Re: Entire Unparsed A_Args?

29 Dec 2023, 15:48

I've tried rejoining A_Args, but many of the parser's effects cannot be precisely reversed
Many of what parser effects? i did a quick skim on source and autohotkey doesn't do anything to the command line arguments, it leaves them as they are received from shell/operating system, whatever autohotkey receives, it's windows' fault for screwing the order of any internal quotes. It receives __targv which is provided by stdlib. It simply matches to the built in switches, then passes the pointer to the function that creates a_args. It does nothing to the quotes, nothing to the contents.

This may not be that "autohotkey" broke it, but more like, no introspection is being done on __targv to account for edge cases, since everyone would have a different edge case. You have to handle your own edge cases.

Matching against a compiled or not script is trivial since you can always regexreplace both a_ahkpath and a_scriptFullPath, which would handle either uncompiled and compiled. The only problem really left is the one you pointed out about new built-in switches being introduced requiring an update to the script.

Now, whether there's a better way to receive arguments from the OS, that's up to the implementer to research.
sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Re: Entire Unparsed A_Args?

29 Dec 2023, 16:08

I learn something new every day. I was assuming the \" final quote thing (for example) was from AHK, but I guess it's just Windows' weak parsing to begin with. I was looking at the docs on __argc, __argv, __wargv and trying to figure out how batch files handle the %* request. Maybe it just removes the batch file's path\filename from the full command line, as we're contemplating doing here?

Also, great suggestion on handling the compiled/uncompiled issue. Thanks for all the info!
TAC109
Posts: 1112
Joined: 02 Oct 2013, 19:41
Location: New Zealand

Re: Entire Unparsed A_Args?

29 Dec 2023, 17:31

Not sure I fully understand what is required, but this is what I use to capture all arguments to a string. Each argument will become enclosed by double-quotes, which should be ok as these will be stripped off by the OS when passed to another app. The problem of a parameter ending with a back-slash (\) is also dealt with. The parameter string ends up in 'Par', which can then be passed to another app.

Code: Select all

For v in A_Args            ; Add quotes to parameters & escape any trailing \
	wk := StrReplace(v,'"','\"'), Par .= '"' wk (SubStr(wk,-1)='\' ? '\' : '') '" '
MsgBox Par                 ; For testing purposes
Cheers
My scripts:-
XRef - Produces Cross Reference lists for scripts
ReClip - A Text Reformatting and Clip Management utility
ScriptGuard - Protects Compiled Scripts from Decompilation
I also maintain Ahk2Exe
User avatar
Seven0528
Posts: 347
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: Entire Unparsed A_Args?  Topic is solved

29 Dec 2023, 20:45

 You're welcome.

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force

Msgbox "A_Args.Length : " A_Args.Length
for i,v in A_Args
    Msgbox "A_Args[" i "] :`n" v

Msgbox "A_.CommandLine :`n" A_.CommandLine
Msgbox "A_.Argv.Length : " A_.Argv.Length
for i,v in A_.Argv
    Msgbox "A_.Argv[" i "] :`n" v

Msgbox "A_.CommandLineExecutablePath :`n" A_.CommandLineExecutablePath
Msgbox "A_.CommandLineArguments :`n" A_.CommandLineArguments



Class A_ ;  v2.0
{
    /*
    A_.CommandLine
    A_.Argv
        A_.Argv[i]
    A_.Argc
    A_.CommandLineExecutablePath
    A_.CommandLineArguments
    */
    static CommandLine    {
        get  {
            static vCommandLine:=GetCommandLine()
            return vCommandLine
        }
    }
    static Argv    {
        get  {
            static vArgv:=CommandLineToArgvW(A_.CommandLine)
            return vArgv
        }
    }
    static Argc    {
        get  {
            static vArgc:=A_.Argv.Length
            return vArgc
        }
    }
    static CommandLineExecutablePath    {
        get  {
            static vCommandLineExecutablePath:=A_.Argv[1]
            return vCommandLineExecutablePath
        }   
    }
    static CommandLineArguments    {
        get  {
            static vArguments:=RegExReplace(RegExReplace(GetCommandLine(),"s)^(?:`"\Q" A_.CommandLineExecutablePath "\E`"|\Q" A_.CommandLineExecutablePath "\E)(.*)","${1}"),"s)^ (.*)","${1}")
            return vArguments
        }
    }
}
GetCommandLine()    { ;  v1.1  v2.0
	return DllCall("Kernel32.dll\GetCommandLine", "Str")
}
CommandLineToArgvW(CmdLine:="")    { ;  v2.0
	args:=[]
	if (pArgs:=DllCall("Shell32.dll\CommandLineToArgvW", "WStr",CmdLine, "Ptr*",&nArgs:=0, "Ptr"))    {
		Loop nArgs
			args.Push(StrGet(NumGet((A_Index-1)*A_PtrSize+pArgs,"Ptr"),"UTF-16"))
		DllCall("Kernel32.dll\LocalFree", "Ptr",pArgs)
	}
	return args
}
Last edited by Seven0528 on 30 Dec 2023, 04:52, edited 1 time in total.
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
User avatar
Seven0528
Posts: 347
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: Entire Unparsed A_Args?

29 Dec 2023, 20:53

 When an AHK file is executed, it is structured in the following command line.:

Code: Select all

AutoHotkey.exe [Switches] [Script Filename] [Script Parameters]
The Switches section might be omitted or contain multiple entries,
so the specific positioning of Script Parameters depends on the location of the Script Filename.
https://www.autohotkey.com/docs/v2/Scripts.htm#cmd

The only solution available might be to retrieve the entire command using A_.CommandLineArguments and extract the necessary details again via RegExReplace.

Code: Select all

Msgbox "A_.CommandLineArguments :`n" A_.CommandLineArguments
Msgbox "A_ScriptFullPath : `n" A_ScriptFullPath

if (!A_IsCompiled)
    Msgbox RegExReplace(RegExReplace(A_.CommandLineArguments,"s)^(?:`"\Q" A_ScriptFullPath "\E`"|\Q" A_ScriptFullPath "\E)(.*)","${1}"),"s)^ (.*)","${1}")

If the AHK script has been compiled (A_IsCompiled), the logic would need to change as well.
While it's an interesting premise, it's not something I personally require, so I won't dwell on it any further...
(If pursued, it would likely involve using RegExReplace with the first argument of A_Args.)

Code: Select all

CompiledScript.exe [Switches] [Script Parameters]
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Re: Entire Unparsed A_Args?

29 Dec 2023, 22:55

@Seven0528, this is super cool! Thanks for taking time to do that. Plus, I like the way you used the class and getters and everything. Gives me lots of good ideas for my own library. I will work through the issues you point out in your subsequent message, but this helps a whole lot. Thanks again!

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: Archimede, CraigM, Datrik, ManuelesAdrian, songdg and 69 guests