]> git.ipfire.org Git - thirdparty/newt.git/commitdiff
sync with 0.52.0 r0-52-0
authormlichvar <mlichvar>
Fri, 25 Aug 2006 13:11:37 +0000 (13:11 +0000)
committermlichvar <mlichvar>
Fri, 25 Aug 2006 13:11:37 +0000 (13:11 +0000)
23 files changed:
Makefile.in
button.c
checkbox.c
checkboxtree.c
config.h.in
configure.in
dialogboxes.c
dialogboxes.h
entry.c
form.c
label.c
listbox.c
newt.0.52.ver [new file with mode: 0644]
newt.c
newt.spec
newt_pr.h
nls.h [new file with mode: 0644]
snack.py
snackmodule.c
textbox.c
whiptail.1 [new file with mode: 0644]
whiptail.c
whiptcl.c

index 4583d72b7d19c06045fe2d0decb40fe1a92f3918..6c32cd7ca45dc29d68b82a1ad90329611c27e427 100644 (file)
@@ -1,18 +1,18 @@
 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
@@ -46,7 +46,10 @@ else
 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
@@ -68,20 +71,23 @@ _snackmodule.so:   snackmodule.c $(LIBNEWTSH)
            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 $@ $^
@@ -105,7 +111,8 @@ $(SHAREDDIR):
 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 $@ $<
