Passing main arguments to init functions of gui libraries - c

When it comes to a library initialization in libraries such as Qt and GTK+
You have to pass the main arguments into the function that initializes the library. Why? What is the library doing with them?

Both Qt and GTK+ are designed to respond to certain command line flags for convenience. (Both respond to various environment variables as well.) You don't necessarily have to send argv and argc to the corresponding init functions, but it doesn't hurt, particularly if you intend to take advantage of the features.
Here's what the GTK+ documentation for gtk_init() has to say:
Although you are expected to pass the argc , argv parameters from
main() to this function, it is possible to pass NULL if argv is not
available or commandline handling is not required.
argc and argv are adjusted accordingly so your own code will never see
those standard arguments.
A full list of the command line options that GTK+ accepts is here.
Qt's QApplication similarly accepts command line arguments and removes the ones that it accepts. This is documented along with the accepted arguments in the QApplication constructor documentation.

Related

getopt does not order arguments in Windows

It seems that getopt behaves differently in Windows than in Linux. Windows requires a strict ordering of parameters while in Linux I can put the arguments in any order. Consider a program test which uses getopt compiled for Linux (gcc) and Windows (MinGW) and take this command line for example:
test file1.bin file2.bin -o output.txt
Executing this command in Linux would correctly parse -o output.txt as an option(+parameter) regardless of where I put -o output.txt. It could be between file1.bin and file2.bin as well and getopt parsing would still work correctly since it sorts the arguments by putting the optional ones infront of the mandatories.
Executing this command in Windows however results in incorrect parsing, giving me a wrong index in optind variable. It seems that the exact same code when compiled in Windows does not do the sorting part for me. Why is this, can we workaround this?
Transferring my comments to an answer as requested.
GNU getopt() permutes the arguments (so options can occur after non-option arguments) by default. Standard POSIX getopt() does not allow that. You can make GNU getopt() conform to POSIX by exporting the environment variable POSIXLY_CORRECT=1, or by starting the options argument with a + symbol.
Check the manual (or source) for MinGW getopt(), or the Microsoft implementation of it. Given what you see, it probably doesn't do the permutation. However, the linked source code does support permutation — you'll need to investigate what goes on there.
If you decide to use GNU getopt(), you'll need to get a copy of the GNU getopt() source code (maybe from GitHub getopt.c) and include it in your build process. If you use that, you'll also need ansidecl.h and getopt.h at minimum and you will need to tweak the configuration appropriately.
Or you'll have to decide that the GNU extension of permuting options isn't portable and therefore shouldn't be used at all.

Is there a standardized way to parse command line arguments in C?

