c console application auto-complete dynamic arguments - c

I am looking for a method of having console auto complete - such that given an application like:
int main (int argc, char ** argv)
{
if (argc == 1) return EXIT_FAILURE;
if (strcmp(argv[1], "good")==0) printf("good\n");
if (strcmp(argv[1], "bad")==0) printf("bad\n");
return EXIT_FAILURE;
}
When running it, I would like pressing [tab] after the command, such that it would give me one of the possible useful options.
Example:
./a.out g[tab]
would auto complete to
./a.out good
I don't want to edit /etc/bash-completion.d/, I was hoping for a much stronger auto-complete, something like a function in the executable itself that would be called - perhaps so it could query a database for the list of possible options. Or perhaps output a message letting you know what the options are.
If you think this is simply totally impossible, let me know!

Completions are a property of the shell you run the application from. You will have to provide completion functions for all the shells you want to support (bash, zsh, tcsh and fish have customizable completions). A completion function can call your application (e.g. run you_application --list-possible-arguments) or do whatever it chooses to generate the completions — it's already a “strong” completion in your terminology.
In bash, you declare completions with the complete built-in. Look in /etc/completion.d for examples (gpg is a fairly simple example; git is a rather involved one).

If you are using BASH then have a look at this similar post:
Auto-complete command line arguments
================================
If you want to provide your own command line then have a look at the Readline library:
The GNU Readline library provides a
set of functions for use by
applications that allow users to edit
command lines as they are typed in.
Both Emacs and vi editing modes are
available. The Readline library
includes additional functions to
maintain a list of previously-entered
command lines, to recall and perhaps
reedit those lines, and perform
csh-like history expansion on previous
commands.

Related

Get highlighted text & open program with it (replicate clipboard.exe behavior)

Is it possible to highlight text with your cursor in any program, like you do with str+c and start a tool with the highlighted text as argument?
As far as I know, in Linux as well as in Windows, one can call a script/program with a custom shortcut. I assume str+c just does the same, calling a little program with the highlighted text as argument. How to replicate this?
For demonstration purposes, let's take this C - program printing the value it was called with:
#include <stdio.h>
int main(int argc, char**argv){
if(argc == 2){
printf("program called with: '%s'\n", argv[1]);
}
}
Can one type the text "HelloWorld" in Word for example, highlight it, and press something like str+alt+p, calling
someprogram.exe HelloWorld
or as for Linux
someprogram HelloWorld
I am really curious if this is possible.
Edit: I'm interested to know, how to replicate the clipboard.exe functionality. I have written a program "write_custom.exe" storing anything given as argument (argv[1]) in a text-file, after deleting it's previous content. Other programs can read the content of this text-file and so are able to use this custom clipboard. It's purpose is mainly for self-teaching.
As I am at the beginning of my codeing career, I only know C, but I am open for solutions in other languages as well. My goal is to run this write_custom.exe, with highlighted text as argument, on my computer and my Linux-VM.
You might want to check out ncurses (Linux) and Console API (Windows). The code will not be cross-platform, but you can pretty easily write some code to make them share some basic behavior :).

Equivalent of bash's -x debug flag for C programs?

I always use the -x (or debug flag) when it come to bash script, or shell scripts in general.
Now i'm curious to know, is there an equivalent, either using a specific compiler options, (i use gcc, but i don't mind any other compilers) or by using a specific code in my project?
Basically i just wanted a way to emulate what bash does (using the debug flag) which show which command/function was launched first, in order, and also show the output of said function, with additional errors message etc.But for C.
I'm aware of most debug option out there, especially considering the compiler, but i really wish i could do this in my C projects too.(especially the part where it show what is executed in order, like bash does with -x)
NB: There isn't any goal in this specific question beside the question itself, as i'm just curious if this exist, and thus don't have any need for it beside the actual knowledge acquired from said answered question.
Yes, you can mimic this behaviour with a debugger.
With GDB for instance you can write "Init Files" and "Command Files" in which you can write a simple loop:
break main
run
while 1
next
end
If you put a file named .gdbinit in the directory where you start gdb, this file will be executed or gdb will lead you on the way to configure it in order that it will be executed.
The other option is to pipe this file into your gdb-call:
gdb a.out < debug_me_like-x
Where the "debug_me_like-x" file is the one mentioned above.
As a reference for the "Command Files" have a look here.

