text auto complete using Tab in command line - c

I wonder how to implement a program in C that can automatically complete the command or text that you are entering in command line.For example, say your program is prompting user for a file name. Mostly one would use scanf() or else to do this. And then in the command line user would be prompt likeplease input the file name:_.
Let's say there is a shakespeare.txt in the same directory. And now I have entered shakes, and then I want the computer to auto-complete the shakespeare.txt for me, as it does for most programs when user hitting Tab. How to implement that?
Edit:to make it more clear, another example:
if you use grep in your command line, like grep -i "shakespeare" shakespeare.txt, before you complete shakespeare.txt yourself, if you simply use Tab, there would be some candidates show up.
How can I implement my program to make it possess this utilities when I try to prompt the user for input when using function like scanf()?

If you consider using an existing utility,
take a look at the GNU readline library which provides a pretty neat implementation of what you're looking for.
There some other helpful features like moving the cursor in your input, providing an input history and an input shell-like prompt.
This library's functionality works identical on different platforms.
As this example from Wikipedia shows, the key to indicate the completion can be set easily:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
int main()
{
char* input, shell_prompt[100];
// Configure readline to auto-complete paths when the tab key is hit.
rl_bind_key('\t', rl_complete);
for(;;) {
// Create prompt string from user name and current working directory.
snprintf(shell_prompt, sizeof(shell_prompt), "%s:%s $ ", getenv("USER"), getcwd(NULL, 1024));
// Display prompt and read input (NB: input must be freed after use)...
input = readline(shell_prompt);
// Check for EOF.
if (!input)
break;
// Add input to history.
add_history(input);
// Do stuff...
// Free input.
free(input);
}
return 0;
}

Because in C there is no portable solution for knowing what you have typed in a promt without pressing enter you need to read character by character.
In windows you can use _getch() function to read one character without the need of pressing enter. The function is defined in conio.h
In linux you can use getch() function.
Note: you may want to use getche() in order to echo the character back.
You will need to define a buffer where you will store character by character everything the user press, until the user hit enter or it press enter. When you find \t you will analyze the content from buffer and take a decision based on that.
The following code is a oversimplified example:
char c;
int i = 0;
do {
c = _getche();
if (c == '\t') {
// Autocomplete
// Print the rest of the word here
}
else {
buff[i++] = c;
}
} while (c != '\n' && c!='\r');
buff[i] = '\0'; // Let's keep the standard

It's not clear whether your asking for completion performed by
The program itself while it is running. Presumably you would be implementing some custom command line.
The operating system command line (e.g., bash) before you've started your program and you just want to auto-complete the arguments passed to it
Your grep example suggests your asking about shell completion. Here is one example.

Related

How to provide an input to my code in order to test it?

I am trying to learn the C language by following K&R2 reference book.
I wrote a program to count how many spaces, tabs and newlines are contained in a given input. (exercise 1-8 p.20)
How can I provide to this program input to test my code ?
#include<stdio.h>
main(){
int c,ne,nt,nf;
ne = 0;
nt = 0;
nf = 0;
while((c = getchar())!=EOF){
if (c == ' '){
ne++;
}if (c== '\t'){
nt++;
}if (c== '\n'){
nf++;
}
}
printf("Input contains %d spaces, %d tabs and %d newlines.",ne,nt,nf);
}
It depends on how you're running your program.
If you're running it from the command line, the program's standard input (which is where getchar reads from) is basically your keyboard, so you can just start typing.
If you're running under an IDE, it can create a new "terminal window" for your program to run in, and for you to type input in. At least for learning, such a terminal window ought to be the default, although unfortunately it seems that sometimes you have to take additional, nonobvious steps to set this up so that it will work.
When you're typing input on your keyboard, you also need a way of saying when you're done typing. You do this by typing a "control character". Under Unix, Linux, and MacOS it's control-D, and under Windows it's control-Z. (See also notes below.)
On a suitably powerful command line, you may also have various input redirection options available to you, such as reading input from a file by involving
./myprogram < filename
or taking some other program's output and "piping" it to your programs input by invoking something like
otherprogram | ./myprogram
A few more notes about control-D and control-Z:
On Unix, Linux, and MacOS, you either have to make sure you're typing the control-D at the beginning of a line (that is, you have to type Enter, then control-D), or if you're not at the beginning of a line, you have to hit control-D twice.
On Windows, you have to hit control-Z, then hit Enter.
(Computers can be so fussy sometimes! :-) )
Also, you should know that although typing control-D or control-Z indirectly results in an EOF value eventually squirting out as getchar's return value in your C program, you will not find that the macro EOF has a value of "control D" or "control Z". EOF is usually the value -1, and the process of turning a control character typed by you on the keyboard, into an EOF value returned by getchar in a C program, is actually a rather elaborate one.
[I've written several long writeups on that "rather elaborate process", but I can't seem to find any of them just now. If you're curious, check back in a couple days, and maybe I'll have found one, or written a new one.]