I'm learning C programming language and trying to do some basic stuff with it. The problem I faced is how to parse command line arguments. I read this answer and tried to find the library summary for unistd.h functions int the standard N1570. But unfortunately it is not defined there (Work only for POSIX compliant OS as far as I can understand).
AFAIK Windows is not really POSIX compliant so something like in the answer I referred to above
#include <unistd.h>
int main(int argc, char *argv[]){
int opt;
while((opt = getopt(argc, argv, "ilv") != -1){
//do some with it
}
}
is not really portable.
QUESTION: The only standardized and portable way to parse command line args is to do it yourself?
Is there a standardized way to parse command line arguments in C?
Yes there is. Not standardized by the C committee, but by others. The most commonly widespread is POSIX with it's Utility Conventions and getopt utility. Using GNU Argument Syntax with argp is just fun and cool. There is also commonly used GNUs getopt_long for supporting long arguments with getopt.
The only standardized and portable way to parse command line args is to do it yourself?
There is none standardized in C11 way to parse command line. The C11 only specifies, that the main arguments are strings, but they're value is just implementation-defined:
If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment.
The C standard doesn't introduce an abstraction of a "command line", so an abstraction consisting of "command line arguments" and furthermore "command line arguments parsing" is just not defined. I think introducing a standardized way to parse command line arguments is out of scope for a C standard.
The most portable way is to write and use the most portable code. Indeed the most portable code would not use any non-standard C libraries and "do it yourself" in a most portable manner.There is little sense to target all possible architectures and environments. If you are going only for GNU/Linux, I would go with getopt if you want to stay portable to some crazy environment and for argp if you want just to target GNU/Linux specific systems. getopt is really widespread, even a library for embedded systems like newlib has getopt and getopt_long implemented. For others, you can just copy/include the code for getopt from other sources into your program, thus protecting against environments that doesn't have it.

Unsymmetry between main and launching process

A C main method has the signature
int main(int argc, char** argv) {
}
It will get an array of command line parameters. But when trying to launch an application, e.g. using CreateProcess or ShellExecute, they only accept 2 parameters, one for the application to launch and one for the parameters. Why the parameters are not specified as array, too? Why every application that uses other applications has to deal with escaping of command line parameters, e.g., when invoking a compare tool with 2 arbitrary file names that might contain spaces or quotes?
On very few system the actual program execution actually start at the main (or WinMain) or similar function. Instead the compiler tells the linker to use a special function which usually doesn't really take any arguments, in the C sense of the word.
The command-line arguments (if any) could be passed through special registers on the assembly level, or they needs to be fetched using special OS-specific functions (like GetCommandLine in the Windows API).
On Windows, the GetCommandLine function does indeed get the command line as a single string. Just like it was passed to e.g. CreateProcess.
For a Windows console program, the special "entry" function does some other initialization (like setting up stdin etc.), and then calls GetCommandLine to get the command-line arguments, which it then parses into an array suitable for the main function, which is then called.
If you look at the POSIX world (where e.g. Linux and macOS lives) then they have the exec family of functions which does indeed take an array for the arguments. Or a variable-argument list which is parsed into such an array.

Is there a way to pass command line arguments to custom entry point (C / C++)

I used -Wl,-e to change the entry point of a C program, is there a way to still get command line arguments?
Thanks in advance
Globals like _argc/_argv are provided by the compiler's runtime and thus require the compiler's default entry point to set them up. If you use your own entry point, you are bypassing all runtime initializations, so you will have to resort to platform-specific APIs to access the command-line parameters (GetCommandLine() on Windows, read from /proc/self/cmdline on Linux, etc).
– Remy Lebeau

Using '__progname' instead of argv[0]

In the C / Unix environment I work in, I see some developers using __progname instead of argv[0] for usage messages. Is there some advantage to this? What's the difference between __progname and argv[0]. Is it portable?
__progname isn't standard and therefore not portable, prefer argv[0]. I suppose __progname could lookup a string resource to get the name which isn't dependent on the filename you ran it as. But argv[0] will give you the name they actually ran it as which I would find more useful.
Using __progname allows you to alter the contents of the argv[] array while still maintaining the program name. Some of the common tools such as getopt() modify argv[] as they process the arguments.
For portability, you can strcopy argv[0] into your own progname buffer when your program starts.
There is also a GNU extension for this, so that one can access the program invocation name from outside of main() without saving it manually. One might be better off doing it manually, however; thus making it portable as opposed to relying on the GNU extension. Nevertheless, I here provide an excerpt from the available documentation.
From the on-line GNU C Library manual (accessed today):
"Many programs that don't read input from the terminal are designed to exit if any system call fails. By convention, the error message from such a program should start with the program's name, sans directories. You can find that name in the variable program_invocation_short_name; the full file name is stored the variable program_invocation_name.
Variable: char * program_invocation_name
This variable's value is the name that was used to invoke the program running in the current process. It is the same as argv[0]. Note that this is not necessarily a useful file name; often it contains no directory names.
Variable: char * program_invocation_short_name
This variable's value is the name that was used to invoke the program running in the current process, with directory names removed. (That is to say, it is the same as program_invocation_name minus everything up to the last slash, if any.)
The library initialization code sets up both of these variables before calling main.
Portability Note: These two variables are GNU extensions. If you want your program to work with non-GNU libraries, you must save the value of argv[0] in main, and then strip off the directory names yourself. We added these extensions to make it possible to write self-contained error-reporting subroutines that require no explicit cooperation from main."
I see at least two potential problems with argv[0].
First, argv[0] or argv itself may be NULL if execve() caller was evil or careless enough. Calling execve("foobar", NULL, NULL) is usually an easy and fun way to prove an over confident programmer his code is not sig11-proof.
It must also be noted that argv will not be defined outside of main() while __progname is usually defined as a global variable you can use from within your usage() function or even before main() is called (like non standard GCC constructors).
It's a BSDism, and definitely not portable.
__progname is just argv[0], and examples in other replies here show the weaknesses of using it. Although not portable either, I'm using readlink on /proc/self/exe (Linux, Android), and reading the contents of /proc/self/exefile (QNX).
If your program was run using, for instance, a symbolic link, argv[0] will contain the name of that link.
I'm guessing that __progname will contain the name of the actual program file.
In any case, argv[0] is defined by the C standard. __progname is not.

Resources