linux, termio strange behaviors, with ncurses - Page 1
Forum section: electronics / general

author: legacy
author_rank: Super Contributor
timestamp: August 16, 2015, 08:36:53 pm
content: I have learnt thatcursesis a terminal control library for Unix-like systems, enabling the construction of Text User Interface (TUI) applications, I think I have also understood why it is called like an expressed wish that some form of adversity or misfortune will befall or attach to some other entity (not to me)I have the following code, as you can see there are two parts: termio_funny1 and ncurses_demo1termio_funny1 is a blocking request for a string from the console (standard input), but … it modify a few attributes (e.g. no echo)running this code1)without termio_funny1, ncurses_demo1 is working as expected2)with termio_funny1 ncurses_demo1 is working as expected3)without ncurses_demo1 termio_funny1 is working as expected4)with ncurses_demo1 termio_funny1 is NOT working as expected: the console has a strange behaviorI wonderwhat is wrong with4), I get a console in where printf seem to be ~executed out of orderI need to understand what is wrong and to provide a fixany idea ?Code:int main(int argc,char* argv[]){ncurses_demo1();termio_funny1();return 0;}Code:void termio_funny1(){boolean_t ans;char_t host_linea;uint32_t host_linea_size;boolean_t is_echo;char_t host_prompt[] = "#";is_echo = True;host_linea_size = sizeof(host_linea);ans = console_linea_get(host_linea, host_linea_size, is_echo, host_prompt);}Code:private void termios_get_curr(p_termios_t p_termios){sint32_t res;res = tcgetattr(STDIN_FILENO, p_termios);}private void termios_set_curr(p_termios_t p_termios){sint32_t res;res = tcsetattr(STDIN_FILENO, TCSANOW, p_termios);}private void termios_set_work(p_termios_t p_termios){sint32_t res;res = tcgetattr(STDIN_FILENO, p_termios);p_termios->c_lflag &= ~ICANON;p_termios->c_lflag &= ~ECHO;p_termios->c_lflag &= ~ECHOE;p_termios->c_lflag &= ~ECHOK;p_termios->c_lflag &= ~ECHONL;p_termios->c_lflag &= ~ECHOPRT;p_termios->c_lflag &= ~ECHOKE;p_termios->c_lflag &= ~ISIG;p_termios->c_lflag &= ~ICRNL;p_termios->c_cc = 1;p_termios->c_cc = 0;tcsetattr(STDIN_FILENO, TCSANOW, p_termios);}Code:boolean_t console_linea_get(uint8_t host_linea[],uint32_t host_linea_size,boolean_t is_echo,uint8_t host_prompt[]){boolean_t ans;char_t ch;termios_t prev_opts;p_termios_t p_prev_opts;termios_t work_opts;p_termios_t p_work_opts;sint32_t arrow;sint32_t i;p_prev_opts = get_address(prev_opts);p_work_opts = get_address(work_opts);termios_get_curr(p_prev_opts);termios_set_work(p_work_opts);printf("%s ", host_prompt);arrow = 0;i = 0;while (i < host_linea_size){ch = getchar();switch (ch){...}termios_set_curr(p_prev_opts);host_linea = '\0';return ans;}Code:void ncurses_demo1(){int ch;initscr(); /* Start curses mode */raw(); /* Line buffering disabled */keypad(stdscr, TRUE); /* We get F1, F2 etc.. */noecho(); /* Don't echo() while we do getch */printw("Type any character to see it in bold\n");ch = getch(); /* If raw() hadn't been called* we have to press enter before it* gets to the program */if(ch == KEY_F(1)) /* Without keypad enabled this will */printw("F1 Key pressed");/* not get to us either *//* Without noecho() some ugly escape* charachters might have been printed* on screen */else{ printw("The pressed key is ");attron(A_BOLD);printw("%c", ch);attroff(A_BOLD);}refresh(); /* Print it on to the real screen */getch(); /* Wait for user input */endwin(); /* End curses mode */}

author: legacy
author_rank: Super Contributor
timestamp: August 16, 2015, 09:34:57 pm
content: the FORK does two copies before ncurses gets called, so thisuglysolutions works. It really seems to me … ncurses modifies something in the termI/O, the problem is … I do not understand/know what.Code:int main(int argc,char* argv[]){int pid;int status;pid = fork();if (pid == 0){/** child*/ncurses_demo2();}else{/** mother*/while (-1 == waitpid(pid, &status, 0)){/* wait the child to finish */;}termio_funny1();}return 0;}

author: kc8apf
author_rank: Regular Contributor
timestamp: August 16, 2015, 09:54:37 pm
content: The code as provided wouldn't compile. I cleaned it up with my best guesses and thus was working with the following:Code:#include <curses.h>#include <stdint.h>#include <termios.h>#include <unistd.h>void ncurses_demo1(){int ch;initscr(); /* Start curses mode */raw(); /* Line buffering disabled */keypad(stdscr, TRUE); /* We get F1, F2 etc.. */noecho(); /* Don't echo() while we do getch */printw("Type any character to see it in bold\n");ch = getch(); /* If raw() hadn't been called* we have to press enter before it* gets to the program */if(ch == KEY_F(1)) /* Without keypad enabled this will */printw("F1 Key pressed");/* not get to us either *//* Without noecho() some ugly escape* charachters might have been printed* on screen */else{ printw("The pressed key is ");attron(A_BOLD);printw("%c", ch);attroff(A_BOLD);}refresh(); /* Print it on to the real screen */getch(); /* Wait for user input */endwin(); /* End curses mode */}void termios_get_curr(struct termios* p_termios){int32_t res;res = tcgetattr(STDIN_FILENO, p_termios);}void termios_set_curr(struct termios* p_termios){int32_t res;res = tcsetattr(STDIN_FILENO, TCSANOW, p_termios);}void termios_set_work(struct termios* p_termios){int32_t res;res = tcgetattr(STDIN_FILENO, p_termios);p_termios->c_lflag &= ~ICANON;p_termios->c_lflag &= ~ECHO;p_termios->c_lflag &= ~ECHOE;p_termios->c_lflag &= ~ECHOK;p_termios->c_lflag &= ~ECHONL;p_termios->c_lflag &= ~ECHOPRT;p_termios->c_lflag &= ~ECHOKE;p_termios->c_lflag &= ~ISIG;p_termios->c_lflag &= ~ICRNL;p_termios->c_cc = 1;p_termios->c_cc = 0;tcsetattr(STDIN_FILENO, TCSANOW, p_termios);}bool console_linea_get(uint8_t host_linea[], uint32_t host_linea_size,bool is_echo, uint8_t host_prompt[]){bool ans;char ch;struct termios prev_opts;struct termios* p_prev_opts;struct termios work_opts;struct termios* p_work_opts;int32_t arrow;int32_t i;p_prev_opts = &prev_opts;p_work_opts = &work_opts;termios_get_curr(p_prev_opts);termios_set_work(p_work_opts);printf("%s ", host_prompt);fflush(stdout);arrow = 0;i = 0;while (i < host_linea_size - 1){ch = getchar();i++;switch (ch){}}termios_set_curr(p_prev_opts);host_linea = '\0';return ans;}void termio_funny1(){bool ans;char host_linea;uint32_t host_linea_size;bool is_echo;char host_prompt[] = "#";is_echo = true;host_linea_size = sizeof(host_linea);ans = console_linea_get(host_linea, host_linea_size, is_echo, host_prompt);}int main(int argc, char* argv[]){ncurses_demo1();termio_funny1();return 0;}I'm not entirely clear on your question but it looks like you expected the prompt to print after the screen cleared (endwin() is called) but before the getch() loop in console_linea_get(). printf(...) is essentially a call to fprintf(stdout, ...). Normally for all files, stdout included, block buffering is enabled. fprintf() will write to the buffer which will be flushed once enough characters have been written. Adding a call to fflush(stdout) after the printf forces it to be written before you start reading input. You can also disable the buffer on stdout all together with a call to setbuf(stdout, NULL).

