Home | History | Annotate | Line # | Download | only in libcurses
slk.c revision 1.13
      1  1.13  christos /*	$NetBSD: slk.c,v 1.13 2021/08/15 11:54:12 christos Exp $	*/
      2   1.1       roy 
      3   1.1       roy /*-
      4   1.1       roy  * Copyright (c) 2017 The NetBSD Foundation, Inc.
      5   1.1       roy  * All rights reserved.
      6   1.1       roy  *
      7   1.1       roy  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1       roy  * by Roy Marples.
      9   1.1       roy  *
     10   1.1       roy  * Redistribution and use in source and binary forms, with or without
     11   1.1       roy  * modification, are permitted provided that the following conditions
     12   1.1       roy  * are met:
     13   1.1       roy  * 1. Redistributions of source code must retain the above copyright
     14   1.1       roy  *    notice, this list of conditions and the following disclaimer.
     15   1.1       roy  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1       roy  *    notice, this list of conditions and the following disclaimer in the
     17   1.1       roy  *    documentation and/or other materials provided with the distribution.
     18   1.1       roy  *
     19   1.1       roy  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1       roy  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1       roy  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1       roy  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1       roy  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1       roy  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1       roy  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1       roy  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1       roy  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1       roy  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1       roy  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1       roy  */
     31   1.1       roy 
     32   1.1       roy #include <sys/cdefs.h>
     33   1.1       roy #ifndef lint
     34  1.13  christos __RCSID("$NetBSD: slk.c,v 1.13 2021/08/15 11:54:12 christos Exp $");
     35   1.1       roy #endif				/* not lint */
     36   1.1       roy 
     37   1.1       roy #include <ctype.h>
     38   1.1       roy #include <stdlib.h>
     39   1.1       roy #include <string.h>
     40  1.13  christos #include <limits.h>
     41   1.1       roy #ifdef HAVE_WCHAR
     42   1.1       roy #include <wctype.h>
     43   1.1       roy #endif
     44   1.1       roy 
     45   1.1       roy #include "curses.h"
     46   1.1       roy #include "curses_private.h"
     47   1.1       roy 
     48   1.1       roy /* Terminals with real soft labels have NOT been tested.
     49   1.1       roy  * If you have such a device, please let us know so this comment
     50   1.1       roy  * can be adjusted. */
     51   1.1       roy 
     52   1.1       roy /* POSIX says that each label can be up to 8 columns.
     53   1.1       roy  * However, our implementation can allow labels to expand beyond that. */
     54   1.1       roy //#define	SLK_SIZE_DYNAMIC
     55   1.1       roy #ifdef SLK_SIZE_DYNAMIC
     56   1.1       roy #define	SLK_SIZE	MAX_SLK_LABEL
     57   1.1       roy #else
     58   1.1       roy #define	SLK_SIZE	MAX_SLK_COLS
     59   1.1       roy #endif
     60   1.1       roy 
     61   1.3       roy static int	 slk_fmt = SLK_FMT_INVAL;	/* fmt of slk_init */
     62   1.1       roy 
     63   1.1       roy /* Safe variants of public functions. */
     64   1.6       uwe static int	 __slk_attroff(SCREEN *, const chtype);
     65   1.6       uwe static int	 __slk_attron(SCREEN *, const chtype);
     66   1.6       uwe static int	 __slk_attrset(SCREEN *, const chtype);
     67   1.5       uwe #ifdef HAVE_WCHAR
     68   1.5       uwe static int	 __slk_attr_off(SCREEN *, const attr_t, void *);
     69   1.1       roy static int	 __slk_attr_on(SCREEN *, const attr_t, void *);
     70   1.5       uwe static int	 __slk_attr_set(SCREEN *, const attr_t, short, void *opt);
     71   1.6       uwe static int	 __slk_color(SCREEN *, short);
     72   1.5       uwe #endif
     73   1.5       uwe 
     74   1.1       roy static int	 __slk_clear(SCREEN *);
     75   1.1       roy static char	*__slk_label(SCREEN *, int);
     76   1.1       roy static int	 __slk_restore(SCREEN *);
     77   1.1       roy static int	 __slk_set(SCREEN *, int, const char *, int);
     78   1.1       roy static int	 __slk_touch(SCREEN *);
     79   1.5       uwe #ifdef HAVE_WCHAR
     80   1.1       roy static int	 __slk_wset(SCREEN *, int, const wchar_t *, int);
     81   1.5       uwe #endif
     82   1.1       roy 
     83   1.1       roy /* Internal engine parts. */
     84   1.1       roy static int	 __slk_ripoffline(WINDOW *, int);
     85   1.1       roy static int	 __slk_set_finalise(SCREEN *, int);
     86   1.1       roy static int	 __slk_draw(SCREEN *, int);
     87   1.1       roy static int	 __slk_redraw(SCREEN *);
     88   1.1       roy 
     89   1.1       roy /*
     90   1.1       roy  * slk_init --
     91   1.1       roy  *	Init Soft Label Keys.
     92   1.1       roy  */
     93   1.1       roy int
     94   1.1       roy slk_init(int fmt)
     95   1.1       roy {
     96   1.1       roy 
     97   1.1       roy 	switch(fmt) {
     98   1.1       roy 	case SLK_FMT_3_2_3:
     99   1.1       roy 	case SLK_FMT_4_4:
    100   1.1       roy 		break;
    101   1.1       roy 	default:
    102   1.1       roy 		return ERR;
    103   1.1       roy 	}
    104   1.1       roy 
    105   1.1       roy 	slk_fmt = fmt;
    106   1.1       roy 	/* Even if the terminal supports soft label keys directly,
    107   1.1       roy 	 * we need to reserve a line. */
    108   1.1       roy 	return ripoffline(-1, __slk_ripoffline);
    109   1.1       roy }
    110   1.1       roy 
    111   1.1       roy /*
    112   1.1       roy  * slk_attron --
    113   1.1       roy  *	Test and set attributes on ripped off slk window.
    114   1.1       roy  */
    115   1.1       roy int
    116   1.1       roy slk_attron(const chtype attr)
    117   1.1       roy {
    118   1.1       roy 
    119   1.1       roy 	return __slk_attron(_cursesi_screen, attr);
    120   1.1       roy }
    121   1.1       roy 
    122   1.5       uwe #ifdef HAVE_WCHAR
    123   1.1       roy /*
    124   1.1       roy  * slk_attr_on --
    125   1.1       roy  *	Test and set wide attributes on ripped off slk window.
    126   1.1       roy  */
    127   1.1       roy int
    128   1.1       roy slk_attr_on(const attr_t attr, void *opt)
    129   1.1       roy {
    130   1.1       roy 
    131   1.1       roy 	return __slk_attr_on(_cursesi_screen, attr, opt);
    132   1.1       roy }
    133   1.5       uwe #endif	/* HAVE_WCHAR */
    134   1.1       roy 
    135   1.1       roy /*
    136   1.1       roy  * slk_attroff --
    137   1.1       roy  *	Test and unset attributes on ripped off slk window.
    138   1.1       roy  */
    139   1.1       roy int
    140   1.1       roy slk_attroff(const chtype attr)
    141   1.1       roy {
    142   1.1       roy 
    143   1.1       roy 	return __slk_attroff(_cursesi_screen, attr);
    144   1.1       roy }
    145   1.1       roy 
    146   1.5       uwe #ifdef HAVE_WCHAR
    147   1.1       roy /*
    148   1.1       roy  * slk_attr_off --
    149   1.1       roy  *	Test and unset wide attributes on ripped off slk window.
    150   1.1       roy  */
    151   1.1       roy int
    152   1.1       roy slk_attr_off(const attr_t attr, void *opt)
    153   1.1       roy {
    154   1.1       roy 
    155   1.1       roy 	return __slk_attr_off(_cursesi_screen, attr, opt);
    156   1.1       roy }
    157   1.5       uwe #endif	/* HAVE_WCHAR */
    158   1.1       roy 
    159   1.1       roy /*
    160   1.1       roy  * slk_attrset --
    161   1.1       roy  *	Set attributes and color pair on ripped off slk window.
    162   1.1       roy  */
    163   1.1       roy int
    164   1.1       roy slk_attrset(const chtype attr)
    165   1.1       roy {
    166   1.1       roy 
    167   1.1       roy 	return __slk_attrset(_cursesi_screen, attr);
    168   1.1       roy }
    169   1.1       roy 
    170   1.5       uwe #ifdef HAVE_WCHAR
    171   1.1       roy /*
    172   1.1       roy  * slk_attr_set --
    173   1.1       roy  *	Set wide attributes and color pair on ripped off slk window.
    174   1.1       roy  */
    175   1.1       roy int
    176   1.1       roy slk_attr_set(const attr_t attr, short pair, void *opt)
    177   1.1       roy {
    178   1.1       roy 
    179   1.1       roy 	return __slk_attr_set(_cursesi_screen, attr, pair, opt);
    180   1.1       roy }
    181   1.5       uwe #endif	/* HAVE_WCHAR */
    182   1.1       roy 
    183   1.1       roy /*
    184   1.1       roy  * slk_clear --
    185   1.1       roy  *	Clear slk from the current screen.
    186   1.1       roy  */
    187   1.1       roy int
    188   1.1       roy slk_clear(void)
    189   1.1       roy {
    190   1.1       roy 
    191   1.1       roy 	return __slk_clear(_cursesi_screen);
    192   1.1       roy }
    193   1.1       roy 
    194   1.6       uwe #ifdef HAVE_WCHAR
    195   1.1       roy /*
    196   1.1       roy  * slk_color --
    197   1.1       roy  *	Set color pair on ripped off slk window.
    198   1.1       roy  */
    199   1.1       roy int
    200   1.1       roy slk_color(short pair)
    201   1.1       roy {
    202   1.1       roy 
    203   1.1       roy 	return __slk_color(_cursesi_screen, pair);
    204   1.1       roy }
    205   1.6       uwe #endif	/* HAVE_WCHAR */
    206   1.1       roy 
    207   1.1       roy /*
    208   1.1       roy  * slk_label --
    209   1.1       roy  *	Return a pointer to the saved label for key labnum.
    210   1.1       roy  */
    211   1.1       roy char *
    212   1.1       roy slk_label(int labnum)
    213   1.1       roy {
    214   1.1       roy 
    215   1.1       roy 	return __slk_label(_cursesi_screen, labnum);
    216   1.1       roy }
    217   1.1       roy 
    218   1.1       roy /*
    219   1.1       roy  * slk_wnoutrefresh --
    220   1.1       roy  *	Add the contents of the ripped off slk window to the virtual window.
    221   1.1       roy  */
    222   1.1       roy int
    223   1.1       roy slk_noutrefresh(void)
    224   1.1       roy {
    225   1.1       roy 
    226   1.1       roy 	return __slk_noutrefresh(_cursesi_screen);
    227   1.1       roy }
    228   1.1       roy 
    229   1.1       roy /*
    230   1.1       roy  * slk_refresh --
    231   1.1       roy  *	Force a refresh for the ripped off slk window.
    232   1.1       roy  */
    233   1.1       roy int
    234   1.1       roy slk_refresh(void)
    235   1.1       roy {
    236   1.1       roy 
    237   1.1       roy 	if (slk_noutrefresh() == ERR)
    238   1.1       roy 		return ERR;
    239   1.1       roy 	return doupdate();
    240   1.1       roy }
    241   1.1       roy 
    242   1.1       roy /*
    243   1.1       roy  * slk_restore --
    244   1.1       roy  *	Retore slk to the screen after a slk_clear.
    245   1.1       roy  */
    246   1.1       roy int
    247   1.1       roy slk_restore(void)
    248   1.1       roy {
    249   1.1       roy 
    250   1.1       roy 	return __slk_restore(_cursesi_screen);
    251   1.1       roy }
    252   1.1       roy 
    253   1.1       roy /*
    254   1.1       roy  * slk_set --
    255   1.1       roy  *	Sets the text of the label specified by labnum
    256   1.1       roy  *	and how it is displayed.
    257   1.1       roy  */
    258   1.1       roy int
    259   1.1       roy slk_set(int labnum, const char *label, int justify)
    260   1.1       roy {
    261   1.1       roy 
    262   1.1       roy 	return __slk_set(_cursesi_screen, labnum, label, justify);
    263   1.1       roy }
    264   1.1       roy 
    265   1.1       roy /*
    266   1.1       roy  * slk_touch --
    267   1.1       roy  *	Sets the ripped off slk window as modified.
    268   1.1       roy  */
    269   1.1       roy int
    270   1.1       roy slk_touch(void)
    271   1.1       roy {
    272   1.1       roy 
    273   1.1       roy 	return __slk_touch(_cursesi_screen);
    274   1.1       roy }
    275   1.1       roy 
    276   1.5       uwe #ifdef HAVE_WCHAR
    277   1.1       roy /*
    278   1.1       roy  * slk_wset --
    279   1.1       roy  *	Sets the wide text of the label specified by labnum
    280   1.1       roy  *	and how it is displayed.
    281   1.1       roy  */
    282   1.1       roy int
    283   1.1       roy slk_wset(int labnum, const wchar_t *label, int justify)
    284   1.1       roy {
    285   1.1       roy 
    286   1.1       roy 	return __slk_wset(_cursesi_screen, labnum, label, justify);
    287   1.1       roy }
    288   1.5       uwe #endif	/* HAVE_WCHAR */
    289   1.1       roy 
    290   1.1       roy /*
    291   1.1       roy  * __slk_attron --
    292   1.1       roy  *	Test and set attributes on ripped off slk window.
    293   1.1       roy  */
    294   1.1       roy static int
    295   1.1       roy __slk_attron(SCREEN *screen, const chtype attr)
    296   1.1       roy {
    297   1.1       roy 
    298   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    299   1.1       roy 		return ERR;
    300   1.1       roy 	return wattron(screen->slk_window, attr);
    301   1.1       roy }
    302   1.1       roy 
    303   1.5       uwe #ifdef HAVE_WCHAR
    304   1.1       roy /*
    305   1.1       roy  * __slk_attr_on --
    306   1.1       roy  *	Test and set wide attributes on ripped off slk window.
    307   1.1       roy  */
    308   1.1       roy static int
    309   1.1       roy __slk_attr_on(SCREEN *screen, const attr_t attr, void *opt)
    310   1.1       roy {
    311   1.1       roy 
    312   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    313   1.1       roy 		return ERR;
    314   1.1       roy 	return wattr_on(screen->slk_window, attr, opt);
    315   1.1       roy }
    316   1.5       uwe #endif	/* HAVE_WCHAR */
    317   1.1       roy 
    318   1.1       roy /*
    319   1.1       roy  * __slk_attroff --
    320   1.1       roy  *	Test and unset attributes on ripped off slk window.
    321   1.1       roy  */
    322   1.1       roy static int
    323   1.1       roy __slk_attroff(SCREEN *screen, const chtype attr)
    324   1.1       roy {
    325   1.1       roy 
    326   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    327   1.1       roy 		return ERR;
    328   1.1       roy 	return wattroff(screen->slk_window, attr);
    329   1.1       roy }
    330   1.1       roy 
    331   1.5       uwe #ifdef HAVE_WCHAR
    332   1.1       roy /*
    333   1.1       roy  * __slk_attr_off --
    334   1.1       roy  *	Test and unset wide attributes on ripped off slk window.
    335   1.1       roy  */
    336   1.1       roy static int
    337   1.1       roy __slk_attr_off(SCREEN *screen, const attr_t attr, void *opt)
    338   1.1       roy {
    339   1.1       roy 
    340   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    341   1.1       roy 		return ERR;
    342   1.1       roy 	return wattr_off(screen->slk_window, attr, opt);
    343   1.1       roy }
    344   1.5       uwe #endif	/* HAVE_WCHAR */
    345   1.1       roy 
    346   1.1       roy /*
    347   1.1       roy  * __slk_attrset --
    348   1.1       roy  *	Set attributes and color pair on ripped off slk window.
    349   1.1       roy  */
    350   1.1       roy static int
    351   1.1       roy __slk_attrset(SCREEN *screen, const chtype attr)
    352   1.1       roy {
    353   1.1       roy 
    354   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    355   1.1       roy 		return ERR;
    356   1.1       roy 	return wattrset(screen->slk_window, attr);
    357   1.1       roy }
    358   1.1       roy 
    359   1.5       uwe #ifdef HAVE_WCHAR
    360   1.1       roy /*
    361   1.1       roy  * __slk_attr_set --
    362   1.1       roy  *	Set wide attributes and color pair on ripped off slk window.
    363   1.1       roy  */
    364   1.1       roy static int
    365   1.1       roy __slk_attr_set(SCREEN *screen, const attr_t attr, short pair, void *opt)
    366   1.1       roy {
    367   1.1       roy 
    368   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    369   1.1       roy 		return ERR;
    370   1.1       roy 	return wattr_set(screen->slk_window, attr, pair, opt);
    371   1.1       roy }
    372   1.5       uwe #endif	/* HAVE_WCHAR */
    373   1.1       roy 
    374   1.1       roy /*
    375   1.1       roy  * __slk_clear --
    376   1.1       roy  *	Clear slk from the current screen.
    377   1.1       roy  */
    378   1.1       roy static int
    379   1.1       roy __slk_clear(SCREEN *screen)
    380   1.1       roy {
    381   1.1       roy 
    382   1.2       roy 	if (screen == NULL)
    383   1.2       roy 		return ERR;
    384   1.1       roy 	screen->slk_hidden = true;
    385   1.1       roy 	if (screen->is_term_slk) {
    386   1.1       roy 		if (t_label_off(screen->term) == NULL)
    387   1.1       roy 			return ERR;
    388   1.1       roy 		return ti_putp(screen->term,
    389   1.1       roy 		    ti_tiparm(screen->term, t_label_off(screen->term)));
    390   1.1       roy 	}
    391   1.1       roy 	if (screen->slk_window == NULL)
    392   1.1       roy 		return ERR;
    393   1.1       roy 	werase(screen->slk_window);
    394   1.1       roy 	return wrefresh(screen->slk_window);
    395   1.1       roy }
    396   1.1       roy 
    397   1.6       uwe #ifdef HAVE_WCHAR
    398   1.1       roy /*
    399   1.1       roy  * __slk_color --
    400   1.1       roy  *	Set color pair on ripped off slk window.
    401   1.1       roy  */
    402   1.1       roy static int
    403   1.1       roy __slk_color(SCREEN *screen, short pair)
    404   1.1       roy {
    405   1.1       roy 
    406   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    407   1.1       roy 		return ERR;
    408   1.1       roy 	return wcolor_set(screen->slk_window, pair, NULL);
    409   1.1       roy }
    410   1.6       uwe #endif	/* HAVE_WCHAR */
    411   1.1       roy 
    412   1.1       roy /*
    413   1.1       roy  * __slk_label --
    414   1.1       roy  *	Return a pointer to the saved label for key labnum.
    415   1.1       roy  */
    416   1.1       roy static char *
    417   1.1       roy __slk_label(SCREEN *screen, int labnum)
    418   1.1       roy {
    419   1.1       roy 
    420   1.2       roy 	if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels)
    421   1.1       roy 		return NULL;
    422   1.1       roy 	return screen->slk_labels[--labnum].text;
    423   1.1       roy }
    424   1.1       roy 
    425   1.1       roy /*
    426   1.1       roy  * __slk_wnoutrefresh --
    427   1.1       roy  *	Add the contents of the ripped off slk window to the virtual window.
    428   1.1       roy  */
    429   1.1       roy int
    430   1.1       roy __slk_noutrefresh(SCREEN *screen)
    431   1.1       roy {
    432   1.1       roy 
    433   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    434   1.1       roy 		return ERR;
    435   1.1       roy 	return wnoutrefresh(screen->slk_window);
    436   1.1       roy }
    437   1.1       roy 
    438   1.1       roy /*
    439   1.1       roy  * __slk_restore --
    440   1.1       roy  *	Retore slk to the screen after a slk_clear.
    441   1.1       roy  */
    442   1.1       roy static int
    443   1.1       roy __slk_restore(SCREEN *screen)
    444   1.1       roy {
    445   1.1       roy 
    446   1.2       roy 	if (screen == NULL)
    447   1.2       roy 		return ERR;
    448   1.1       roy 	screen->slk_hidden = false;
    449   1.1       roy 	if (screen->is_term_slk) {
    450   1.1       roy 		if (t_label_on(screen->term) == NULL)
    451   1.1       roy 			return ERR;
    452   1.1       roy 		return ti_putp(screen->term,
    453   1.1       roy 		    ti_tiparm(screen->term, t_label_on(screen->term)));
    454   1.1       roy 	}
    455   1.1       roy 	if (screen->slk_window == NULL)
    456   1.1       roy 		return ERR;
    457   1.1       roy 	if (__slk_redraw(screen) == ERR)
    458   1.1       roy 		return ERR;
    459   1.1       roy 	return wrefresh(screen->slk_window);
    460   1.1       roy }
    461   1.1       roy 
    462   1.1       roy /*
    463   1.1       roy  * __slk_set --
    464   1.1       roy  *	Sets the text of the label specified by labnum
    465   1.1       roy  *	and how it is displayed.
    466   1.1       roy  */
    467   1.1       roy static int
    468   1.1       roy __slk_set(SCREEN *screen, int labnum, const char *label, int justify)
    469   1.1       roy {
    470   1.1       roy 	struct __slk_label *l;
    471   1.1       roy 	const char *end;
    472   1.1       roy 	size_t len;
    473   1.1       roy 	char *text;
    474   1.1       roy #ifdef HAVE_WCHAR
    475   1.1       roy 	wchar_t wc;
    476   1.1       roy 	size_t wc_len;
    477   1.1       roy #endif
    478   1.1       roy 
    479   1.1       roy 	/* Check args. */
    480   1.2       roy 	if (screen == NULL || labnum < 1 || labnum > screen->slk_nlabels)
    481   1.1       roy 		return ERR;
    482   1.1       roy 	switch(justify) {
    483   1.1       roy 	case SLK_JUSTIFY_LEFT:
    484   1.1       roy 	case SLK_JUSTIFY_CENTER:
    485   1.1       roy 	case SLK_JUSTIFY_RIGHT:
    486   1.1       roy 		break;
    487   1.1       roy 	default:
    488   1.1       roy 		return ERR;
    489   1.1       roy 	}
    490   1.1       roy 	if (label == NULL)
    491   1.1       roy 		label = "";
    492   1.1       roy 
    493   1.1       roy 	/* Skip leading whitespace. */
    494   1.1       roy 	while(isspace((unsigned char)*label))
    495   1.1       roy 		label++;
    496   1.1       roy 	/* Grab end. */
    497   1.1       roy 	end = label;
    498   1.1       roy 
    499   1.1       roy #ifdef HAVE_WCHAR
    500   1.7       uwe 	size_t endlen = strlen(end);
    501   1.1       roy 	while (*end != '\0') {
    502   1.7       uwe 		wc_len = mbrtowc(&wc, end, endlen, &screen->sp);
    503   1.7       uwe 		if ((ssize_t)wc_len < 0)
    504   1.1       roy 			return ERR;
    505   1.1       roy 		if (!iswprint((wint_t)wc))
    506   1.1       roy 			break;
    507   1.1       roy 		end += wc_len;
    508   1.7       uwe 		endlen -= wc_len;
    509   1.1       roy 	}
    510   1.1       roy #else
    511   1.1       roy 	while(isprint((unsigned char)*end))
    512   1.1       roy 		end++;
    513   1.7       uwe #endif
    514   1.1       roy 	len = end - label;
    515   1.1       roy 
    516   1.1       roy 	/* Take a backup, in-case we can grow the label. */
    517   1.1       roy 	if ((text = strndup(label, len)) == NULL)
    518   1.1       roy 		return ERR;
    519   1.1       roy 
    520   1.1       roy 	/* All checks out, assign. */
    521   1.1       roy 	l = &screen->slk_labels[--labnum]; /* internal zero based index */
    522   1.1       roy 	l->text = text;
    523   1.1       roy 	l->justify = justify;
    524   1.1       roy 
    525   1.1       roy 	__slk_set_finalise(screen, labnum);
    526   1.1       roy 	return OK;
    527   1.1       roy }
    528   1.1       roy 
    529   1.1       roy /*
    530   1.1       roy  * __slk_touch --
    531   1.1       roy  *	Sets the ripped off slk window as modified.
    532   1.1       roy  */
    533   1.1       roy static int
    534   1.1       roy __slk_touch(SCREEN *screen)
    535   1.1       roy {
    536   1.1       roy 
    537   1.2       roy 	if (screen == NULL || screen->slk_window == NULL)
    538   1.1       roy 		return ERR;
    539   1.1       roy 	return touchwin(screen->slk_window);
    540   1.1       roy }
    541   1.1       roy 
    542   1.5       uwe 
    543   1.5       uwe #ifdef HAVE_WCHAR
    544   1.1       roy /*
    545   1.1       roy  * __slk_wset --
    546   1.1       roy  *	Sets the wide text of the label specified by labnum
    547   1.1       roy  *	and how it is displayed.
    548   1.1       roy  */
    549   1.1       roy static int
    550   1.1       roy __slk_wset(SCREEN *screen, int labnum, const wchar_t *label, int justify)
    551   1.1       roy {
    552   1.1       roy 	const wchar_t *olabel;
    553   1.1       roy 	size_t len;
    554   1.1       roy 	char *str;
    555   1.1       roy 	int result = ERR;
    556   1.1       roy 
    557   1.2       roy 	if (screen == NULL)
    558   1.2       roy 		return ERR;
    559   1.9     blymn #ifdef DEBUG
    560   1.9     blymn 	__CTRACE(__CTRACE_INPUT, "__slk_wset: entry\n");
    561   1.9     blymn #endif
    562   1.1       roy 	olabel = label;
    563   1.9     blymn 	if ((len = wcsrtombs(NULL, &olabel, 0, &screen->sp)) == -1) {
    564   1.9     blymn #ifdef DEBUG
    565   1.9     blymn 	__CTRACE(__CTRACE_INPUT, "__slk_wset: conversion failed on char 0x%x\n",
    566   1.9     blymn 	    (uint16_t) *olabel);
    567   1.9     blymn #endif
    568   1.1       roy 		return ERR;
    569   1.9     blymn 	}
    570   1.9     blymn 
    571   1.9     blymn #ifdef DEBUG
    572  1.11    martin 	__CTRACE(__CTRACE_INPUT, "__slk_wset: wcsrtombs %zu\n", len);
    573   1.9     blymn #endif
    574   1.1       roy 	len++; /* We need to store the NULL character. */
    575   1.1       roy 	if ((str = malloc(len)) == NULL)
    576   1.1       roy 		return ERR;
    577   1.1       roy 	olabel = label;
    578   1.1       roy 	if (wcsrtombs(str, &olabel, len, &screen->sp) == -1)
    579   1.1       roy 		goto out;
    580   1.1       roy 	result = __slk_set(screen, labnum, str, justify);
    581   1.1       roy out:
    582   1.1       roy 	free(str);
    583   1.9     blymn #ifdef DEBUG
    584   1.9     blymn 	__CTRACE(__CTRACE_INPUT, "__slk_wset: return %s\n",
    585   1.9     blymn 	    (result == OK)?"OK":"ERR");
    586   1.9     blymn #endif
    587   1.1       roy 	return result;
    588   1.1       roy }
    589   1.5       uwe #endif	/* HAVE_WCHAR */
    590   1.1       roy 
    591   1.1       roy 
    592   1.1       roy /*
    593   1.1       roy  * __slk_init --
    594   1.1       roy  *	Allocate structures.
    595   1.1       roy  */
    596   1.1       roy int
    597   1.1       roy __slk_init(SCREEN *screen)
    598   1.1       roy {
    599   1.1       roy 
    600   1.1       roy 	__slk_free(screen);	/* safety */
    601   1.4       roy 
    602   1.4       roy 	screen->slk_format = slk_fmt;
    603   1.3       roy 	if (slk_fmt == SLK_FMT_INVAL)
    604   1.3       roy 		return OK;
    605   1.4       roy 	slk_fmt = SLK_FMT_INVAL;
    606   1.1       roy 
    607   1.1       roy 	switch(screen->slk_format) {
    608   1.1       roy 	case SLK_FMT_3_2_3:
    609   1.1       roy 	case SLK_FMT_4_4:
    610   1.1       roy 		screen->slk_nlabels = 8;
    611   1.1       roy 		break;
    612   1.1       roy 	default:	/* impossible */
    613   1.1       roy 		return ERR;
    614   1.1       roy 	}
    615   1.1       roy 
    616   1.1       roy 	screen->slk_labels = calloc(screen->slk_nlabels,
    617   1.1       roy 				    sizeof(*screen->slk_labels));
    618   1.1       roy 	if (screen->slk_labels == NULL)
    619   1.1       roy 		return ERR;
    620   1.1       roy 
    621   1.1       roy 	screen->is_term_slk =
    622   1.1       roy 	    t_plab_norm(screen->term) != NULL &&
    623   1.1       roy 	    t_num_labels(screen->term) > 0;
    624   1.1       roy 	if (screen->is_term_slk) {
    625   1.1       roy 		__unripoffline(__slk_ripoffline);
    626   1.1       roy 		screen->slk_nlabels = t_num_labels(screen->term);
    627   1.1       roy 		screen->slk_label_len = t_label_width(screen->term);
    628   1.1       roy 		/* XXX label_height, label_format? */
    629   1.1       roy 	}
    630   1.1       roy 
    631   1.1       roy 	return OK;
    632   1.1       roy }
    633   1.1       roy 
    634   1.1       roy /*
    635   1.1       roy  * __slk_free --
    636   1.1       roy  *	Free allocates resources.
    637   1.1       roy  */
    638   1.1       roy void
    639   1.1       roy __slk_free(SCREEN *screen)
    640   1.1       roy {
    641   1.1       roy 	int i;
    642   1.1       roy 
    643   1.1       roy 	if (screen->slk_window != NULL)
    644   1.1       roy 		delwin(screen->slk_window);
    645   1.1       roy 	for (i = 0; i < screen->slk_nlabels; i++)
    646   1.1       roy 		free(screen->slk_labels[i].text);
    647   1.1       roy 	free(screen->slk_labels);
    648   1.1       roy }
    649   1.1       roy 
    650   1.1       roy /*
    651   1.1       roy  * __slk_ripoffline --
    652   1.1       roy  *	ripoffline callback to accept a WINDOW to create our keys.
    653   1.1       roy  */
    654   1.1       roy static int
    655   1.1       roy __slk_ripoffline(WINDOW *window, int cols)
    656   1.1       roy {
    657   1.1       roy 
    658   1.1       roy 	if (window == NULL)
    659   1.1       roy 		return ERR;
    660   1.1       roy 	window->screen->slk_window = window;
    661   1.1       roy 	wattron(window,
    662   1.1       roy 	    (t_no_color_video(window->screen->term) & 1) == 0
    663   1.1       roy 	    ? A_STANDOUT : A_REVERSE);
    664   1.1       roy 	__slk_resize(window->screen, cols);
    665   1.1       roy 	return OK;
    666   1.1       roy }
    667   1.1       roy 
    668   1.1       roy /*
    669   1.1       roy  * __slk_resize --
    670   1.1       roy  *	Size and position the labels in the ripped off slk window.
    671   1.1       roy  */
    672   1.1       roy int
    673   1.1       roy __slk_resize(SCREEN *screen, int cols)
    674   1.1       roy {
    675   1.1       roy 	int x = 0;
    676   1.1       roy 	struct __slk_label *l;
    677   1.1       roy 
    678   1.2       roy 	if (screen == NULL)
    679   1.2       roy 		return ERR;
    680   1.1       roy 	if (screen->is_term_slk || screen->slk_nlabels == 0)
    681   1.1       roy 		return OK;
    682   1.1       roy 
    683   1.1       roy 	screen->slk_label_len = (cols / screen->slk_nlabels) - 1;
    684   1.1       roy 	if (screen->slk_label_len > SLK_SIZE)
    685   1.1       roy 		screen->slk_label_len = SLK_SIZE;
    686   1.1       roy 
    687   1.1       roy 	l = screen->slk_labels;
    688   1.1       roy 
    689   1.1       roy 	switch(screen->slk_format) {
    690   1.1       roy 	case SLK_FMT_3_2_3:
    691   1.1       roy 		/* Left 3 */
    692   1.1       roy 		(l++)->x = x;
    693   1.1       roy 		(l++)->x = (x += screen->slk_label_len + 1);
    694   1.1       roy 		(l++)->x = (x += screen->slk_label_len + 1);
    695   1.1       roy 
    696   1.1       roy 		/* Middle 2 */
    697   1.1       roy 		x = cols / 2;
    698   1.1       roy 		(l++)->x = x -(screen->slk_label_len + 1);
    699   1.1       roy 		(l++)->x = x + 1;
    700   1.1       roy 
    701   1.1       roy 		/* Right 3 */
    702   1.1       roy 		x = (cols - ((screen->slk_label_len + 1) * 3)) + 1;
    703   1.1       roy 		(l++)->x = x;
    704   1.1       roy 		(l++)->x = (x += screen->slk_label_len + 1);
    705   1.1       roy 		(l++)->x = (x += screen->slk_label_len + 1);
    706   1.1       roy 		break;
    707   1.1       roy 
    708   1.1       roy 	case SLK_FMT_4_4:
    709   1.1       roy 	{
    710   1.1       roy 		int i, half;
    711   1.1       roy 
    712   1.1       roy 		half = screen->slk_nlabels / 2;
    713   1.1       roy 		for (i = 0; i < screen->slk_nlabels; i++) {
    714   1.1       roy 			(l++)->x = x;
    715   1.1       roy 			x += screen->slk_label_len;
    716   1.1       roy 			/* Split labels in half */
    717   1.1       roy 			if (i == half - 1)
    718   1.1       roy 				x = cols - (screen->slk_label_len * half) + 1;
    719   1.1       roy 		}
    720   1.1       roy 		break;
    721   1.1       roy 	}
    722   1.1       roy 	}
    723   1.1       roy 
    724   1.1       roy 	/* Write text to the labels. */
    725   1.1       roy 	for (x = 0; x < screen->slk_nlabels; x++)
    726   1.1       roy 		__slk_set_finalise(screen, x);
    727   1.1       roy 
    728   1.1       roy 	return __slk_redraw(screen);
    729   1.1       roy }
    730   1.1       roy 
    731   1.1       roy /*
    732   1.1       roy  * __slk_set_finalise --
    733   1.1       roy  *	Does the grunt work of positioning and sizing the text in the label.
    734   1.1       roy  */
    735   1.1       roy static int
    736   1.1       roy __slk_set_finalise(SCREEN *screen, int labnum)
    737   1.1       roy {
    738   1.1       roy 	struct __slk_label *l;
    739   1.8       uwe 	size_t spc, len, width, x;
    740   1.1       roy 	char *p;
    741   1.1       roy 
    742   1.1       roy 	l = &screen->slk_labels[labnum];
    743   1.1       roy 	spc = screen->slk_label_len;
    744   1.1       roy 
    745   1.1       roy #ifdef HAVE_WCHAR
    746   1.1       roy 	len = 0;
    747   1.8       uwe 	width = 0;
    748   1.1       roy 	if (l->text != NULL) {
    749   1.8       uwe 		size_t plen;
    750   1.1       roy 
    751   1.1       roy 		p = l->text;
    752   1.8       uwe 		plen = strlen(l->text);
    753   1.1       roy 		while (*p != '\0') {
    754   1.8       uwe 			size_t mblen;
    755   1.8       uwe 			wchar_t wc;
    756   1.8       uwe 			int w;
    757   1.8       uwe 
    758   1.8       uwe 			mblen = mbrtowc(&wc, p, plen, &screen->sp);
    759   1.8       uwe 			if ((ssize_t)mblen < 0)
    760   1.1       roy 				return ERR;
    761   1.8       uwe 			w = wcwidth(wc);
    762   1.8       uwe 			if (width + w > spc)
    763   1.1       roy 				break;
    764   1.8       uwe 			width += w;
    765   1.8       uwe 			len += mblen;
    766   1.8       uwe 			p += mblen;
    767   1.8       uwe 			plen -= mblen;
    768   1.1       roy 		}
    769   1.1       roy 	}
    770   1.1       roy #else
    771   1.1       roy 	len = l->text == NULL ? 0 : strlen(l->text);
    772   1.1       roy 	if (len > spc)
    773   1.1       roy 		len = spc;
    774   1.8       uwe 	width = len;
    775   1.1       roy #endif
    776   1.1       roy 
    777   1.1       roy 	switch(l->justify) {
    778   1.1       roy 	case SLK_JUSTIFY_LEFT:
    779   1.1       roy 		x = 0;
    780   1.1       roy 		break;
    781   1.1       roy 	case SLK_JUSTIFY_CENTER:
    782   1.8       uwe 		x = (spc - width) / 2;
    783   1.8       uwe 		if (x + width > spc)
    784   1.1       roy 			x--;
    785   1.1       roy 		break;
    786   1.1       roy 	case SLK_JUSTIFY_RIGHT:
    787   1.8       uwe 		x = spc - width;
    788   1.1       roy 		break;
    789   1.1       roy 	default:
    790   1.1       roy 		return ERR; /* impossible */
    791   1.1       roy 	}
    792   1.1       roy 
    793   1.1       roy 	p = l->label;
    794   1.1       roy 	if (x != 0) {
    795   1.1       roy 		memset(p, ' ', x);
    796   1.1       roy 		p += x;
    797   1.1       roy 		spc -= x;
    798   1.1       roy 	}
    799   1.1       roy 	if (len != 0) {
    800   1.1       roy 		memcpy(p, l->text, len);
    801   1.1       roy 		p += len;
    802   1.8       uwe 		spc -= width;
    803   1.1       roy 	}
    804   1.1       roy 	if (spc != 0) {
    805   1.1       roy 		memset(p, ' ', spc);
    806   1.1       roy 		p += spc;
    807   1.1       roy 	}
    808   1.1       roy 	*p = '\0'; /* Terminate for plab_norm. */
    809   1.1       roy 
    810   1.1       roy 	return __slk_draw(screen, labnum);
    811   1.1       roy }
    812   1.1       roy 
    813   1.1       roy /*
    814   1.1       roy  * __slk_draw --
    815   1.1       roy  *	Draws the specified key.
    816   1.1       roy  */
    817   1.1       roy static int
    818   1.1       roy __slk_draw(SCREEN *screen, int labnum)
    819   1.1       roy {
    820   1.1       roy 	const struct __slk_label *l;
    821   1.9     blymn 	int retval, inc, lcnt, tx;
    822  1.12  christos 	char ts[MB_LEN_MAX];
    823  1.10     blymn #ifdef HAVE_WCHAR
    824   1.9     blymn 	cchar_t cc;
    825   1.9     blymn 	wchar_t wc[2];
    826  1.10     blymn #endif
    827   1.1       roy 
    828   1.1       roy 	if (screen->slk_hidden)
    829   1.1       roy 		return OK;
    830   1.1       roy 
    831   1.9     blymn 	retval = OK; /* quiet gcc... */
    832   1.9     blymn 
    833   1.1       roy 	l = &screen->slk_labels[labnum];
    834   1.1       roy 	if (screen->is_term_slk)
    835   1.1       roy 		return ti_putp(screen->term,
    836   1.1       roy 		    ti_tiparm(screen->term,
    837   1.1       roy 		    t_plab_norm(screen->term), labnum + 1, l->label));
    838   1.9     blymn 	else if (screen->slk_window != NULL) {
    839   1.9     blymn 		if ((labnum != screen->slk_nlabels - 1) ||
    840   1.9     blymn 		    (screen->slk_window->flags & __SCROLLOK) ||
    841   1.9     blymn 		    ((l->x + screen->slk_label_len) < screen->slk_window->maxx)) {
    842   1.9     blymn 			retval = mvwaddnstr(screen->slk_window, 0, l->x,
    843   1.9     blymn 			    l->label, screen->slk_label_len);
    844   1.9     blymn 		} else {
    845   1.9     blymn 			lcnt = 0;
    846   1.9     blymn 			tx = 0;
    847   1.9     blymn 			while (lcnt < screen->slk_label_len) {
    848   1.9     blymn 				inc = wctomb(ts, l->label[lcnt]);
    849   1.9     blymn 				if (inc < 0) {
    850   1.9     blymn 					/* conversion failed, skip? */
    851   1.9     blymn 					lcnt++;
    852   1.9     blymn 					continue;
    853   1.9     blymn 				}
    854   1.9     blymn 
    855   1.9     blymn #ifdef DEBUG
    856   1.9     blymn 	__CTRACE(__CTRACE_INPUT, "__slk_draw: last label, (%d,%d) char[%d] 0x%x\n",
    857   1.9     blymn 	    l->x + tx, 0, lcnt, l->label[lcnt]);
    858   1.9     blymn 	__CTRACE(__CTRACE_INPUT, "__slk_draw: label len %d, wcwidth %d\n",
    859   1.9     blymn 	    screen->slk_label_len, wcwidth(l->label[lcnt]));
    860   1.9     blymn #endif
    861  1.10     blymn #ifdef HAVE_WCHAR
    862   1.9     blymn 				wc[0] = l->label[lcnt];
    863   1.9     blymn 				wc[1] = L'\0';
    864   1.9     blymn 				if (setcchar(&cc, wc,
    865   1.9     blymn 				    screen->slk_window->wattr, 0,
    866   1.9     blymn 				    NULL) == ERR)
    867   1.9     blymn 					return ERR;
    868  1.10     blymn #endif
    869   1.9     blymn 
    870   1.9     blymn 				if (l->x + wcwidth(l->label[lcnt] + tx) >=
    871   1.9     blymn 				    screen->slk_label_len) {
    872   1.9     blymn 					/* last character that will fit
    873   1.9     blymn 					 * so insert it to avoid scroll
    874   1.9     blymn 					 */
    875  1.10     blymn #ifdef HAVE_WCHAR
    876   1.9     blymn 					retval = mvwins_wch(screen->slk_window,
    877   1.9     blymn 					    0, l->x + tx, &cc);
    878  1.10     blymn #else
    879  1.10     blymn 					retval = mvwinsch(screen->slk_window,
    880  1.10     blymn 					    0, l->x + tx, l->label[lcnt]);
    881  1.10     blymn #endif
    882   1.9     blymn 				} else {
    883  1.10     blymn #ifdef HAVE_WCHAR
    884   1.9     blymn 					retval = mvwadd_wch(screen->slk_window,
    885   1.9     blymn 					    0, l->x + tx, &cc);
    886  1.10     blymn #else
    887  1.10     blymn 					retval = mvwaddch(screen->slk_window,
    888  1.10     blymn 					    0, l->x + tx, l->label[lcnt]);
    889  1.10     blymn #endif
    890   1.9     blymn 				}
    891   1.9     blymn 				tx += wcwidth(l->label[lcnt]);
    892   1.9     blymn 				lcnt += inc;
    893   1.9     blymn 			}
    894   1.9     blymn 		}
    895   1.9     blymn 
    896   1.9     blymn 		return retval;
    897   1.9     blymn 	} else
    898   1.1       roy 		return ERR;
    899   1.1       roy }
    900   1.1       roy 
    901   1.1       roy /*
    902   1.1       roy  * __slk_draw --
    903   1.1       roy  *	Draws all the keys.
    904   1.1       roy  */
    905   1.1       roy static int
    906   1.1       roy __slk_redraw(SCREEN *screen)
    907   1.1       roy {
    908   1.1       roy 	int i, result = OK;
    909   1.1       roy 
    910   1.1       roy 	for (i = 0; i < screen->slk_nlabels; i++) {
    911   1.1       roy 		if (__slk_draw(screen, i) == ERR)
    912   1.1       roy 			result = ERR;
    913   1.1       roy 	}
    914   1.1       roy 	return result;
    915   1.1       roy }
    916