Simulating shell like behavior - c

So what I want is when the user presses the up button, I want to instantly display the command and not show the ^[[A I already know how to identify up and down from the keyboard, and I know termios might be the solution, but coming from a java background, I don't quite know how to do this. Ncurses is not an option, due to certain constraints. If you can, please help.
What I expect to happen is, when the user presses the up button, I want to instantly do a printf on the same line
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char input[100];
char *history[5];
int currentHistory=0;
int historyCount=5;
history[0]="hi";
history[1]="bye";
history[2]="computer";
history[3]="science";
history[4]="Yo";
while(input[0]!='Q')
{
if(input[0]==LEFT_ARROW;
}
}

You'll find this functionality, and more, in either the GNU readline or the BSD editline libraries. They offer largely the same functionality, however the GNU readline library is under a GPL license, and editline is under a BSD license.

It isn't clear if you want to handle your input better, or your terminal handling better.
If you want to handle input better, I suggest wrapping your character recogonition into a function that returns an integer, which has defines for each "handled" key. That way your input looks more like
int char = readChar(input);
if (char == KEY_UP_ARROW) {
...
}
where readChar detects if the first key is an escape and then "peeks" to see if there is extra information available (to differentiate between a stand alone escape and the arrow keys).
If you intend to handle the screen side of things better, and your intent is to drive the terminal with your own wrapped terminal handling software, you need to reference the VT100 terminal reference (assuming that your xterm emulates VT100 (which many do)). The VT100 codes are described here.
Note that the operating system does some extra processing on input (to combine key combinations, making programs easier to differentiate between deadkey keyboard setups, etc.), so you might to disable this in-terminal processing by putting the terminal in a different "mode". Typical modes include "cooked", and "raw", where "raw" provides you with key codes that are not combined for simplicity.

Related

Is it possible to get input live from fgets() in C?

Apologies if this is unclear, but I'm really not sure how to describe this.
See, my issue is that I'm trying to read from the text for user input using fgets(), however, I also need to know if the user presses a special key like /b (backspace) since ideally I want it to start deleting characters from the line before if the current line is empty, like a text editor, which isn't possible with C.
Anyways, let me know if you need more information, thanks in advance.
EDIT: Thought I'd go ahead and post what I have as of now in case someone comes across this later with the same issue to get a better idea
for (; ;)
{
int i;
int key = getch();
if (key == '/b')
{
printf("Hello World");
}
else
{
buffer[i++] = key; // adding character to text user is writing
}
i++;
}
note that this code doesn't work at the moment because of a linker error and something with the /b, but in essence, this could work.
EDIT 2: Thank you chqrlie for bringing up the right way to refer to special characters. Forgot you had to use the backslash for them.
You can certainly write text editors in C :-) A lot of them are.
However, you can't write them in portable C because the facilities required for interactive character-by-character terminal I/O don't exist in standard C. They don't exist because standard C doesn't assume that there is such a thing as a terminal (lots of embedded CPUs don't have any such thing, for example), and it would go far beyond the mandate of ISO C to try to standardise the disparate communications protocols of the various operating systems which do have terminal-like I/O.
getch is an obsolete interface in the Windows conio.h header, and also one of the interfaces in the Curses library, which is available for many operating systems (including Windows). It has nothing to do with fgets, which is part of standard C, and it cannot be implemented using fgets.
It seems likely that what you are trying to do could best be accomplished using an implementation of Curses. (If you're using Linux, as suggested by your avatar, you would be looking for Ncurses.) You might want to look at the Forms library built on top of Ncurses, which provides higher-level input facilities, like editable text boxes.
Another common input-handling library, GNU readline, might also be useful, but it doesn't handle multiline input forms so it would probably be a lot more work.

How could I guarantee a terminal has Unicode/wide character support with NCURSES?

I am developing an NCURSES application for a little TUI (text user interface) exercise. Unfortunately, I do not have the option of using the ever-so-wonderful-and-faithful ASCII. My program uses a LOT of Unicode box drawing characters.
My program can already detect if the terminal is color-capable. I need to do something like:
if(!supportsUnicode()) //I prefer camel-case, it's just the way I am.
{
fprintf(stderr, "This program requires a Unicode-capable terminal.\n\r");
exit(1);
}
else
{
//Yay, we have Unicode! some random UI-related code goes here.
}
This isn't just a matter of simply including ncursesw and just setting the locale. I need to get specific terminal info and actually throw an error if it's not gonna happen. I need to, for example, throw an error when the user tries to run the program in the lovely XTerm rather than the Unicode-capable UXTerm.
As noted, you cannot detect the terminal's capabilities reliably. For that matter, you cannot detect the terminal's support for color either. In either case, your application can only detect what you have configured, which is not the same thing.
Some people have had partial success detecting Unicode support by writing a UTF-encoded character and using the cursor-position report to see where the cursor is (see for example Detect how much of Unicode my terminal supports, even through screen).
Compiling/linking with ncursesw relies upon having your locale configured properly, with some workarounds for terminals (such as PuTTY) which do not support VT100 line-graphics when in UTF-8 mode.
Further reading:
Line Graphics curs_add_wch(3x)
NCURSES_NO_UTF8_ACS ncurses(3x)
You can't. ncurses(w) uses termcap to determine what capabilities a terminal has, and that looks at the $TERM environment variable to determine what terminal is being used. There is no special value of that variable that indicates that a terminal supports Unicode; both XTerm and UXTerm set TERM=xterm. Many other terminal applications use that value of $TERM as well, including both ones that support Unicode and ones that don't. (Indeed, in many terminal emulators, it's possible to enable and disable Unicode support at runtime.)
If you want to start outputting Unicode text to the terminal, you will just have to take it on faith that the user's terminal will support that.
If all you want to do is output box drawing characters, though, you may not need Unicode at all — those characters are available as part of the VT100 graphical character set. You can output these characters in a ncurses application using the ACS_* constants (e.g, ACS_ULCORNER for ┌), or use a function like box() to draw a larger figure for you.
The nl_langinfo() function shall return a pointer to a string containing information relevant to the particular language or cultural area defined in the current locale.
#include <langinfo.h>
#include <locale.h>
#include <stdbool.h>
#include <string.h>
bool supportsUnicode()
{
/* Set a locale for the ctype and multibyte functions.
* This controls recognition of upper and lower case,
* alphabetic or non-alphabetic characters, and so on.
*/
setlocale(LC_CTYPE, "en_US.UTF-8");
return (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) ? true : false;
}
Refer to htop source code which can draw lines with/without Unicode.

alternative to the fscanf()/vscanf() functions family for using an alternative validation key or how to create a custom language layout?

I am rather knew in C. And the only way I know for setting a variable from stdin is by using thefscanf()/vscanf()functions family.
DOS operating systems are seeing a resurgence in the embedded market. The device which I am using is programmatically compatible with DOS and use a NEC V30Mx which feature the 80286 instruction set.
The problem is the built-in keyboard doesn’t feature the enter key and instead use the EXE key which enter the 0x1C00 key code (Alt enter).
So when I write a program like this :
#include <stdio.h>
#include <dir.h>
#include <dos.h>
int main(void) {
int res, number = 0;
printf("int value?");
res = scanf("%d", &number);
printf("The value is %d", number);
return;
}
scanf()is called and "int value?" is displayed on the screen. I can write numbers and upercase letters. but I can’t validate the output since nothing feature the 0x1C0D key code, and the EXE key use a different keycode.
Of course C has no knowledge of keyboard but the C standard library binaries look for the 0x1C0D key code for entering a\n.
So is there an alternative to thefscanf()/vscanf()functions family which is part of the C standard library?
Update :
I thought most C standard libraries under dos use software implementation for doing this.
I saw a DOS call for reading files and of course, using the number 0 cause to read from stdin.
So I assembled this example, loaded it on the calculator and find myself surprised the manufacturer preferred handling the issue in it’s built-in software rather than fixing the OS... :-( (I got the the same previous result)
Update
I didn’t thought about it but thanks to the comments, I forgot keyboard languages do key code remapping.
So, creating a custom mapping for the qwerty keyboard would be an another way to solve the problem.
The problem is scanf does not read past the bytes present in stdin that represent the EXE key.
Can you investigate to see what actual characters are read by getchar() when you press the EXE key, and write a function hasexe() that skips these if present. Call this function before or after the scanf().
Also check scanf() return value and check for EOF.
The only way to solve such a problem with standard C library is to use getchar() (or fgetc() on stdin) to get a character one at a time, detect the EXE key yourself, NUL terminate the string and pass it to sscanf().

Unbuffered I/O in ANSI C

For the sake of education, and programming practice, I'd like to write a simple library that can handle raw keyboard input, and output to the terminal in 'real time'.
I'd like to stick with ansi C as much as possible, I just have no idea where to start something like this. I've done several google searches, and 99% of the results use libraries, or are for C++.
I'd really like to get it working in windows, then port it to OSX when I have the time.
Sticking with Standard C as much as possible is a good idea, but you are not going to get very far with your adopted task using just Standard C. The mechanisms to obtain characters from the terminal one at a time are inherently platform specific. For POSIX systems (MacOS X), look at the <termios.h> header. Older systems use a vast variety of headers and system calls to achieve similar effects. You'll have to decide whether you are going to do any special character handling, remembering that things like 'line kill' can appear at the end of the line and zap all the characters entered so far.
For Windows, you'll need to delve into the WIN32 API - there is going to be essentially no commonality in the code between Unix and Windows, at least where you put the 'terminal' into character-by-character mode. Once you've got a mechanism to read single characters, you can manage common code - probably.
Also, you'll need to worry about the differences between characters and the keys pressed. For example, to enter 'ï' on MacOS X, you type option-u and i. That's three key presses.
To set an open stream to be non-buffered using ANSI C, you can do this:
#include <stdio.h>
if (setvbuf(fd, NULL, _IONBF, 0) == 0)
printf("Set stream to unbuffered mode\n");
(Reference: C89 4.9.5.6)
However, after that you're on your own. :-)
This is not possible using only standard ISO C. However, you can try using the following:
#include <stdio.h>
void setbuf(FILE * restrict stream, char * restrict buf);
and related functions.
Your best bet though is to use the ncurses library.

Equivalent to Windows getch() for Mac/Linux crashes

I am using getch() and my app crashes instantly. Including when doing:
int main()
{
getch();
}
I can't find the link but supposedly the problem is that it needs to turn off buffering or something strange along those lines, and I still want cout to work along with cross platform code.
I was told to use std::cin.get(), but I'd like the app to quit when a key is pressed, not when the user typed in a letter or number then press enter to quit.
Is there any function for this? The code must work under Mac (my os) and Windows.
Linking/compiling is not an issue; I include <curses.h> and link with -lcurses in XCode, while Windows uses <conio.h>.
Have you looked in <curses.h> to see what the getch() function does?
Hint: OSX and Linux are not the same as Windows.
Specifically, as a macro in <curses.h>, we find:
#define getch() wgetch(stdscr)
Now, there appears, on your system, to be an actual function getch() in the curses library, but it expects stdscr to be set up, and that is done by the curses initialization functions (initscr() and relatives), and that is signally not done by your code. So, your code is invoking undefined behaviour by calling curses routines before the correct initialization is done, leading to the crash.
(Good hint from dmckee - it helped get the link line out of acidzombie24, which was important.)
To get to a point where a single key-stroke can be read and the program terminated cleanly, you have to do a good deal of work on Unix (OSX, Linux). You would have to trap the initial state of the terminal, arrange for an atexit() function - or some similar mechanism - to restore the state of the terminal, change the terminal from cooked mode into raw mode, then invoke a function to read a character (possibly just read(0, &c, 1)), and do your exit. There might be other ways to do it - but it certainly will involve some setup and teardown operations.
One book that might help is Advanced Unix Programming, 2nd Edn by Mark Rochkind; it covers terminal handling at the level needed. Alternatively, you can use <curses.h> properly - that will be simpler than a roll-your-own solution, and probably more reliable.
You have not exhibited a
#include <stdio.h>
or
#include <curses.h>
or similar line. Are you sure that you are linking against a library that includes getch()?
Use the cin.get() function for example:
#include <iostream>
using namespace std;
int main()
{
char input = cin.get();
cout << "You Pressed: " << input;
}
The program would then wait for you to press a key.
Once you have, the key you pressed would be printed to the screen.
The getch function is not available on Unix-like systems, but you can replace it with console commands through your compiler with the system function.
Usage:
In Windows you can use system("pause");
In Unix-like systems (such as OSX) you can use system("read -n1 -p ' ' key");
Note: system is declared in <stdlib.h>.

Resources