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

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.

Related

how print in c without jumping to end of text?

I'm very new to coding in general so please excuse any stupid things I say.
I am trying to print (in c) a rather long text using printf() but since it can't all fit on the screen it jumps to the end of the text and the beginning is not visible unless you scroll up. Is there an easy way to have it print the long text but stay at the beginning and allow the user to scroll down as they read before they put in the next command?
On Unix (including Linux and Mac), there are command line programs built in called more and less that does exactly what you describe. more is a program that simply waits for the user to press enter or space before showing the next page of output. less is slightly improved in that it allows vi editor keystrokes (such as j and k) to scroll up and down in the output.
more is also available on the Windows command line as well. You might even be able to find a version of less for Windows as well.
c:\users\selbie> your_program.exe | more
$> ./your_program | less
As to how to do this programmatically, that's a bit more difficult as it would involve measuring the console width and implementing your own scroll buffers. There might be open-source libraries that provide this functionality, but the console environment already has a solution for apps that produce long output.
Not really, though you may find a reasonable and simple solution is to print only a certain number of lines (say 30), then prompt the user to press Enter before display more lines.
You can even find out the current size of the terminal. That's platform specific; for Linux it's explained here: How to get terminal window width?
Not in a standard way, no.
Your output stream in C is just a stream of characters -- scrolling is handled by your terminal.
Depending on your terminal, it may be possible to control scrolling by outputting special characters, like ANSI escape codes. The ncurses library provides a portable way to manipulate terminals.
However, if you just want a more convenient way to look through your output (or really any command output), #selbie's answer is the best: use more or less. This will avoid any extra complexity in your program.

Scan all characters entered until see a tab char

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.)

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.

Add a string to the input space of the console

I don't really know how to explain this so the title is probably misleading.
I'm making a small text editor in C and I'm saving the contents of an entire file into an array of chars. Now I want to display the entire string to the user in a way that the user will be able to edit the string inside the command window by positioning the cursor/seek and then typing or deleting characters. Pressing enter or some other key would save the text to a new string and write it to the file.
Similar to what happens when you open a file in a linux text editor like nano or vi... You get that cursor which you can move around the file and make changes.
How can that be done in C? I don't need it to be like in the linux editors, simply putting the string inside the input area (as if the user typed the text) would be enough.
You must use Terminal capabilities (a.k.a Termcaps). They are special characters which can be interpreted by your terminal (e.g moving the cursor back and forth, or clearing the screen). Here's what Wikipedia says about Termcap databases :
A termcap database can describe the capabilities of hundreds of
different display terminals. This allows programs to have
character-based display output, independent of the type of terminal.
On-screen text editors such as vi and emacs are examples of programs
that may use termcap.
By using terminal capabilities, you will be able to control the way the cursor behaves in your editor, and how input characters shows up. A good example of this would be using colors for syntax highlighting.
I would suggest that you use the GNU Termcap library to build a cross-terminal application. Once you get the main principles, its usage is relatively straightforward, I used it back in the days to actually build a shell (such as bash, or sh).
Next, you might also want to look at the differences between canonical and non-canonical terminal modes. Given what kind of functionalities you are wanting to implement in your editor, you will likely want to override the way your terminal interprets some inputs.
See also :
Moving the cursor using Termcaps
Characters for Input Editing only available in canonical mode
This is done by writing certain special control characters to stdout, which can do things like set the color, move the cursor, etc. See https://en.wikipedia.org/wiki/ANSI_escape_code for more info.
However, if you want your editor to be portable, or you don't want to worry yourself with details, you may want to consider using the ncurses library (https://en.wikipedia.org/wiki/Ncurses), which editors like nano/vi use rather than doing it themselves.

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