about summary refs log tree commit diff
path: root/Src/Modules/curses.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/curses.c')
-rw-r--r--Src/Modules/curses.c134
1 files changed, 118 insertions, 16 deletions
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c
index 0ea43f1c1..92d906aee 100644
--- a/Src/Modules/curses.c
+++ b/Src/Modules/curses.c
@@ -53,8 +53,10 @@
 #include <stdio.h>
 
 enum zc_win_flags {
+    /* Window is permanent (probably "stdscr") */
+    ZCWF_PERMANENT = 0x0001,
     /* Scrolling enabled */
-    ZCWF_SCROLL = 0x0001
+    ZCWF_SCROLL = 0x0002
 };
 
 typedef struct zc_win {
@@ -82,13 +84,12 @@ struct zcurses_subcommand {
     int maxargs;
 };
 
-static WINDOW *win_zero;
 static struct ttyinfo saved_tty_state;
 static struct ttyinfo curses_tty_state;
 static LinkList zcurses_windows;
 static HashTable zcurses_colorpairs = NULL;
 
-#define ZCURSES_ERANGE 1
+#define ZCURSES_EINVALID 1
 #define ZCURSES_EDEFINED 2
 #define ZCURSES_EUNDEFINED 3
 
@@ -151,11 +152,12 @@ zcurses_strerror(int err)
 {
     static const char *errs[] = {
 	"unknown error",
-	"window number out of range",
+	"window name invalid",
 	"window already defined",
+	"window undefined",
 	NULL };
 
-    return errs[(err < 1 || err > 2) ? 0 : err];
+    return errs[(err < 1 || err > 3) ? 0 : err];
 }
 
 static LinkNode
@@ -177,7 +179,7 @@ zcurses_validate_window(char *win, int criteria)
     LinkNode target;
 
     if (win==NULL || strlen(win) < 1) {
-	zc_errno = ZCURSES_ERANGE;
+	zc_errno = ZCURSES_EINVALID;
 	return NULL;
     }
 
@@ -200,7 +202,7 @@ zcurses_validate_window(char *win, int criteria)
 static int
 zcurses_free_window(ZCWin w)
 {
-    if (delwin(w->win)!=OK)
+    if (!(w->flags & ZCWF_PERMANENT) && delwin(w->win)!=OK)
 	return 1;
 
     if (w->name)
@@ -317,9 +319,23 @@ freecolorpairnode(HashNode hn)
 static int
 zccmd_init(const char *nam, char **args)
 {
-    if (!win_zero) {
+    LinkNode stdscr_win = zcurses_getwindowbyname("stdscr");
+
+    if (!stdscr_win) {
+	ZCWin w = (ZCWin)zshcalloc(sizeof(struct zc_win));
+	if (!w)
+	    return 1;
+
 	gettyinfo(&saved_tty_state);
-	win_zero = initscr();
+	w->name = ztrdup("stdscr");
+	w->win = initscr();
+	if (w->win == NULL) {
+	    zsfree(w->name);
+	    zfree(w, sizeof(struct zc_win));
+	    return 1;
+	}
+	w->flags = ZCWF_PERMANENT;
+	zinsertlinknode(zcurses_windows, lastnode(zcurses_windows), (void *)w);
 	if (start_color() != ERR) {
 	    if(!zc_color_phase)
 		zc_color_phase = 1;
@@ -410,6 +426,10 @@ zccmd_delwin(const char *nam, char **args)
 	zwarnnam(nam, "record for window `%s' is corrupt", args[0]);
 	return 1;
     }
+    if (w->flags & ZCWF_PERMANENT) {
+	zwarnnam(nam, "window `%s' can't be deleted", args[0]);
+	return 1;
+    }
     if (delwin(w->win)!=OK)
 	return 1;
 
@@ -421,6 +441,7 @@ zccmd_delwin(const char *nam, char **args)
     return 0;
 }
 
+
 static int
 zccmd_refresh(const char *nam, char **args)
 {
@@ -441,7 +462,7 @@ zccmd_refresh(const char *nam, char **args)
     }
     else
     {
-	return (refresh() != OK) ? 1 : 0;
+	return (wrefresh(curscr) != OK) ? 1 : 0;
     }
 }
 
@@ -472,6 +493,35 @@ zccmd_move(const char *nam, char **args)
 
 
 static int
+zccmd_clear(const char *nam, char **args)
+{
+    LinkNode node;
+    ZCWin w;
+
+    node = zcurses_validate_window(args[0], ZCURSES_USED);
+    if (node == NULL) {
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
+	return 1;
+    }
+
+    w = (ZCWin)getdata(node);
+
+    if (!args[1]) {
+	return werase(w->win) != OK;
+    } else if (!strcmp(args[1], "redraw")) {
+	return wclear(w->win) != OK;
+    } else if (!strcmp(args[1], "eol")) {
+	return wclrtoeol(w->win) != OK;
+    } else if (!strmp(args[1], "bot")) {
+	return wclrtobot(w->win) != OK;
+    } else {
+	zwarnnam(nam, "`clear' expects `redraw', `eol' or `bot'");
+	return 1;
+    }
+}
+
+
+static int
 zccmd_char(const char *nam, char **args)
 {
     LinkNode node;
@@ -574,7 +624,9 @@ zccmd_border(const char *nam, char **args)
 static int
 zccmd_endwin(const char *nam, char **args)
 {
-    if (win_zero) {
+    LinkNode stdscr_win = zcurses_getwindowbyname("stdscr");
+
+    if (stdscr_win) {
 	endwin();
 	/* Restore TTY as it was before zcurses -i */
 	settyinfo(&saved_tty_state);
@@ -727,6 +779,7 @@ zccmd_input(const char *nam, char **args)
 	break;
 
     case KEY_CODE_YES:
+	*instr = '\0';
 	keypadnum = (int)wi;
 	break;
 
@@ -736,8 +789,11 @@ zccmd_input(const char *nam, char **args)
     }
 #else
     ci = wgetch(w->win);
+    if (ci == ERR)
+	return 1;
     if (ci >= 256) {
 	keypadnum = ci;
+	*instr = '\0';
     } else {
 	if (imeta(ci)) {
 	    instr[0] = Meta;
@@ -753,16 +809,17 @@ zccmd_input(const char *nam, char **args)
 	var = args[1];
     else
 	var = "REPLY";
-    if (!setsparam(var, ztrdup(keypadnum > 0 ? "" : instr)))
+    if (!setsparam(var, ztrdup(instr)))
 	return 1;
-    if (args[2]) {
+    if (args[1] && args[2]) {
 	if (keypadnum > 0) {
 	    const struct zcurses_namenumberpair *nnptr;
 	    char fbuf[DIGBUFSIZE+1];
 
 	    for (nnptr = keypad_names; nnptr->name; nnptr++) {
 		if (keypadnum == nnptr->number) {
-		    setsparam(args[2], ztrdup(nnptr->name));
+		    if (!setsparam(args[2], ztrdup(nnptr->name)))
+			return 1;
 		    return 0;
 		}
 	    }
@@ -773,15 +830,51 @@ zccmd_input(const char *nam, char **args)
 		/* print raw number */
 		sprintf(fbuf, "%d", keypadnum);
 	    }
-	    setsparam(args[2], ztrdup(fbuf));
+	    if (!setsparam(args[2], ztrdup(fbuf)))
+		return 1;
 	} else {
-	    setsparam(args[2], ztrdup(""));
+	    if (!setsparam(args[2], ztrdup("")))
+		return 1;
 	}
     }
     return 0;
 }
 
 
+static int
+zccmd_position(const char *nam, char **args)
+{
+    LinkNode node;
+    ZCWin w;
+    int i, intarr[6];
+    char **array, dbuf[DIGBUFSIZE];
+
+    node = zcurses_validate_window(args[0], ZCURSES_USED);
+    if (node == NULL) {
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
+	return 1;
+    }
+
+    w = (ZCWin)getdata(node);
+
+    /* Look no pointers:  these are macros. */
+    if (getyx(w->win, intarr[0], intarr[1]) == ERR ||
+	getbegyx(w->win, intarr[2], intarr[3]) == ERR ||
+	getmaxyx(w->win, intarr[4], intarr[5]) == ERR)
+	return 1;
+
+    array = (char **)zalloc(7*sizeof(char *));
+    for (i = 0; i < 6; i++) {
+	sprintf(dbuf, "%d", intarr[i]);
+	array[i] = ztrdup(dbuf);
+    }
+    array[6] = NULL;
+
+    setaparam(args[1], array);
+    return 0;
+}
+
+
 /*********************
   Main builtin handler
  *********************/
@@ -800,6 +893,8 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
 	{"delwin", zccmd_delwin, 1, 1},
 	{"refresh", zccmd_refresh, 0, 1},
 	{"move", zccmd_move, 3, 3},
+	{"clear", zccmd_clear, 1, 2},
+	{"position", zccmd_position, 2, 2},
 	{"char", zccmd_char, 2, 2},
 	{"string", zccmd_string, 2, 2},
 	{"border", zccmd_border, 1, 1},
@@ -832,6 +927,13 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
 	return 1;
     }
 
+    if (zcsc->cmd != zccmd_init && zcsc->cmd != zccmd_endwin &&
+	!zcurses_getwindowbyname("stdscr")) {
+	zwarnnam(nam, "command `%s' can't be used before `zcurses init'",
+		 zcsc->name);
+	return 1;
+    }
+
     return zcsc->cmd(nam, args+1);
 }