index 467efdb3534e76565dd399f72f72ba94e0163fec..01ae1f5daef5ef74b4f25eba5bdaa073f56d6816 100644 (file)
--- a/button.c
+++ b/button.c
@@ -104,13 +104,13 @@ static void buttonDrawIt(newtComponent co, int active, int pushed) {
     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) {
@@ -140,7 +140,7 @@ static void buttonDrawText(newtComponent co, int active, int 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(' ');
 }
 
index c753374bb701a02fd4d5360913aff0a74b031f34..d52324351dfdbe4ed45d5c3060e6b8234b1a88f8 100644 (file)
@@ -79,7 +79,7 @@ newtComponent newtRadioGetCurrent(newtComponent setMember) {
 char newtCheckboxGetValue(newtComponent co) {
     struct checkbox * cb = co->data;
 
-    return *cb->result;
+    return cb->value;
 }
 
 void newtCheckboxSetValue(newtComponent co, char value) {
@@ -141,6 +141,12 @@ void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense
 
     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
@@ -181,7 +187,7 @@ static void cbDraw(newtComponent c) {
        break;
     }
 
-    SLsmg_write_string(cb->text);
+    write_string_int(cb->text, NULL);
 
     if (cb->hasFocus)
        SLsmg_set_color(cb->active);
@@ -242,7 +248,10 @@ struct eventResult cbEvent(newtComponent co, struct event ev) {
                    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;
            }
index 815cc52e66c75f094d155ad76b76631824a47463..b4c6d8f5decc1dad1928d74de94348cf76287519 100644 (file)
@@ -443,7 +443,7 @@ static void ctDraw(newtComponent co) {
     struct items ** item; 
     int i, j;
     char * spaces;
-    int currRow = 0;
+    int currRow;
 
     if (!co->isMapped) return ;
 
@@ -482,12 +482,13 @@ static void ctDraw(newtComponent co) {
            } 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);
 
index 9fbcdf44c7e0fac9a757427dd282eef8411d44fa..db8101212d49e67fb0b0ceaa03b4fecca46f453f 100644 (file)
@@ -1,11 +1,21 @@
-/* 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"
index 42861ca333b1c0e405daed8ff92fc929c760880e..eaeb27c4202a20b08d447fb62d2eb393a1403455 100644 (file)
@@ -4,8 +4,8 @@ AC_INIT(newt_pr.h)
 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)
@@ -13,7 +13,7 @@ AC_PROG_CC
 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])
 
index d2b220968fb81c2768f30b606c5ea26d9d2558b5..70d367ddd55235b7c60e10c47cd1e2d0ac21f834 100644 (file)
@@ -1,11 +1,15 @@
 /* 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);
     }
 }
@@ -135,6 +154,7 @@ int inputBox(const char * text, int height, int width, poptContext optCon,
                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;
 
@@ -144,7 +164,7 @@ int inputBox(const char * text, int height, int width, poptContext optCon,
 
     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);
 
@@ -153,14 +173,45 @@ int inputBox(const char * text, int height, int width, poptContext optCon,
     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;
@@ -170,10 +221,12 @@ int listBox(const char * text, int height, int width, poptContext optCon,
     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;
@@ -192,6 +245,9 @@ int listBox(const char * text, int height, int width, poptContext optCon,
        }
 
        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)) {
@@ -226,17 +282,47 @@ int listBox(const char * text, int height, int width, poptContext optCon,
        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);
@@ -244,6 +330,8 @@ int listBox(const char * text, int height, int width, poptContext optCon,
     answer = newtRunForm(form);
     if (answer == cancel)
        rc = DLG_CANCEL;
+    if (answer == NULL)
+       rc = DLG_ESCAPE;
 
     i = (int) newtListboxGetCurrent(listBox);
     *result = itemInfo[i].tag;
@@ -263,7 +351,7 @@ int checkList(const char * text, int height, int width, poptContext optCon,
     int i;
     int numSelected;
     int rc = DLG_OKAY;
-    char buf[80], format[20];
+    char buf[MAXBUF], format[MAXFORMAT];
     int maxWidth = 0;
     int top;
     struct {
@@ -307,7 +395,6 @@ int checkList(const char * text, int height, int width, poptContext optCon,
        numBoxes++;
     }
 
-       
     form = newtForm(NULL, NULL, 0);
 
     tb = textbox(height - 3 - buttonHeight - listHeight, width - 2,
@@ -335,6 +422,7 @@ int checkList(const char * text, int height, int width, poptContext optCon,
            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);
     }
 
@@ -348,6 +436,8 @@ int checkList(const char * text, int height, int width, poptContext optCon,
     answer = newtRunForm(form);
     if (answer == cancel)
        rc = DLG_CANCEL;
+    if (answer == NULL)
+       rc = DLG_ESCAPE;
 
     if (useRadio) {
        answer = newtRadioGetCurrent(cbInfo[0].comp);
@@ -383,6 +473,7 @@ int checkList(const char * text, int height, int width, poptContext optCon,
 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);
@@ -397,13 +488,16 @@ int messageBox(const char * text, int height, int width, int type, int flags) {
     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)
@@ -411,7 +505,8 @@ int messageBox(const char * text, int height, int width, int type, int flags) {
     }
 
     if ( type != MSGBOX_INFO ) {
-       newtRunForm(form);
+       if (newtRunForm(form) == NULL)
+               rc = DLG_ESCAPE;
 
        answer = newtFormGetCurrent(form);
 
@@ -425,7 +520,7 @@ int messageBox(const char * text, int height, int width, int type, int flags) {
        
 
 
-    return DLG_OKAY;
+    return rc;
 }
 
 void useFullButtons(int state) {
index 27f072c301d25e7099ca435f4cf4b29060e0e292..b1824640f305967f1f1ed310dc310018e234d5a4 100644 (file)
 #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, 
diff --git a/entry.c b/entry.c
index 2b289549b749759be5efb8dc5c9664bfeecc66bc..8676369db3f320b80b130a6345844827a53ae0f5 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -8,6 +8,7 @@
 #include <slang.h>
 #include <stdlib.h>
 #include <string.h>
+#include <wchar.h>
 
 #include "newt.h"
 #include "newt_pr.h"
@@ -90,8 +91,8 @@ newtComponent newtEntry(int left, int top, const char * initialValue, int width,
     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;
@@ -111,11 +112,48 @@ newtComponent newtEntry(int left, int top, const char * initialValue, int width,
     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;
 
@@ -138,16 +176,15 @@ static void entryDraw(newtComponent co) {
     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++)
@@ -159,19 +196,22 @@ static void entryDraw(newtComponent co) {
 
     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) {
@@ -212,7 +252,7 @@ static struct eventResult entryEvent(newtComponent co,
                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;
 
@@ -252,6 +292,30 @@ static struct eventResult entryEvent(newtComponent co,
     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;
@@ -282,49 +346,63 @@ static struct eventResult entryHandleKey(newtComponent co, int key) {
        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;
            }
@@ -357,7 +435,7 @@ static struct eventResult entryHandleKey(newtComponent co, int key) {
                }
 
            }
-
+            /* FIXME */
            en->buf[en->cursorPosition++] = key;
        } else {
            er.result = ER_IGNORED;
diff --git a/form.c b/form.c
index 534ca29c17e4e7a18b7b65f8dab5319e6b73e709..63188ea04f27ed364115223a91e0324d0aa12fc2 100644 (file)
--- a/form.c
+++ b/form.c
@@ -471,6 +471,7 @@ newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
     if (!(form->flags & NEWT_FLAG_NOF12)) {
        newtFormAddHotKey(co, NEWT_KEY_F12);
     }
+    /* TEST */ newtFormAddHotKey (co, NEWT_KEY_ESCAPE);
 
     if (vertBar)
        form->vertBar = vertBar;
diff --git a/label.c b/label.c
index ad8665b82068cea9a6b3f76478f3ae6de31b0c7e..6f666f7dd53c47fa9b739078de30b7012bf7629e 100644 (file)
--- a/label.c
+++ b/label.c
@@ -69,7 +69,9 @@ static void labelDraw(newtComponent co) {
     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) {
index a8957373107725e76453b192e1090158dcbe4e1b..7573940d54392f60762ce7deed4e00285367d8cc 100644 (file)
--- a/listbox.c
+++ b/listbox.c
@@ -527,7 +527,7 @@ static void listboxDraw(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,
diff --git a/newt.0.52.ver b/newt.0.52.ver
new file mode 100644 (file)
index 0000000..e80cb62
--- /dev/null
@@ -0,0 +1,6 @@
+NEWT_0.52 {
+       global: newt*;
+               _newt_wstrlen;
+       local: *;
+};
+
diff --git a/newt.c b/newt.c
index 4cc22d0507eca8084136aacbe7f3213e4af45f11..25ca7adf0194edb32dbaea34fe26f0e2496c4a85 100644 (file)
--- a/newt.c
+++ b/newt.c
 #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;
@@ -66,34 +519,38 @@ const struct newtColors newtDefaultColorPalette = {
        "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 },
@@ -106,23 +563,27 @@ static const struct keymap keymap[] = {
        { "\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 " $"
@@ -145,7 +606,7 @@ static int getkeyInterruptHook(void) {
     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;
@@ -169,6 +630,37 @@ int wstrlen(const char *str, int len) {
        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;
 
@@ -251,6 +743,8 @@ int newtInit(void) {
 
     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 ) {
@@ -266,7 +760,7 @@ int newtInit(void) {
 
     newtSetColors(newtDefaultColorPalette);
     newtCursorOff();
-    /*initKeymap();*/
+    initKeymap();
 
     /*memset(&sa, 0, sizeof(sa));
     sa.sa_handler = handleSigwinch;
@@ -360,10 +854,142 @@ void newtSetColors(struct newtColors colors) {
                   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();
@@ -387,66 +1013,35 @@ int newtGetKey(void) {
            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;
 }
 
 /**
@@ -477,7 +1072,8 @@ void newtClearKeyBuffer(void) {
  * @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;
@@ -521,9 +1117,12 @@ int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
     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);
@@ -532,7 +1131,7 @@ int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
        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);
@@ -562,8 +1161,9 @@ int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
  * @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;
 
@@ -662,32 +1262,44 @@ void newtClearBox(int left, int top, int width, int height) {
     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;
 
@@ -731,7 +1343,7 @@ void newtRedrawHelpLine(void) {
        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) {
@@ -772,7 +1384,7 @@ void newtDrawRootText(int col, int row, 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) {
index 54f72a0c92c804b02145d9566a5aa2a22651c052..2e5e0314371c36051062613f923bd111adc6a471 100644 (file)
--- a/newt.spec
+++ b/newt.spec
@@ -2,12 +2,14 @@
 
 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
@@ -38,11 +40,13 @@ newt.
 
 %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
 
@@ -69,9 +73,10 @@ rm -rf $RPM_BUILD_ROOT
 
 %files
 %defattr (-,root,root)
-%doc CHANGES COPYING
+%doc COPYING
 %{_bindir}/whiptail
 %{_libdir}/libnewt.so.*
+%{_libdir}/whiptcl.so
 %{_libdir}/python%{pythonver}/site-packages/*
 
 %files devel
@@ -82,15 +87,36 @@ rm -rf $RPM_BUILD_ROOT
 %{_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
index 911898cfb38fc0fc7f6c7fe65cfc0df0fe43ad61..08df449f5cbce1f5b9d5ad03279fd87ee2877911 100644 (file)
--- a/newt_pr.h
+++ b/newt_pr.h
@@ -80,6 +80,11 @@ void newtDefaultMappedHandler(newtComponent c, int isMapped);
 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 */
diff --git a/nls.h b/nls.h
new file mode 100644 (file)
index 0000000..7becf84
--- /dev/null
+++ b/nls.h
@@ -0,0 +1,16 @@
+
+
+#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 
+
index b0f51d5bca8fb8a60f008fe1ff0da31c37b7035a..ff6d8d440ea5682b23df46b79cd7b8d96b345103 100644 (file)
--- a/snack.py
+++ b/snack.py
@@ -282,7 +282,7 @@ hotkeys = { "F1" : _snack.KEY_F1, "F2" : _snack.KEY_F2, "F3" : _snack.KEY_F3,
             "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
@@ -925,5 +925,5 @@ class CListbox(Grid):
     def setCurrent(self, item):
         self.listbox.setCurrent(item)
 
-        def clear(self):
-            self.listbox.clear()
+    def clear(self):
+        self.listbox.clear()
index f992e44692a893d8556cd3da3cc32479cadaf652..deb38671c9fb2539b320ae276e67493821e80558 100644 (file)
@@ -12,6 +12,7 @@
 #include <unistd.h>
 
 #include "Python.h"
+#include "nls.h"
 #include "newt.h"
 #include "newt_pr.h"
 
@@ -1219,6 +1220,10 @@ static PyObject * pywstrlen(PyObject * s, PyObject * args)
 void init_snack(void) {
     PyObject * d, * m;
 
+    setlocale (LC_ALL, "");
+    bindtextdomain (PACKAGE, LOCALEDIR);
+    textdomain (PACKAGE);
+
     m = Py_InitModule("_snack", snackModuleMethods);
     d = PyModule_GetDict(m);
 
@@ -1251,6 +1256,7 @@ void init_snack(void) {
     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));
index 68742cfef46c3720853f41ef76d467de2c44633c..5a43df05e95d99467178669e987167a100d34172 100644 (file)
--- a/textbox.c
+++ b/textbox.c
@@ -91,6 +91,8 @@ newtComponent newtTextbox(int left, int top, int width, int height, int flags) {
     tb = malloc(sizeof(*tb));
     co->data = tb;
 
+    if (width < 2) width = 2;
+
     co->ops = &textboxOps;
 
     co->height = height;
@@ -337,20 +339,42 @@ static void textboxDraw(newtComponent c) {
     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';
     }
 }
 
diff --git a/whiptail.1 b/whiptail.1
new file mode 100644 (file)
index 0000000..1d2e63d
--- /dev/null
@@ -0,0 +1,268 @@
+.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)
index 6b9a4fb8f3c9ccd465d8a541bdd98279075b2df3..70bbe9f622d0c2eca262bb24670c3de533e5a647 100644 (file)
@@ -1,18 +1,24 @@
-/* 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
@@ -23,12 +29,267 @@ enum mode { MODE_NONE, MODE_INFOBOX, MODE_MSGBOX, MODE_YESNO, MODE_CHECKLIST,
 #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 *
@@ -44,7 +305,7 @@ readTextFile(const char * filename)
      }
 
     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);
@@ -59,9 +320,10 @@ int main(int argc, const char ** argv) {
     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;
@@ -71,16 +333,19 @@ int main(int argc, const char ** argv) {
     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 },
@@ -95,16 +360,25 @@ int main(int argc, const char ** argv) {
            { "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) {
@@ -112,54 +386,71 @@ int main(int argc, const char ** argv) {
 
        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), 
@@ -173,19 +464,19 @@ int main(int argc, const char ** argv) {
         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);
@@ -193,12 +484,24 @@ int main(int argc, const char ** argv) {
        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);
 
@@ -224,18 +527,24 @@ int main(int argc, const char ** argv) {
 
       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;
@@ -263,14 +572,14 @@ int main(int argc, const char ** argv) {
        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;
 }
index 6e496f84c785803dadff8570c2834de3cef13b3d..7d01f343dbf5349717db94f610aa1c312e0c5ade 100644 (file)
--- a/whiptcl.c
+++ b/whiptcl.c
@@ -1,6 +1,8 @@
+#include "config.h"
 #include <string.h>
 #include <stdlib.h>
 
+#include "nls.h"
 #include "dialogboxes.h"
 #include "newt.h"
 #include "popt.h"
@@ -72,6 +74,7 @@ static int wtCmd(ClientData clientData, Tcl_Interp * interp, int argc,
     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 },
@@ -83,10 +86,15 @@ static int wtCmd(ClientData clientData, Tcl_Interp * interp, int argc,
            { "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) {
@@ -194,15 +202,15 @@ static int wtCmd(ClientData clientData, Tcl_Interp * interp, int argc,
 
       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;
        }
@@ -210,7 +218,7 @@ static int wtCmd(ClientData clientData, Tcl_Interp * interp, int argc,
 
       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;
        }
@@ -219,7 +227,7 @@ static int wtCmd(ClientData clientData, Tcl_Interp * interp, int argc,
       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);
 
@@ -241,6 +249,8 @@ static int wtCmd(ClientData clientData, Tcl_Interp * interp, int argc,
 
     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;
 }