summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Doc/Zsh/mod_curses.yo59
-rw-r--r--Src/Modules/curses.c262
3 files changed, 240 insertions, 88 deletions
diff --git a/ChangeLog b/ChangeLog
index 9f6e2d0c3..336cd89ff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2007-10-24  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 24017: Doc/Zsh/mod_curses.yo, Src/Modules/curses.c:
+	fold color support into attr subcommand and improve error
+	handling; add various readonly parameters; replace strtok();
+	tidy some zwarnnam().
+
 2007-10-24  Peter Stephenson  <pws@csr.com>
 
 	* 24016: configure.ac, Src/Modules/curses.c: compilation with
diff --git a/Doc/Zsh/mod_curses.yo b/Doc/Zsh/mod_curses.yo
index e85aa5c67..a7101f543 100644
--- a/Doc/Zsh/mod_curses.yo
+++ b/Doc/Zsh/mod_curses.yo
@@ -1,7 +1,10 @@
 COMMENT(!MOD!zsh/curses
 curses windowing commands
 !MOD!)
-The tt(zsh/curses) module makes available one builtin command:
+The tt(zsh/curses) module makes available one builtin command and
+various parameters.
+
+subsect(Builtin)
 
 startitem()
 findex(zcurses)
@@ -15,7 +18,7 @@ xitem(tt(zcurses) tt(move) var(targetwin) var(new_y) var(new_x) )
 xitem(tt(zcurses) tt(char) var(targetwin) var(character) )
 xitem(tt(zcurses) tt(string) var(targetwin) var(string) )
 xitem(tt(zcurses) tt(border) var(targetwin) var(border) )(
-item(tt(zcurses) tt(addwin) var(targetwin) var({+/-}attribute) [var({+/-}attribute)] [...])(
+item(tt(zcurses) tt(attr) var(targetwin) [ var({+/-}attribute) | var(fg_col)tt(/)var(bg_col) ] [...])(
 Manipulate curses windows.  All uses of this command should be
 bracketed by `tt(zcurses init)' to initialise use of curses, and
 `tt(zcurses end)' to end it; omitting `tt(zcurses end)' can cause
@@ -26,7 +29,8 @@ Its upper left corner will be placed at row var(begin_y) and column
 var(begin_x) of the screen.  var(targetwin) is a string and refers
 to the name of a window that is not currently assigned.
 
-Use tt(delwin) to delete a window created with tt(addwin).
+Use tt(delwin) to delete a window created with tt(addwin).  Note
+that tt(end) does em(not) implicitly delete windows.
 
 The tt(refresh) command will refresh window var(targetwin); this is necessary to
 make any pending changes (such as characters you have prepared for output
@@ -41,10 +45,49 @@ respectively.
 
 To draw a border around window var(targetwin), use tt(border).
 
-tt(addwin) will set var(targetwin)'s attributes for any successive character
-output.  Each var(attribute) given on the line should be prepended by a
-tt(+) to set or a tt(-) to unset that attribute.  The attributes supported
-are tt(blink), tt(bold), tt(dim), tt(reverse), tt(standout), and
-tt(underline).
+tt(attr) will set var(targetwin)'s attributes or foreground/background
+color pair for any successive character output.  Each var(attribute)
+given on the line may be prepended by a tt(+) to set or a tt(-) to
+unset that attribute; tt(+) is assumed if absent.  The attributes
+supported are tt(blink), tt(bold), tt(dim), tt(reverse), tt(standout),
+and tt(underline).  Each var(fg_col)tt(/)var(bg_col) (to be read as
+`var(fg_col) on var(bg_col)') sets the foreground and background color
+for character output.
+)
+enditem()
+
+subsect(Parameters)
+
+startitem()
+vindex(ZCURSES_COLORS)
+item(tt(ZCURSES_COLORS))(
+Readonly integer.  The maximum number of colors the terminal
+supports.  This value is initialised by the curses library and is not
+available until the first time tt(zcurses init) is run.
+)
+vindex(ZCURSES_COLOR_PAIRS)
+item(tt(ZCURSES_COLOR_PAIRS))(
+Readonly integer.  The maximum number of color pairs
+var(fg_col)tt(/)var(bg_col) that may be defined in `tt(zcurses attr)'
+commands; note this limit applies to all color pairs that have been
+used whether or not they are currently active.  This value is initialised
+by the curses library and is not available until the first time tt(zcurses
+init) is run.
+)
+vindex(zcurses_attrs)
+item(tt(zcurses_attrs))(
+Readonly array.  The attributes supported by tt(zsh/curses); available
+as soon as the module is loaded.
+)
+vindex(zcurses_colors)
+item(tt(zcurses_colors))(
+Readonly array.  The colors supported by tt(zsh/curses); available
+as soon as the module is loaded.
+)
+vindex(zcurses_windows)
+item(tt(zcurses_windows))(
+Readonly array.  The current list of windows, i.e. all windows that
+have been created with `tt(zcurses addwin)' and not removed with
+`tt(zcurses delwin)'.
 )
 enditem()
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c
index dd38b5e95..de9173b9e 100644
--- a/Src/Modules/curses.c
+++ b/Src/Modules/curses.c
@@ -94,6 +94,48 @@ static HashTable zcurses_colorpairs = NULL;
 static int zc_errno, zc_color_phase=0;
 static short next_cp=0;
 
+static const struct zcurses_namenumberpair zcurses_attributes[] = {
+    {"blink", A_BLINK},
+    {"bold", A_BOLD},
+    {"dim", A_DIM},
+    {"reverse", A_REVERSE},
+    {"standout", A_STANDOUT},
+    {"underline", A_UNDERLINE},
+    {NULL, 0}
+};
+
+static const struct zcurses_namenumberpair zcurses_colors[] = {
+    {"black", COLOR_BLACK},
+    {"red", COLOR_RED},
+    {"green", COLOR_GREEN},
+    {"yellow", COLOR_YELLOW},
+    {"blue", COLOR_BLUE},
+    {"magenta", COLOR_MAGENTA},
+    {"cyan", COLOR_CYAN},
+    {"white", COLOR_WHITE},
+    {NULL, 0}
+};
+
+static char **
+zcurses_pairs_to_array(const struct zcurses_namenumberpair *nnps)
+{
+    char **arr, **arrptr;
+    int count;
+    const struct zcurses_namenumberpair *nnptr;
+
+    for (nnptr = nnps; nnptr->name; nnptr++)
+	;
+    count = nnptr - nnps;
+
+    arrptr = arr = (char **)zhalloc((count+1) * sizeof(char *));
+
+    for (nnptr = nnps; nnptr->name; nnptr++)
+	*arrptr++ = dupstring(nnptr->name);
+    *arrptr = NULL;
+
+    return arr;
+}
+
 static const char *
 zcurses_strerror(int err)
 {
@@ -164,16 +206,6 @@ zcurses_attribute(WINDOW *w, char *attr, int op)
 {
     struct zcurses_namenumberpair *zca;
 
-    static const struct zcurses_namenumberpair zcurses_attributes[] = {
-	{"blink", A_BLINK},
-	{"bold", A_BOLD},
-	{"dim", A_DIM},
-	{"reverse", A_REVERSE},
-	{"standout", A_STANDOUT},
-	{"underline", A_UNDERLINE},
-	{NULL, 0}
-    };
-
     if (!attr)
 	return 1;
 
@@ -199,18 +231,6 @@ zcurses_color(const char *color)
 {
     struct zcurses_namenumberpair *zc;
 
-    static const struct zcurses_namenumberpair zcurses_colors[] = {
-	{"black", COLOR_BLACK},
-	{"red", COLOR_RED},
-	{"green", COLOR_GREEN},
-	{"yellow", COLOR_YELLOW},
-	{"blue", COLOR_BLUE},
-	{"magenta", COLOR_MAGENTA},
-	{"cyan", COLOR_CYAN},
-	{"white", COLOR_WHITE},
-	{NULL, 0}
-    };
-
     for(zc=(struct zcurses_namenumberpair *)zcurses_colors;zc->name;zc++)
 	if (!strcmp(color, zc->name)) {
 	    return (short)zc->number;
@@ -220,9 +240,9 @@ zcurses_color(const char *color)
 }
 
 static int
-zcurses_colorset(WINDOW *w, char *colorpair)
+zcurses_colorset(const char *nam, WINDOW *w, char *colorpair)
 {
-    char *fg, *bg, *cp;
+    char *bg, *cp;
     short f, b;
     Colorpairnode cpn;
 
@@ -230,36 +250,43 @@ zcurses_colorset(WINDOW *w, char *colorpair)
 	!(cpn = (Colorpairnode) gethashnode(zcurses_colorpairs, colorpair))) {
 	zc_color_phase = 2;
 	cp = ztrdup(colorpair);
-	fg = strtok(cp, "/");
-	bg = strtok(NULL, "/");
 
+	bg = strchr(cp, '/');
 	if (bg==NULL) {
 	    zsfree(cp);
 	    return 1;
 	}
-        
-	f = zcurses_color(fg);
-	b = zcurses_color(bg);
 
-	zsfree(cp);
+	*bg = '\0';        
+	f = zcurses_color(cp);
+	b = zcurses_color(bg+1);
 
-	if (f==-1 || b==-1)
+	if (f==-1 || b==-1) {
+	    if (f == -1)
+		zwarnnam(nam, "foreground color `%s' not known", cp);
+	    if (b == -1)
+		zwarnnam(nam, "background color `%s' not known", bg+1);
+	    *bg = '/';
+	    zsfree(cp);
 	    return 1;
+	}
+	*bg = '/';
 
 	++next_cp;
-	if (next_cp >= COLOR_PAIRS)
-	    return 1;
-
-	if (init_pair(next_cp, f, b) == ERR)
+	if (next_cp >= COLOR_PAIRS || init_pair(next_cp, f, b) == ERR)  {
+	    zsfree(cp);
 	    return 1;
+	}
 
 	cpn = (Colorpairnode)zalloc(sizeof(struct colorpairnode));
 	
-	if (!cpn)
+	if (!cpn) {
+	    zsfree(cp);
 	    return 1;
+	}
 
 	cpn->colorpair = next_cp;
-	addhashnode(zcurses_colorpairs, ztrdup(colorpair), (void *)cpn);
+	addhashnode(zcurses_colorpairs, cp, (void *)cpn);
     }
 
     return (wcolor_set(w, cpn->colorpair, NULL) == ERR);
@@ -353,14 +380,14 @@ zccmd_delwin(const char *nam, char **args)
 
     node = zcurses_validate_window(args[0], ZCURSES_USED);
     if (node == NULL) {
-	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0], 0);
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
 	return 1;
     }
 
     w = (ZCWin)getdata(node);
 
     if (w == NULL) {
-	zwarnnam(nam, "record for window `%s' is corrupt", args[0], 0);
+	zwarnnam(nam, "record for window `%s' is corrupt", args[0]);
 	return 1;
     }
     if (delwin(w->win)!=OK)
@@ -408,7 +435,7 @@ zccmd_move(const char *nam, char **args)
 
     node = zcurses_validate_window(args[0], ZCURSES_USED);
     if (node == NULL) {
-	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0], 0);
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
 	return 1;
     }
 
@@ -436,7 +463,7 @@ zccmd_char(const char *nam, char **args)
 
     node = zcurses_validate_window(args[0], ZCURSES_USED);
     if (node == NULL) {
-	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0], 0);
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
 	return 1;
     }
 
@@ -475,7 +502,7 @@ zccmd_string(const char *nam, char **args)
 
     node = zcurses_validate_window(args[0], ZCURSES_USED);
     if (node == NULL) {
-	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0], 0);
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
 	return 1;
     }
 
