From 28a3fa7afebb9937fa42b9d53678eb8fd0be529d Mon Sep 17 00:00:00 2001 From: ache Date: Wed, 8 Nov 2017 03:49:10 +0100 Subject: Init commit --- Makefile | 43 +++++++++++++ README.md | 6 ++ main.c | 142 +++++++++++++++++++++++++++++++++++++++++++ main.h | 56 +++++++++++++++++ readline.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ readline.h | 27 +++++++++ wind.c | 16 +++++ wind.h | 9 +++ 8 files changed, 500 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 main.c create mode 100644 main.h create mode 100644 readline.c create mode 100644 readline.h create mode 100644 wind.c create mode 100644 wind.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..17c5f37 --- /dev/null +++ b/Makefile @@ -0,0 +1,43 @@ + + +CC=gcc +PROG=mesms +LIBS=-lcurses -lreadline +HEADERS=$(wildcard *.h) +FILES=readline.c wind.c +OBJ_FILES := $(FILES:.c=.o) +CFLAGS+=-std=gnu99 + + +all: $(PROG) + +debug: CFLAGS += -DDEBUG -g +debug: $(PROG) + +$(PROG): main.c main.h $(OBJ_FILES) + $(CC) $(CFLAGS) $(LIBS) -o $@ main.c $(OBJ_FILES) + + + + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) $(LIBS) -c -o $@ $< + + + +.PHONY: clean mrproper + +clean: + rm -f $(OBJ_FILES) + +mrproper: clean + rm -f ./$(PROG) + + +install: $(PROG) + cp $(PROG) /usr/bin/$(PROG) + @echo 'Installation success' + +uninstall: /usr/bin/$(PROG) + rm -f /usr/bin/$(PROG) + diff --git a/README.md b/README.md new file mode 100644 index 0000000..98437d4 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +mesms +===== + +A ncurses based SMS manager + + diff --git a/main.c b/main.c new file mode 100644 index 0000000..3c5a6f5 --- /dev/null +++ b/main.c @@ -0,0 +1,142 @@ +#include "main.h" +#include "readline.h" + +#include +#include +#include +#include +#include + +#include "wind.h" + +/* + * Entry point of mesms and event loop + */ + + +#ifdef DEBUG + +#include + +#endif + +const int color[] = { + COLOR_BLACK, COLOR_RED, + COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, + COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE}; + + + + + +#define MAX_PATH 1024 + + + +extern char* msg_win_str; + +static bool visual_mode = false; +WINDOW *cmd_win; +WINDOW *sep_win; +char status[10]; + + +void fail_exit(const char *msg) { + if (visual_mode) + endwin(); + fprintf(stderr, "%s\n", msg); + exit(EXIT_FAILURE); +} + +int main(int argc, char* argv[]){ + + /* Gestion des paramètres */ + while (1) { + int c; + int optIndex = 0; + static struct option optlv[] = { + {"help", no_argument, 0, 'h' }, + {"version", no_argument, 0, 'v' }, + {NULL, 0, 0, 0 } + }; + + + c = getopt_long(argc, argv, "hv:", optlv, &optIndex); + if (c == -1) + break; + + switch (c) { + case 'v': + if( !strcmp(optlv[optIndex].name, "version") ) { + puts( VERSION_MESMS ); + } + break; + + case 'h': + puts( HELP_STRING_MESMS ); + return EXIT_SUCCESS; + + break; + case '?': + default: + return EXIT_FAILURE; + } + } + + + + + /* Initialisation */ + + int size = 0; + int c; + int comp = 0; + + setlocale(LC_ALL, ""); + + initscr(); + if (has_colors()) { + CHECK(start_color); + } + + CHECK(cbreak); + CHECK(noecho); + CHECK(nonl); + CHECK(intrflush, NULL, FALSE); + visual_mode = true; + curs_set(0); + + cmd_win = newwin(1, COLS, LINES - 20, 0); + sep_win = newwin(1, COLS, LINES - 2, 0); + + init_pair( 12, COLOR_WHITE, COLOR_BLUE); + + CHECK(wbkgd, sep_win, COLOR_PAIR(12)); + CHECK(wrefresh, sep_win); + init_readline(); + + for(int i = 0 ; i < 9 ; i++) { + init_pair( i+1, i, COLOR_BLACK); + } + + /* Premier affichage */ + + /* Event loop */ + while( c = getch() ) { + if (c == KEY_RESIZE) { + continue; + } + + refresh(); + } + + refresh(); + getch(); +end: + endwin(); + + return 0; +} + + + diff --git a/main.h b/main.h new file mode 100644 index 0000000..cd72393 --- /dev/null +++ b/main.h @@ -0,0 +1,56 @@ +#ifndef MAIN_MESMS_H +#define MAIN_MESMS_H + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 // For strnlen() +#endif + + +#include +#include +#include +#include +#include +#include + + +#define HIDDEN 1 + +void resize(void); + + +void fail_exit(const char *msg); + + + +// Checks errors for (most) ncurses functions. CHECK(fn, x, y, z) is a checked +// version of fn(x, y, z). +#define CHECK(fn, ...) \ + do \ + if (fn(__VA_ARGS__) == ERR) \ + fail_exit(#fn"() failed"); \ + while (false) + + +#define max(a, b) \ + ({ typeof(a) _a = a; \ + typeof(b) _b = b; \ + _a > _b ? _a : _b; }) + + +#define VERSION_MESMS "Alpha" +#define HELP_STRING_MESMS "Utilisation : mesms [OPTION]..." "\n"\ + "Gestionnaire de SMS" "\n"\ + "Options :" "\n"\ + "\t\t--help -h Affiche l'aide simple" "\n"\ + "\t\t--version -v Affiche la version" "\n"\ + "\n" "\n"\ + "" + + + +#endif diff --git a/readline.c b/readline.c new file mode 100644 index 0000000..55795b9 --- /dev/null +++ b/readline.c @@ -0,0 +1,201 @@ +#include "readline.h" + + +/* + * Sets of functions to read a line with readline library and ncurses together + */ + + +static bool input_avail = false; +static unsigned char input; +static bool should_exit = false; +char *msg_win_str = NULL; +extern WINDOW *cmd_win; + + +// Calculates the cursor column for the readline window in a way that supports +// multibyte, multi-column and combining characters. readline itself calculates +// this as part of its default redisplay function and does not export the +// cursor column. +// +// Returns the total width (in columns) of the characters in the 'n'-byte +// prefix of the null-terminated multibyte string 's'. If 'n' is larger than +// 's', returns the total width of the string. Tries to emulate how readline +// prints some special characters. +// +// 'offset' is the current horizontal offset within the line. This is used to +// get tabstops right. +// +// Makes a guess for malformed strings. +static size_t strnwidth(const char *s, size_t n, size_t offset) +{ + mbstate_t shift_state; + wchar_t wc; + size_t wc_len; + size_t width = 0; + + // Start in the initial shift state + memset(&shift_state, '\0', sizeof shift_state); + + for (size_t i = 0; i < n; i += wc_len) { + // Extract the next multibyte character + wc_len = mbrtowc(&wc, s + i, MB_CUR_MAX, &shift_state); + switch (wc_len) { + case 0: + // Reached the end of the string + goto done; + + case (size_t)-1: case (size_t)-2: + // Failed to extract character. Guess that the remaining characters + // are one byte/column wide each. + width += strnlen(s, n - i); + goto done; + } + + if (wc == '\t') + width = ((width + offset + 8) & ~7) - offset; + else + // TODO: readline also outputs ~ and the like for some + // non-printable characters + width += iswcntrl(wc) ? 2 : max(0, wcwidth(wc)); + } + +done: + return width; +} + +// Like strnwidth, but calculates the width of the entire string +static size_t strwidth(const char *s, size_t offset) +{ + return strnwidth(s, SIZE_MAX, offset); +} + + +// Not bothering with 'input_avail' and just returning 0 here seems to do the +// right thing too, but this might be safer across readline versions +static int readline_input_avail(void) +{ + return input_avail; +} + +static int readline_getc(FILE *dummy) +{ + input_avail = false; + return input; +} +static void forward_to_readline(char c) +{ + input = c; + input_avail = true; + rl_callback_read_char(); +} +static void msg_win_redisplay(bool for_resize) +{ + CHECK(mvaddstr, 0, 0, msg_win_str ? msg_win_str : ""); + + // We batch window updates when resizing +/* + if (for_resize) + CHECK(wnoutrefresh, msg_win); + else + CHECK(wrefresh, msg_win); +*/ +} +static void got_command(char *line) +{ + if( line ) + if (*line != '\0') + add_history(line); + + free(msg_win_str); + msg_win_str = line; + //msg_win_redisplay(false); + should_exit = true; +} + +void cmd_win_redisplay(bool for_resize) +{ + size_t prompt_width = strwidth(rl_display_prompt, 0); + size_t cursor_col = prompt_width + + strnwidth(rl_line_buffer, rl_point, prompt_width); + + CHECK(werase, cmd_win); + // This might write a string wider than the terminal currently, so don't + // check for errors + mvwprintw(cmd_win, 0, 0, "%s%s", rl_display_prompt, rl_line_buffer); + if (cursor_col >= COLS) + // Hide the cursor if it lies outside the window. Otherwise it'll + // appear on the very right. + curs_set(0); + else { + CHECK(wmove, cmd_win, 0, cursor_col); + //curs_set(2); + } + // We batch window updates when resizing + if (for_resize) + CHECK(wnoutrefresh, cmd_win); + else + CHECK(wrefresh, cmd_win); +} + +static void readline_redisplay(void) +{ + cmd_win_redisplay(false); +} + + +void init_readline(void) +{ + // Disable completion. TODO: Is there a more robust way to do this? + if (rl_bind_key('\t', rl_insert) != 0) + fail_exit("Invalid key passed to rl_bind_key()"); + + // Let ncurses do all terminal and signal handling + rl_catch_signals = 0; + rl_catch_sigwinch = 0; + rl_deprep_term_function = NULL; + rl_prep_term_function = NULL; + + // Prevent readline from setting the LINES and COLUMNS environment + // variables, which override dynamic size adjustments in ncurses. When + // using the alternate readline interface (as we do here), LINES and + // COLUMNS are not updated if the terminal is resized between two calls to + // rl_callback_read_char() (which is almost always the case). + rl_change_environment = 0; + + // Handle input by manually feeding characters to readline + rl_getc_function = readline_getc; + rl_input_available_hook = readline_input_avail; + rl_redisplay_function = readline_redisplay; + + rl_callback_handler_install("> ", got_command); +} + + +void readline_n(void) { + curs_set(2); + //resize(); + while (!should_exit) { + // Using getch() here instead would refresh stdscr, overwriting the + // initial contents of the other windows on startup + int c = wgetch(cmd_win); + + if( c == '\n') + should_exit = 1; + if (c == KEY_RESIZE) + ;//resize(); + else if (c == '\f') { // Ctrl-L -- redraw screen. + // Makes the next refresh repaint the screen from scratch + CHECK(clearok, curscr, TRUE); + // Resize and reposition windows in case that got messed up + // somehow + //resize(); + } + else + forward_to_readline(c); + } + should_exit = 0; +} + + + diff --git a/readline.h b/readline.h new file mode 100644 index 0000000..cf96e11 --- /dev/null +++ b/readline.h @@ -0,0 +1,27 @@ + +#ifndef READLINE_METAG_H +#define READLINE_METAG_H + +#include "main.h" +#include +#include +#include +#include +#include +#include +#include + + + + + +void readline_n(void); + +void init_readline(void); + +void cmd_win_redisplay(bool for_resize); + +void deinit_readline(void); + +#endif + diff --git a/wind.c b/wind.c new file mode 100644 index 0000000..0051cd4 --- /dev/null +++ b/wind.c @@ -0,0 +1,16 @@ +/* + * Ache - 2017-08-14 - GPLv3 + */ + +#include "wind.h" + +/* Managed windows */ + + + +static short my_fg = COLOR_WHITE; +static short my_bg = COLOR_BLACK; +extern char status[10]; +extern WINDOW *cmd_win; +extern WINDOW *sep_win; + diff --git a/wind.h b/wind.h new file mode 100644 index 0000000..8fc3c3c --- /dev/null +++ b/wind.h @@ -0,0 +1,9 @@ + +#ifndef WIND_METAG_H +#define WIND_METAG_H + +#include "main.h" +#include "readline.h" + + +#endif -- cgit v1.2.3