author: legacy
author_rank: Super Contributor
timestamp: August 16, 2015, 10:44:49 pm
content: Quoteexactly, the code above is extracted from an other project in where I have implemented a shell which launch functions on demand.Everything was fine until I introduced a text-editor I have developed with ncursesStrange behaviors happened, so I wanted to isolate the cause, and I created the little demo above.because the output of printf does not appear as expectedQuoteOK, good explanation. I am putting your tricks on code

author: legacy
author_rank: Super Contributor
timestamp: August 16, 2015, 11:57:48 pm
content: "code view", ncurses (demo mode, just as proof of concept, it's not completed yet)Code:tokener_init: done# helphelpnew parser kind3 1:1 token_StrictAlphaNum, type20command (2)cmd_help()cmd_list, 50 itemsexit................ - byebye?................... - cmd listhelp................ - show specific cmd helpver................. - versionmy.................. - proof, provided by shell_initidevice............. - swi tap seticlass.............. - swi tap setireg................ - swi tap setget................. - swi tap reg getput................. - swi tap reg putid.................. - swi tap identifyping................ - swi tap pingresync.............. - swi tap resyncopen................ - swi tap openclose............... - swi tap closecon................. - swi tap connecttapS................ - swi tap serverscan................ - swi tap client scangrid................ - swi tap gripregs................ - swi tap reg showcv.................. - code viewans=(1)#this is the output of my shell, as you can see I can launch commands, an interesting one is "cv", which launches a "code view", it's a text-editor modified to be code-viever for a debug processor. It runs as built-in function (it lives on the stack) and it has its driver to access the uart and the lan.If i launch "cv" inside the shell … it will work as expected, the problem happens when it ends and the control returns to the shell … in this case … all the printf experiment a strange behavior, in short you stop to see what you type, then you see a shot with everything shown

author: legacy
author_rank: Super Contributor
timestamp: August 16, 2015, 11:57:58 pm
content: Solved, it was the printf buffer, the following code compile on linux (with a classic environment), and works as expectedI have just add a few lines to get_linea's switch, just to obtain a string from the consolethank youCode:#include <curses.h>//#include "types.h" /* my env */#include <stdint.h>#include <termios.h>#include <unistd.h>typedef struct termios termios_t;typedef termios_t* p_termios_t;void ncurses_demo1(){int ch;initscr(); /* Start curses mode */raw(); /* Line buffering disabled */keypad(stdscr, TRUE); /* We get F1, F2 etc.. */noecho(); /* Don't echo() while we do getch */printw("Type any character to see it in bold\n");ch = getch(); /* If raw() hadn't been called* we have to press enter before it* gets to the program */if (ch == KEY_F(1)) /* Without keypad enabled this will */{printw("F1 Key pressed"); /* not get to us either *//* Without noecho() some ugly escape* charachters might have been printed* on screen */}else{printw("The pressed key is ");attron(A_BOLD);printw("%c", ch);attroff(A_BOLD);}refresh(); /* Print it on to the real screen */getch(); /* Wait for user input */endwin(); /* End curses mode */}void termios_get_curr(p_termios_t p_termios){//sint32_t res;int32_t res;res = tcgetattr(STDIN_FILENO, p_termios);}void termios_set_curr(p_termios_t p_termios){//sint32_t res;int32_t res;res = tcsetattr(STDIN_FILENO, TCSANOW, p_termios);}void termios_set_work(p_termios_t p_termios){//sint32_t res;int32_t res;res = tcgetattr(STDIN_FILENO, p_termios);p_termios->c_lflag &= ~ICANON;p_termios->c_lflag &= ~ECHO;p_termios->c_lflag &= ~ECHOE;p_termios->c_lflag &= ~ECHOK;p_termios->c_lflag &= ~ECHONL;p_termios->c_lflag &= ~ECHOPRT;p_termios->c_lflag &= ~ECHOKE;p_termios->c_lflag &= ~ISIG;p_termios->c_lflag &= ~ICRNL;p_termios->c_cc = 1;p_termios->c_cc = 0;tcsetattr(STDIN_FILENO, TCSANOW, p_termios);}bool console_linea_get(uint8_t host_linea[],uint32_t host_linea_size,bool is_echo,uint8_t host_prompt[]){bool ans;char ch;termios_t prev_opts;p_termios_t p_prev_opts;termios_t work_opts;p_termios_t p_work_opts;//sint32_t arrow;//sint32_t i;int32_t arrow;int32_t i;p_prev_opts = &prev_opts;p_work_opts = &work_opts;termios_get_curr(p_prev_opts);termios_set_work(p_work_opts);printf("%s ", host_prompt);fflush(stdout);ans = 0;arrow = 0;i = 0;while (i < host_linea_size - 1){ch = getchar();switch (ch){case '\n':printf("%c", ch);fflush(stdout);host_linea = '\0';ans = 1;return ans;break;default:printf("%c", ch);fflush(stdout);host_linea = ch;i++;break;}}termios_set_curr(p_prev_opts);host_linea = '\0';return ans;}void termio_funny1(){bool ans;char host_linea;uint32_t host_linea_size;bool is_echo;char host_prompt[] = "#";is_echo = true;host_linea_size = sizeof(host_linea);ans = console_linea_get(host_linea, host_linea_size, is_echo, host_prompt);}int main(int argc, char* argv[]){ncurses_demo1();termio_funny1();return 0;}

author: legacy
author_rank: Super Contributor
timestamp: August 16, 2015, 11:59:51 pm
content: when possible and reasonable, I have also replaced printf withCode:fputs(string, stdout);Code:putchar(ch);