LIBS = -lslang -lm -ldl #-lefence
-SHLIBS = -lslang -lm -dl -lc
+SHLIBS = -lslang -lm -dl -lc
+LIBTCL = -ltcl8.4
GPM_SUPPORT=@gpm_support@
+CFLAGS = $(RPM_OPT_FLAGS) -Wall -D_GNU_SOURCE -g -O2 -DUTF8 -fPIC -I/usr/include/slang
-CFLAGS = $(RPM_OPT_FLAGS) -Wall -I/usr/include/slang -D_GNU_SOURCE -g -O2 -DUTF8
-
+SHLIBFLAGS= -Wl,-O1 -Wl,--version-script,newt.0.52.ver
VERSION = @VERSION@
CVSTAG = r$(subst .,-,$(VERSION))
SONAME = @SONAME@
-PYTHONVERS = $(shell ls /usr/include/python*/Python.h | sed "s|/usr/include/||g"| sed "s|/Python.h||g")
+PYTHONVERS = python2.4
-WHIPTCLSO=
-#WHIPTCLSO=whiptcl.so
+WHIPTCLSO=whiptcl.so
PROGS = test whiptail $(WHIPTCLSO) testgrid testtree showchars showkey
TESTOBJS = test.o
TARGET=depend $(PROGS)
endif
-all: $(TARGET) _snackmodule.so
+all: $(TARGET) _snackmodule.so po/po-stamp
+
+po/po-stamp:
+ $(MAKE) -C po po-stamp
test: $(TESTOBJS) $(LIBNEWT)
$(CC) -g -o test $(TESTOBJS) $(LIBNEWT) $(LIBS) -static
if [ ! -f "$$ver/_snackmodule.so" -o $(LIBNEWTSH) -nt "$$ver/_snackmodule.so" ]; then \
mkdir -p $$ver ;\
$(CC) $(CFLAGS) -I/usr/include/$$ver -fPIC -c -o $$ver/snackmodule.o snackmodule.c ;\
- $(CC) --shared $(SHCFLAGS) -o $$ver/_snackmodule.so $$ver/snackmodule.o -L . $(LIBNEWTSH) ;\
+ $(CC) --shared $(SHCFLAGS) -o $$ver/_snackmodule.so $$ver/snackmodule.o -L . -lnewt -lslang ;\
fi ; \
done
whiptail: $(NDIALOGOBJS) $(LIBNEWTSH)
- $(CC) -g -o whiptail $(NDIALOGOBJS) -L . $(LIBNEWTSH) $(LIBS) -lpopt
+ $(CC) -g -o whiptail $(NDIALOGOBJS) -L . -lnewt $(LIBS) -lpopt
whiptcl.so: $(WHIPTCLOBJS) $(LIBNEWTSH)
- gcc -shared $(SHCFLAGS) -o whiptcl.so $(WHIPTCLOBJS) -L . $(LIBNEWTSH) -ltcl -lslang -lpopt -lm
+ $(CC) -shared $(SHCFLAGS) -o whiptcl.so $(WHIPTCLOBJS) -L . -lnewt $(LIBTCL) -lslang -lpopt -lm
# Ensure dialogboxes is compiled -fPIC
dialogboxes.o: dialogboxes.c
$(CC) $(CFLAGS) $(SHCFLAGS) -c dialogboxes.c
-
+
+whiptcl.o: whiptcl.c
+ $(CC) $(SHCFLAGS) $(CFLAGS) -c whiptcl.c
+
$(LIBNEWT): $(LIBOBJS)
ar rv $@ $^
sharedlib: $(LIBNEWTSH)
$(LIBNEWTSH): $(SHAREDDIR) $(SHAREDOBJS)
- $(CC) -shared -o $(LIBNEWTSH) -Wl,-soname,$(LIBNEWTSONAME) $(SHAREDOBJS) $(SHLIBS)
+ $(CC) -shared -o $(LIBNEWTSH) $(SHLIBFLAGS) -Wl,-soname,$(LIBNEWTSONAME) $(SHAREDOBJS) $(SHLIBS)
+ ln -s $(LIBNEWTSH) libnewt.so
$(SHAREDDIR)/%.o : %.c
$(CC) $(SHCFLAGS) -c $(CFLAGS) -o $@ $<
SLsmg_set_color(NEWT_COLORSET_BUTTON);
if (bu->compact) {
- if (active)
+ if (!active)
SLsmg_set_color(NEWT_COLORSET_COMPACTBUTTON);
else
SLsmg_set_color(NEWT_COLORSET_BUTTON);
newtGotorc(co->top+ pushed, co->left + 1 + pushed);
SLsmg_write_char('<');
- SLsmg_write_string(bu->text);
+ write_string_int(bu->text, NULL);
SLsmg_write_char('>');
} else {
if (pushed) {
newtGotorc(co->top + 1 + pushed, co->left + 1 + pushed);
SLsmg_write_char(' ');
- SLsmg_write_string(bu->text);
+ write_string_int(bu->text, NULL);
SLsmg_write_char(' ');
}
char newtCheckboxGetValue(newtComponent co) {
struct checkbox * cb = co->data;
- return *cb->result;
+ return cb->value;
}
void newtCheckboxSetValue(newtComponent co, char value) {
cb->flags = newtSetFlags(cb->flags, flags, sense);
+ // If the flag just sets a property (eg. NEWT_FLAG_RETURNEXIT),
+ // don't redraw, etc. as the component might be 'hidden' and not to
+ // be drawn (eg. in a scrolled list)
+ if (flags == NEWT_FLAG_RETURNEXIT)
+ return;
+
if (!(cb->flags & NEWT_FLAG_DISABLED))
co->takesFocus = 1;
else
break;
}
- SLsmg_write_string(cb->text);
+ write_string_int(cb->text, NULL);
if (cb->hasFocus)
SLsmg_set_color(cb->active);
er.result = ER_IGNORED;
}
} else if(ev.u.key == NEWT_KEY_ENTER) {
- er.result = ER_IGNORED;
+ if (cb->flags & NEWT_FLAG_RETURNEXIT)
+ er.result = ER_EXITFORM;
+ else
+ er.result = ER_IGNORED;
} else {
er.result = ER_IGNORED;
}
struct items ** item;
int i, j;
char * spaces;
- int currRow = 0;
+ int currRow;
if (!co->isMapped) return ;
} else {
char tmp[5];
snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]);
+ /* BIDI: no need to use _int funcs here: only ASCII characters */
SLsmg_write_string(tmp);
}
}
- SLsmg_write_nstring((*item)->text, co->width - 4 -
- (3 * (*item)->depth));
+ write_nstring_int((*item)->text, co->width - 4 -
+ (3 * (*item)->depth), NULL);
SLsmg_set_color(NEWT_COLORSET_LISTBOX);
-/* config.h.in. Generated automatically from configure.in by autoheader. */
+/* config.h.in. Generated automatically from configure.in by autoheader 2.13. */
/* Define if you have the <alloca.h> header file. */
#undef HAVE_ALLOCA_H
+/* Define if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define if you have the <fribidi/fribidi.h> header file. */
+#undef HAVE_FRIBIDI_FRIBIDI_H
+
/* Define if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
/* Define to 1 if GPM support is enabled */
#undef USE_GPM
+#define PACKAGE "newt"
+#define ENABLE_NLS 1
+
+#define VERSION "0.51.6"
AC_CONFIG_HEADER(config.h)
PACKAGE=newt
-VERSION=$(awk '/^%define version/ {print $3}' $srcdir/newt.spec)
-SONAME=0.51
+VERSION=0.52.0
+SONAME=0.52
AC_SUBST(PACKAGE)
AC_SUBST(VERSION)
AC_SUBST(SONAME)
AC_PROG_INSTALL
AC_PROG_LN_S
-AC_CHECK_HEADERS(sys/select.h alloca.h)
+AC_CHECK_HEADERS(sys/select.h alloca.h fribidi/fribidi.h dlfcn.h)
AC_ARG_WITH(gpm-support, [ --with-gpm-support Compile with GPM support])
/* simple dialog boxes, used by both whiptail and tcl dialog bindings */
+#include "config.h"
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
+#include <wchar.h>
+#include <slang.h>
+#include "nls.h"
#include "dialogboxes.h"
#include "newt.h"
#include "newt_pr.h"
/* globals -- ick */
static int buttonHeight = 1;
+
+int max (int a, int b)
+{
+ return (a > b) ? a : b;
+}
+
+int min (int a, int b)
+{
+ return ( a < b) ? a : b ;
+}
+
static newtComponent (*makeButton)(int left, int right, const char * text) =
newtCompactButton;
static void addButtons(int height, int width, newtComponent form,
newtComponent * okay, newtComponent * cancel,
int flags) {
+ // FIXME: DO SOMETHING ABOUT THE HARD-CODED CONSTANTS
if (flags & FLAG_NOCANCEL) {
- *okay = makeButton((width - 8) / 2, height - buttonHeight - 1, "Ok");
- *cancel = NULL;
+ *okay = makeButton((width - 8) / 2, height - buttonHeight - 1,
+ dgettext(PACKAGE, "Ok"));
+ *cancel = NULL;
newtFormAddComponent(form, *okay);
} else {
- *okay = makeButton((width - 18) / 3, height - buttonHeight - 1, "Ok");
+ *okay = makeButton((width - 18) / 3, height - buttonHeight - 1,
+ dgettext(PACKAGE,"Ok"));
*cancel = makeButton(((width - 18) / 3) * 2 + 9,
- height - buttonHeight - 1, "Cancel");
+ height - buttonHeight - 1,
+ dgettext(PACKAGE,"Cancel"));
newtFormAddComponents(form, *okay, *cancel, NULL);
}
}
int flags, const char ** result) {
newtComponent form, entry, okay, cancel, answer, tb;
const char * val;
+ int pFlag = (flags & FLAG_PASSWORD) ? NEWT_FLAG_PASSWORD : 0;
int rc = DLG_OKAY;
int top;
form = newtForm(NULL, NULL, 0);
entry = newtEntry(1, top + 1, val, width - 2, &val,
- NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
+ NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT | pFlag);
newtFormAddComponents(form, tb, entry, NULL);
answer = newtRunForm(form);
if (answer == cancel)
rc = DLG_CANCEL;
+ else if (answer == NULL)
+ rc = DLG_ESCAPE;
*result = val;
return rc;
}
+static int mystrncpyw(char *dest, const char *src, int n, int *maxwidth)
+{
+ int i = 0;
+ int w = 0, cw;
+ wchar_t c;
+ mbstate_t ps;
+ const char *p = src;
+ char *d = dest;
+
+ memset(&ps, 0, sizeof(ps));
+
+ for (;;) {
+ int ret = mbrtowc(&c, p, MB_CUR_MAX, &ps);
+ if (ret <= 0) break;
+ if (ret + i >= n) break;
+ cw = wcwidth(c);
+ if (cw < 0) break;
+ if (cw + w > *maxwidth) break;
+ w += cw;
+ memcpy(d, p, ret);
+ d += ret;
+ p += ret;
+ i += ret;
+ }
+ dest[i] = '\0';
+ *maxwidth = w;
+ return i;
+}
+
int listBox(const char * text, int height, int width, poptContext optCon,
- int flags, const char ** result) {
+ int flags, const char *default_item, const char ** result) {
newtComponent form, okay, tb, answer, listBox;
newtComponent cancel = NULL;
const char * arg;
int allocedItems = 5;
int i, top;
int rc = DLG_OKAY;
- char buf[MAXBUF], format[MAXFORMAT];
+ char buf[MAXBUF];
int maxTagWidth = 0;
int maxTextWidth = 0;
+ int defItem = -1;
int scrollFlag;
+ int lineWidth, textWidth, tagWidth;
struct {
const char * text;
const char * tag;
}
itemInfo[numItems].tag = arg;
+ if (default_item && (strcmp(default_item, arg) == 0)) {
+ defItem = numItems;
+ }
if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
if (!(flags & FLAG_NOITEM)) {
i = 2;
}
- listBox = newtListbox(3 + ((width - 10 - maxTagWidth - maxTextWidth - i)
- / 2),
- top + 1, listHeight,
- NEWT_FLAG_RETURNEXIT | scrollFlag);
+ lineWidth = min(maxTagWidth + maxTextWidth + i, SLtt_Screen_Cols - 10);
+ listBox = newtListbox( (width - lineWidth) / 2 , top + 1, listHeight,
+ NEWT_FLAG_RETURNEXIT | scrollFlag);
- snprintf(format, MAXFORMAT, "%%-%ds %%s", maxTagWidth);
- for (i = 0; i < numItems; i++) {
- snprintf(buf, MAXBUF, format, itemInfo[i].tag, itemInfo[i].text);
- newtListboxAddEntry(listBox, buf, (void *) i);
+ textWidth = maxTextWidth;
+ tagWidth = maxTagWidth;
+ if (maxTextWidth == 0) {
+ tagWidth = lineWidth;
+ } else {
+ if (maxTextWidth + maxTagWidth + i > lineWidth)
+ tagWidth = textWidth = (lineWidth / 2) - 2;
+ else {
+ tagWidth++;
+ textWidth++;
+ }
}
+ if (!(flags & FLAG_NOTAGS)) {
+ for (i = 0; i < numItems; i++) {
+ int w = tagWidth;
+ int len, j;
+ len = mystrncpyw(buf, itemInfo[i].tag, MAXBUF, &w);
+ for (j = 0; j < tagWidth - w; j++) {
+ if (len >= MAXBUF) break;
+ buf[len++] = ' ';
+ }
+ buf[len] = '\0';
+ w = textWidth;
+ mystrncpyw(buf + len, itemInfo[i].text, MAXBUF-len, &w);
+ newtListboxAddEntry(listBox, buf, (void *) i);
+ }
+ } else {
+ for (i = 0; i < numItems; i++) {
+ snprintf(buf, MAXBUF, "%s", itemInfo[i].text);
+ newtListboxAddEntry(listBox, buf, (void *) i);
+ }
+ }
+
+ if (defItem != -1)
+ newtListboxSetCurrent (listBox, defItem);
+
newtFormAddComponents(form, tb, listBox, NULL);
addButtons(height, width, form, &okay, &cancel, flags);
answer = newtRunForm(form);
if (answer == cancel)
rc = DLG_CANCEL;
+ if (answer == NULL)
+ rc = DLG_ESCAPE;
i = (int) newtListboxGetCurrent(listBox);
*result = itemInfo[i].tag;
int i;
int numSelected;
int rc = DLG_OKAY;
- char buf[80], format[20];
+ char buf[MAXBUF], format[MAXFORMAT];
int maxWidth = 0;
int top;
struct {
numBoxes++;
}
-
form = newtForm(NULL, NULL, 0);
tb = textbox(height - 3 - buttonHeight - listHeight, width - 2,
cbInfo[i].comp = newtCheckbox(4, top + 1 + i, buf,
cbStates[i], NULL, cbStates + i);
+ newtCheckboxSetFlags(cbInfo[i].comp, NEWT_FLAG_RETURNEXIT, NEWT_FLAGS_SET);
newtFormAddComponent(subform, cbInfo[i].comp);
}
answer = newtRunForm(form);
if (answer == cancel)
rc = DLG_CANCEL;
+ if (answer == NULL)
+ rc = DLG_ESCAPE;
if (useRadio) {
answer = newtRadioGetCurrent(cbInfo[0].comp);
int messageBox(const char * text, int height, int width, int type, int flags) {
newtComponent form, yes, tb, answer;
newtComponent no = NULL;
+ int rc = DLG_OKAY;
int tFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
form = newtForm(NULL, NULL, 0);
case MSGBOX_INFO:
break;
case MSGBOX_MSG:
- yes = makeButton((width - 8) / 2, height - 1 - buttonHeight, "Ok");
+ // FIXME Do something about the hard-coded constants
+ yes = makeButton((width - 8) / 2, height - 1 - buttonHeight,
+ dgettext(PACKAGE,"Ok"));
newtFormAddComponent(form, yes);
break;
default:
- yes = makeButton((width - 16) / 3, height - 1 - buttonHeight, "Yes");
+ yes = makeButton((width - 16) / 3, height - 1 - buttonHeight,
+ dgettext(PACKAGE,"Yes"));
no = makeButton(((width - 16) / 3) * 2 + 9, height - 1 - buttonHeight,
- "No");
+ dgettext(PACKAGE,"No"));
newtFormAddComponents(form, yes, no, NULL);
if (flags & FLAG_DEFAULT_NO)
}
if ( type != MSGBOX_INFO ) {
- newtRunForm(form);
+ if (newtRunForm(form) == NULL)
+ rc = DLG_ESCAPE;
answer = newtFormGetCurrent(form);
- return DLG_OKAY;
+ return rc;
}
void useFullButtons(int state) {
#define FLAG_NOCANCEL (1 << 1)
#define FLAG_SCROLL_TEXT (1 << 2)
#define FLAG_DEFAULT_NO (1 << 3)
+#define FLAG_PASSWORD (1 << 4)
#define FLAG_NOTAGS (1 << 5)
#define DLG_ERROR -1
#define DLG_OKAY 0
#define DLG_CANCEL 1
+#define DLG_ESCAPE 2
+
+int min(int a, int b);
+int max(int a, int b);
int messageBox(const char * text, int height, int width, int type, int flags);
int checkList(const char * text, int height, int width, poptContext optCon,
int useRadio, int flags, const char *** selections);
int listBox(const char * text, int height, int width, poptContext optCon,
- int flags, const char ** result);
+ int flags, const char *default_item, const char ** result);
int inputBox(const char * text, int height, int width, poptContext optCon,
int flags, const char ** result);
int gauge(const char * text, int height, int width, poptContext optCon, int fd,
#include <slang.h>
#include <stdlib.h>
#include <string.h>
+#include <wchar.h>
#include "newt.h"
#include "newt_pr.h"
else
co->takesFocus = 0;
- if (initialValue && wstrlen(initialValue,-1) > (unsigned int)width) {
- en->bufAlloced = wstrlen(initialValue,-1) + 1;
+ if (initialValue && strlen(initialValue) > (unsigned int)width) {
+ en->bufAlloced = strlen(initialValue) + 1;
}
en->buf = malloc(en->bufAlloced);
en->resultPtr = resultPtr;
return co;
}
+static int visible_width(const char *str, int start, int end)
+{
+ int width = wstrlen(str + start, end-start);
+ int len, w = 0;
+ wchar_t wc;
+
+ len = mbtowc(&wc, str+end, MB_CUR_MAX);
+ if (len == 0)
+ w = 1;
+ else if (len > 0)
+ w = wcwidth(wc);
+ return width + w;
+}
+
+static void scroll(struct entry *en, int width)
+{
+ wchar_t wc;
+ int len, w;
+ int newwidth = visible_width(en->buf, en->firstChar, en->cursorPosition);
+
+ while (newwidth > width) {
+ len = mbtowc(&wc, en->buf+en->firstChar, MB_CUR_MAX);
+ if (!len) {
+ en->firstChar++;
+ break;
+ }
+ if (len < 0)
+ break;
+ w = wcwidth(wc);
+ if (w < 0)
+ break;
+ en->firstChar += len;
+ newwidth -= w;
+ }
+}
+
static void entryDraw(newtComponent co) {
struct entry * en = co->data;
int i;
char * chptr;
int len;
+ char *tmpptr = NULL;
if (!co->isMapped) return;
if (en->cursorPosition < en->firstChar) {
/* scroll to the left */
en->firstChar = en->cursorPosition;
- } else if ((en->firstChar + co->width) <= en->cursorPosition) {
+ } else {
/* scroll to the right */
- en->firstChar = en->cursorPosition - co->width + 1;
+ scroll(en, co->width);
}
chptr = en->buf + en->firstChar;
if (en->flags & NEWT_FLAG_PASSWORD) {
- char *tmpptr, *p;
-
+ char *p;
tmpptr = alloca(strlen(chptr)+2);
strcpy(tmpptr, chptr);
for (p = tmpptr; *p; p++)
if (len <= co->width) {
i = len;
+ /* BIDI: do not replaced, because it will not work.
+ * More work needed */
SLsmg_write_string(chptr);
while (i < co->width) {
SLsmg_write_char('_');
i++;
}
} else {
+ /* BIDI: will not work for RTL text */
SLsmg_write_nstring(chptr, co->width);
}
if (en->flags & NEWT_FLAG_HIDDEN)
newtGotorc(co->top, co->left);
else
- newtGotorc(co->top, co->left + (en->cursorPosition - en->firstChar));
+ newtGotorc(co->top, co->left + wstrlen(en->buf+en->firstChar, en->cursorPosition - en->firstChar));
}
void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
newtGotorc(co->top, co->left);
else
newtGotorc(co->top, co->left +
- (en->cursorPosition - en->firstChar));
+ wstrlen(en->buf + en->firstChar, en->cursorPosition - en->firstChar));
er.result = ER_SWALLOWED;
break;
return er;
}
+static int previous_char(const char *buf, int pos)
+{
+ int len = 0;
+ int off = 0;
+
+ while (off < pos) {
+ len = mblen(buf+off, MB_CUR_MAX);
+ if (len <= 0)
+ return pos;
+ off+=len;
+ }
+ return off-len;
+}
+
+static int next_char(const char *buf, int pos)
+{
+ int len = mblen(buf + pos, MB_CUR_MAX);
+ if (len < 0)
+ return pos;
+ if (len == 0)
+ return ++pos;
+ return pos+len;
+}
+
static struct eventResult entryHandleKey(newtComponent co, int key) {
struct entry * en = co->data;
struct eventResult er;
memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed);
break;
+ case '\025': /* ^U */
+ en->bufUsed -= en->cursorPosition;
+ memmove(en->buf, en->buf + en->cursorPosition, en->bufUsed);
+ en->cursorPosition = 0;
+ memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed);
+ break;
+
case '\002': /* ^B */
case NEWT_KEY_LEFT:
if (en->cursorPosition)
- en->cursorPosition--;
+ en->cursorPosition = previous_char(en->buf, en->cursorPosition);
break;
case '\004':
case NEWT_KEY_DELETE:
chptr = en->buf + en->cursorPosition;
if (*chptr) {
- chptr++;
- while (*chptr) {
- *(chptr - 1) = *chptr;
- chptr++;
+ int delta = next_char(en->buf, en->cursorPosition)-en->cursorPosition;
+ if (delta) {
+ chptr+=delta;
+ while (*chptr) {
+ *(chptr - delta) = *chptr;
+ chptr++;
+ }
+ memset(chptr - delta, 0, delta);
+ en->bufUsed-=delta;
}
- *(chptr - 1) = '\0';
- en->bufUsed--;
}
break;
- case NEWT_KEY_BKSPC:
- if (en->cursorPosition) {
+ case NEWT_KEY_BKSPC: {
+ int prev = previous_char(en->buf, en->cursorPosition);
+ if (en->cursorPosition != prev) {
/* if this isn't true, there's nothing to erase */
+ int delta = en->cursorPosition - prev;
chptr = en->buf + en->cursorPosition;
- en->bufUsed--;
- en->cursorPosition--;
+ en->bufUsed-=delta;
+ en->cursorPosition-=delta;
while (*chptr) {
- *(chptr - 1) = *chptr;
+ *(chptr - delta) = *chptr;
chptr++;
}
- *(chptr - 1) = '\0';
+ memset(chptr - delta, 0, delta);
+ }
}
break;
case '\006': /* ^B */
case NEWT_KEY_RIGHT:
if (en->cursorPosition < en->bufUsed)
- en->cursorPosition++;
+ en->cursorPosition = next_char(en->buf, en->cursorPosition);
break;
default:
- if ((key >= 0x20 && key <= 0x7e) || (key >= 0xa0 && key <= 0xff)) {
- if (!(en->flags & NEWT_FLAG_SCROLL) && en->bufUsed >= co->width) {
+ if ((key >= 0x20 && key <= 0x7e) || (key >= 0x80 && key <= 0xff)) {
+ if (!(en->flags & NEWT_FLAG_SCROLL) && wstrlen(en->buf, -1) >= co->width) {
+ /* FIXME this is broken */
SLtt_beep();
break;
}
}
}
-
+ /* FIXME */
en->buf[en->cursorPosition++] = key;
} else {
er.result = ER_IGNORED;
if (!(form->flags & NEWT_FLAG_NOF12)) {
newtFormAddHotKey(co, NEWT_KEY_F12);
}
+ /* TEST */ newtFormAddHotKey (co, NEWT_KEY_ESCAPE);
if (vertBar)
form->vertBar = vertBar;
SLsmg_set_color(COLORSET_LABEL);
newtGotorc(co->top, co->left);
- SLsmg_write_string(la->text);
+ /* BIDI: need to check if nstring is really needed.
+ * Where it is used? */
+ write_nstring_int(la->text, co->width, NULL);
}
static void labelDestroy(newtComponent co) {
else
SLsmg_set_color(NEWT_COLORSET_LISTBOX);
- SLsmg_write_nstring(item->text, li->curWidth);
+ write_nstring_int(item->text, li->curWidth, NULL);
}
newtGotorc(co->top + (li->currItem - li->startShowItem) + li->bdyAdjust,
--- /dev/null
+NEWT_0.52 {
+ global: newt*;
+ _newt_wstrlen;
+ local: *;
+};
+
#include "newt.h"
#include "newt_pr.h"
+#if defined(HAVE_FRIBIDI_FRIBIDI_H) && defined(HAVE_DLFCN_H)
+#include <fribidi/fribidi.h>
+#include <dlfcn.h>
+
+/* No sense in enabling shaping if we don't have BIDI support. */
+typedef struct
+{
+ int is_shaped;
+ wchar_t isolated;
+ wchar_t initial;
+ wchar_t medial;
+ wchar_t final;
+}
+arabic_char_node;
+
+#define ARABIC_BASE 0x621
+#define ARABIC_END 0x64A
+
+static const arabic_char_node arabic_shaping_table[] = {
+/* 0x621 */ { TRUE , 0xFE80, 0x0000, 0x0000, 0x0000},
+/* 0x622 */ { TRUE , 0xFE81, 0x0000, 0x0000, 0xFE82},
+/* 0x623 */ { TRUE , 0xFE83, 0x0000, 0x0000, 0xFE84},
+/* 0x624 */ { TRUE , 0xFE85, 0x0000, 0x0000, 0xFE86},
+/* 0x625 */ { TRUE , 0xFE87, 0x0000, 0x0000, 0xFE88},
+/* 0x626 */ { TRUE , 0xFE89, 0xFE8B, 0xFE8C, 0xFE8A},
+/* 0x627 */ { TRUE , 0xFE8D, 0x0000, 0x0000, 0xFE8E},
+/* 0x628 */ { TRUE , 0xFE8F, 0xFE91, 0xFE92, 0xFE90},
+/* 0x629 */ { TRUE , 0xFE93, 0x0000, 0x0000, 0xFE94},
+/* 0x62A */ { TRUE , 0xFE95, 0xFE97, 0xFE98, 0xFE96},
+/* 0x62B */ { TRUE , 0xFE99, 0xFE9B, 0xFE9C, 0xFE9A},
+/* 0x62C */ { TRUE , 0xFE9D, 0xFE9F, 0xFEA0, 0xFE9E},
+/* 0x62D */ { TRUE , 0xFEA1, 0xFEA3, 0xFEA4, 0xFEA2},
+/* 0x62E */ { TRUE , 0xFEA5, 0xFEA7, 0xFEA8, 0xFEA6},
+/* 0x62F */ { TRUE , 0xFEA9, 0x0000, 0x0000, 0xFEAA},
+/* 0x630 */ { TRUE , 0xFEAB, 0x0000, 0x0000, 0xFEAC},
+/* 0x631 */ { TRUE , 0xFEAD, 0x0000, 0x0000, 0xFEAE},
+/* 0x632 */ { TRUE , 0xFEAF, 0x0000, 0x0000, 0xFEB0},
+/* 0x633 */ { TRUE , 0xFEB1, 0xFEB3, 0xFEB4, 0xFEB2},
+/* 0x634 */ { TRUE , 0xFEB5, 0xFEB7, 0xFEB8, 0xFEB6},
+/* 0x635 */ { TRUE , 0xFEB9, 0xFEBB, 0xFEBC, 0xFEBA},
+/* 0x636 */ { TRUE , 0xFEBD, 0xFEBF, 0xFEC0, 0xFEBE},
+/* 0x637 */ { TRUE , 0xFEC1, 0xFEC3, 0xFEC4, 0xFEC2},
+/* 0x638 */ { TRUE , 0xFEC5, 0xFEC7, 0xFEC8, 0xFEC6},
+/* 0x639 */ { TRUE , 0xFEC9, 0xFECB, 0xFECC, 0xFECA},
+/* 0x63A */ { TRUE , 0xFECD, 0xFECF, 0xFED0, 0xFECE},
+/* 0x63B */ { FALSE, 0x0000, 0x0000, 0x0000, 0x0000},
+/* 0x63C */ { FALSE, 0x0000, 0x0000, 0x0000, 0x0000},
+/* 0x63D */ { FALSE, 0x0000, 0x0000, 0x0000, 0x0000},
+/* 0x63E */ { FALSE, 0x0000, 0x0000, 0x0000, 0x0000},
+/* 0x63F */ { FALSE, 0x0000, 0x0000, 0x0000, 0x0000},
+/* 0x640 */ { TRUE , 0x0640, 0x0640, 0x0640, 0x0640},
+/* 0x641 */ { TRUE , 0xFED1, 0xFED3, 0xFED4, 0xFED2},
+/* 0x642 */ { TRUE , 0xFED5, 0xFED7, 0xFED8, 0xFED6},
+/* 0x643 */ { TRUE , 0xFED9, 0xFEDB, 0xFEDC, 0xFEDA},
+/* 0x644 */ { TRUE , 0xFEDD, 0xFEDF, 0xFEE0, 0xFEDE},
+/* 0x645 */ { TRUE , 0xFEE1, 0xFEE3, 0xFEE4, 0xFEE2},
+/* 0x646 */ { TRUE , 0xFEE5, 0xFEE7, 0xFEE8, 0xFEE6},
+/* 0x647 */ { TRUE , 0xFEE9, 0xFEEB, 0xFEEC, 0xFEEA},
+/* 0x648 */ { TRUE , 0xFEED, 0x0000, 0x0000, 0xFEEE},
+/* 0x649 */ { TRUE , 0xFEEF, 0x0000, 0x0000, 0xFEF0},
+/* 0x64A */ { TRUE , 0xFEF1, 0xFEF3, 0xFEF4, 0xFEF2}
+};
+
+typedef struct {
+ wchar_t c;
+ arabic_char_node ar_node;
+}
+extra_char_node;
+
+#define EXTRA_BASE 0x67E
+#define EXTRA_END 0x6CC
+static const extra_char_node extra_shaping_table[] = {
+ {0x067E, {TRUE, 0xFB56, 0xFB58, 0xFB59, 0xFB57}},
+ {0x0686, {TRUE, 0xFB7A, 0xFB7C, 0xFB7D, 0xFB7B}},
+ {0x0698, {TRUE, 0xFB8A, 0x0000, 0x0000, 0xFB8B}},
+ {0x06A9, {TRUE, 0xFB8E, 0xFB90, 0xFB91, 0xFB8F}},
+ {0x06AF, {TRUE, 0xFB92, 0xFB94, 0xFB95, 0xFB93}},
+ {0x06CC, {TRUE, 0xFBFC, 0xFBFE, 0xFBFF, 0xFBFD}},
+ {0x0000, {FALSE, 0x0000, 0x0000, 0x0000, 0x0000}},
+};
+
+static const arabic_char_node *get_char_node(wchar_t w)
+{
+ if (w >= ARABIC_BASE && w <= ARABIC_END)
+ return &arabic_shaping_table[w - ARABIC_BASE];
+ else if (w >= EXTRA_BASE && w <= EXTRA_END) {
+ const extra_char_node *node = extra_shaping_table;
+
+ while (node->c) {
+ if (node->c == w)
+ return &node->ar_node;
+ node++;
+ }
+ return NULL;
+ }
+ return NULL;
+}
+
+static int do_shaping(wchar_t *buf, int len) {
+ int i,j;
+
+ wchar_t *newbuf;
+
+ if (len < 1)
+ return 0;
+
+ newbuf = (wchar_t *)malloc(sizeof(wchar_t)*len);
+
+ for (i = 0, j = 0; i < len; i++, j++) {
+ int have_previous = FALSE, have_next = FALSE;
+ const arabic_char_node *node, *node1;
+ int prev, next;
+
+ if (buf[i] == L'\0')
+ break;
+
+ /* If it is non-joiner, ignore it */
+ if (buf[i] == 0x200C) {
+ j--;
+ continue;
+ }
+
+ newbuf[j] = buf[i];
+
+ /* If it's not in our range, skip it. */
+ node = get_char_node(buf[i]);
+ if (!node)
+ {
+ continue;
+ }
+
+ /* The character wasn't included in the unicode shaping table. */
+ if (!node->is_shaped)
+ {
+ continue;
+ }
+
+ for (prev = i - 1; prev >= 0; prev--)
+ if (wcwidth(buf[prev]) || buf[prev] == 0x200C)
+ break;
+
+ if (prev >= 0 && (node1 = get_char_node(buf[prev]))
+ && ( node1->initial || node1->medial))
+ {
+ have_previous = TRUE;
+ }
+
+ for (next = i + 1; next < len; next++)
+ if (wcwidth(buf[next]) || buf[next] == 0x200C)
+ break;
+
+ if (next < len && (node1 = get_char_node(buf[next]))
+ && (node1->medial || node1->final))
+ {
+ have_next = TRUE;
+ }
+
+ /*
+ * FIXME: do not make ligature if there are combining
+ * characters between two parts.
+ */
+ if (buf[i] == 0x644 && have_next && next == i + 1)
+ {
+ switch (buf[next])
+ {
+ case 0x622:
+ newbuf[j] = 0xFEF5 + (have_previous ? 1 : 0);
+ i++;
+ continue;
+ case 0x623:
+ newbuf[j] = 0xFEF7 + (have_previous ? 1 : 0);
+ i++;
+ continue;
+ case 0x625:
+ newbuf[j] = 0xFEF9 + (have_previous ? 1 : 0);
+ i++;
+ continue;
+ case 0x627:
+ newbuf[j] = 0xFEFB + (have_previous ? 1 : 0);
+ i++;
+ continue;
+ default:
+ break;
+ }
+ }
+
+ /** Medial **/
+ if (have_previous && have_next && node->medial)
+ {
+ newbuf[j] = node->medial;
+ }
+
+ /** Final **/
+ else if (have_previous && node->final)
+ {
+ newbuf[j] = node->final;
+ }
+
+ /** Initial **/
+ else if (have_next && node->initial)
+ {
+ newbuf[j] = node->initial;
+ }
+
+ /** Isolated **/
+ else if (node->isolated)
+ {
+ newbuf[j] = node->isolated;
+ }
+ }
+ for (i = 0; i < len && i < j; i++) {
+ buf[i] = newbuf[i];
+ }
+ while (i < len) {
+ buf[i++] = L'\0';
+ }
+
+ free(newbuf);
+ return 0;
+}
+
+/* Converts bidi wchar text {in} to visual wchar text which is displayable
+ * in text mode. Uses {base_dir} as default base direction.
+ * Returns malloc'ed converted text or NULL in case of error or if {need_out} is
+ * not set. Modifies {base_dir} to reflect actual direction.
+ */
+static wchar_t* wchar_to_textmod_visual(wchar_t *in,unsigned int len,FriBidiCharType *base_dir, int need_out)
+{
+ FriBidiChar *out = NULL;
+ static void *handle = NULL;
+
+ fribidi_boolean (*func_ptr) (FriBidiChar *, FriBidiStrIndex,
+ FriBidiCharType *, FriBidiChar *,
+ FriBidiStrIndex *, FriBidiStrIndex *,
+ FriBidiLevel *);
+
+ if (!handle)
+ handle = dlopen("/usr/lib/libfribidi.so.0", RTLD_LAZY | RTLD_GLOBAL);
+ if (!handle)
+ handle = dlopen("/lib/libfribidi.so.0", RTLD_LAZY | RTLD_GLOBAL);
+ if (!handle)
+ return NULL;
+
+ func_ptr = dlsym(handle, "fribidi_log2vis");
+ if (!func_ptr) {
+ dlclose(handle);
+ handle = NULL;
+ return NULL;
+ }
+
+ if (need_out) {
+ out = (FriBidiChar *)malloc(sizeof(FriBidiChar)*(len+1));
+ if(!out)
+ {
+ dlclose(handle);
+ handle = NULL;
+ return (wchar_t *) out;
+ }
+
+ do_shaping(in, len);
+ len = wcsnlen(in, len);
+ }
+ (*func_ptr)(in, len, base_dir, out, NULL, NULL, NULL);
+
+ return (wchar_t *) out;
+}
+
+/*
+ * Converts text given in {str} from logical order to visual order.
+ * Uses {dir} as base direction ('N', 'R', 'L').
+ * Returns malloc'ed converted string. Modifies {dir} to reflect actual
+ * direction.
+ */
+static char *_newt_log2vis(const char *str, char *dir)
+{
+ wchar_t *wcs;
+ char *rstr = NULL;
+ int len = strlen(str);
+ int ret;
+ FriBidiCharType basedir;
+
+ switch (*dir)
+ {
+ case 'R': basedir = FRIBIDI_TYPE_R;
+ break;
+ case 'L': basedir = FRIBIDI_TYPE_L;
+ break;
+ default: basedir = FRIBIDI_TYPE_ON;
+ break;
+ }
+
+ if (len) {
+ wchar_t *owcs;
+ int newlen;
+
+ wcs = malloc(sizeof(*wcs) * (len + 1));
+ if (!wcs)
+ return NULL;
+ ret = mbstowcs(wcs, str, len + 1);
+ if (ret < 0) {
+ free(wcs);
+ return NULL;
+ }
+ owcs = wchar_to_textmod_visual(wcs, ret, &basedir, 1);
+ if (FRIBIDI_DIR_TO_LEVEL(basedir))
+ *dir = 'R';
+ else
+ *dir = 'L';
+
+ free(wcs);
+ if (!owcs)
+ return NULL;
+
+ newlen = wcstombs(NULL, owcs, 0);
+ if (newlen < 0) {
+ free(owcs);
+ return NULL;
+ }
+ rstr = malloc(newlen + 1);
+ if (!rstr) {
+ free(owcs);
+ return NULL;
+ }
+ ret = wcstombs(rstr, owcs, newlen + 1);
+ free(owcs);
+ if (ret < 0) {
+ free(rstr);
+ return NULL;
+ }
+ }
+ return rstr;
+}
+
+/* Returns base direction of text given in {str}.
+ */
+char get_text_direction(const char *str)
+{
+ int len = strlen(str);
+ char dir = 'N';
+ wchar_t *wcs;
+ int ret;
+
+ FriBidiCharType basedir = FRIBIDI_TYPE_ON;
+
+ if (len) {
+ wcs = malloc(sizeof(*wcs) * (len + 1));
+ if (!wcs)
+ return dir;
+ ret = mbstowcs(wcs, str, len + 1);
+ if (ret < 0) {
+ free(wcs);
+ return dir;
+ }
+ wchar_to_textmod_visual(wcs, ret, &basedir, 1);
+ free(wcs);
+ if (FRIBIDI_DIR_TO_LEVEL(basedir))
+ dir = 'R';
+ else
+ dir = 'L';
+ }
+ return dir;
+}
+
+/* If width of string {str} is less then {width} adds
+ * final spaces to make it {width} position wide.
+ * Returns malloc'ed padded string or NULL in case of errors
+ * or if string does not need padding.
+ */
+static char *pad_line(const char *str, int width)
+{
+ int len = strlen(str);
+ int w = _newt_wstrlen(str, len);
+
+ if (w < width) {
+ char *newstr = malloc(len + 1 + (width - w));
+ if (!newstr)
+ return NULL;
+ memcpy(newstr, str, len);
+ memset(newstr + len, ' ', width - w);
+ newstr[len+width-w] = '\0';
+ return newstr;
+ }
+ return NULL;
+}
+
+/*
+ * Writes string {str}. Uses {dir} as default direction.
+ * Returns direction of the string in {dir}.
+ */
+void write_string_int(const char *str, char *dir)
+{
+ char dummy;
+ char *tmpstr;
+
+ if (!dir) {
+ dummy = 'N';
+ dir = &dummy;
+ }
+
+ tmpstr = _newt_log2vis(str, dir);
+ if (tmpstr)
+ str = tmpstr;
+ SLsmg_write_string(str);
+ if (tmpstr)
+ free(tmpstr);
+}
+
+/* Writes at most {n} positions of the string {str}.
+ * Adds final (logical) spaces if string width is less than {n}.
+ * Uses {dir} as default direction.
+ * Returns direction of the string in {dir}
+ */
+void write_nstring_int(const char *str, int n, char *dir)
+{
+ char dummy;
+ char *tmpstr, *tmpstr1;
+
+ if (!dir) {
+ dummy = 'N';
+ dir = &dummy;
+ }
+
+ tmpstr1 = pad_line(str, n);
+ if (tmpstr1)
+ str = tmpstr1;
+ tmpstr = _newt_log2vis(str, dir);
+ if (tmpstr) {
+ free(tmpstr1);
+ str = tmpstr;
+ }
+ SLsmg_write_nstring(str, n);
+ if (tmpstr)
+ free(tmpstr);
+ else
+ free(tmpstr1);
+}
+#else
+void write_string_int(const char *str, char *dir)
+{
+ SLsmg_write_string(str);
+}
+
+void write_nstring_int(const char *str, int w, char *dir)
+{
+ SLsmg_write_nstring(str, w);
+}
+
+char get_text_direction(const char *str)
+{
+ return 'L';
+}
+#endif
+
struct Window {
int height, width, top, left;
SLsmg_Char_Type * buffer;
"blue", /* scale full */
"red", /* scale empty */
"blue", "lightgray", /* disabled entry fg, bg */
- "white", "blue", /* compact button fg, bg */
+ "black", "lightgray", /* compact button fg, bg */
"yellow", "red", /* active & sel listbox */
"black", "brown" /* selected listbox */
};
static const struct keymap keymap[] = {
- { "\033OA", NEWT_KEY_UP, "kh" },
- { "\033[A", NEWT_KEY_UP, "ku" },
+ { "\033OA", NEWT_KEY_UP, "ku" },
+ { "\020", NEWT_KEY_UP, NULL }, /* emacs ^P */
{ "\033OB", NEWT_KEY_DOWN, "kd" },
- { "\033[B", NEWT_KEY_DOWN, "kd" },
- { "\033[C", NEWT_KEY_RIGHT, "kr" },
+ { "\016", NEWT_KEY_DOWN, NULL }, /* emacs ^N */
{ "\033OC", NEWT_KEY_RIGHT, "kr" },
- { "\033[D", NEWT_KEY_LEFT, "kl" },
+ { "\006", NEWT_KEY_RIGHT, NULL }, /* emacs ^F */
{ "\033OD", NEWT_KEY_LEFT, "kl" },
- { "\033[H", NEWT_KEY_HOME, "kh" },
- { "\033[1~", NEWT_KEY_HOME, "kh" },
+ { "\002", NEWT_KEY_LEFT, NULL }, /* emacs ^B */
+ { "\033OH", NEWT_KEY_HOME, "kh" },
+ { "\033[1~", NEWT_KEY_HOME, NULL },
+ { "\001", NEWT_KEY_HOME, NULL }, /* emacs ^A */
{ "\033Ow", NEWT_KEY_END, "kH" },
- { "\033[4~", NEWT_KEY_END, "kH" },
+ { "\033[4~", NEWT_KEY_END, "@7" },
+ { "\005", NEWT_KEY_END, NULL }, /* emacs ^E */
- { "\033[3~", NEWT_KEY_DELETE, "kl" },
- { "\033[2~", NEWT_KEY_INSERT, NULL },
+ { "\033[3~", NEWT_KEY_DELETE, "kD" },
+ { "\004", NEWT_KEY_DELETE, NULL }, /* emacs ^D */
+ { "\033[2~", NEWT_KEY_INSERT, "kI" },
- { "\033\t", NEWT_KEY_UNTAB, NULL },
+ { "\033\t", NEWT_KEY_UNTAB, "kB" },
- { "\033[5~", NEWT_KEY_PGUP, NULL },
- { "\033[6~", NEWT_KEY_PGDN, NULL },
- { "\033V", NEWT_KEY_PGUP, "kH" },
- { "\033v", NEWT_KEY_PGUP, "kH" },
+ { "\033[5~", NEWT_KEY_PGUP, "kP" },
+ { "\033[6~", NEWT_KEY_PGDN, "kN" },
+ { "\033V", NEWT_KEY_PGUP, NULL },
+ { "\033v", NEWT_KEY_PGUP, NULL },
+ { "\026", NEWT_KEY_PGDN, NULL },
{ "\033[[A", NEWT_KEY_F1, NULL },
{ "\033[[B", NEWT_KEY_F2, NULL },
{ "\033OR", NEWT_KEY_F3, NULL },
{ "\033OS", NEWT_KEY_F4, NULL },
- { "\033[11~", NEWT_KEY_F1, NULL },
- { "\033[12~", NEWT_KEY_F2, NULL },
- { "\033[13~", NEWT_KEY_F3, NULL },
- { "\033[14~", NEWT_KEY_F4, NULL },
- { "\033[15~", NEWT_KEY_F5, NULL },
- { "\033[17~", NEWT_KEY_F6, NULL },
- { "\033[18~", NEWT_KEY_F7, NULL },
- { "\033[19~", NEWT_KEY_F8, NULL },
- { "\033[20~", NEWT_KEY_F9, NULL },
- { "\033[21~", NEWT_KEY_F10, NULL },
- { "\033[23~", NEWT_KEY_F11, NULL },
- { "\033[24~", NEWT_KEY_F12, NULL },
- { "\033", NEWT_KEY_ESCAPE, NULL },
-
+ { "\033[11~", NEWT_KEY_F1, "k1" },
+ { "\033[12~", NEWT_KEY_F2, "k2" },
+ { "\033[13~", NEWT_KEY_F3, "k3" },
+ { "\033[14~", NEWT_KEY_F4, "k4" },
+ { "\033[15~", NEWT_KEY_F5, "k5" },
+ { "\033[17~", NEWT_KEY_F6, "k6" },
+ { "\033[18~", NEWT_KEY_F7, "k7" },
+ { "\033[19~", NEWT_KEY_F8, "k8" },
+ { "\033[20~", NEWT_KEY_F9, "k9" },
+ { "\033[21~", NEWT_KEY_F10, "k;" },
+ { "\033[23~", NEWT_KEY_F11, "F1" },
+ { "\033[24~", NEWT_KEY_F12, "F2" },
+ { "\033", NEWT_KEY_ESCAPE, "@2" },
+ { "\033", NEWT_KEY_ESCAPE, "@9" },
+
+ { "\177", NEWT_KEY_BKSPC, NULL },
+ { "\010", NEWT_KEY_BKSPC, NULL },
+
{ 0 }, /* LEAVE this one */
};
-static char keyPrefix = '\033';
+static void initKeymap();
static const char ident[] = // ident friendly
"$Version: Newt windowing library v" VERSION " $"
return -1;
}
-int wstrlen(const char *str, int len) {
+int _newt_wstrlen(const char *str, int len) {
mbstate_t ps;
wchar_t tmp;
int nchars = 0;
return nchars;
}
+/** Trim a string to fit
+ * @param title - string. NULL will be inserted if necessary
+ * @param chrs - available space. (character cells)
+ */
+void trim_string(char *title, int chrs)
+{
+ char *p = title;
+ int ln = chrs;
+ int x = 0,y = 0;
+ wchar_t tmp;
+ mbstate_t ps;
+
+ memset(&ps, 0, sizeof(ps));
+
+ while (*p) {
+ x = mbrtowc(&tmp, p, ln, &ps);
+ if (x < 0) { // error
+ *p = '\0';
+ return;
+ }
+ y = wcwidth(tmp);
+ if (y > ln) {
+ *p = '\0';
+ return;
+ } else {
+ p += x;
+ ln -= y;
+ }
+ }
+}
+
static int getkey() {
int c;
SLtt_get_terminfo();
SLtt_get_screen_size();
+ // there is no such function in slang?!
+ // SLutf8_enable(-1); /* init. utf8 according to locale */
MonoValue = getenv(MonoEnv);
if ( MonoValue == NULL ) {
newtSetColors(newtDefaultColorPalette);
newtCursorOff();
- /*initKeymap();*/
+ initKeymap();
/*memset(&sa, 0, sizeof(sa));
sa.sa_handler = handleSigwinch;
colors.selListboxBg);
}
+/* Keymap handling - rewritten by Henning Makholm <henning@makholm.net>,
+ * November 2003.
+ */
+
+struct kmap_trie_entry {
+ char c ; /* character got from terminal */
+ int code; /* newt key, or 0 if c does not make a complete sequence */
+ struct kmap_trie_entry *contseq; /* sub-trie for character following c */
+ struct kmap_trie_entry *next; /* try this if char received != c */
+};
+/* Here are some static entries that will help in handling esc O foo and
+ esc [ foo as variants of each other: */
+static struct kmap_trie_entry
+ kmap_trie_escO = { 'O', 0, 0, 0 },
+ kmap_trie_escBrack = { '[', 0, 0, &kmap_trie_escO },
+ kmap_trie_root = { '\033', 0, &kmap_trie_escBrack, 0 };
+static int keyreader_buf_len = 10 ;
+static unsigned char default_keyreader_buf[10];
+static unsigned char *keyreader_buf = default_keyreader_buf;
+
+#if 0 /* for testing of the keymap manipulation code */
+static void dumpkeys_recursive(struct kmap_trie_entry *curr, int i, FILE *f) {
+ int j, ps ;
+ char seen[256]={0};
+ if( curr && i >= keyreader_buf_len ) {
+ fprintf(f,"ARGH! Too long sequence!\n") ;
+ return ;
+ }
+ for(;curr;curr=curr->next) {
+ keyreader_buf[i] = curr->c ;
+ ps = seen[(unsigned char)curr->c]++ ;
+ if( ps || curr->code || (!curr->code && !curr->contseq) ) {
+ for(j=0;j<=i;j++) {
+ if( keyreader_buf[j] > 32 && keyreader_buf[j]<127 &&
+ keyreader_buf[j] != '^' && keyreader_buf[j] != '\\' )
+ fprintf(f,"%c",keyreader_buf[j]);
+ else if( keyreader_buf[j] > 0 && keyreader_buf[j]<=32 )
+ fprintf(f,"^%c",keyreader_buf[j] + 0x40);
+ else
+ fprintf(f,"\\%03o",
+ (unsigned)(unsigned char)keyreader_buf[j]);
+ }
+ if( curr->code )
+ fprintf(f,": 0x%X\n",curr->code);
+ else
+ fprintf(f,": (just keymap)\n");
+ }
+ dumpkeys_recursive(curr->contseq,i+1,f);
+ }
+}
+static void dump_keymap(void) {
+ FILE *f = fopen("newt.keydump","wt");
+ if (f) {
+ dumpkeys_recursive(&kmap_trie_root,0,f);
+ fclose(f);
+ }
+}
+#endif
+
+/* newtBindKey may overwrite a binding that is there already */
+static void newtBindKey(char *keyseq, int meaning) {
+ struct kmap_trie_entry *root = &kmap_trie_root ;
+ struct kmap_trie_entry **curptr = &root ;
+
+ /* Try to make sure the common matching buffer is long enough. */
+ if( strlen(keyseq) > keyreader_buf_len ) {
+ int i = strlen(keyseq)+10;
+ unsigned char *newbuf = malloc(i);
+ if (newbuf) {
+ if (keyreader_buf != default_keyreader_buf)
+ free(keyreader_buf);
+ keyreader_buf = newbuf;
+ keyreader_buf_len = i;
+ }
+ }
+
+ if (*keyseq == 0) return; /* binding the empty sequence is meaningless */
+
+ while(1) {
+ while ((*curptr) && (*curptr)->c != *keyseq)
+ curptr = &(*curptr)->next;
+ if ((*curptr)==0) {
+ struct kmap_trie_entry* fresh
+ = calloc(strlen(keyseq),sizeof(struct kmap_trie_entry));
+ if (fresh == 0) return; /* despair! */
+ *curptr = fresh;
+ while (keyseq[1]) {
+ fresh->contseq = fresh+1;
+ (fresh++)->c = *(keyseq++);
+ }
+ fresh->c = *keyseq;
+ fresh->code = meaning;
+ return;
+ }
+ if (keyseq[1]==0) {
+ (*curptr)->code = meaning;
+ return;
+ } else {
+ curptr = &(*curptr)->contseq;
+ keyseq++;
+ }
+ }
+}
+
+/* This function recursively inserts all entries in the "to" trie into
+ corresponding positions in the "from" trie, except positions that
+ are already defined in the "from" trie. */
+static void kmap_trie_fallback(struct kmap_trie_entry *to,
+ struct kmap_trie_entry **from) {
+ if (*from == NULL)
+ *from = to ;
+ if (*from == to)
+ return ;
+ for (;to!=NULL;to=to->next) {
+ struct kmap_trie_entry **fromcopy = from ;
+ while ((*fromcopy) && (*fromcopy)->c != to->c)
+ fromcopy = &(*fromcopy)->next ;
+ if (*fromcopy) {
+ if ((*fromcopy)->code == 0)
+ (*fromcopy)->code = to->code;
+ kmap_trie_fallback(to->contseq, &(*fromcopy)->contseq);
+ } else {
+ *fromcopy = malloc(sizeof(struct kmap_trie_entry));
+ if (*fromcopy) {
+ **fromcopy = *to ;
+ (*fromcopy)->next = 0 ;
+ }
+ }
+ }
+}
+
int newtGetKey(void) {
int key;
- char buf[10], * chptr = buf;
- const struct keymap * curr;
+ unsigned char *chptr = keyreader_buf, *lastmatch;
+ int lastcode;
+ struct kmap_trie_entry *curr = &kmap_trie_root;
do {
key = getkey();
suspendCallback(suspendCallbackData);
} while (key == NEWT_KEY_SUSPEND);
- switch (key) {
- case 'v' | 0x80:
- case 'V' | 0x80:
- return NEWT_KEY_PGUP;
-
- case 22:
- return NEWT_KEY_PGDN;
-
- return NEWT_KEY_BKSPC;
- case 0x7f:
- return NEWT_KEY_BKSPC;
-
- case 0x08:
- return NEWT_KEY_BKSPC;
-
- default:
- if (key != keyPrefix) return key;
- }
-
- memset(buf, 0, sizeof(buf));
-
- *chptr++ = key;
- while (SLang_input_pending(5)) {
- key = getkey();
- if (key == keyPrefix) {
- /* he hit unknown keys too many times -- start over */
- memset(buf, 0, sizeof(buf));
- chptr = buf;
- }
-
- *chptr++ = key;
-
- /* this search should use bsearch(), but when we only look through
- a list of 20 (or so) keymappings, it's probably faster just to
- do a inline linear search */
-
- for (curr = keymap; curr->code; curr++) {
- if (curr->str) {
- if (!strcmp(curr->str, buf))
- return curr->code;
- }
- }
- }
-
- for (curr = keymap; curr->code; curr++) {
- if (curr->str) {
- if (!strcmp(curr->str, buf))
- return curr->code;
- }
+ /* Read more characters, matching against the trie as we go */
+ lastcode = *chptr = key;
+ lastmatch = chptr ;
+ while(1) {
+ while (curr->c != key) {
+ curr = curr->next ;
+ if (curr==NULL) goto break2levels;
+ }
+ if (curr->code) {
+ lastcode = curr->code;
+ lastmatch = chptr;
+ }
+ curr = curr->contseq;
+ if (curr==NULL) break;
+
+ if (SLang_input_pending(5) <= 0)
+ break;
+
+ if (chptr==keyreader_buf+keyreader_buf_len-1) break;
+ *++chptr = key = getkey();
}
-
- /* Looks like we were a bit overzealous in reading characters. Return
- just the first character, and put everything else back in the buffer
- for later */
-
- chptr--;
- while (chptr > buf)
- SLang_ungetkey(*chptr--);
-
- return *chptr;
+ break2levels:
+
+ /* The last time the trie matched was at position lastmatch. Back
+ * up if we have read too many characters. */
+ while (chptr > lastmatch)
+ SLang_ungetkey(*chptr--);
+
+ return lastcode;
}
/**
* @param title - title string
* @return zero on success (currently no errors reported)
*/
-int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
+int newtOpenWindow(unsigned int left, unsigned int top,
+ unsigned int width, unsigned int height,
const char * title) {
int j, row, col;
int n;
newtTrashScreen();
SLsmg_set_color(NEWT_COLORSET_BORDER);
+ SLsmg_set_char_set(1);
SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
+ SLsmg_set_char_set(0);
if (currentWindow->title) {
+ trim_string (currentWindow->title, width-4);
i = wstrlen(currentWindow->title,-1) + 4;
i = ((width - i) / 2) + left;
SLsmg_gotorc(top - 1, i);
SLsmg_set_char_set(0);
SLsmg_write_char(' ');
SLsmg_set_color(NEWT_COLORSET_TITLE);
- SLsmg_write_string((char *)currentWindow->title);
+ write_string_int((char *)currentWindow->title, NULL);
SLsmg_set_color(NEWT_COLORSET_BORDER);
SLsmg_write_char(' ');
SLsmg_set_char_set(1);
* @param title - fixed title
* @returns 0. No errors reported
*/
-int newtCenteredWindow(unsigned width, unsigned height, const char * title) {
- unsigned top, left;
+int newtCenteredWindow(unsigned int width,unsigned int height,
+ const char * title) {
+ unsigned int top, left;
top = (SLtt_Screen_Rows - height) / 2;
SLsmg_fill_region(top, left, height, width, ' ');
}
-#if 0
-/* This doesn't seem to work quite right. I don't know why not, but when
- I rsh from an rxvt into a box and run this code, the machine returns
- console key's (\033[B) rather then xterm ones (\033OB). */
static void initKeymap(void) {
- struct keymap * curr;
+ const struct keymap * curr;
+ /* First bind built-in default bindings. They may be shadowed by
+ the termcap entries that get bound later. */
for (curr = keymap; curr->code; curr++) {
- if (!curr->str)
- curr->str = SLtt_tgetstr(curr->tc);
+ if (curr->str)
+ newtBindKey(curr->str,curr->code);
}
- /* Newt's keymap handling is a bit broken. It assumes that any extended
- keystrokes begin with ESC. If you're using a homebrek terminal you
- will probably need to fix this, or just yell at me and I'll be so
- ashamed of myself for doing it this way I'll fix it */
+ /* Then bind strings from termcap entries */
+ for (curr = keymap; curr->code; curr++) {
+ if (curr->tc) {
+ char *pc = SLtt_tgetstr(curr->tc);
+ if (pc) {
+ newtBindKey(pc,curr->code);
+ }
+ }
+ }
- keyPrefix = 0x1b; /* ESC */
+ /* Finally, invent lowest-priority keybindings that correspond to
+ searching for esc-O-foo if esc-[-foo was not found and vice
+ versa. That is needed because of strong confusion among
+ different emulators of VTxxx terminals; some terminfo/termcap
+ descriptions are apparently written by people who were not
+ aware of the differences between "applicataion" and "terminal"
+ keypad modes. Or perhaps they were, but tried to make their
+ description work with a program that puts the keyboard in the
+ wrong emulation mode. In short, one needs this: */
+ kmap_trie_fallback(kmap_trie_escO.contseq, &kmap_trie_escBrack.contseq);
+ kmap_trie_fallback(kmap_trie_escBrack.contseq, &kmap_trie_escO.contseq);
}
-#endif
/**
* @brief Delay for a specified number of usecs
* @param int - number of usecs to wait for.
*/
-void newtDelay(unsigned usecs) {
+void newtDelay(unsigned int usecs) {
fd_set set;
struct timeval tv;
buf[SLtt_Screen_Cols] = '\0';
}
SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
- SLsmg_write_string(buf);
+ write_string_int(buf, NULL);
}
void newtPushHelpLine(const char * text) {
}
SLsmg_gotorc(row, col);
- SLsmg_write_string((char *)text);
+ write_string_int((char *)text, NULL);
}
int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) {
Summary: A development library for text mode user interfaces.
Name: newt
-Version: 0.51.7
-Release: 2
+%define version 0.52.0
+Version: %{version}
+Release: 0
License: LGPL
Group: System Environment/Libraries
Source: newt-%{version}.tar.gz
-BuildRequires: python,python-devel,perl, slang-devel
+Patch1: newt-0.51.6-if1close.patch
+BuildRequires: python,python-devel,perl, slang-devel, tcl-devel
Requires: slang
Provides: snack
BuildRoot: %{_tmppath}/%{name}-%{version}-root
%prep
%setup -q
+%patch1 -p1 -b .if1close
%build
# gpm support seems to smash the stack w/ we use help in anaconda??
#./configure --with-gpm-support
%configure
+make depend
make %{?_smp_mflags} all
chmod 0644 peanuts.py popcorn.py
%files
%defattr (-,root,root)
-%doc CHANGES COPYING
+%doc COPYING
%{_bindir}/whiptail
%{_libdir}/libnewt.so.*
+%{_libdir}/whiptcl.so
%{_libdir}/python%{pythonver}/site-packages/*
%files devel
%{_libdir}/libnewt.so
%changelog
-* Thu Apr 8 2004 Adrian Havill <havill@redhat.com> 0.51.7-2
-- incorporated some debian memcheck fixes, whiptail features
-- change .spec to not use hardcoded python version much like up2date (#114419)
+* Wed Sep 21 2005 Petr Rockai <prockai@redhat.com> - 0.52.0-0
+- new upstream version
-* Fri Dec 5 2003 Jeremy Katz <katzj@redhat.com> 0.51.7-1
-- rebuild against new slang
+* Fri Sep 02 2005 Petr Rockai <prockai@redhat.com>
+- use versioned symbols, patch by Alastair McKinstry, mckinstry at
+ debian dot org, thanks
+- need private wstrlen due to versioned syms, patch from debian
+ package of newt
+- both of the above needed to be forward-ported
-* Mon Nov 17 2003 Nalin Dahyabhai <nalin@redhat.com>
-- fix newtCheckboxGetValue not working if checkbox created with non-NULL result
+* Sun Mar 06 2005 Petr Rockai <prockai@redhat.com>
+- rebuild
+
+* Mon Nov 8 2004 Jeremy Katz <katzj@redhat.com> - 0.51.6-6
+- rebuild for python 2.4
+
+* Fri Oct 15 2004 Adrian Havill <havill@redhat.com> 0.51.6-5
+- only do gpmclose if gpmopen succeeed (#118530)
+
+* Thu Oct 14 2004 Adrian Havill <havill@redhat.com> 0.51.6-4
+- make the python version dynamic (#114419)
+
+* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Tue Mar 02 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
* Thu Nov 6 2003 Jeremy Katz <katzj@redhat.com> 0.51.6-2
- rebuild for python 2.3
struct eventResult newtDefaultEventHandler(newtComponent c,
struct event ev);
-int wstrlen(const char *str, int len);
+int _newt_wstrlen(const char *str, int len);
+void write_string_int(const char *, char *);
+void write_nstring_int(const char *, int, char *);
+char get_text_direction(const char *);
+
+#define wstrlen(str,len) _newt_wstrlen((str),(len))
#endif /* H_NEWT_PR */
--- /dev/null
+
+
+#ifndef LOCALEDIR
+#define LOCALEDIR "/usr/share/locale"
+#endif
+
+# include <locale.h>
+
+# include <libintl.h>
+# define _(Text) gettext (Text)
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+
"F4" : _snack.KEY_F4, "F5" : _snack.KEY_F5, "F6" : _snack.KEY_F6,
"F7" : _snack.KEY_F7, "F8" : _snack.KEY_F8, "F9" : _snack.KEY_F9,
"F10" : _snack.KEY_F10, "F11" : _snack.KEY_F11,
- "F12" : _snack.KEY_F12, " " : ord(" ") }
+ "F12" : _snack.KEY_F12, "ESC" : _snack.KEY_ESC , " " : ord(" ") }
for n in hotkeys.keys():
hotkeys[hotkeys[n]] = n
def setCurrent(self, item):
self.listbox.setCurrent(item)
- def clear(self):
- self.listbox.clear()
+ def clear(self):
+ self.listbox.clear()
#include <unistd.h>
#include "Python.h"
+#include "nls.h"
#include "newt.h"
#include "newt_pr.h"
void init_snack(void) {
PyObject * d, * m;
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
m = Py_InitModule("_snack", snackModuleMethods);
d = PyModule_GetDict(m);
PyDict_SetItemString(d, "KEY_F10", PyInt_FromLong(NEWT_KEY_F10));
PyDict_SetItemString(d, "KEY_F11", PyInt_FromLong(NEWT_KEY_F11));
PyDict_SetItemString(d, "KEY_F12", PyInt_FromLong(NEWT_KEY_F12));
+ PyDict_SetItemString(d, "KEY_ESC", PyInt_FromLong(NEWT_KEY_ESCAPE));
PyDict_SetItemString(d, "FLAG_DISABLED", PyInt_FromLong(NEWT_FLAG_DISABLED));
PyDict_SetItemString(d, "FLAGS_SET", PyInt_FromLong(NEWT_FLAGS_SET));
tb = malloc(sizeof(*tb));
co->data = tb;
+ if (width < 2) width = 2;
+
co->ops = &textboxOps;
co->height = height;
int i;
struct textbox * tb = c->data;
int size;
-
+ char dir = 'N';
+ int newdir = 1;
+ int dw = 0;
+
if (tb->sb) {
size = tb->numLines - c->height;
newtScrollbarSet(tb->sb, tb->topLine, size ? size : 0);
tb->sb->ops->draw(tb->sb);
+ dw = 2;
}
SLsmg_set_color(NEWT_COLORSET_TEXTBOX);
+ /* find direction of first visible paragraph */
+ for (i = 0; i < tb->topLine; i++) {
+ if (!*tb->lines[i]) {
+ /* new line: new paragraph starts at the next line */
+ newdir = 1;
+ dir = 'N';
+ }
+ else if (newdir) {
+ /* get current paragraph direction, if possible */
+ dir = get_text_direction(tb->lines[i]);
+ newdir = (dir == 'N') ? 1 : 0;
+ }
+ }
+
for (i = 0; (i + tb->topLine) < tb->numLines && i < c->height; i++) {
newtGotorc(c->top + i, c->left);
SLsmg_write_string(tb->blankline);
newtGotorc(c->top + i, c->left);
- SLsmg_write_string(tb->lines[i + tb->topLine]);
+ /* BIDI: we need *nstring* here to properly align lines */
+ write_nstring_int(tb->lines[i + tb->topLine], c->width - dw, &dir);
+ /* Does new paragraph follow? */
+ if (!*tb->lines[i + tb->topLine])
+ dir = 'N';
}
}
--- /dev/null
+.TH WHIPTAIL 1 "20 September 2004" "Whiptail Version 0.51.6"
+.SH NAME
+whiptail \- display dialog boxes from shell scripts
+.SH SYNOPSIS
+.B whiptail
+[
+.B \-\-title
+.I title
+]
+[
+.B \-\-backtitle
+.I backtitle
+]
+[
+.B \-\-clear
+]
+[
+.B \-\-default\-item
+.I string
+]
+[
+.B \-\-defaultno
+]
+[
+.B \-\-fb
+]
+[
+.B \-\-nocancel
+]
+[
+.B \-\-noitem
+[
+]
+.B \-\-output\-fd
+.I fd
+]
+[
+.B \-\-separate\-output
+]
+[
+.B \-\-scrolltext
+]
+.B box-options
+.SH DESCRIPTION
+.B whiptail
+is a program that will let you present a variety of questions or
+display messages using dialog boxes from a shell script. Currently,
+these types of dialog boxes are implemented:
+.LP
+.BR yes/no " box," " menu" " box," " input" " box,"
+.BR message " box," " text" " box," " info" " box,"
+.BR checklist " box," " radiolist" " box" " gauge" " box, and"
+.BR password " box."
+.SH OPTIONS
+.TP
+.B \-\-clear
+The screen will be cleared to the
+.BR "screen attribute" " on exit."
+This doesn't work in an xterm (and descendants) if alternate screen
+switching is enabled, because in that case slang writes to (and clears)
+an alternate screen.
+.TP
+.B \-\-defaultno
+The dialog box will open with the cursor over the
+.BR No " button."
+.TP
+.B \-\-default\-item "string"
+Set the default item in a menu box.
+Normally the first item in the box is the default.
+.TP
+.B \-\-fb
+Use full buttons. (By default,
+.B whiptail
+uses compact buttons).
+.TP
+.B \-\-nocancel
+The dialog box won't have a
+.BR Cancel " button".
+.TP
+.B \-\-noitem
+The menu, checklist and radiolist widgets will display tags only, not
+the item strings.
+.TP
+.BI \-\-separate\-output
+For checklist widgets, output result one line at a time, with no
+quoting. This facilitates parsing by another program.
+.TP
+.BI \-\-output\-fd " fd"
+Direct output to the given file descriptor. Most
+.B whiptail
+scripts
+write to standard error, but error messages may also be
+written there, depending on your script.
+.TP
+.BI \-\-title " title"
+Specifies a
+.I title
+string to be displayed at the top of the dialog box.
+.TP
+.BI \-\-backtitle " backtitle"
+Specifies a
+.I backtitle
+string to be displayed on the backdrop, at the top of the screen.
+.TP
+.BI \-\-scrolltext
+Force the display of a vertical scrollbar.
+.TP
+.B Box Options
+.TP
+.BI \-\-yesno " text height width"
+.RB A " yes/no" " dialog box of size"
+.I height
+rows by
+.I width
+columns will be displayed. The string specified by
+.I text
+is displayed inside the dialog box. If this string is too long to be fit
+in one line, it will be automatically divided into multiple lines at
+appropriate places. The
+.I text
+string may also contain the sub-string
+.I
+"\en"
+or newline characters
+.I `\en'
+to control line breaking explicitly. This dialog box is useful for
+asking questions that require the user to answer either yes or no.
+.RB "The dialog box has a" " Yes" " button and a " No
+button, in which the user can switch between by pressing the
+.IR TAB " key."
+.TP
+.BI \-\-msgbox " text height width"
+.RB A " message" " box is very similar to a" " yes/no" " box."
+The only difference between a
+.B message
+box and a
+.B yes/no
+box is that a
+.B message
+box has only a single
+.B OK
+button. You can use this dialog box to display any message you like.
+After reading the message, the user can press the
+.I ENTER
+key so that
+.B whiptail
+will exit and the calling shell script can continue its operation.
+.TP
+.BI \-\-infobox " text height width"
+.RB An " info" " box is basically a" " message" " box."
+However, in this case,
+.B whiptail
+will exit immediately after displaying the message to the user. The
+screen is not cleared when
+.B whiptail
+exits, so that the message will remain on the screen until the calling
+shell script clears it later. This is useful when you want to inform
+the user that some operations are carrying on that may require some
+time to finish.
+.TP
+.BI \-\-inputbox " text height width [init]"
+.RB "An " input " box is useful when you want to ask questions that"
+require the user to input a string as the answer. If init is supplied
+it is used to initialize the input string.
+When inputing the
+string, the
+.I BACKSPACE
+key can be used to correct typing errors. If the input string is longer than
+the width of the dialog box, the input field will be scrolled. On exit,
+the input string will be printed on
+.IR stderr "."
+.TP
+.BI \-\-passwordbox " text height width [init]"
+.RB "A " password " box is similar to an input box, except the text the user"
+enters is not displayed. This is useful when prompting for passwords or other
+sensitive information. Be aware that if anything is passed in "init", it
+will be visible in the system's process table to casual snoopers. Also, it
+is very confusing to the user to provide them with a default password they
+cannot see. For these reasons, using "init" is highly discouraged.
+.TP
+.BI \-\-textbox " file height width"
+.RB A " text" " box lets you display the contents of a text file in a"
+dialog box. It is like a simple text file viewer. The user can move
+through the file by using the
+.IR UP/DOWN ", " PGUP/PGDN
+.RI and " HOME/END" " keys available on most keyboards."
+If the lines are too long to be displayed in the box, the
+.I LEFT/RIGHT
+keys can be used to scroll the text region horizontally. For more
+convenience, forward and backward searching functions are also provided.
+.IP "\fB\-\-menu \fItext height width menu-height \fR[ \fItag item \fR] \fI..."
+As its name suggests, a
+.B menu
+box is a dialog box that can be used to present a list of choices in
+the form of a menu for the user to choose. Each menu entry consists of a
+.IR tag " string and an " item " string. The"
+.I tag
+gives the entry a name to distinguish it from the other entries in the
+menu. The
+.I item
+is a short description of the option that the entry represents. The
+user can move between the menu entries by pressing the
+.I UP/DOWN
+keys, the first letter of the
+.I tag
+as a hot-key. There are
+.I menu-height
+entries displayed in the menu at one time, but the menu will be
+scrolled if there are more entries than that. When
+.B whiptail
+exits, the
+.I tag
+of the chosen menu entry will be printed on
+.IR stderr "."
+.IP "\fB\-\-checklist \fItext height width list-height \fR[ \fItag item status \fR] \fI..."
+.RB "A " checklist " box is similar to a " menu " box in that there are"
+multiple entries presented in the form of a menu.
+You can select and deselect items using the SPACE key.
+The initial on/off state of each entry is specified by
+.IR status "."
+On exit, a list of the
+.I tag
+strings of those entries that are turned on will be printed on
+.IR stderr "."
+
+.IP "\fB\-\-radiolist \fItext height width list-height \fR [ \fItag item status \fR] \fI..."
+.RB "A " radiolist " box is similar to a " menu " box. The only difference is"
+that you can indicate which entry is currently selected, by setting its
+.IR status " to " on "."
+
+.IP "\fB\-\-gauge \fItext height width percent\fR"
+.RB "A " gauge " box displays a meter along the bottom of the box.
+The meter indicates a percentage. New percentages are read from
+standard input, one integer per line. The meter is updated
+to reflect each new percentage. If stdin is XXX, then subsequent
+lines up to another XXX are used for a new prompt.
+The gauge exits when EOF is reached on stdin.
+
+.SH NOTES
+whiptail interprets arguments starting with a dash "\-" as being arguments.
+To avoid this, and start some text in, for example, a menubox item, with a
+dash, whiptail honours the getopt convention of accepting the special
+argument "\-\-" which means that all following arguments with dashes are to
+be treated verbatim and not parsed as options.
+.SH DIAGNOSTICS
+Exit status is 0 if
+.BR whiptail " is exited by pressing the " Yes " or " OK
+button, and 1 if the
+.BR No " or " Cancel
+button is pressed. Otherwise, if errors occur inside
+.B whiptail
+or
+.B whiptail
+is exited by pressing the
+.I ESC
+key, the exit status is -1.
+.SH AUTHOR
+Based on the man page for dialog(1) by:
+.LP
+Savio Lam (lam836@cs.cuhk.hk) - version 0.3
+.LP
+Stuart Herbert (S.Herbert@sheffield.ac.uk) - patch for version 0.4
+.LP
+Modifications for whiptail by:
+.LP
+Enrique Zanardi (ezanard@debian.org)
+.LP
+Alastair McKinstry (mckinstry@debian.org)
-/* a reasonable dialog */
-
+#include "config.h"
#include <fcntl.h>
#include <popt.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <signal.h>
#include <unistd.h>
+#include <wchar.h>
+#include <slang.h>
+#include "nls.h"
#include "dialogboxes.h"
#include "newt.h"
+#include "newt_pr.h"
+
+enum { NO_ERROR = 0, WAS_ERROR = 1 };
enum mode { MODE_NONE, MODE_INFOBOX, MODE_MSGBOX, MODE_YESNO, MODE_CHECKLIST,
- MODE_INPUTBOX, MODE_RADIOLIST, MODE_MENU, MODE_GAUGE,
- MODE_TEXTBOX };
+ MODE_INPUTBOX, MODE_RADIOLIST, MODE_MENU, MODE_GAUGE ,
+ MODE_TEXTBOX, MODE_PASSWORDBOX};
#define OPT_MSGBOX 1000
#define OPT_CHECKLIST 1001
#define OPT_RADIOLIST 1006
#define OPT_GAUGE 1007
#define OPT_INFOBOX 1008
-#define OPT_TEXTBOX 1009
+#define OPT_TEXTBOX 1009
+#define OPT_PASSWORDBOX 1010
+
+static void usage(int err) {
+ newtFinished();
+ fprintf (err ? stderr : stdout,
+ _("Box options: \n"
+ "\t--msgbox <text> <height> <width>\n"
+ "\t--yesno <text> <height> <width>\n"
+ "\t--infobox <text> <height> <width>\n"
+ "\t--inputbox <text> <height> <width> [init] \n"
+ "\t--passwordbox <text> <height> <width> [init] \n"
+ "\t--textbox <file> <height> <width>\n"
+ "\t--menu <text> <height> <width> <listheight> [tag item] ...\n"
+ "\t--checklist <text> <height> <width> <listheight> [tag item status]...\n"
+ "\t--radiolist <text> <height> <width> <listheight> [tag item stautus]...\n"
+ "\t--gauge <text> <height> <width> <percent>\n"
+ "Options: (depend on box-option)\n"
+ "\t--clear clear screen on exit\n"
+ "\t-defaultno default no button\n"
+ "\t--default-item <string> set default string\n"
+ "\t--fb use full buttons\n"
+ "\t--nocancel no cancel button\n"
+ "\t--noitem display tags only\n"
+ "\t--separate-output <fd> output one line at a time\n"
+ "\t--output-fd <fd> output to fd, not stdout\n"
+ "\t--title <title> display title\n"
+ "\t--backtitle <backtitle> display backtitle\n"
+ "\t--scrolltext force verical scrollbars\n\n"));
+ exit(err ? DLG_ERROR : 0 );
+}
+
+static void print_version(void) {
+ fprintf (stdout, _("whiptail (newt): %s\n"), VERSION);
+}
+
+static void handleSighup(int signum) {
+ exit(DLG_ERROR);
+}
+
+#if 0
+/* FIXME Copied from newt.c
+ * Place somewhere better -- dialogboxes? -- amck
+ */
+int wstrlen(const char *str, int len) {
+ mbstate_t ps;
+ wchar_t tmp;
+ int nchars = 0;
+
+ if (!str) return 0;
+ if (!len) return 0;
+ if (len < 0) len = strlen(str);
+ memset(&ps,0,sizeof(mbstate_t));
+ while (len > 0) {
+ int x,y;
+
+ x = mbrtowc(&tmp,str,len,&ps);
+ if (x >0) {
+ str += x;
+ len -= x;
+ y = wcwidth(tmp);
+ if (y>0)
+ nchars+=y;
+ } else break;
+ }
+ return nchars;
+}
+#endif
+
+/*
+ * The value of *width is increased if it is not as large as the width of
+ * the line.
+ */
+static const char * lineWidth(int * width, const char * line, int *chrs)
+{
+ const char * s = line;
+
+ if ( line == NULL )
+ return 0;
+
+ while ( *s != '\0' && *s != '\n' )
+ s++;
+
+ if ( *s == '\n' )
+ s++;
+
+ *chrs = _newt_wstrlen (line, s - line );
+ *width = max(*width, *chrs);
-static void usage(void) {
- newtFinished();
- fprintf(stderr, "whiptail: bad parameters (see man whiptail(1) for details)\n");
- exit(DLG_ERROR);
+ return s;
+}
+
+
+/*
+ * cleanNewlines
+ * Handle newlines in text. Hack.
+ */
+void cleanNewlines (char *text)
+{
+ char *p = text;
+ while (*p) {
+ if ((*p == '\\') && (*(p+1) == 'n')) {
+ *p = '\n';
+ *(p+1) = ' ';
+ } else {
+ p++;
+ }
+ }
+}
+
+/*
+ * The height of a text string is added to height, and width is increased
+ * if it is not big enough to store the text string.
+ */
+static const char * textSize(int * height, int * width,
+ int maxWidth,
+ const char * text)
+{
+ int h = 0;
+ int w = 0;
+ int chrs = 0;
+
+
+ if ( text == NULL )
+ return 0;
+
+ while ( *text != '\0' ) {
+ h++;
+ text = lineWidth(width, text, &chrs);
+ /* Allow for text overflowing. May overestimate a bit */
+ h += chrs / maxWidth;
+ }
+
+ h += 2;
+ w += 2;
+
+ *height += h;
+ *width += w;
+
+ *width = min(*width, maxWidth);
+ return text;
+}
+
+/*
+ * Add space for buttons.
+ * NOTE: when this is internationalized, the button width might change.
+ */
+static void spaceForButtons(int * height, int * width, int count, int full) {
+ /* Make space for the buttons */
+ if ( full ) {
+ *height += 4;
+ if ( count == 1 )
+ *width = max(*width, 7);
+ else
+ *width = max(*width, 20);
+ }
+ else {
+ *height += 2;
+ if ( count == 1 )
+ *width = max(*width, 7);
+ else
+ *width = max(*width, 19);
+ }
+}
+
+static int menuSize(int * height, int * width, enum mode mode,
+ poptContext options) {
+ char ** argv = poptGetArgs(options);
+ char * * items = argv;
+ int h = 0;
+ int tagWidth = 0;
+ int descriptionWidth = 0;
+ int overhead = 10;
+ static char buf[20];
+
+ if ( argv == 0 || *argv == 0 )
+ return 0;
+
+ argv++;
+ if ( mode == MODE_MENU )
+ overhead = 5;
+
+ while ( argv[0] != 0 && argv[1] ) {
+ tagWidth = max(tagWidth, strlen(argv[0]));
+ descriptionWidth = max(descriptionWidth, strlen(argv[1]));
+
+ if ( mode == MODE_MENU )
+ argv += 2;
+ else
+ argv += 3;
+ h++;
+ }
+
+ *width = max(*width, tagWidth + descriptionWidth + overhead);
+ *width = min(*width, SLtt_Screen_Cols);
+
+ h = min(h, SLtt_Screen_Rows - *height - 4);
+ *height = *height + h + 1;
+ sprintf(buf, "%d", h);
+ *items = buf;
+ return 0;
+}
+
+/*
+ * Guess the size of a window, given what will be displayed within it.
+ */
+static void guessSize(int * height, int * width, enum mode mode,
+ int * flags, int fullButtons,
+ const char * title, const char * text,
+ poptContext options) {
+
+ int w = 0, h = 0, chrs = 0;
+
+ textSize(&h, &w, SLtt_Screen_Cols -4 , text); /* Width and height for text */
+ lineWidth(&w, title, &chrs); /* Width for title */
+
+ if ( w > 0 )
+ w += 4;
+
+ switch ( mode ) {
+ case MODE_CHECKLIST:
+ case MODE_RADIOLIST:
+ case MODE_MENU:
+ spaceForButtons(&h, &w, *flags & FLAG_NOCANCEL ? 1 : 2,
+ fullButtons);
+ menuSize(&h, &w, mode, options);
+ break;
+ case MODE_YESNO:
+ case MODE_MSGBOX:
+ spaceForButtons(&h, &w, 1, fullButtons);
+ break;
+ case MODE_INPUTBOX:
+ spaceForButtons(&h, &w, *flags & FLAG_NOCANCEL ? 1 : 2,
+ fullButtons);
+ h += 1;
+ break;
+ case MODE_GAUGE:
+ h += 2;
+ break;
+ case MODE_NONE:
+ break;
+ default:
+ break;
+ };
+
+ /*
+ * Fixed window-border overhead.
+ * NOTE: This will change if we add a way to turn off drop-shadow and/or
+ * box borders. That would be desirable for display-sized screens.
+ */
+ w += 2;
+ h += 2;
+
+ if ( h > SLtt_Screen_Rows - 1 ) {
+ h = SLtt_Screen_Rows - 1;
+ *flags |= FLAG_SCROLL_TEXT;
+ w += 2; /* Add width of slider - is this right? */
+ }
+
+ *width = min(max(*width, w), SLtt_Screen_Cols);
+ *height = max(*height, h);
}
char *
}
if ( (buf = malloc(s.st_size)) == 0 )
- fprintf(stderr, "%s: too large to display.\n", filename);
+ fprintf(stderr, _("%s: too large to display.\n"), filename);
if ( read(fd, buf, s.st_size) != s.st_size ) {
perror(filename);
poptContext optCon;
int arg;
const char * optArg;
- const char * text;
+ char * text;
const char * nextArg;
char * end;
+ struct sigaction sa;
int height;
int width;
int fd = -1;
int noItem = 0;
int clear = 0;
int scrollText = 0;
- int rc = 1;
+ int rc = DLG_CANCEL;
int flags = 0;
int defaultNo = 0;
int separateOutput = 0;
+ int fullButtons = 0;
int outputfd = 2;
FILE *output = stderr;
const char * result;
const char ** selections, ** next;
char * title = NULL;
+ char *default_item = NULL;
char * backtitle = NULL;
+ int help = 0, version = 0;
struct poptOption optionsTable[] = {
{ "backtitle", '\0', POPT_ARG_STRING, &backtitle, 0 },
{ "checklist", '\0', 0, 0, OPT_CHECKLIST },
{ "msgbox", '\0', 0, 0, OPT_MSGBOX },
{ "nocancel", '\0', 0, &noCancel, 0 },
{ "noitem", '\0', 0, &noItem, 0 },
+ { "default-item", '\0', POPT_ARG_STRING, &default_item, 0},
{ "notags", '\0', 0, &noTags, 0 },
{ "radiolist", '\0', 0, 0, OPT_RADIOLIST },
{ "scrolltext", '\0', 0, &scrollText, 0 },
{ "separate-output", '\0', 0, &separateOutput, 0 },
{ "title", '\0', POPT_ARG_STRING, &title, 0 },
- { "yesno", '\0', 0, 0, OPT_YESNO },
{ "textbox", '\0', 0, 0, OPT_TEXTBOX },
+ { "yesno", '\0', 0, 0, OPT_YESNO },
+ { "passwordbox", '\0', 0, 0, OPT_PASSWORDBOX },
+ { "output-fd", '\0', POPT_ARG_INT, &outputfd, 0 },
+ { "help", 'h', 0, &help, 0, NULL, NULL },
+ { "version", 'v', 0, &version, 0, NULL, NULL },
{ 0, 0, 0, 0, 0 }
};
-
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
optCon = poptGetContext("whiptail", argc, argv, optionsTable, 0);
while ((arg = poptGetNextOpt(optCon)) > 0) {
switch (arg) {
case OPT_INFOBOX:
- if (mode != MODE_NONE) usage();
+ if (mode != MODE_NONE) usage(WAS_ERROR);
mode = MODE_INFOBOX;
break;
case OPT_MENU:
- if (mode != MODE_NONE) usage();
+ if (mode != MODE_NONE) usage(WAS_ERROR);
mode = MODE_MENU;
break;
case OPT_MSGBOX:
- if (mode != MODE_NONE) usage();
+ if (mode != MODE_NONE) usage(WAS_ERROR);
mode = MODE_MSGBOX;
break;
- case OPT_TEXTBOX:
- if (mode != MODE_NONE) usage();
- mode = MODE_TEXTBOX;
- break;
+
+ case OPT_TEXTBOX:
+ if (mode != MODE_NONE) usage(WAS_ERROR);
+ mode = MODE_TEXTBOX;
+ break;
+
+ case OPT_PASSWORDBOX:
+ if (mode != MODE_NONE) usage(WAS_ERROR);
+ mode = MODE_PASSWORDBOX;
+ break;
+
case OPT_RADIOLIST:
- if (mode != MODE_NONE) usage();
+ if (mode != MODE_NONE) usage(WAS_ERROR);
mode = MODE_RADIOLIST;
break;
case OPT_CHECKLIST:
- if (mode != MODE_NONE) usage();
+ if (mode != MODE_NONE) usage(WAS_ERROR);
mode = MODE_CHECKLIST;
break;
case OPT_FULLBUTTONS:
+ fullButtons = 1;
useFullButtons(1);
break;
case OPT_YESNO:
- if (mode != MODE_NONE) usage();
+ if (mode != MODE_NONE) usage(WAS_ERROR);
mode = MODE_YESNO;
break;
case OPT_GAUGE:
- if (mode != MODE_NONE) usage();
+ if (mode != MODE_NONE) usage(WAS_ERROR);
mode = MODE_GAUGE;
break;
case OPT_INPUTBOX:
- if (mode != MODE_NONE) usage();
+ if (mode != MODE_NONE) usage(WAS_ERROR);
mode = MODE_INPUTBOX;
break;
}
}
+ if (help) {
+ usage(NO_ERROR);
+ exit(0);
+ }
+ if (version) {
+ print_version();
+ exit(0);
+ }
+
if (arg < -1) {
fprintf(stderr, "%s: %s\n",
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
exit (DLG_ERROR);
}
- if (mode == MODE_NONE) usage();
+ if (mode == MODE_NONE) usage(WAS_ERROR);
- if (!(text = poptGetArg(optCon))) usage();
+ if (!(text = poptGetArg(optCon))) usage(WAS_ERROR);
- if ( mode == MODE_TEXTBOX ) text = readTextFile(text);
+ if (mode == MODE_TEXTBOX ) text = readTextFile(text);
- if (!(nextArg = poptGetArg(optCon))) usage();
+ if (!(nextArg = poptGetArg(optCon))) usage(WAS_ERROR);
height = strtoul(nextArg, &end, 10);
- if (*end) usage();
+ if (*end) usage(WAS_ERROR);
- if (!(nextArg = poptGetArg(optCon))) usage();
+ if (!(nextArg = poptGetArg(optCon))) usage(WAS_ERROR);
width = strtoul(nextArg, &end, 10);
- if (*end) usage();
+ if (*end) usage(WAS_ERROR);
if (mode == MODE_GAUGE) {
fd = dup(0);
if (open("/dev/tty", O_RDWR) != 0) perror("open /dev/tty");
}
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handleSighup;
+ sigaction(SIGWINCH, &sa, NULL);
+
newtInit();
newtCls();
+
+ cleanNewlines(text);
+
+ if ( height <= 0 || width <= 0 )
+ guessSize(&height, &width, mode, &flags, fullButtons, title, text,
+ optCon);
+
width -= 2;
height -= 2;
- newtOpenWindow((80 - width) / 2, (24 - height) / 2, width, height, title);
+ newtOpenWindow((SLtt_Screen_Cols - width) / 2,
+ (SLtt_Screen_Rows - height) / 2, width, height, title);
if (backtitle)
newtDrawRootText(0, 0, backtitle);
case MODE_INPUTBOX:
rc = inputBox(text, height, width, optCon, flags, &result);
- if (rc == DLG_OKAY) fprintf(output, "%s", result);
+ if (rc == DLG_OKAY) fprintf(output, "%s", result);
+ break;
+
+ case MODE_PASSWORDBOX:
+ rc = inputBox(text, height, width, optCon, flags | FLAG_PASSWORD,
+ &result);
+ if (rc == DLG_OKAY) fprintf (output, "%s", result);
break;
case MODE_MENU:
- rc = listBox(text, height, width, optCon, flags, &result);
+ rc = listBox(text, height, width, optCon, flags, default_item, &result);
if (rc == DLG_OKAY) fprintf(output, "%s", result);
break;
case MODE_RADIOLIST:
rc = checkList(text, height, width, optCon, 1, flags, &selections);
- if (rc == DLG_OKAY) {
- fprintf(output, "%s", selections[0]);
+ if (rc == DLG_OKAY) {
+ fprintf(output, "%s", selections[0]);
free(selections);
}
break;
break;
default:
- usage();
+ usage(WAS_ERROR);
}
- if (rc == -1) usage();
+ if (rc == DLG_ERROR) usage(WAS_ERROR);
if (clear)
newtPopWindow();
newtFinished();
- return rc;
+ return ( rc == DLG_ESCAPE ) ? -1 : rc;
}
+#include "config.h"
#include <string.h>
#include <stdlib.h>
+#include "nls.h"
#include "dialogboxes.h"
#include "newt.h"
#include "popt.h"
const char * result;
const char ** selections, ** next;
char * title = NULL;
+ char *default_item = NULL;
struct poptOption optionsTable[] = {
{ "checklist", '\0', 0, 0, OPT_CHECKLIST },
{ "defaultno", '\0', 0, &defaultNo, 0 },
{ "radiolist", '\0', 0, 0, OPT_RADIOLIST },
{ "scrolltext", '\0', 0, &scrollText, 0 },
{ "title", '\0', POPT_ARG_STRING, &title, 0 },
+ { "default-item", '\0', POPT_ARG_STRING, &default_item, 0 },
{ "yesno", '\0', 0, 0, OPT_YESNO },
{ 0, 0, 0, 0, 0 }
};
-
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
optCon = poptGetContext("whiptcl", argc, argv, optionsTable, 0);
while ((arg = poptGetNextOpt(optCon)) > 0) {
case MODE_INPUTBOX:
rc = inputBox(text, height, width, optCon, flags, &result);
- if (!rc) {
+ if (rc ==DLG_OKAY) {
interp->result = strdup(result);
interp->freeProc = TCL_DYNAMIC;
}
break;
case MODE_MENU:
- rc = listBox(text, height, width, optCon, flags, &result);
- if (!rc) {
+ rc = listBox(text, height, width, optCon, flags, default_item, &result);
+ if (rc==DLG_OKAY) {
interp->result = strdup(result);
interp->freeProc = TCL_DYNAMIC;
}
case MODE_RADIOLIST:
rc = checkList(text, height, width, optCon, 1, flags, &selections);
- if (!rc) {
+ if (rc==DLG_OKAY) {
interp->result = strdup(selections[0]);
interp->freeProc = TCL_DYNAMIC;
}
case MODE_CHECKLIST:
rc = checkList(text, height, width, optCon, 0, flags, &selections);
- if (!rc) {
+ if (rc==DLG_OKAY) {
for (next = selections; *next; next++)
Tcl_AppendElement(interp, *next);
Tcl_SetVar(interp, "whiptcl_canceled", (rc == DLG_CANCEL) ? "1" : "0",
0);
+ Tcl_SetVar(interp, "whiptcl_escaped", (rc == DLG_ESCAPE) ? "1" : "0",
+ 0);
return TCL_OK;
}