Differentiate clipboard event when using read() function in c from stdin

I am working on terminal based text editor and stuck at a point where I need to differentiate whether the input text from read() function is a clipboard paste text or a keyboard text input.
#include <unistd.h>
char read_key_input() {
char ch;
int read_count;
while ((read_count = read(STDIN_FILENO, &ch, 1)) != 1)
{
// Handle error if any
}
return ch;
}
...
Edit: Here's what I ended up doing.
void read_key_input(void (*callback)(int)) {
char* text = malloc(UINT8_MAX);
int read_count;
while ((read_count = read(STDIN_FILENO, text, UINT8_MAX)) == -1)
{
// Handle error if any
}
// Handle escape sequences if found and return early
...
if (read_count > 1) {
// It's probably a clipboard text. So change the editor mode to input and loop through all the characters one by one.
else {
// It's a user keyboard text input
}
// Revert back to the original editor mode if changed
}
I updated the code to retrieve more than one byte at a time (as suggested by #AnttiHaapala) and process each byte. Seems to be sufficient for my text editor's need for now. Will post back if I update.
Usually you can differentiate this by counting the number of characters you've received in rapid succession. So if you get the keypresses more rapidly than say 1000 characters per minute, then it is likely a clipboard paste... or nonsense.
Furthermore, if you've set the terminal to raw mode, then you can easily monitor individual keypresses. Also make read accept more than one byte at once - with read that is the maximum number of bytes to receive without blocking when available anyway.
One example of such an interactive terminal program would be IPython - here two lines typed separately:
In [1]: print("Hello")
Hello
In [2]: print("World")
World
And here pasted in one go:
In [3]: print("Hello")
...: print("World")
...:
Hello
World
Notice how the prompt is different, and the program runs only after there has been a separate Enter key hit after a small delay.
AFAIK, you cannot do what you want (reliably).
The clipboard is related (usually) to some display server, e.g. Xorg or Wayland server (Weston). And X11 might have distant clients (hence, a clipboard operation could be slow, if crossing some ocean).
Some Linux machines (perhaps the web server at Stackoverflow) do not run any display server.
You could code a GUI application, e.g. using GTK or Qt.
You could test if your standard input is a terminal with termios(3) functions or isatty(3) (i.e. with isatty(STDIN_FILENO) or isatty(STDOUT_FILENO) for standard output)
If your program is run inside a crontab(1) job, or a unix pipeline, the standard input won't be a terminal, and there might not even be any display server running.
You could take inspiration from the source code of GNU emacs, which does detect when a display server is available (probably using environ(7), e.g. getenv(3) of "DISPLAY"...)
On Linux you might open(2) /dev/tty (see tty(4)) to access your terminal. In some cases, it does not exist.
Hey #jiten not sure if you checked like
its key input detect and check wether it's input is one by one key
or its instant bulk input.

Allowing the user to edit text already printed on the screen in C

I want to change the text on my screen like a word processor by user input, so can i do gets("text the user can edit", variable to edit by text)
I have tried arrays, and have tried researching dynamically created variables for this. My code is below:
#include <stdio.h>
int main(void) {
int run;
int run = 1;
char string;
do
{
char string = getchar();
} while (run == 1);
}
I expect the result to be like a word processor, and allow the user to edit the text already displayed on the screen. The results I have is the program acting like a typewriter for each paragraph, making it unable to be edited after I pressed enter
Under Linux you can use the readline library and there each line read will be using a system defined line reader, which will allow edits , tossing arrows and such until you press enter. See http://web.mit.edu/gnu/doc/html/rlman_2.html.
In the other hand, if you want to build your own be line editor, or mini word processor, then you will have to keep, at least, the relative position of your current cursor, erase and redraw the line on each meet press, and reposition there caret.
Here is an example of a line editor https://www.dreamincode.net/forums/topic/136583-line-editor-in-c/

C Lang - How to detect if a file has been used as input argument?

I am having issues with handling the arguments that are passed to my program. The user should have the ability to provide his own arguments or to provide a JSON file containing the arguments at launch.
The individual can enter their own arguments at the launch. For example:
prog --x 1 --y 2
The individual can also send the arguments through a file input (JSON).
prog < arguments.json
The issue I am having is trying to get to recognize if a file has been passed through stdin. More specifically, if the user runs the program without any arguments or file input.
I can easily find out if any arguments have been passed by checking argc, but then my program gets stuck at verifying if anything has been passed in stdin by going through this ;
[...]
char str[150];
char c;
while ((c = fgetc(stdin)) != EOF) {
strncat(str, &c, sizeof(char));
}
[...]
After launching the program with no arguments, it sits in the terminal waiting for my input (which it should not be doing since there is no file input). The problem is only when the user has put in no arguments at launch, and the program tries to check the stdin. Is there anyway for me to check if stdin is empty before using fgetc?
Not easily. There are two immediate problems.
As mentioned, it's not that easy to detect if the standard input is tied to a file. You could possibly use isatty but there may be perfectly valid reasons why you wish to send a file with real input to your program, not options.
As foreshadowed in the preceding point, if you use standard input for passing in arguments, that rather stops you from also using it for "proper" input. Now it may be that your program expects no input in which case that's fine. But, if you want to provide a file with options and allow input, things start to get difficult.
The way this is usually handled is to not use standard input for the options, rather you provide another option which will specify a file to be used.
For example, the file my.options could contain --x 1 --y 2 and you would run your program as one of:
prog --opts-file=my_options.json
prog -o my_options.json
That requires an extra level of indirection in that you have to handle both command line options and options read in from the file but it leaves standard input for what ${DEITY} intended :-)

How to input of a string which contain '\n' in it

I have created an auto typing bot which simulate characters of string given by user.
My code is this:
printf("Enter speed (wpm) (1 to 11750):");
scanf("%d", &speed);
if(speed < 1 || speed > 11750)
{
printf("\nPlease provide CORRECT DATA\n");
return -1;
}
printf("Paste the String : \n");
gets(exaArray);
exaArrayLength = strlen(exaArray);
relation = (int)11750/speed;
printf("typing will start in 2 sec-\n");
Sleep(2000);
i=pos=0;
while(i<=exaArrayLength)
{
Sleep(relation);
if((exaArray[pos]>96) && (exaArray[pos]<123)) //small letters
{
keycode=0x41 + (exaArray[pos]%97);
smallLetter(keycode); //function for key simulation
}
.....
I am taking input using gets function. This program works fine when I paste text which does not contain Enter. So this program works fine with one paragraph.
But if the user provides more than one paragraph, then it simulates only the first paragraph.
Because gets terminates at '\n'. Which function could take multiple paragraph input and assign it to a string.
This is actually a very hard and complex problem, and not easy to solve in an automated way.
It would seem like reading in a loop would be a good solution, but then you come to the point when there is no more input and the reading function just blocks waiting for more input. The easiest way out of this is to have the user enter the "end of file" key combination (CTRL-D on POSIX systems like Linux or OSX, CTRL-Z on Windows), but the user must then be told to do that.
The problem stems from that your program simply have no idea how much data it is expected to read, and there is no function which is able to, basically, read the users mind when the user thinks "that's it, no more data".
Besides the above solution to have the user give an "end of file", you can use other sequences or special keys or even phrases of input to mark the end, but it all comes down to this: Read input in a loop until users says "no more input".
Well, there is no way for the computer to make a difference between the user pressing enter and the "pasted" string containing newlines. (Technically, pasting something into the console is like typing it.)
If you just don't want the problem to exit after one paragraph but continue, you can do it as commenter alk suggested (loop around the reading function) - then you would need Ctrl+C to exit the program and then there would technically still be one paragraph at a time written. Depends on what you further want to do with the program.
On the other hand, if you want a way for the user to input all text at once and only then process it, you would need to define something other than "newline" as "end of input" marker, for example something like ESC.
You would do this by using getchar instead of gets and manually concatenating each char which is entered this way to a string buffer, and if the character has the value 27 (escape key) for instance, you would end the input loop and start outputting.

Resources