@@ -511,7 +538,7 @@ zccmd_border(const char *nam, char **args)
 
     node = zcurses_validate_window(args[0], ZCURSES_USED);
     if (node == NULL) {
-	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0], 0);
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
 	return 1;
     }
 
@@ -555,52 +582,44 @@ zccmd_attr(const char *nam, char **args)
 
     node = zcurses_validate_window(args[0], ZCURSES_USED);
     if (node == NULL) {
-	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0], 0);
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
 	return 1;
     }
 
     w = (ZCWin)getdata(node);
 
     for(attrs = args+1; *attrs; attrs++) {
-	switch(*attrs[0]) {
-	case '-':
-	    if (zcurses_attribute(w->win, (*attrs)+1, ZCURSES_ATTROFF))
+	if (strchr(*attrs, '/')) {
+	    if (zcurses_colorset(nam, w->win, *attrs))
 		ret = 1;
-	    break;
-	case '+':
-	    if (zcurses_attribute(w->win, (*attrs)+1, ZCURSES_ATTRON))
+	} else {
+	    char *ptr;
+	    int onoff;
+
+	    switch(*attrs[0]) {
+	    case '-':
+		onoff = ZCURSES_ATTROFF;
+		ptr = (*attrs) + 1;
+		break;
+	    case '+':
+		onoff = ZCURSES_ATTRON;
+		ptr = (*attrs) + 1;
+		break;
+	    default:
+		onoff = ZCURSES_ATTRON;
+		ptr = *attrs;
+		break;
+	    }
+	    if (zcurses_attribute(w->win, ptr, onoff)) {
+		zwarnnam(nam, "attribute `%s' not known", ptr);
 		ret = 1;
-	    break;
-	default:
-	    /* maybe a bad idea to spew warnings here */
-	    break;
+	    }
 	}
     }
     return ret;
 }
 
 
