basicqbasicqb64

Triple quotes required on command line in QB64


Have a program which parses the command line in QB64. The COMMAND$ function returns the command line. I need to parse a long filename which might contain a space by parsing it from within quotes to differ from a filename with no space. For example, "long filename.ext"

The problem is that, when the command line has no quotes, the command$ returns the filename, when in quotes, the same, for example "filename", and ""filename"" both return filename. However, """filename""" returns the filename with quotes... Is there another way to send a quote to command$??


Solution

  • QB64 provides the COMMAND$ and _COMMANDCOUNT functions—mostly analogous to argv and argc in C++. COMMAND$ without arguments will return a single string containing all command line args, but QB64 also allows COMMAND$(i) to retrieve the argument at index i as a string. Example from the _COMMANDCOUNT entry on the QB64 Wiki:

    limit = _COMMANDCOUNT
    FOR i = 1 TO limit
        PRINT COMMAND$(i)
    NEXT
    

    You'd use them to deal with the command-line arguments in QB64. If you want to pass command-line args that include quotes to a program, you'd likely need to escape the quotes you want kept using a backslash.

    Unfortunately, the backslash escape isn't foolproof and can lead to trouble in cmd.exe specifically, mainly because backslashes are used in file paths. Combine this with spaces in a file path, and you have a nightmarish command interpreter. From this answer, you double the quotes inside a quoted string to pass a proper quote to a program:

    > program.exe hello world
    hello
    world
    
    > program.exe hello"" world
    hello (+ empty quoted string)
    world
    
    > program.exe "hello"" world
    hello"
    world
    
    > program.exe "hello""" world
    hello" world
    

    In Wine's cmd.exe, the "" escaped quote also closes the quoted string as shown above, so an immediately successive quote is needed to continue grouping the next spaced item with the current argument. I'm not sure about the Windows implementation since I'm not running a Windows machine, but it seems likely to me that the same behavior occurs.

    In other words, you pass """filename""" because:

    "        Open quoted string
    ""       Escaped double quote, closes quoted string
    filename Concatenated at the end of the first quoted string
    "        Open quoted string, concatenated to filename
    ""       Escaped double quote, closes quoted string
    

    Edit

    You can use ^" outside of a quoted string, but that has its own issues as ""^" results in " for example, just like """. Passing ""^" to a batch file requires an extra escape as ""^^". Using ^ is therefore not recommended, especially when "" and """ work just as well. See the answer I linked above for info on the ^ escape character.

    You should also be careful with backslashes and quoted strings. Consider how you might pass the proper Windows representation of the Unix-like argument 'C:/Program Files/"file" name' as a single argument to your program:

    > program.exe "C:\Program Files\\""file\"" name"
    C:\Program Files\"file" name
    

    cmd.exe explanation:

    "                   Open quoted string
    C:\Program Files\\  Quoted string contents, including escaped \
    ""                  Escaped double quote, closes quoted string
    file\               Unquoted string contents, including C escape char
    ""                  Open quoted string with escaped double quote
    [ ]name             Quoted string contents
    "                   Close quoted string
    

    This results in a command-line of "C:\Program Files\\"file\" name" being passed to the program, which then results in a path of C:\Program Files\"file" name. Of course, such a path isn't possible in Windows (and maybe not at all on NTFS filesystems?), but it illustrates the point: you need to account for both cmd.exe's quoting rules and the C runtime's quoting rules and backslash escapes.