views:

224

answers:

3

Hi I am using raw.c for keyboard capture. Following code finds when an arrow key/ esc is pressed. At the same time I want to read whole words that user inputs and these should be shown on stdout as well.

char pp = 0;
char p = 0;
while( (i = read(0, &c, 1)) == 1) {
if (pp == 033 && p == 0133 && (c &= 255) == 0102) /* DOWN */ break;
if (c == 0177) /* ASCII DELETE */ break;
printf( "%o, %o, %o\t%s\n\r", pp, p, c, &c);
pp = p;
p = c; 
}
...
...
getchar(); //I want to capture here what was entered before
           //  **return key** was pressed.

But this code does not work if I remove '\n'. I want stdout should behave as a normal shell.

A: 

getchar() is likely implemented in terms of a read() that reads far more than 1 byte (usually a whole PIPE_BUF, or 4096 bytes). It then maintains a private cursor to that buffer, extracting bytes as needed.

This is done because read() has a non-trivial overhead associated with just calling it.

printf(), and fwrite() (and etc) also buffer for the same reason (write() has a non-trivial overhead). The call to fflush(stdout) will translate into a write() call of whatever has been buffered, but not sent to the underlying IO port.

Finally, you have \n\r backwards; it's almost certainly supposed to be \r\n

geocar
A: 

insert

setbuf( stdout, NULL);

somewhere at the start and remove the \n.

drhirsch
+1  A: 

printf(3) goes through the <stdio.h> buffered I/O facility, which includes fputs(3) and fputc(3). You are observing the normal line buffering behavior. You can defeat this buffering as noted with setbuf(3), however, since you don't want it in the first place and you are already using a direct kernel call (read(2)) for reading, why not change your logic just a little to directly call the kernel with write(2) as well?

char buffer[100];

int n;

n = snprintf(buffer, sizeof buffer, "format string...", args...);
write(1, buffer, n)

And if you wanted to, you could define your own directPrintf to make this easier:

#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>

int directPrintf(const char *format, ...)
{
va_list ap;
char buffer[200];

    va_start(ap, format);
    int n = vsnprintf(buffer, sizeof buffer, format, ap);
    va_end(ap);
    return write(1, buffer, n);
}
DigitalRoss