diff options
author | ache <ache@ache.one> | 2017-11-08 03:49:10 +0100 |
---|---|---|
committer | ache <ache@ache.one> | 2017-11-08 03:49:10 +0100 |
commit | 28a3fa7afebb9937fa42b9d53678eb8fd0be529d (patch) | |
tree | 83e5caf6ce15aed1cfc1145f1bea91722b67ec9b |
Init commit
-rw-r--r-- | Makefile | 43 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | main.c | 142 | ||||
-rw-r--r-- | main.h | 56 | ||||
-rw-r--r-- | readline.c | 201 | ||||
-rw-r--r-- | readline.h | 27 | ||||
-rw-r--r-- | wind.c | 16 | ||||
-rw-r--r-- | wind.h | 9 |
8 files changed, 500 insertions, 0 deletions
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 + + @@ -0,0 +1,142 @@ +#include "main.h" +#include "readline.h" + +#include <dirent.h> +#include <stdnoreturn.h> +#include <wchar.h> +#include <wctype.h> +#include <unistd.h> + +#include "wind.h" + +/* + * Entry point of mesms and event loop + */ + + +#ifdef DEBUG + +#include <assert.h> + +#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; +} + + + @@ -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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <ncurses.h> +#include <getopt.h> + + +#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 ~<letter> 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 <stdio.h> +#include <wchar.h> +#include <locale.h> +#include <wctype.h> +#include <unistd.h> +#include <readline/history.h> +#include <readline/readline.h> + + + + + +void readline_n(void); + +void init_readline(void); + +void cmd_win_redisplay(bool for_resize); + +void deinit_readline(void); + +#endif + @@ -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; + @@ -0,0 +1,9 @@ + +#ifndef WIND_METAG_H +#define WIND_METAG_H + +#include "main.h" +#include "readline.h" + + +#endif |