Scan all characters entered until see a tab char - c

I want to autocomplete on a command line application a but like in bash you can use tab key which will complete the command. But getchar() seems to wait until a newline char is received before it starts reading any characters.
scanf seems to work the same way.
Is there any way I can scan characters one at a time no matter if they are whitespace or control characters?
I want to be able to read char by char as entered building up a command and then as soon as tab char received I will attempt to lookup how to complete and print full command in my application.

Don't reinvent the wheel.
Use what other projects use to build command lines: Libraries that implement that job for you.
Many CLI prompts depend on GNU readline, which I think is fine, if a bit cluttered and heavy. Also, it's GPL, so depends on whether you like that or not.
I'd look into linenoise. It's very lightweight, and if you decide you really want to implement user interface yourself rather than including one or two files, OK, do that, but look at the rather concise reference implementation that seems to be. Caveat: haven't used it myself, so far. The API is pretty simple, though, as can be seen in their example.
A popular alternative is libedit/editline.

You need the GNU Readline Library. Use the rl_bind_key() function to add a filename-completion processing function whenever the users presses a key ('\t', in your case).
You are in for a world of hurt if you try to roll your own readline style function.
(If you are on Windows.)

Related

Using C I would like to format my output such that the output in the terminal stops once it hits the edge of the window

If you type ps aux into your terminal and make the window really small, the output of the command will not wrap and the format is still very clear.
When I use printf and output my 5 or 6 strings, sometimes the length of my output exceeds that of the terminal window and the strings wrap to the next line which totally screws up the format. How can I write my program such that the output continues to the edge of the window but no further?
I've tried searching for an answer to this question but I'm having trouble narrowing it down and thus my search results never have anything to do with it so it seems.
Thanks!
There are functions that can let you know information about the terminal window, and some others that will allow you to manipulate it. Look up the "ncurses" or the "termcap" library.
A simple approach for solving your problem will be to get the terminal window size (specially the width), and then format your output accordingly.
There are two possible answers to fix your problem.
Turn off line wrapping in your terminal emulator(if it supports it).
Look into the Curses library. Applications like top or vim use the Curses library for screen formatting.
You can find, or at least guess, the width of the terminal using methods that other answers describe. That's only part of the problem however -- the tricky bit is formatting the output to fit the console. I don't believe there's any alternative to reading the text word by word, and moving the output to the next line when a word would overflow the width. You'll need to implement a method to detect where the white-space is, allowing for the fact that there could be multiple white spaces in a row. You'll need to decide how to handle line-breaking white-space, like CR/LF, if you have any. You'll need to decide whether you can break a word on punctuation (e.g, a hyphen). My approach is to use a simple finite-state machine, where the states are "At start of line", "in a word", "in whitespace", etc., and the characters (or, rather character classes) encountered are the events that change the state.
A particular complication when working in C is that there is little-to-no built-in support for multi-byte characters. That's fine for text which you are certain will only ever be in English, and use only the ASCII punctuation symbols, but with any kind of internationalization you need to be more careful. I've found that it's easiest to convert the text into some wide format, perhaps UTF-32, and then work with arrays of 32-bit integers to represent the characters. If your text is UTF-8, there are various tricks you can use to avoid having to do this conversion, but they are a bit ugly.
I have some code I could share, but I don't claim it is production quality, or even comprehensible. This simple-seeming problem is actually far more complicated than first impressions suggest. It's easy to do badly, but difficult to do well.

ASCII codes for Ctrl-Up and Ctrl-Down

I'm implementing a small shell in C and I want to use Ctrl-Up and Ctrl-Down. Are there ASCII codes for Ctrl-Up, Ctrl-Down and Ctrl-Shift+C? I have searched everywhere for them and I couldn't find them.
As #MateoConLechuga mentioned, what you're looking for simply doesn't exist. What actually happens when you press Ctrl-Up is that the terminal sends a special sequence of characters starting with the ESC character. For example, on my terminal, Ctrl-Up sends ESC[1;5A.
What you need to to is use something like the ncurses and/or the termcap libraries to deal with things like terminal input in a terminal-independent manner.
Unfortunately for you, this is probably way more work that you were hoping for. Writing a "small" shell is non-trivial.

