Conio.h not working in codeblocks (Undefined reference to ..) - c

I'm working with Code::Blocks and the thing is I tried many times to fix the problem with the Conio library and probably some other libraries as well. Every time I use something like clrscr(); textcolor(); or anything it says ;
Undefined reference to textcolor.
For example, this simple program is supposed to show the sum in a specific color but it's not working out though I have seen it work before.
#include <stdio.h>
#include <conio.h>
int fx(int x,int y,int z)
{
return x+y+z;
}
int main()
{
int a,b,c;
printf("Enter three values to a, b and c.\n");
scanf("%d%d%d",&a,&b,&c);
int total=fx(a,b,c);
textcolor(14);
printf("Output ="); cprintf(" %d",&total);
getch();
return 0;
}
P.S.: I'm using GNU GCC. And sometimes when I select another compiler or just open Code::Blocks it says, "Some plugins are missing," or something like that.
Can anyone help??

conio.h is not supported with gcc.

conio.h is not supported by gcc. Here is an implementation of conio.h for gcc though.

conio.h is not supported in gcc. You may try the curses library, which supports creation of text-user interface.
There are many flavor of curses, you may use ncurses or pdcurses library with code-blocks.

Some of the functions in the original Borland conio.h are easy to duplicate -- I've recently been porting from Turbo-C programs (from 1990!) to gcc, and found versions of getch and getche (for Linux) that I could use online (but not the C++ version, which won't compile using the gcc command). I wrote my own version of cgets, but haven't found the need to create my own versions of the other functions from that header file yet.
char getch()
{
char c; // This function should return the keystroke without allowing it to echo on screen
system("stty raw"); // Raw input - wait for only a single keystroke
system("stty -echo"); // Echo off
c = getchar();
system("stty cooked"); // Cooked input - reset
system("stty echo"); // Echo on - Reset
return c;
}
char getche()
{
char c; // This function should return the keystroke, with echo to screen
system ("stty raw"); // Raw input - wait for only a single keystroke
c = getchar();
system ("stty cooked"); // Cooked input - reset
return c;
}
char *cgets(char *buf)
/* gets a string from console and stores it in *buf; buf[0] must be initialized to maximum string size and *buf must
be declared by caller to maximum string size plus 3 bytes, to accommodate string, terminating null, size byte in buf[0]
and length of entered string in buf[1]; sets buf[1] to length of string entered and returns pointer to buf[2] */
{
/* declare and initialize internal variables */
unsigned int count = 2; /* start at 2 because [0] is max size including terminator and [1] returns actual */
/* entry size, also including terminating null */
char input = '\0'; /* initialize to null */
/* start actual function */
while (count < buf[0] + 2) /* while within permitted string length -- +2 for size control bytes */
{
input=getch(); /* get a single character, without echo */
if (input != (char) 13) /* not cr/enter key -- presumed meaningful input */
{
printf("%c",input);
buf[count++] = input; /* store character and increment counter */
}
else
{
buf[count] = '\0'; /* change cr/enter key to terminating null */
buf[1]=(char) count - 2;/* store length of entered string (including terminating null) */
count = buf[0] + 2; /* terminate entry loop -- +2 for size control again */
}
}
return &buf[2]; /* return pointer to start of string */
}
The key thing to remember is that an included file (such as conio.h) doesn't have to be precompiled; it can be just as functional if it's just more C source code.

Try this library: https://sourceforge.net/projects/coniohcloneturboccpp/.
The CONIO features for Windows and Linux are almost complete. It seems to work well.

Related

Backspace and multibyte characters using getchar() in C

