Преглед изворни кода

More on curses and program structure...

master
Ognjen Milan Robovic пре 7 месеци
родитељ
комит
95d48ca3bc
2 измењених фајлова са 62 додато и 28 уклоњено
  1. +55
    -24
      chapters/chapter_2.c
  2. +7
    -4
      xhartae.c

+ 55
- 24
chapters/chapter_2.c Прегледај датотеку

@@ -162,14 +162,64 @@ int curses_screen_width = 0;
int curses_screen_height = 0;
int curses_active = 1;

static void curses_deinitialize (void) {
curses_screen = deallocate (curses_screen);
/*
I need to quickly explain how I'm structuring this subprogram. You can think of functions and variables starting with 'curses_*' as tiny standalone library if it's easier. They
deal with terminal input and output. User only needs to call function 'curses_configure' only once, before doing any rendering, then make an "infinite" loop that'll stop when
external variable 'curses_active' is equal to zero. In that loop, user can call any 'curses_render_*' function, and at the end call function 'curses_synchronize' only once. So the
following program structure would look something like this:

@C
// ...
int main (int argc, char * * argv) {
// ...
curses_configure ();

while (curses_active != 0) { // Notice the negative condition, the loop will stop then the condition is 0, so when 'curses_active' is 0.
// Calling functions 'curses_render_*' and doing other work...
curses_synchronize ();
}

// ...
return (0);
}
@
*/

static void curses_initialize (void) { // This function will be called when 'curses_configure' is called, automatically.
struct winsize screen_dimension;

fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, // If function 'ioctl' failed, we immediately aborting the entire program.
"ioctl: Failed to get terminal dimensions."); // I split those error messages, you can find your own formatting style.

curses_screen_width = (int) screen_dimension.ws_col; // We get the dimensions of terminal window by calling that 'ioctl' function.
curses_screen_height = (int) screen_dimension.ws_row;

fatal_failure (tcgetattr (STDIN_FILENO, & curses_old_terminal) == -1, // Now we need to obtain data for current non-raw terminal to restore it later.
"tcgetattr: Failed to get default terminal attributes.");

curses_new_terminal = curses_old_terminal; // Here we set our raw terminal to be the same as the non-raw one.

curses_new_terminal.c_cc [VMIN] = (unsigned char) 0;
curses_new_terminal.c_cc [VTIME] = (unsigned char) 1;

curses_new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); // Now it's time to modify it to be raw, this essentially means no-echo.
curses_new_terminal.c_oflag &= (unsigned int) ~(OPOST);
curses_new_terminal.c_cflag |= (unsigned int) (CS8);
curses_new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG);

fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_new_terminal) == -1, // Finally, we're passing intormations to our terminal, and it becomes raw.
"tcsetattr: Failed to set reverse terminal attributes.");
}

static void curses_deinitialize (void) { // This function will be only called once, automatically, at the program exit.
curses_screen = deallocate (curses_screen); // It's important to deallocate all previously allocated memory.
curses_activator = deallocate (curses_activator);
curses_action = deallocate (curses_action);

terminal_clear ();
terminal_clear (); // This only make things look prettier, we don't have mess when we exit the program.

fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_old_terminal) == -1, "tcsetattr: Failed to set default terminal attributes.");
fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_old_terminal) == -1, // Again, if this fails, we're doomed, we're aborting.
"tcsetattr: Failed to set default terminal attributes.");
}

static char * curses_screen_offset (int x, int y) {
@@ -223,28 +273,9 @@ External function definitions, those found in "chapter_2.h" header file.
*/

void curses_configure (void) {
struct winsize screen_dimension;

atexit (curses_deinitialize);

fatal_failure (ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension) == -1, "ioctl: Failed to get terminal dimensions.");

curses_screen_width = (int) screen_dimension.ws_col;
curses_screen_height = (int) screen_dimension.ws_row;

fatal_failure (tcgetattr (STDIN_FILENO, & curses_old_terminal) == -1, "tcgetattr: Failed to get default terminal attributes.");

curses_new_terminal = curses_old_terminal;

curses_new_terminal.c_cc [VMIN] = (unsigned char) 0;
curses_new_terminal.c_cc [VTIME] = (unsigned char) 1;

curses_new_terminal.c_iflag &= (unsigned int) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
curses_new_terminal.c_oflag &= (unsigned int) ~(OPOST);
curses_new_terminal.c_cflag |= (unsigned int) (CS8);
curses_new_terminal.c_lflag &= (unsigned int) ~(ECHO | ICANON | IEXTEN | ISIG);

fatal_failure (tcsetattr (STDIN_FILENO, TCSAFLUSH, & curses_new_terminal) == -1, "tcsetattr: Failed to set reverse terminal attributes.");
curses_initialize ();

curses_screen = allocate (CURSES_REVERT + CURSES_FORMAT * curses_screen_width * curses_screen_height + CURSES_CURSOR + 1);



+ 7
- 4
xhartae.c Прегледај датотеку

@@ -93,13 +93,16 @@ One sane C program should have the following structure (please keep in mind that
*/

int main (int argc, char * * argv) {
int i;

(void) argc;
(void) argv;

for (i = 0; i != (int) (sizeof (hello_world) / sizeof (* hello_world)); ++i) {
hello_world [i] ();
curses_configure ();

while (curses_active != 0) {
curses_render_background ('.', COLOUR_GREY, EFFECT_BOLD);
curses_render_character ('@', COLOUR_RED, EFFECT_BOLD, 1, 1);

curses_synchronize ();
}

return (EXIT_SUCCESS);


Loading…
Откажи
Сачувај