diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | Doc/Zsh/mod_curses.yo | 59 | ||||
-rw-r--r-- | Src/Modules/curses.c | 262 |
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 }; |