I was reading BeeJ's C programming guide and copied his readline() function, that reads a line from stdin. Due to the way it's implemented it has no problem reading multibyte characters, as it reallocates the spaces in accordance with the total amount of received bytes, and as such, it has no problem with unicode input. Here's a program with the function included:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define printPrompt printf("db > ")
/* The readLine function, allocates memory for a short string and
** reads characters into it. When the string's size limit is met,
** the same memory block is reallocated, but twice the size.
** Shamelessly stolen from BeeJ's guide to C programming |=
*/
char* read_line(void) {
int i = 0; /* Position of the current character */
int linbuf = 4; /* Size of our line in memory, will be
duplicated once the line length surpasses it */
char* lin; /* The pointer value to our line */
int c; /* The value we'll use to accept characters */
if( !(lin = malloc( linbuf*sizeof(char))) )
return NULL;
while( c = getchar(), c != '\n' && c != EOF ) {
/* Check if the amount of bytes accepted has surpassed the
* amount of memory we've allocated so far */
if(i == linbuf - 1) {
/* If it did, reallocate double the space */
linbuf *= 2;
char* tmpbuf = realloc(lin, linbuf);
/* If the space couldn't have been allocated then we'd
* run out of memory. Delete everything and abort. */
if(tmpbuf == NULL) {
free(tmpbuf);
return NULL;
}
/* If we've arrived here that means there were no
* problems, so we'll assign the newly reallocated
* memory to "lin" */
lin = tmpbuf;
}
/* Add the new character to our allocated space */
lin[i++] = c;
}
/* If we've received an EOF signal after having read 0
* characters, we'd like to delete our allocated memory and
* return a NULL */
if(c == EOF && i == 0) {
free(lin);
return NULL;
}
/* Here we'll shrink the allocated memory to perfectly fit our
* string */
if(i < linbuf - 1) {
char* tmpbuf = realloc(lin, i + 1);
if(tmpbuf != NULL)
lin = tmpbuf;
}
/* Here we'll terminate the string */
lin[i] = '\0';
/* Finally, we'll return it */
return lin;
}
int main(int argc, char* argv[]) {
char* hey = read_line();
printf("%s\n", hey);
return 0;
}
An input of
Hello, World! (:
would result in the output of
Hello, World! (:
An input of multibyte characters such as
שלום, עולם! (:
would result in the correct output of
שלום, עולם! (:
However, if I were to press the backspace key, it would only delete a one byte character, resulting in garbled output; an input of (backspaces marked as \b):
שיהיה לכם בוקר טוב\b\b\b\b\b\b\b\bערב טוב
which is supposed to end up being:
שיהיה לכם ערב טוב
actually ends up being:
�שיהיה לכם בוק�ערב טוב
My computer runs a Musl-libc version of Void Linux, and I compiled the program with both tcc and gcc, both yielding the same results.
Does this problem have to do with my libc, with my terminal (suckless st), with my kernel, or is it something I'm missing in the code? Whatever might be the case, is there any way I can handle it, preferably without using any external libraries such as ICU or what have you?
"is there any way I can handle it [...] without using any external libraries" The answer is a big fat no. Unless you are prepared to write a big and complex library yourself, that is.
With external libraries this is trivial:
sudo apt install libreadline-dev # no idea how to say that in Void
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h> // optional, to enable line history
int main()
{
using_history(); // optional
char* s;
while ((s = readline("Type something > ")))
{
printf("You have typed: %s\n", s);
add_history(s);
}
printf ("Bye!\n");
}
With this, you get a bunch of goodies for free, including full Unicode-aware line editing, programmable keybindings, and input history.
Edit On a machine I first checked this, your program behaved like you describe. But on another machine, which happens to be my home desktop, it works as expected, no weird backspace behaviour at all. I checked both X11 terminals and the text linux tty. So I guess there is something with some kernels and/or terminals after all.
Later edit There is an stty setting that controls this behaviour, at least for UTF-8.
stty iutf8
and your program should behave as expected, with no big fat libraries needed.

Accepting a single character in C?

What I intend to do is to get the character entered and used it as a pattern. I've tried using getchar() but it won't work. I've hear of using scanf but it skips and stops whenever I press "shift" for the special characters on my keyboard.
int i, j, n;
char c;
c = getchar();
printf("Enter value of n: ");
scanf("%d", &n);
printf("Enter a Character: ");
getchar();
for(i=1; i<=n; i++)
{
for(j=1; j<=i; j++)
{
printf("%c", c);
}
printf("\n");
}
You need to assign the value returned by getchar to the variable c, and you had a redundent call to getchar that's why it skips reading the desired input:
int i, j, n;
char c;
printf("Enter value of n: ");
scanf("%d", &n);
printf("Enter a Character: ");
scanf(" %c", &c);
for(i=1; i<=n; i++)
{
for(j=1; j<=i; j++)
{
printf("%c", c);
}
printf("\n");
}
You can use %c with scanf:
scanf("%d %c", &n, %c);
This eliminates the need for the two getchar calls.
The space is required; it tells scanf to skip whitespace.
The problem you have is that your assumptions on getchar(3) are incorrect. You think getchar() is going to return the next key pressed in the input stream, but you are incorrectly assuming that it will be done without buffering or system processing (the terminal driver gives the program complete lines, or even worse, if you are reading from a file, complete buffer blocks, that have to be buffered so you miss no characters from the input stream)
You are assuming incorrectly that the end of line you need to press for the input to be feeded to the program does not count in the input stream.
What actually happens is:
you feed a complete line (because the kernel driver works that way) so you press your character, and then you see nothing, not after you have pressed the return key.
once you press it, you have more than one character (depending on how many you pressed before hitting the return key) that will stay in the buffer, until they are so consumed by the program. Normally this happens when you have executed more getchar() or scanf() statements.
The idea of this buffering mechanism is to allow a programmer to process character by charcacter large amounts of text, without the overhead of making a system call per character reading (this is a costly operation) so think of getchar() not as a sample function to get new users introduced to the world of programming, but as a hint to experienced programmers to use efficiently without having to think on buffering large amounts of text.
With stdio package, every character counts, so you have to think slowly and minuciously when you feed input to getchar(3).
The next question is: Right, then how can I solve and stop my program until I press some key? The first answer, with the set of tools you have exposed here is, be careful on what you input, instead of asking for any key, ask the user to press the return key, and then, do something like:
printf("Hit <ENTER> to continue"); fflush(stdout); /* so we get the line out, bypassing the buffering mechanism */
int c;
while ((c = getchar()) != EOF && c != '\n') {
/* just ignore the character we have received */
}
/* c == '\n' || c == EOF, so we can continue */
or, if you prefer, you can write a function just to do this (as there can be so many criteria to implement it, nobody included such a function in the standard C library, my apologies for that. ;) )
void wait_for_enter()
{
/* I use stderr, for two reasons:
* o stderr is normally unbuffered, so there's no need to fflush()
* o stdout can be redirected, so the prompt will not be visible in
* case you want to save the output of your program.
*/
fprintf(stderr, "Hit <ENTER> to continue");
int c;
while ((c = getchar()) != EOF && c != '\n') {
/* just ignore the character we have received
* until we get the end of file (ctrl-d at the terminal)
* or a new line */
}
/* c == '\n' || c == EOF, so we can continue */
/* it's assumed that the user pressed the enter key, so the echoed
* enter already did a newline, no need to do it here */
} /* wait_for_enter */
In order to wait for any character and in raw mode, you need first to ensure your input comes from a terminal (you cannot do the following on a normal file), then you have to switch the terminal driver to raw mode, so each character is given immediately to the program and no line editing processing is done, and then set the stdin descriptor to no buffering at all. Only then, you can receive individual characters with getchar(3), one by one, as they are keyed in. I think this is far out of the scope of this question, as the code to do that is far more complex than the above.
EDIT
Following is a complete sample of a program that uses raw input to process characters as they are keyed in.
/* pru.c -- program to show raw input from the terminal.
* Author: Luis Colorado <luiscoloradourcola#gmail.com>
* Date: Fri Sep 20 08:46:06 EEST 2019
* Copyright: (C) 2019 Luis Colorado. All rights reserved.
* License: BSD.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h> /* see termios(3) for a description on terminal conf */
#define F(_fmt) __FILE__":%d:%s: " _fmt, __LINE__, __func__
/* this function switches the terminal into raw mode and returns a malloc(3)ed
* terminal configuration, so it can be later restored. BEWARE that the returned
* configuration info must be deallocated by free(3) once it's not needed anymore.
* In case of failure of any system call, the function returns NULL, and errno is
* set to the failing cause. */
struct termios *set_raw(int fd)
{
struct termios *ret = malloc(sizeof *ret), cfg;
if (!ret) return NULL;
int res = tcgetattr(fd, &cfg);
if (res < 0) goto error;
*ret = cfg; /* save it for return */
cfmakeraw(&cfg);
/* set it after all buffered characters in the driver have drained out */
res = tcsetattr(fd, TCSADRAIN, &cfg);
if (res < 0) goto error;
return ret;
error:
free(ret);
return NULL;
} /* set_raw */
/* restores the configuration back to the associated file descriptor */
int restore_cfg(int fd, struct termios *cf)
{
/* set it after all buffered characters in the driver have drained out */
return tcsetattr(fd, TCSADRAIN, cf);
} /* restore_cfg */
int main()
{
struct termios *cfg = set_raw(fileno(stdin));
if (!cfg) {
fprintf(stderr, F("stdin: %s\n"),
strerror(errno));
}
setbuf(stdin, NULL); /* stdin unbuffered */
setbuf(stdout, NULL); /* stdout unbuffered */
/* BEWARE that raw mode doesn't process any characters, so no Ctrl-C(interrupt), Ctrl-D(EOF), etc.
* will be available, only if you read from a file, you'll get EOF, but you'll not be able to produce
* that on the terminal, you'll need to swith to another console and kill the process. */
int c;
while ((c = getchar()) != EOF && c != '\033') { /* ESCAPE key('\033') is a safeguard to end input */
/* print the input char as an hex number */
printf("[%02x]", c);
}
if (cfg) { /* if we were able to set the terminal to raw mode */
/* restore config */
restore_cfg(fileno(stdin), cfg);
/* and free it */
free(cfg);
}
exit(EXIT_SUCCESS);
} /* main */
The full source code can be also downloaded from here.
You can use this program to see how input keys get mapped into characters, as you'll note that when you press the enter key, the raw input is [0d] (ascii char 13, CARRY RETURN) while in normal line mode you get '\n' which is [0a] or ASCII LINE FEED, instead (you can check this if you redirect input from the pru.c text file). Also you'll see that you are unable to specify EOF from the terminal driver with Ctrl-D and that Ctrl-C does not come to help. Well, I have included a safeguard, by ending the program in case you press the ESC key, which generates an ASCII ESCAPE character (\033). This is also commented in the source code.
All of this processing is done by the kernel driver, so all unix implementations get the same line end characters or interpret the control characters the same way.

Change input separator in c

Hi i was reading K & R C where in the example to use getchar we have to press RET to end the input. Is there any way to change the input so that I can change the newline as the input separator to a comma. I use a Linux Mint . 64 bit. I get the input by running the program as ./Hello.o
Eg.
Hello world<RET>
but as I type a comma or dot the input should end
Eg.
Hello world, //End of input due to comma
Is there any way to change new line to another character to comma
It depends what function you want to use. For example, if you want to use getdelim you can provide a delimiter argument
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
for example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * lineptr = malloc(1000 * sizeof(char));
size_t n = 1000;
/*type something in that ends in a comma*/
getdelim(&lineptr, &n, ',', stdin);
/*print the result*/
printf("%s\n", lineptr);
free(lineptr);
return 0;
}
Note that this still requires you to press enter but everything after the comma will be discarded.
edit
Maybe you could try something like this?
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
/* Use this variable to remember original terminal attributes. */
struct termios saved_attributes;
void
reset_input_mode (void)
{
tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes);
}
void set_input_mode (void)
{
struct termios tattr;
char *name;
/* Make sure stdin is a terminal. */
if (!isatty (STDIN_FILENO))
{
fprintf (stderr, "Not a terminal.\n");
exit (EXIT_FAILURE);
}
/* Save the terminal attributes so we can restore them later. */
tcgetattr (STDIN_FILENO, &saved_attributes);
atexit (reset_input_mode);
/* Set the funny terminal modes. */
tcgetattr (STDIN_FILENO, &tattr);
tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
tattr.c_cc[VMIN] = 1;
tattr.c_cc[VTIME] = 0;
tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr);
}
int main()
{
char c;
set_input_mode ();
while (1)
{
read (STDIN_FILENO, &c, 1);
if (c == ',')
break;
else
putchar (c);
}
return 0;
}
This program will receive input until a comma. I can't take any credit for it, I found this link on noncanonical input.
You can use getch() function available in ncurses library.
You do no need to press Enter after each character input, therefore you can scan input in a while loop using getch() unless you get a , or any special character you want.
I would first read the standard input line by line using getline(3). Then you can do your own tokenizing on that line, e.g. with sscanf(3), strtok(3) or other means (e.g. using strchr(3) appropriately). See this answer for some code (but getline won't enable you to avoid pressing the return key, because the kernel tty subsystem is processing that key, unless you do raw keyboard input which is really difficult).
On Linux, you might be interested in using readline(3) from the readline library (which is quite powerful, so learn more about it). Maybe you could use the ncurses library.
Be aware that terminals are very complex things (or abstractions), mostly for historical reasons. Read with care the tty demystified page, and the Keyboard and Console HowTo.
Avoiding pressing the enter or return key is surprisingly difficult on Unix systems (and probably on others too!) because the kernel (and not only the application or its libc i.e. <stdio.h> functions) is usually buffering the input line. To avoid that, you need to do very low level and difficult programming (which could take you several weeks of work). Read first Advanced Linux Programming.
So instead of doing all the difficult coding by yourself, take several days to learn how to use readline (or maybe ncurses). Even with the help of such libraries, it is not that easy!

Number Pad [Enter] not \n in C?

I'm working on a small C program for a college assignment and I've noticed a weird bug in my code. I use an iMac with the short keyboard generally, but its battery was flat so i plugged in a standard USB keyboard with number pad.
The weird thing is that if I hit [Enter] on my number pad, it seems to do what the regular [Enter} key does, but the \n I am trying to detect in the stdin function I made to read the keyboard input, doesn't work when I use the number pad's [Enter] key.
Wtf?
Here is my function that reads the user input:
/* This is my implementation of a stdin "scanner" function which reads
* on a per character basis until the the termination signals are found
* and indescriminately discarding all characters in the input in excess
* of the supplied (limit) parameter. Eliminates the problem of 'left-over'
* characters 'polluting' future stdin reads.
*/
int readStdin(int limit, char *buffer)
{
char c;
int i = 0;
int read = FALSE;
while ((c = myfgetc(stdin)) != '\n' && c != '\0') {
/* if the input string buffer has already reached it maximum
limit, then abandon any other excess characters. */
if (i <= limit) {
*(buffer + i) = c;
i++;
read = TRUE;
}
}
/* clear the remaining elements of the input buffer with a null character. */
for (i = i; i < strlen(buffer); i++) {
*(buffer + i) = '\0';
}
return read;
}
/* This function used to wrap the standard fgetc so that I can inject programmable
* values into the stream to test my readStdin functions.
*/
int myfgetc (FILE *fin) {
if (fakeStdIn == NULL || *fakeStdIn == '\0')
return fgetc (fin);
return *fakeStdIn++;
}
NB: The myfgetc and the subsequent *fakeStdIn are part of a way that I can unit test my code and 'inject' items into the stdin stream programatically as someone suggested on this question: How do I write a testing function for another function that uses stdin input?.
What output do you get for this tiny test?
#include <stdio.h>
int main(int argc, char* argv[]) {
int c;
while((c=getchar()) != EOF) {
printf("%d\n", c);
}
return 0;
}
Could well be that on Mac, you are getting \r\n, not just \n.
So it turns out that it's a Mac OSX thing. I've spoken to other Mac users and they have the same problem. Never found a fix because one may simply not exist. The problem doesn't occur on Solaris machines and since that's the OS which the code will be run on, I guess it doesn't really matter.
I am going to answer this myself with the answer that its just one of those OSX "quirks" and be done with it.

Writing a command line shell with C; trying to use ncurses/C for the first time

I'm working on a class project in which I must write a command line shell with the following requirements:
The shell must able to read buffered input
Buffer should be 64 characters
Error conditions should be handled
Exceeded buffer size
Interruptions (when a signal arrives) – see the man page for read()
Invalid input (unparsable characters, blank lines, etc)
Any other error that may be encountered.
Shell must have a history of at least 20 items, and the history must not be of a static size. When the history buffer is full, the oldest item is removed and the newest item added.
Programs should be able to run in the foreground or background. (using &)
Ctrl-D will exit the shell
Ctrl-C will print the complete history
The Command ‘history’ will also print the complete history. Newest items will be at the bottom of the list.
All other signals will be trapped and displayed to the user in the shell
Program will use the read() command to read in input, unless the arrow keys are supported
I have opted to implement arrow keys for history cycling, so I'm using ncurses for input, rather than read(). I think I'm doing all right using strtok() to parse input, and fork() and execvp() to run the processes, but I'm not doing all right implementing ncurses correctly. All I've gotten it to do so far is init a new screen, display the prompt, then segfault upon any key press. Not good.
I reckon the problem must be in my design. I'm not wrapping my head around ncurses too well. What sort of data structures should I be using for this project? How should I handle the ncurses setup, teardown, and everything in between? What's the deal with windows and screens, and should I have a single globally accessible window/screen that I work with? Also, I've been trying to use a char* for the input buffer, and a char** for the command history, but I have no experience in C, so despite reading up on malloc, calloc, and realloc, I'm not sure of the best way to store commands in the buffer and the history. Any tips on managing these char arrays?
tl;dr: How do I use ncurses correctly to make a command line shell, and how do I handle the command memory management with C?
I realize this is a pretty hefty question. :(
edit: I have already seen http://www.gnu.org/software/libc/manual/html_node/Implementing-a-Shell.html and http://www.linuxinfor.com/english/NCURSES-Programming/ but the ncurses documentation has actually too much overhead. I just want to use its ability to recognize arrow keys.
Here's some sample code which:
Performs dynamic memory allocation.
Reads from the console in non-blocking mode.
Uses VT100 codes to print a frame buffer to the console.
It compiles on Linux using GCC without warnings or errors. It's far from bug free, but it should give you some ideas of what's possible. Compile and run it, pressing [up] and [down] will print messages, typing characters and hitting [enter] will "execute" the command.
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/** VT100 command to clear the screen. Use puts(VT100_CLEAR_SCREEN) to clear
* the screen. */
#define VT100_CLEAR_SCREEN "\033[2J"
/** VT100 command to reset the cursor to the top left hand corner of the
* screen. */
#define VT100_CURSOR_TO_ORIGIN "\033[H"
struct frame_s
{
int x;
int y;
char *data;
};
static int draw_frame(struct frame_s *frame)
{
int row;
char *data;
int attrib;
puts(VT100_CLEAR_SCREEN);
puts(VT100_CURSOR_TO_ORIGIN);
for (row = 0, data = frame->data; row < frame->y; row++, data += frame->x)
{
/* 0 for normal, 1 for bold, 7 for reverse. */
attrib = 0;
/* The VT100 commands to move the cursor, set the attribute, and the
* actual frame line. */
fprintf(stdout, "\033[%d;%dH\033[0m\033[%dm%.*s", row + 1, 0, attrib, frame->x, data);
fflush(stdout);
}
return (0);
}
int main(void)
{
const struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 };
struct frame_s frame;
struct termios tty_old;
struct termios tty_new;
unsigned char line[128];
unsigned int count = 0;
int ret;
struct pollfd fds[1];
sigset_t sigmask;
struct tm *tp;
time_t current_time;
/* Set up a little frame. */
frame.x = 80;
frame.y = 5;
frame.data = malloc(frame.x * frame.y);
if (frame.data == NULL)
{
fprintf(stderr, "No memory\n");
exit (1);
}
memset(frame.data, ' ', frame.x * frame.y);
/* Get the terminal state. */
tcgetattr(STDIN_FILENO, &tty_old);
tty_new = tty_old;
/* Turn off "cooked" mode (line buffering) and set minimum characters
* to zero (i.e. non-blocking). */
tty_new.c_lflag &= ~ICANON;
tty_new.c_cc[VMIN] = 0;
/* Set the terminal attributes. */
tcsetattr(STDIN_FILENO, TCSANOW, &tty_new);
/* Un-mask all signals while in ppoll() so any signal will cause
* ppoll() to return prematurely. */
sigemptyset(&sigmask);
fds[0].events = POLLIN;
fds[0].fd = STDIN_FILENO;
/* Loop forever waiting for key presses. Update the output on every key
* press and every 1.0s (when ppoll() times out). */
do
{
fds[0].revents = 0;
ret = ppoll(fds, sizeof(fds) / sizeof(struct pollfd), &timeout, &sigmask);
if (fds[0].revents & POLLIN)
{
ret = read(STDIN_FILENO, &line[count], sizeof(line) - count);
if (ret > 0)
{
line[count + ret] = '\0';
if (strcmp(&line[count], "\033[A") == 0)
{
snprintf(frame.data, frame.x, "up");
count = 0;
}
else if (strcmp(&line[count], "\033[B") == 0)
{
snprintf(frame.data, frame.x, "down");
count = 0;
}
else if (line[count] == 127) // backspace
{
if (count != 0) { count -= ret;}
}
else if (line[count] == '\n')
{
snprintf(frame.data, frame.x, "entered: %s", line);
count = 0;
}
else
{
count += ret;
}
}
}
/* Print the current time to the output buffer. */
current_time = time(NULL);
tp = localtime(&current_time);
strftime(&frame.data[1 * frame.x], frame.x, "%Y/%m/%d %H:%M:%S", tp);
/* Print the command line. */
line[count] = '\0';
snprintf(&frame.data[(frame.y - 1) * frame.x], frame.x, "$ %s", line);
draw_frame(&frame);
}
while (1);
/* Restore terminal and free resources. */
tcsetattr(STDIN_FILENO, TCSANOW, &tty_old);
free(frame.data);
return (0);
}
If your input buffer is defined to be 64 characters, then I would recommend using a char array instead of a char*. Something like char input_buffer[65]; should serve your purposes (add an extra character for the trailing '\0').
As far as command history goes, you can use a two-dimensional array for that. Something like char command_history[20][65]; should let you store 20 old commands of 64 characters each.
Allocating these buffers statically should make things a bit easier for you, as you won't have to worry about malloc and friends.
It's hard to give you too much specific advice without seeing your code. I have a feeling that you are making the same type of mistakes that are typical to people first learning C. Can you post the part of your code that is giving you problems so that we can learn more about what you are doing?
Update after posted provided code:
One problem I'm seeing is that the function takeInput doesn't have a return statement. When you use input = takeInput(); inside your main function, the value of input isn't being set to what you think it is. It's probably not a valid pointer, which is causing your line that says input[j] to segfault.
Your usage of cmdHistory also needs revisiting. You allocate it with cmdHistory = (char**)calloc(21,sizeof(int));, which gives you enough space to store 21 integers. In the function printHistory, you pass elements of cmdHistory to printw as if they were strings (they're only integers). This is most definitely not doing what you want it to do. Instead, your allocation logic for cmdHistory needs to look more like your de-allocation logic (except backwards). Allocate an array of char**, then iterate through the array, assigning each pointer to a newly-allocated buffer. Just like you have one free statement for each element in the array plus a free for the array as a whole, you should have one malloc for each element plus one malloc for the array as a whole.
Even if you can't use a statically-allocated stack, try writing your program using one anyway. This will let you work the kinks out of your key detection logic, etc without having to worry about the dynamic memory part of the program. Once the rest of it is working, go back in and swap out the static memory for dynamic memory allocation. That way, you're only having to debug a little bit at a time.
Have you looked at the Readline library? It's ideal for use in your project.
http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html

Resources