Author: bdonlan
Date: 2004-12-15 15:08:55 -0500 (Wed, 15 Dec 2004)
New Revision: 413
Added:
trunk/clients/ncurses/
trunk/clients/ncurses/display.c
trunk/clients/ncurses/display.h
trunk/clients/ncurses/entry.c
trunk/clients/ncurses/entry.h
trunk/clients/ncurses/event.c
trunk/clients/ncurses/event.h
trunk/clients/ncurses/main.c
trunk/clients/ncurses/mymalloc.c
trunk/clients/ncurses/mymalloc.h
Log:
Imported beginnings of a C/ncurses client. Currently this is mostly a test
of the event/IO systems, and the command line.
Property changes on: trunk/clients/ncurses
___________________________________________________________________
Name: svn:ignore
+ ? configure
? Makefile.in
? config.log
? depcomp
? config.guess
? config.h
? config.sub
? ltmain.sh
? .libs
? .deps
? Makefile
? mkinstalldirs
? config.status
? stamp-h1
? config.h.in
? havercurs
? autom4te.cache
? libtool
? missing
? aclocal.m4
? install-sh
Added: trunk/clients/ncurses/display.c
===================================================================
--- trunk/clients/ncurses/display.c 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/display.c 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,23 @@
+#include "display.h"
+#include <ncurses.h>
+
+static WINDOW *dwin = NULL;
+
+void display_init(int lines) {
+ dwin = newwin(lines, COLS, 0, 0);
+ idlok(dwin, TRUE);
+ scrollok(dwin, TRUE);
+}
+
+void display_free(void) {
+ delwin(dwin);
+ dwin = NULL;
+}
+
+void display_print(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vw_printw(dwin, fmt, ap);
+ va_end(ap);
+ wnoutrefresh(dwin);
+}
Property changes on: trunk/clients/ncurses/display.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/clients/ncurses/display.h
===================================================================
--- trunk/clients/ncurses/display.h 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/display.h 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,9 @@
+#ifndef DISPLAY_H
+#define DISPLAY_H 1
+
+void display_init(int lines);
+void display_free(void);
+
+void display_print(const char *fmt, ...);
+
+#endif
Property changes on: trunk/clients/ncurses/display.h
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/clients/ncurses/entry.c
===================================================================
--- trunk/clients/ncurses/entry.c 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/entry.c 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,108 @@
+#include "mymalloc.h"
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ncurses.h>
+
+static char *buffer = NULL;
+int pos, len, blen, win;
+
+void entry_init(void) {
+ pos = len = win = 0;
+ blen = 32;
+ buffer = mymalloc(blen);
+}
+
+void entry_free(void) {
+ free(buffer);
+ buffer = NULL;
+}
+
+int entry_get_pos(void) {
+ return pos;
+}
+
+int entry_get_len(void) {
+ return len;
+}
+
+static void checkpos(void) {
+ if (pos < 0)
+ pos = 0;
+ if (pos > len)
+ pos = len;
+}
+
+char entry_remove_ch(int offset) {
+ char c;
+ if (offset >= len || offset < 0)
+ return 0;
+ c = buffer[offset];
+ memmove(&buffer[offset], &buffer[offset + 1], len - offset - 1);
+ len--;
+ checkpos();
+ return c;
+}
+
+static void expand_buf(void) {
+ blen = (blen * 3) / 2;
+ buffer = myrealloc(buffer, blen);
+}
+
+void entry_insert_ch(int offset, char c) {
+ if (offset < 0 || offset > len) {
+ assert(0);
+ abort();
+ }
+ if (len + 1 > blen)
+ expand_buf();
+ memmove(&buffer[offset + 1], &buffer[offset], len - offset);
+ buffer[offset] = c;
+ len++;
+}
+
+int entry_move_abs(int offset) {
+ pos = offset;
+ checkpos();
+ return pos;
+}
+
+int entry_move_rel(int offset) {
+ pos += offset;
+ checkpos();
+ return pos;
+}
+
+const char *entry_get(void) {
+ if (len + 1 > blen)
+ expand_buf();
+ buffer[len] = '\0'; /* null-terminate it for the caller */
+ return buffer;
+}
+
+void entry_clear(void) {
+ len = pos = win = 0;
+}
+
+void entry_refresh(WINDOW *w, int yoff, int cols) {
+ int i, lim;
+ wmove(w, yoff, 0);
+ wclrtoeol(w);
+
+ /* Is the window sane? */
+ if (pos < win ||
+ pos > win + cols
+ )
+ {
+ win = pos - (cols / 2);
+ if (win < 0)
+ win = 0;
+ }
+
+ lim = win + cols;
+ for (i = win; i < lim && i < len; i++) {
+ addch(buffer[i]);
+ }
+ wmove(w, yoff, pos - win);
+ wnoutrefresh(w);
+}
Property changes on: trunk/clients/ncurses/entry.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/clients/ncurses/entry.h
===================================================================
--- trunk/clients/ncurses/entry.h 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/entry.h 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,21 @@
+#ifndef ENTRY_H
+#define ENTRY_H 1
+
+void entry_init(void);
+void entry_free(void);
+
+int entry_get_pos(void);
+int entry_get_len(void);
+
+char entry_remove_ch(int offset);
+void entry_insert_ch(int offset, char c);
+
+int entry_move_abs(int offset);
+int entry_move_rel(int offset);
+
+const char *entry_get(void);
+void entry_clear(void);
+
+void entry_refresh(WINDOW *w, int yoff, int cols);
+
+#endif
Property changes on: trunk/clients/ncurses/entry.h
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/clients/ncurses/event.c
===================================================================
--- trunk/clients/ncurses/event.c 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/event.c 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,265 @@
+#include "mymalloc.h"
+#include "event.h"
+#include <sys/time.h>
+#include <sys/select.h>
+
+typedef struct event_timer_struct {
+ struct event_timer_struct *next;
+ struct timeval when;
+ event_timer_callback *cb;
+ void *baton;
+} event_timer_t;
+
+typedef struct event_fd_struct {
+ struct event_fd_struct *next;
+ int fd;
+ int mode;
+ event_fd_callback *cb;
+ void *baton;
+} event_fd_t;
+
+static event_timer_t *t_head = NULL;
+static event_fd_t *fd_head = NULL;
+
+static fd_set cache_r, cache_w, cache_e;
+static int fd_max = 0;
+
+void event_init(void) {
+ FD_ZERO(&cache_r);
+ FD_ZERO(&cache_w);
+ FD_ZERO(&cache_e);
+}
+
+void event_free(void) {
+ event_timer_t *t_cur = t_head;
+ event_fd_t *io_cur = fd_head;
+ while (t_cur) {
+ event_timer_t *next = t_cur;
+ free(t_cur);
+ t_cur = next;
+ }
+ t_head = NULL;
+ while (io_cur) {
+ event_fd_t *next = io_cur;
+ free(io_cur);
+ io_cur = next;
+ }
+ fd_head = NULL;
+}
+
+void event_timer_abs(
+ const struct timeval *when,
+ event_timer_callback *cb,
+ void *baton
+ ) {
+ event_timer_t *new = mymalloc(sizeof *new);
+ event_timer_t *cur, *prev;
+ new->when = *when;
+ new->cb = cb;
+ new->baton = baton;
+ prev = NULL;
+ cur = t_head;
+ while (cur) {
+ if (cur->when.tv_sec < new->when.tv_sec ||
+ cur->when.tv_usec < new->when.tv_usec
+ )
+ {
+ break;
+ }
+ cur = cur->next;
+ }
+ if (prev)
+ prev->next = new;
+ else
+ t_head = new;
+ new->next = cur;
+}
+
+void event_timer_rel(
+ const struct timeval *when,
+ event_timer_callback *cb,
+ void *baton
+ )
+{
+ struct timeval absolute;
+ gettimeofday(&absolute, NULL);
+ absolute.tv_sec += when->tv_sec;
+ absolute.tv_usec += when->tv_usec;
+ if (absolute.tv_usec > 1000000) {
+ absolute.tv_sec += absolute.tv_usec / 1000000;
+ absolute.tv_usec %= 1000000;
+ }
+ event_timer_abs(&absolute, cb, baton);
+}
+
+static int check_timers(
+ const struct timeval *now,
+ const struct timeval **next
+ )
+{
+ int counter = 0;
+ const struct timeval *dummy;
+ if (!next)
+ next = &dummy;
+ while (t_head) {
+ if (t_head->when.tv_sec < now->tv_sec ||
+ (t_head->when.tv_sec == now->tv_sec &&
+ t_head->when.tv_usec < now->tv_usec
+ ))
+ {
+ event_timer_t *cur = t_head;
+ counter++;
+ t_head = cur->next;
+ cur->cb(&cur->when, cur->baton);
+ free(cur);
+ } else break;
+ }
+ if (t_head)
+ *next = &t_head->when;
+ else
+ *next = NULL;
+ return counter;
+}
+
+static void recache_fd(event_fd_t *what, int add) {
+ if (what->mode & EVENT_FD_READABLE)
+ FD_SET(what->fd, &cache_r);
+ else
+ FD_CLR(what->fd, &cache_r);
+ if (what->mode & EVENT_FD_WRITABLE)
+ FD_SET(what->fd, &cache_w);
+ else
+ FD_CLR(what->fd, &cache_w);
+ if (what->mode & EVENT_FD_ERROR)
+ FD_SET(what->fd, &cache_e);
+ else
+ FD_CLR(what->fd, &cache_e);
+
+ if (add) {
+ if (what->fd + 1 > fd_max)
+ fd_max = what->fd + 1;
+ } else {
+ if (what->fd + 1 == fd_max) {
+ event_fd_t *cur = fd_head;
+ fd_max = 0;
+ while (cur) {
+ if (cur->fd + 1 > fd_max)
+ fd_max = cur->fd + 1;
+ cur = cur->next;
+ }
+ }
+ }
+}
+
+static event_fd_t *search(int fd, event_fd_t **prev) {
+ event_fd_t *dummy, *cur;
+ if (!prev)
+ prev = &dummy;
+ cur = fd_head;
+ while (cur) {
+ if (cur->fd == fd)
+ return cur;
+ *prev = cur;
+ cur = cur->next;
+ }
+ return NULL;
+}
+
+void event_addfd(
+ int fd,
+ int mode,
+ event_fd_callback *cb,
+ void *baton
+ ) {
+ static event_fd_t *prev, *cur;
+ cur = search(fd, &prev);
+ if (!cur) {
+ cur = mymalloc(sizeof *cur);
+ cur->fd = fd;
+ if (prev) {
+ cur->next = prev->next;
+ prev->next = cur;
+ } else {
+ cur->next = fd_head;
+ fd_head = cur;
+ }
+ }
+ cur->cb = cb;
+ cur->mode = mode;
+ cur->baton = baton;
+ recache_fd(cur, 1);
+}
+
+void event_delfd(int fd) {
+ static event_fd_t *prev, *cur;
+ cur = search(fd, &prev);
+ if (!cur)
+ return;
+ if (prev)
+ prev->next = cur->next;
+ else
+ fd_head = cur->next;
+ recache_fd(cur, 0);
+}
+
+static int io_poll(struct timeval *timeout) {
+ fd_set r, w, e;
+ int count = 0;
+ int remain = 0;
+ event_fd_t *cur = fd_head;
+ r = cache_r;
+ w = cache_w;
+ e = cache_e;
+ remain = select(fd_max, &r, &w, &e, timeout);
+ while (remain > 0 && cur) {
+ int mode = 0;
+ int fd = cur->fd;
+ if (FD_ISSET(fd, &r)) {
+ remain--;
+ mode |= EVENT_FD_READABLE;
+ }
+ if (FD_ISSET(fd, &w)) {
+ remain--;
+ mode |= EVENT_FD_WRITABLE;
+ }
+ if (FD_ISSET(fd, &e)) {
+ remain--;
+ mode |= EVENT_FD_ERROR;
+ }
+ if (mode & ~cur->mode)
+ recache_fd(cur, 1);
+ mode &= cur->mode;
+ if (mode) {
+ count++;
+ cur->cb(fd, mode, cur->baton);
+ }
+ cur = cur->next;
+ }
+ return count;
+}
+
+int event_poll(int block) {
+ int counter = 0;
+ struct timeval now;
+ const struct timeval *next;
+ struct timeval tv, *p_tv = NULL;
+ gettimeofday(&now, NULL);
+ counter += check_timers(&now, &next);
+ if (block && next) {
+ tv.tv_sec = next->tv_sec - now.tv_sec;
+ tv.tv_usec = next->tv_usec - now.tv_usec;
+ if (tv.tv_usec < 0) {
+ tv.tv_sec--;
+ tv.tv_usec += 1000000;
+ }
+ p_tv = &tv;
+ }
+ if (!block) {
+ tv.tv_sec = tv.tv_usec = 0;
+ p_tv = &tv;
+ }
+ counter += io_poll(p_tv);
+ gettimeofday(&now, NULL);
+ counter += check_timers(&now, NULL);
+ return counter;
+}
Property changes on: trunk/clients/ncurses/event.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/clients/ncurses/event.h
===================================================================
--- trunk/clients/ncurses/event.h 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/event.h 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,37 @@
+#ifndef EVENT_H
+#define EVENT_H 1
+
+#define EVENT_FD_READABLE 1
+#define EVENT_FD_WRITABLE 2
+#define EVENT_FD_ERROR 4
+
+typedef void event_fd_callback(int fd, int mode, void *baton);
+typedef void event_timer_callback(const struct timeval *when, void *baton);
+
+void event_init(void);
+void event_free(void);
+
+void event_timer_abs(
+ const struct timeval *when,
+ event_timer_callback *cb,
+ void *baton
+ );
+
+void event_timer_rel(
+ const struct timeval *when,
+ event_timer_callback *cb,
+ void *baton
+ );
+
+void event_addfd(
+ int fd,
+ int mode,
+ event_fd_callback *cb,
+ void *baton
+ );
+
+void event_delfd(int fd);
+
+int event_poll(int block);
+
+#endif
Property changes on: trunk/clients/ncurses/event.h
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/clients/ncurses/main.c
===================================================================
--- trunk/clients/ncurses/main.c 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/main.c 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,116 @@
+#include <ncurses.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "mymalloc.h"
+#include "entry.h"
+#include "display.h"
+/*#include "io.h"*/
+#include "event.h"
+
+void finish(int);
+void handle_input(int fd, int mode, void *baton);
+void heartbeat(const struct timeval *when, void *baton);
+
+int main(void) {
+ int i;
+ signal(SIGINT, finish); /* arrange interrupts to terminate */
+ initscr();
+ nonl();
+ cbreak();
+ noecho();
+ idlok(stdscr, TRUE);
+ keypad(stdscr, TRUE);
+
+ move(LINES - 2, 0);
+ for (i = 0; i < COLS; i++)
+ addch('-');
+ move(LINES - 1, 0);
+
+ entry_init();
+/* io_init();*/
+ event_init();
+ display_init(LINES - 2);
+
+ heartbeat(NULL, "Heartbeat 1");
+
+ refresh();
+
+ event_addfd(0, EVENT_FD_READABLE | EVENT_FD_ERROR, handle_input, NULL);
+
+ for (;;) {
+ int c = event_poll(1);
+ entry_refresh(stdscr, LINES - 1, COLS);
+ refresh();
+ }
+}
+
+void finish(int sig) {
+ endwin();
+ exit(0);
+}
+
+void handle_input(int fd, int mode, void *baton) {
+ int c;
+ size_t pos, len;
+
+ mode = mode & (EVENT_FD_READABLE | EVENT_FD_ERROR);
+ if (!mode)
+ return; /* We're willing to block on stdout. */
+
+ if (mode & EVENT_FD_ERROR) {
+ endwin();
+ exit(0);
+ }
+ pos = entry_get_pos();
+ len = entry_get_len();
+
+ switch (c = getch()) {
+ case KEY_UP:
+ break;
+ case KEY_DOWN:
+ break;
+ case KEY_BACKSPACE:
+ if (pos > 0)
+ entry_remove_ch(pos - 1);
+ entry_move_abs(pos - 1);
+ break;
+ case KEY_DC:
+ if (len && pos < len)
+ entry_remove_ch(pos);
+ entry_move_abs(pos);
+ break;
+ case KEY_ENTER:
+ case '\n':
+ case '\r':
+ display_print("%s\n",entry_get());
+ /* fallthru */
+ case KEY_DL:
+ entry_clear();
+ break;
+ case KEY_LEFT:
+ entry_move_rel(-1);
+ break;
+ case KEY_RIGHT:
+ entry_move_rel(1);
+ break;
+ default:
+ if (!isprint(c)) {
+ display_print("%d\n", (int)c);
+ break;
+ }
+ entry_insert_ch(pos, c);
+ entry_move_rel(1);
+ };
+}
+
+void heartbeat(const struct timeval *when, void *baton) {
+ const char *message = baton;
+ struct timeval next;
+ display_print("%s\n", message);
+ next.tv_sec = 1;
+ next.tv_usec = 0;
+ event_timer_rel(&next, heartbeat, baton);
+}
Property changes on: trunk/clients/ncurses/main.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/clients/ncurses/mymalloc.c
===================================================================
--- trunk/clients/ncurses/mymalloc.c 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/mymalloc.c 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+#include <ncurses.h>
+#include "mymalloc.h"
+
+void *mymalloc(size_t s) {
+ void *p = malloc(s);
+ if (!p) {
+ endwin();
+ abort();
+ }
+ return p;
+}
+
+void *myrealloc(void *oldp, size_t s) {
+ void *p = realloc(oldp, s);
+ if (!p) {
+ endwin();
+ abort();
+ }
+ return p;
+}
Property changes on: trunk/clients/ncurses/mymalloc.c
___________________________________________________________________
Name: svn:eol-style
+ native
Added: trunk/clients/ncurses/mymalloc.h
===================================================================
--- trunk/clients/ncurses/mymalloc.h 2004-12-15 04:35:17 UTC (rev 412)
+++ trunk/clients/ncurses/mymalloc.h 2004-12-15 20:08:55 UTC (rev 413)
@@ -0,0 +1,9 @@
+#ifndef MYMALLOC_H
+#define MYMALLOC_H 1
+
+#include <stdlib.h>
+
+void *mymalloc(size_t s);
+void *myrealloc(void *oldp, size_t s);
+
+#endif
Property changes on: trunk/clients/ncurses/mymalloc.h
___________________________________________________________________
Name: svn:eol-style
+ native