Using linux system() function C++ beagle bone issue [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have searched around but can't find an answer to my problem.
I am cross compiling a C++ application for the beagle bone black and wish to use the linux system() function as follows :
system("echo DM-GPIO-Test > $SLOTS");
It is to add a device overlay to control GPIO pins. The echo command "echo DM-GPIO-Test > $SLOTS" works fine when executed directly on the terminal on the beagle bone from anywhere. SLOTS is an environmental variable I defined and DM-GPIO-Test-00A0.dtb0 is in /lib/firmware
I get the following error on execution of the c++ application however:
"sh: 1: cannot create : Directory nonexistent"
Is it incorrect to call the system function like I did ?
Thanks in advance
system("echo DM-GPIO-Test > $SLOTS");
This smells bad and should be avoided.
What you probably want is to write a string in a file given by your SLOTS environment variable (see environ(7)). For that particular use, you don't need to fork any /bin/sh process (which is what system(3) does). You could simply fetch that environment variable using getenv(3).
So you might try:
const char*slotspath = getenv("SLOTS");
if (!slotspath) {
fprintf(stderr, "no SLOTS\n");
exit(EXIT_FAILURE);
}
FILE* fslots = fopen(slotspath, "w");
if (!fslots) { perror(slotspath); exit(EXIT_FAILURE); };
fputs("DM-GPIO-Test\n", fslots);
fclose(fslots), fslots = NULL;
Be aware that the environment of your program -assuming it is started by some other utility (or from init or systemd)- is probably different (and smaller) than your interactive environment.
Perhaps your slotspath should not come from your environment, but from some configuration file under /etc/ (that your program should parse), or some program argument.
So I suggest to define the format of some configuration file and parse it, and get your slotspath from it.
No, it doesn't display anything doing system("echo $SLOTS")
In this case the environment variable SLOTS is simply unset/empty in the environment used by your application. Depending on your use case you either need to set it before you start the binary, or using setenv(), or replacing it directly in the string you pass to system(). If you expect the variable to be set in any of the user's profile settings you need to be aware of the different behaviour of your shell (e. g. bash) at invocation, and place it in the right file, or create a wrapper script that sets it.
$ cat .profile
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
[...]
A good idea would also be to check it for valid values in your application prior to the system() call, using getenv() to obtain it and asserting if it doesn't match the requirements.
Be aware that it is best practice to enclose shell variables containing strings into double quotes, in case they contain spaces, and the identifier into curly brackets, to avoid ambiguities:
system("echo DM-GPIO-Test > \"${SLOTS}\"");
And as Basile points out in a separate answer, avoiding invocation of the shell and handling the logic of writing the file completely in C would even be more powerful regarding the handling of errors and special cases, but also results in more code (which could contain bugs of its own...).

Read a line of c code from file and execute in a c program

I have a C program which calculates f(x) for some x values (main.c). I need to get a line of c code from file and that code is my function to execute (function.dot). For example function.dot will contain:
pow((1-x), 0.333);
I need to read this file, get that function and execute in my code (main.c). How can I do that?
Basic steps would be:
Read the line from the file.
Generate a new source file which wraps the line of code inside appropriate code.
Invoke a compiler to compile that code into a shared object/dll.
Load the library.
Call the function in the library.
If the single line of code in the file could be any language, it would be far easier to use something like Lua that can be linked into your main executable.
I will provide some options:
Switch to another interpreted language including python, ruby, perl, ...
If you are working on small project, I recommend this option.
Implement your own interpreter in C.
Parse your input, analyze it, execute it. You might find open source implementations: one choice is slang
http://www.jedsoft.org/slang/doc/html/slang.html
Call C compiler and dynamically link it.
It depends on your operating system but system or exec functions help you to call your compiler to handle your input file. If you are using Linux, dlsym can open a shared-object compiled from your input file.
You might need to convert your input file into C program.
Very slow to compile but fastest to run.
You have several options I can think of:
1) Switch to any number of interpreted langauges (python, perl, etc.) which support this as an easy mechanism. (Example: in python
data = open("function.dot").read()
x = 5
eval(data) #note that this is unsafe if you can't trust data, and you might also need to play with environment
)
2) You could wrap the code in it's own c file... something like (but with more error checking etc... you probably don't want to do this)
void generate_c_program(char *line)
{
FILE *fp = fopen("myfile.c","wt");
fprintf(fp,"#include <math.h>\nint main(char *argv, int argc) {\n double x = atof(argv[1]); printf(\"%f\",(%s));}\n");",line); //this is also unsafe if you can't trust data
fclose(fp);
//now execute gcc myfile.c
//now execute a.out
//optionally cleanup by deleting a.out and myfile.c
}
3) Effectively write your own compiler / parser (which may be fairly easy IF you've done this before and the number of functions / operations you need to support is small or may be a much bigger deal and will rather not fit in this answer)... the extensible way would be to use LEX/YACC or similar)

What does initialize_main (&argc, &argv) do?

I 'm reading coreutils source code to learn programming under linux.
I find that in most of the programs like ls.c, cat.c, they invoke the macro function initialize_main() at the first few lines. So I looked into system.h to find the implementation:
/* Redirection and wildcarding when done by the utility itself.
Generally a noop, but used in particular for native VMS. */
#ifndef initialize_main
# define initialize_main(ac, av)
#endif
I don't understand why define such a macro and I don't understand the comment.
The first step in understanding the comment is to know what VMS is. So here's a link for that:
http://en.wikipedia.org/wiki/OpenVMS
The next step is to understand redirection and wildcarding. In Linux and other members of the unix family, a command like
cat foo* > /tmp/foolist
will call the main function of cat with argv containing the matches for foo*. The output file /tmp/foolist will already be open as stdout before main is entered.
VMS doesn't do that. cat will find the unexpanded string "foo*" and the redirection operator > in its argv. So the utility itself (cat) must do the redirection (opening the output file) and wildcarding (replacing "foo*" with "foo1", "foo2", "foo3"). That's what initialize_main will do on VMS. On unix, it'll do nothing ("Generally a noop").
This is left over from times gone by. OpenVMS is an operating system which roughly competed with Unix in the past. There is still a fair amount of OpenVMS running in the world, but HP have dropped support for it and it will be going away in the next 10-15 years.
Anyway, this function is used on OpenVMS to allow stdout and stderr redirection on VMS.
Since cat foo.txt > stuff.txt on Unix, the cat command only sees one argument foo.txt, but on VMS, which knows nothing of the > symbol, the cat command sees 3 arguments.
The code inside initialize_main on VMS, allows the basic unix style commands to support output redirection, such as ls and
OpenVMS later added a command called pipe which allows redirection to work via any command.
You can view the source code for initialize_main on VMS here: Link

Resources