aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorache <ache@ache.one>2017-11-08 03:49:10 +0100
committerache <ache@ache.one>2017-11-08 03:49:10 +0100
commit28a3fa7afebb9937fa42b9d53678eb8fd0be529d (patch)
tree83e5caf6ce15aed1cfc1145f1bea91722b67ec9b
Init commit
-rw-r--r--Makefile43
-rw-r--r--README.md6
-rw-r--r--main.c142
-rw-r--r--main.h56
-rw-r--r--readline.c201
-rw-r--r--readline.h27
-rw-r--r--wind.c16
-rw-r--r--wind.h9
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
+
+
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 <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;
+}
+
+
+
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 <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
+
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