-static int
-zccmd_color(const char *nam, char **args)
-{
-    LinkNode node;
-    ZCWin w;
-
-    if (!args[0] || !args[1] || !zc_color_phase)
-	return 1;
-
-    node = zcurses_validate_window(args[0], ZCURSES_USED);
-    if (node == NULL) {
-	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0], 0);
-	return 1;
-    }
-
-    w = (ZCWin)getdata(node);
-
-    return zcurses_colorset(w->win, args[1]);
-}
-
-
 /*********************
   Main builtin handler
  *********************/
@@ -624,7 +643,6 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
 	{"border", zccmd_border, 1, 1},
 	{"end", zccmd_endwin, 0, 0},
 	{"attr", zccmd_attr, 2, -1},
-	{"color", zccmd_color, 2, 2},
 	{NULL, (zccmd_t)0, 0, 0}
     };
 
@@ -653,19 +671,103 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
     return zcsc->cmd(nam, args+1);
 }
 
-/*
- * boot_ is executed when the module is loaded.
- */
 
 static struct builtin bintab[] = {
     BUILTIN("zcurses", 0, bin_zcurses, 1, 6, 0, "", NULL),
 };
 
+
+/*******************
+ * Special variables
+ *******************/
+
+static char **
+zcurses_colorsarrgetfn(UNUSED(Param pm))
+{
+    return zcurses_pairs_to_array(zcurses_colors);
+}
+
+static const struct gsu_array zcurses_colorsarr_gsu =
+{ zcurses_colorsarrgetfn, arrsetfn, stdunsetfn };
+
+
+static char **
+zcurses_attrgetfn(UNUSED(Param pm))
+{
+    return zcurses_pairs_to_array(zcurses_attributes);
+}
+
+static const struct gsu_array zcurses_attrs_gsu =
+{ zcurses_attrgetfn, arrsetfn, stdunsetfn };
+
+
+static char **
+zcurses_windowsgetfn(UNUSED(Param pm))
+{
+    LinkNode node;
+    char **arr, **arrptr;
+    int count = countlinknodes(zcurses_windows);
+
+    arrptr = arr = (char **)zhalloc((count+1) * sizeof(char *));
+
+    for (node = firstnode(zcurses_windows); node; incnode(node))
+	*arrptr++ = dupstring(((ZCWin)getdata(node))->name);
+    *arrptr = NULL;
+
+    return arr;
+}
+
+static const struct gsu_array zcurses_windows_gsu =
+{ zcurses_windowsgetfn, arrsetfn, stdunsetfn };
+
+
+static zlong
+zcurses_colorsintgetfn(UNUSED(Param pm))
+{
+    return COLORS;
+}
+
+static const struct gsu_integer zcurses_colorsint_gsu =
+{ zcurses_colorsintgetfn, nullintsetfn, stdunsetfn };
+
+
+static zlong
+zcurses_colorpairsintgetfn(UNUSED(Param pm))
+{
+    return COLOR_PAIRS;
+}
+
+static const struct gsu_integer zcurses_colorpairsint_gsu =
+{ zcurses_colorpairsintgetfn, nullintsetfn, stdunsetfn };
+
+
+static struct paramdef partab[] = {
+    SPECIALPMDEF("zcurses_colors", PM_ARRAY|PM_READONLY,
+		 &zcurses_colorsarr_gsu, NULL, NULL),
+    SPECIALPMDEF("zcurses_attrs", PM_ARRAY|PM_READONLY,
+		 &zcurses_attrs_gsu, NULL, NULL),
+    SPECIALPMDEF("zcurses_windows", PM_ARRAY|PM_READONLY,
+		 &zcurses_windows_gsu, NULL, NULL),
+    SPECIALPMDEF("ZCURSES_COLORS", PM_INTEGER|PM_READONLY,
+		 &zcurses_colorsint_gsu, NULL, NULL),
+    SPECIALPMDEF("ZCURSES_COLOR_PAIRS", PM_INTEGER|PM_READONLY,
+		 &zcurses_colorpairsint_gsu, NULL, NULL)
+};
+
+/***************************
+ * Standard module interface
+ ***************************/
+
+
+/*
+ * boot_ is executed when the module is loaded.
+ */
+
 static struct features module_features = {
     bintab, sizeof(bintab)/sizeof(*bintab),
     NULL, 0,
     NULL, 0,
-    NULL, 0,
+    partab, sizeof(partab)/sizeof(*partab),
     0
 };