diff --git a/src/cli.c b/src/cli.c index b2b330c..62ca381 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1,5 +1,5 @@ //=-------------------------------------------------------------------------=// -// Command line interface management module // +// Command line interface main file // // // // Copyright © 2021 The Gem-graph Project // // // @@ -22,11 +22,13 @@ #include "../include/base.h" #include +#include #include #include #include #include #include +#include #define SEND_BUFFER_SIZE 80 #define RECEIVE_BUFFER_SIZE 80 * 24 @@ -43,6 +45,7 @@ #define KEY_ARROW_LEFT 68 #define KEY_DELETE 127 +#define C_CLEARSCREEN "\e[2J" #define C_CLEARLINE "\e[2K" #define C_CURSORLEFT "\e[1D" #define C_CURSORRIGHT "\e[1C" @@ -54,15 +57,25 @@ #define C_COLOR_BLUE "\e[01;34m" #define C_COLOR_NORMAL "\e[0m" -static char getch(void) +#define NON_BLOCKING 1 + + +// +// Get a character code from the keyboard +// +static inline int getch(bool nonBlocking) { - char buf = 0; + int buf = 0; // old terminal struct termios old = {0}; // force flush stdout fflush(stdout); + // Set non-blocking mode if asked + if(nonBlocking) + fcntl(0, F_SETFL, O_NONBLOCK); + if(tcgetattr(0, &old) < 0) { printLog("%sError getting terminal settings! (%s)\n", C_COLOR_RED, @@ -72,8 +85,6 @@ static char getch(void) old.c_lflag &= ~ICANON; // disable buffered I/O old.c_lflag &= ~ECHO; // set no echo mode - old.c_cc[VMIN] = 1; - old.c_cc[VTIME] = 0; if(tcsetattr(0, TCSANOW, &old) < 0) { printLog("%sError setting terminal settings! (%s)\n", @@ -82,7 +93,12 @@ static char getch(void) return -1; } - if(read(0, &buf, 1) < 0) { + buf = getchar(); + if(buf < 0) { + // Check target busy (try again) + if(errno == EAGAIN) + return 0; + printLog("%sError reading character! (%s)\n", C_COLOR_RED, strerror(errno)); @@ -98,11 +114,120 @@ static char getch(void) strerror(errno)); return -1; } + + // Reset blocking mode + if(nonBlocking) + fcntl(0, F_SETFL, 0); + return buf; } + // + // Decorations + // + void decorateMonitor(struct winsize *terminalSize) +{ + printf(C_CLEARSCREEN "\n"); -void connectedCommunication(int sockfd) + // print decorations + for (int i = 0; i < terminalSize->ws_col; i++) { + printf("*"); + } + + for (int i = 0; + i < (terminalSize->ws_row-2) * terminalSize->ws_col; + i++) { + if ((i % terminalSize->ws_col == 0) || + (i % terminalSize->ws_col == terminalSize->ws_col - 1)) + printf("|"); + else + printf(" "); + } + + for (int i = 0; i < terminalSize->ws_col; i++) { + printf("*"); + } + + fflush(stdout); +} + + +// +// Monitor mode main loop +// +int connectedMonitor(int sockfd) +{ + char sendBuff[SEND_BUFFER_SIZE] = {0}; + char receiveBuff[RECEIVE_BUFFER_SIZE] = {0}; + + int pleaseStop = 0; + + char curChar; + int answerLength; + + struct winsize terminalSize, oldTerminalSize; + + // Get current terminal size + ioctl(STDOUT_FILENO, TIOCGWINSZ, &terminalSize); + memcpy(&oldTerminalSize, &terminalSize, sizeof(struct winsize)); + + decorateMonitor(&terminalSize); + + + while (!pleaseStop) { + // Zeroing buffer + bzero(sendBuff, sizeof(sendBuff)); + + + // Get current terminal size and redecorate if it has changed + ioctl(STDOUT_FILENO, TIOCGWINSZ, &terminalSize); + if (terminalSize.ws_row != oldTerminalSize.ws_row || + terminalSize.ws_col != oldTerminalSize.ws_col + ) { + memcpy(&oldTerminalSize, &terminalSize, sizeof(struct winsize)); + decorateMonitor(&terminalSize); + } + + // Read command from terminal + curChar = getch(NON_BLOCKING); + + if (curChar > 0) { + printLog("Char detected : %d\n", curChar); + } + + switch (curChar) { + case 'q': + pleaseStop = true; + break; + + } + + /* // Otherwise send command to server */ + /* send(sockfd, sendBuff, sizeof(sendBuff), 0); */ + + /* // Zeroing buffer */ + /* bzero(receiveBuff, sizeof(receiveBuff)); */ + + /* // Reading server answer */ + /* answerLength = recv(sockfd, receiveBuff, sizeof(receiveBuff), 0); */ + + /* // Detect disconnection */ + /* if (answerLength == 0) { */ + /* break; */ + /* } */ + + /* // Detect null-string returned */ + /* if (receiveBuff[0] == '\0') { */ + /* // Invalid command */ + /* } */ + } + printf("%sEnd of monitoring session\n\e[0m", C_COLOR_YELLOW); +} + +// +// Main CLI loop +// +void connectedCommandLine(int sockfd) { char sendBuff[SEND_BUFFER_SIZE] = {0}; char receiveBuff[RECEIVE_BUFFER_SIZE] = {0}; @@ -113,8 +238,9 @@ void connectedCommunication(int sockfd) char curChar; int curLineLength, curPosition, continueReadLine, answerLength; - char *exitCommand = "exit"; - char *promptString = C_COLOR_BLUE "gem-graph console" C_COLOR_NORMAL "> "; + const char *exitCommand = "exit"; + const char *monitorCommand = "monitor"; + const char *promptString = C_COLOR_BLUE "gem-graph console" C_COLOR_NORMAL "> "; for (;;) { // Zeroing buffer @@ -126,7 +252,7 @@ void connectedCommunication(int sockfd) curPosition = 0; continueReadLine = 1; historyModifier = -1; - while (continueReadLine && (curChar = getch())) { + while (continueReadLine && (curChar = getch(0))) { switch (curChar) { @@ -164,9 +290,9 @@ void connectedCommunication(int sockfd) break; case KEY_ESCAPE: - if (getch() == KEY_DIRECTIONS) { + if (getch(0) == KEY_DIRECTIONS) { - switch(getch()) { + switch(getch(0)) { case KEY_ARROW_UP: if (historyIndex <= 0) @@ -228,7 +354,7 @@ void connectedCommunication(int sockfd) break; default: - if (curLineLength < SEND_BUFFER_SIZE) { + if (curLineLength < SEND_BUFFER_SIZE && curChar > 0) { printf("%s", C_SAVE_CURSORPOS); memmove(sendBuff + curPosition + 1, sendBuff + curPosition, @@ -266,6 +392,12 @@ void connectedCommunication(int sockfd) break; } + // Launch monitor mode if asked + if (strcmp(monitorCommand, sendBuff) == 0) { + connectedMonitor(sockfd); + continue; + } + // Otherwise send command to server send(sockfd, sendBuff, sizeof(sendBuff), 0); @@ -290,6 +422,9 @@ void connectedCommunication(int sockfd) printf("%sDisconnected\n\e[0m", C_COLOR_YELLOW); } +// +// main +// int main(void) { int sockfd; @@ -321,7 +456,7 @@ int main(void) printLog("%sConnected to server!\n\n", C_COLOR_GREEN); - connectedCommunication(sockfd); + connectedCommandLine(sockfd); // close the socket close(sockfd);