Why is libargtable behaving strangely with optional arguemnts? - c

On the off-chance that anyone uses argtable as a command line argument parser for C-Code, here is my question:
My Intention
I'm programming in C on a Linux platform using the most recent version of the argtable2 library.
What I want to archive is have a program that takes multiple input files and an optional option (let's call it -o). If -o is not provided as an option in a shell call, no output is written by the program whatsoever. If -o is provided by itself the program's output is written to a default file called "output.txt". If the option is provided together with a file name, e.g. -o other.txt, the output should be written to the file name that was given - in this case to "other.txt".
The Problem
In all my tries argtable misbehaved. It interprets the optional value given along with -o as an input file. So ./program -o other.txt inputfile1.dat inputfile2.dat inputfile3.dat would be interpreted as having four inputfiles - the three "inputfile*.dat"s and "other.txt" which is supposed to be the output file.
Reproduce the problem
Here is a shell session to illustrate, what I mean. It uses a minimal example that produces the problem. I'm not sure if I did something wrong or if it is a bug in libargtable2:
confus#confusion:~$ gcc -o argbug argbug.c -largtable2
confus#confusion:~$ ./argbug
Error: missing option INPUT-FILES
Usage:
./argbug [-o [<file>]] INPUT-FILES
-o [<file>] File to write output to. Default is 'output.txt'.
Omit whole option to discard all output
INPUT-FILES Input files
confus#confusion:~$ ./argbug inputfile1.dat inputfile2.dat inputfile3.dat -o other.txt
inputfile[0] = inputfile1.dat # this is okay output
inputfile[1] = inputfile2.dat # as is this line
inputfile[2] = inputfile3.dat # also okay output
inputfile[3] = other.txt # "other.txt" is falsely recognized as an input file
outputfile = output.txt # should be "other.txt" instead of the default "output.txt"
Either way neither I nor Steward, the author of argtable seem to have time to really look into my problem. Any ideas?

I ran your test and found the same problem. Looking into the source, it seems libargtable is handling it correctly, but it boils down to getopt behavior.
If you look beginning at line 647 in getopt.c, you can see that getopt first checks if there is an argument attached without any space in between the option and the argument (e.g. -oother.txt). If that is the case, it handles it. That is the only case in which it will notice an optional argument.
To test this, try
void *argtable[] = { argOutput, end };
in your testcase, and then
./argbug -o other.txt
You will see that it gives an error.
However, it then has an additional piece of code which checks if there is a required option. If so, is will perform an additional search for options to satisfy this even if there is a space between the flag and argument.
Hint for looking at the code: has_arg is an enum with 0=No argument 1=Required arguemnt 2=Optional argument
Short Answer
libargtable will not process optional arguments if there is a space between the flag and the argument. Remove the space and it should work.
I might consider this a bug, but perhaps some people like this behavior.

Related

what are dump and auxillary files?

Im a newcommer to Linux and the gcc commands. I was reading the
gcc documentation particularly about the -o flag where it mentions the following:
Though -o names only the primary output, it also affects the naming of
auxiliary and dump outputs. See the examples below. Unless overridden,
both auxiliary outputs and dump outputs are placed in the same
directory as the primary output. In auxiliary outputs, the suffix of
the input file is replaced with that of the ...
They mention it quite a lot following this paragraph but don't explain it. I've skimmed the document and also looked online but haven't found any satisfactory explanation. If someone could provide me some explanation or even link me to some resources where I can learn about these terms it would be greatly appreciated. Thanks!
-o file
Place the output in file. This applies regardless of the type of output produced, whether it is an executable file, an object file, an assembler file or preprocessed C code.
Since only one output file can be specified, it makes no sense to use -o when compiling more than one input file, unless you want to output an executable file.
If -o is not specified, the default behavior is to produce an executable file named a.out, an object file for source.suffix named source.o, its assembler file in source.s, and all C source code preprocessed on standard output.
source: http://www.linuxcertif.com/man/1/gcc/
hope it will be useful

How is rustc able to compile source code from bash process substitution but gcc cannot?

$ rustc <(echo 'fn main(){ print!("Hello world!");}')
$ ls
63
$ gcc <(echo '#include<stdio.h> int main(){ printf("Hello world!\n"); return 0;}')
/dev/fd/63: file not recognized: Illegal seek
collect2: error: ld returned 1 exit status
Why can't ld link the program?
The gcc command is mostly a dispatch engine. For each input file, it determines what sort of file it is from the filename's extension, and then passes the file on to an appropriate processor. So .c files are compiled by the C compiler, .h files are assembled into precompiled headers, .go files are sent to the cgo compiler, and so on.
If the filename has no extension or the extension is not recognised, gcc assumes that it is some kind of object file which should participate in the final link step. These files are passed to the collect2 utility, which then invokes ld, possibly twice. This will be the case with process substitution, which produces filenames like /dev/fd/63, which do not include extensions.
ld does not rely on the filename to identify the object file format. It is generally built with several different object file recognisers, each of which depends on some kind of "magic number" (that is, a special pattern at or near the beginning of the file). It calls these recognisers one at a time until it finds one which is happy to interpret the file. If the file is not recognised as a binary format, ld assumes that it is a linker script (which is a plain text file) and attempts to parse it as such.
Naturally, between attempts ld needs to rewind the file, and since process substitution arranges for a pipe to be passed instead of a file, the seek will fail. (The same thing would happen if you attempted to pass the file through redirection of stdin to a pipe, which you can do: gcc will process stdin as a file if you specify - as a filename. But it insists that you tell it what kind of file it is. See below.)
Since ld can't rewind the file, it will fail after the file doesn't match its first guess. Hence the error message from ld, which is a bit misleading since you might think that the file has already been compiled and the subsequent failure was in the link step. That's not the case; because the filename had no extension, gcc skipped directly to the link phase and almost immediately failed.
In the case of process substitution, pipes, stdin, and badly-named files, you can still manually tell gcc what the file is. You do that with the -x option, which is documented in the GCC manual section on options controlling the kind of output (although in this case, the option actually controls the kind of input).
There are a number of answers to questions like this floating around the Internet, including various answers here on StackOverflow, which claim that GCC attempts to detect the language of input files. It does not do that, and it never has. (And I doubt that it ever will, since some of the languages it compiles are sufficiently similar to each other that accurate detection would be impossible.) The only component which does automatic detection is ld, and it only does that once GCC has irrevocably decided to treat the input file as an object file or linker script.
At least in your case, you can use process substition when specifying the input language manually, using -xc. However, you should put a newline after the include statement.
$ gcc -xc <(echo '#include<stdio.h>
int main(){ printf("Hello world!\n"); return 0;}')
$ ls
a.out
$ ./a.out
Hello world!
For a possible reason why this works, see Charles' answer and the comments on this answer.

Syntax error near unexpected token '('

As a beginner, I am trying to write a simple c program to learn and execute the "write" function.
I am trying to execute a simple c program simple_write.c
#include <unistd.h>
#include <stdlib.h>
int main()
{
if ((write(1, “Here is some data\n”, 18)) != 18)
write(2, “A write error has occurred on file descriptor 1\n”,46);
exit(0);
}
I also execute chmod +x simple_write.c
But when i execute ./simple_write.c, it gives me syntax error near unexpected token '('
Couldn't figure out why this happens ??
P.S: The expected output is:-
$ ./simple_write
Here is some data
$
You did
$ chmod +x simple_write.c
$ ./simple_write.c
when you should have done
$ cc simple_write.c -o simple_write
$ chmod +x simple_write # On second thought, you probably don’t need this.
$ ./simple_write
In words: compile the program to create an executable simple_write
(without .c) file, and then run that. 
What you did was attempt to execute your C source code file
as a shell script.
Notes:
The simple_write file will be a binary file. 
Do not look at it with tools meant for text files
(e.g., cat, less, or text editors such as gedit).
cc is the historical name for the C compiler. 
If you get cc: not found (or something equivalent),
try the command again with gcc (GNU C compiler). 
If that doesn’t work,
If you’re on a shared system (e.g., school or library),
ask a system administrator how to compile a C program.
If you’re on your personal computer (i.e., you’re the administrator),
you will need to install the compiler yourself (or get a friend to do it). 
There’s lots of guidance written about this; just search for it.
When you get to writing more complicated programs,
you are going to want to use
make simple_write
which has the advantages of
being able to orchestrate a multi-step build,
which is typical for complex programs, and
it knows the standard ways of compiling programs on that system
(for example, it will probably “know” whether to use cc or gcc).
And, in fact, you should be able to use the above command now. 
This may (or may not) simplify your life.
P.S. Now that this question is on Stack Overflow,
I’m allowed to talk about the programming aspect of it. 
It looks to me like it should compile, but
The first write line has more parentheses than it needs.
if (write(1, "Here is some data\n", 18) != 18)
should work.
In the second write line,
I count the string as being 48 characters long, not 46.
By the way, do you know how to make the first write fail,
so the second one will execute?  Try
./simple_write >&-
You cannot execute C source code in Linux (or other systems) directly.
C is a language that requires compilation to binary format.
You need to install C compiler (the actual procedure differs depending on your system), compile your program and only then you can execute it.
Currently it was interpreted by shell. The first two lines starting with # were ignored as comments. The third line caused a syntax error.
Ok,
I got what i was doing wrong.
These are the steps that I took to get my problem corrected:-
$ gedit simple_write.c
Write the code into this file and save it (with .c extension).
$ make simple_write
$ ./simple_write
And I got the desired output.
Thanks!!

command line arguments into make file

I have a C file for which I want to give cmd line arguments.
Say
$ make --argument1
or something like this.
So that in my main program I should be able to do argv[1] and be able to access the variable.
I have tried looking for ways of doing this. Is there actually a way of doing this?
These were the relevant content I found on the GNULinux manual about make.
variables defined on the command line are passed to the sub-make
through MAKEFLAGS. Words in the value of MAKEFLAGS that contain ‘=’,
make treats as variable definitions just as if they appeared on the
command line.
Is this what I need to read up more or is this in a different context?
Do let me know.
I think you misunderstand the use of command line arguments - they are given when the executable is executed not when it is compiled.
Better example
foo.c
#include <stdio.h>
int main()
{
int myval=DEFVAL;
printf("myval=%d\n", myval);
return 0;
}
Makefile
DEFVAL=17
foo: foo.c
gcc -DDEFVAL=${DEFVAL} foo.c -o $#
Your question doesn't make a whole lot of sense, so I'm going to read between the lines and guess that you have a Makefile that someone else wrote, and when you run make, it runs some program, and that's the program that you want to give command line arguments.
In order to do that, you'll probably have to modify the Makefile. In order to that, it helps to understand how make works and how to use it (you might want to find a book on the subject, such as this one), but it may possible to modify the Makefile without too much trouble.
Somewhere in the Makefile, you'll find the action line that is used to invoke you're program. If you can find that line, you can add the argument you want.

"Too few arguments" error trying to run my compiled program

I'm trying to code to refresh my memory preparing myself for a course.
int main(){
int x;
for( x = 0;x < 10; x++){
printf("Hello world\n");
}
return 0;
}
But when I tried to run this I get Too few arguments
I compiled the code above using gcc -o repeat file.c Then to run this I just type repeat
Sorry if this was a stupid question, it has been a while since I took the introduction class.
When you type
filename
at a prompt, your OS searches the path. By default, Linux doesn't include the current directory in the path, so you end up running something like /bin/filename, which complains because it wants arguments. To find out what file you actually ran, try
which filename
To run the filename file gcc created in the working directory, use
./filename
Your code compiles fine. Try:
gcc -o helloworld file.c
./helloworld
UPDATE :
Based on more recent comments, the problem is that the executable is named repeat, and you're using csh or tcsh, so repeat is a built-in command.
Type ./repeat rather than repeat.
And when asking questions, don't omit details like that; copy-and-paste your source code, any commands you typed, and any messages you received.
The executable is named file, which is also a command.
To run your own program, type
./file
EDIT :
The above was an educated guess, based on the assumption that:
The actual compilation command was gcc file.c -o file or gcc -o file file.c; and
The predefined file command (man file for information) would produce that error message if you invoke it without arguments.
The question originally said that the compilation command was gcc file.c; now it says gcc -o filename file.c. (And the file command prints a different error message if you run it without arguments).
The correct way to do this is:
gcc file.c -o filename && ./filename
(I'd usually call the executable file to match the name of the source file, but you can do it either way.)
The gcc command, if it succeeds, gives you an executable file in your current directory named filename. The && says to execute the second command only if the first one succeeds (no point in trying to run your program if it didn't compile). ./filename explicitly says to run the filename executable that's in the current directory (.); otherwise it will search your $PATH for it.
If you get an error message Too few arguments, it's not coming from your program; you won't see that message unless something prints it explicitly. The explanation must be that you're running some other program. Perhaps there's already a command on your system called filename.
So try doing this:
gcc file.c -o filename && ./filename
and see what happens; it should run your program. If that works, try typing just
filename
and see what that does. If that doesn't run your program, then type
type -a filename
or
which filename
to see what you're actually executing.
And just to avoid situations like this, cultivate the habit of using ./whatever to execute a program in the current directory.

Resources