How to implement previous-command-scroll in a standalone shell program?

For a class project we have to implement a basic Linux shell. As it stands now I have everything working to fully implement basic functionality except for the "UP" key previous command scrolling feature.
How might something like this be implemented? I realize it may be as simple as retaining an array of char* to the input strings, but how do we capture "UP" key button presses?
Once we have the above implemented, how can you write to stdout without making it permanent? That is, when you press "UP" again then it erases what was previously written with another command.
A practical way to implement the up key would be to use GNU readline library (and its history sub-library). BTW, some shells actually do use GNU readline (it is under GPL license). And you'll get line edition also. And you could implement completion with the tab key, etc.
There are other ways, like using ncurses or termcap etc... Or emitting ANSI escape codes on a raw terminal. See also the tty demystified & termios(3)...
BTW, most Linux shells are free software, so you could study their source code.
If you are using non-buffered character-by-character input directly from STDIN (which means, among other things, control characters such as CTRL+C are not handled automatically), then you will be reading byte-by-byte. Arrow keys, unlike ASCII symbols, put multiple bytes on STDIN because they are excape sequences. These bytes differ from system to system. The easiest way to determine the escape sequence on your system is to execute the cat command with no arguments, then hit the arrow keys. Something like ^[[A will be displayed, you will need to convert that sequence from ASCII to hex bytes.
Once you've done that, you can read the bytes one at a time with get_char(), just like you're probably already doing in your input function anyway.

Is it possible to capture Enter keypresses in C?

I want to write a C program that tokenizes a string and prints it out word by word, slowly, and I want it to simultaneously listen for the user pressing Enter, at which point they will be able to input data. Is this possible?
Update: see #modifiable-lvalue 's comment below for additional helpful information, e.g., using getchar() instead of getch(), if you go that route.
Definitely possible. Just be aware that gets() may not be entirely helpful for this purpose, since gets() interprets enter not as enter per se, but as "now, I the user, have entered as much string as I want to". So the input gathered by gets() from pressing just an enter will appear as an empty string (which might be workable for you).
See: http://www.cplusplus.com/reference/cstdio/gets/.
But there are other reasons not to use gets()--it does not let you specify a maximum to read in, so it's easy to overflow whatever buffer you are using. A security and bug nightmare waiting to happen. So you want fgets(), which allows you to specify a maximum size to read in. fgets() will place a newline in the string when an enter is pressed. (BTW, props to #jazzbassrob on fgets()).
You could also consider something like getch()--which really deals with individual key-presses (but it gets a bit complicated handling keys that have non-straightforward scan-codes). You may find this example helpful: http://www.daniweb.com/software-development/cpp/code/216732/reading-scan-codes-from-the-keyboard. But because of the scancodes issues, getch() is subject to platform details.
So if you want a more portable approach, you may need to use something heavier weight, but fairly portable, such as ncurses.
I suspect you can do what you want with either fgets(), keeping in mind that enter will give you a string with just a newline in it, or getch().
I just wanted you to be aware of some of the implementation/platform issues that can arise.
C can absolutely do this, but it's a little more complicated than one might guess at first attempt. That's because terminal input is, historically, very platform dependent.
Check out the conio.h library and its use in game making. You can compile with Borland. That was my first experience in unbuffered input and listening for keypresses in real time. There are certainly other ways though.

interpret arrow keys in raw mode (posix)

I'm trying to create a shell (nothing serious just messing around) and want to read the arrow keys in raw mode to avoid control characters being printed to the screen, and actually be able to use them to go back and edit a line before I hit enter. It's probably possible to do with termios but is there an easier way of doing this? Or is it perhaps easy to do with termios? It just seems like a rather large subject that has to be studied in full.
I'm reading in lines from stdin in a loop and call fork > execvp with an argument vector that I create from the input string.
It's probably possible to do with termios but is there an easier way
of doing this
By far the easiest approach would be to use the readline library which offers everything and more than what you're mentioning. It should be fairly easy to make your shell behave like a full-blown bash (line editing, command history) with relative ease.
Unless you actually want to do it yourself, I'd recommend you the GNU Readline Library which does these things for you.

Resources