]> git.ipfire.org Git - thirdparty/newt.git/commitdiff
split whiptail dialog stuff out; added whiptcl
authorewt <ewt>
Mon, 18 Aug 1997 21:12:01 +0000 (21:12 +0000)
committerewt <ewt>
Mon, 18 Aug 1997 21:12:01 +0000 (21:12 +0000)
Makefile
dialogboxes.c [new file with mode: 0644]
dialogboxes.h [new file with mode: 0644]
newt.c
newt.h
scale.c
whiptail.c
whiptcl.c [new file with mode: 0644]

index ca56d8bce89aabfebfbf821c193f66bfcf7c44ee..11e8a5776bc702389812c990f80bfa59622fadee 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,17 @@
-LIBS = -lslang -lm #-lefence
+LIBS = -lslang -lm -lc #-lefence
 
 CFLAGS = $(RPM_OPT_FLAGS) -Wall
 ifeq ($(RPM_OPT_FLAGS),)
-CFLAGS += -g
+CFLAGS += -g -O2
 endif
 
 VERSION = 0.9
-SONAME = 0
+SONAME = 0.9
 
-PROGS = test whiptail
+PROGS = test whiptail whiptcl.so
 TESTOBJS = test.o 
-NDIALOGOBJS = whiptail.o popt.o
+NDIALOGOBJS = whiptail.o dialogboxes.o popt.o
+WHIPTCLOBJS = whiptcl.o dialogboxes.o popt.o
 LIBNEWT = libnewt.a
 LIBNEWTSH = libnewt.so.$(VERSION)
 LIBNEWTSONAME = libnewt.so.$(SONAME)
@@ -45,6 +46,9 @@ test: $(TESTOBJS) $(LIBNEWT)
 whiptail: $(NDIALOGOBJS) $(LIBNEWTSH)
        gcc -g -o whiptail $(NDIALOGOBJS) $(LIBNEWTSH) $(LIBS)
 
+whiptcl.so: $(WHIPTCLOBJS) $(LIBNEWTSH)
+       gcc -shared -o whiptcl.so $(WHIPTCLOBJS) $(LIBNEWTSH) -ltcl -lslang -lm
+
 $(LIBNEWT): $(LIBNEWT)($(LIBOBJS))
 
 newt.o: newt.c Makefile
@@ -86,6 +90,7 @@ install: $(LIBNEWT)
 install-sh: sharedlib
        install -m 755 $(LIBNEWTSH) $(libdir)
        ln -sf $(LIBNEWTSH) $(libdir)/libnewt.so
+       install -m 755 whiptcl.so $(libdir)
        /sbin/ldconfig
 
 archive: 
diff --git a/dialogboxes.c b/dialogboxes.c
new file mode 100644 (file)
index 0000000..55a59b2
--- /dev/null
@@ -0,0 +1,405 @@
+/* simple dialog boxes, used by both whiptail and tcl dialog bindings */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "dialogboxes.h"
+#include "newt.h"
+#include "popt.h"
+
+/* globals -- ick */
+int buttonHeight = 1;
+newtComponent (*makeButton)(int left, int right, char * text) = 
+               newtCompactButton;
+
+static void addButtons(int height, int width, newtComponent form, 
+                      newtComponent * okay, newtComponent * cancel, 
+                      int flags) {
+    if (flags & FLAG_NOCANCEL) {
+       *okay = makeButton((width - 8) / 2, height - buttonHeight - 1, "Ok");
+       *cancel = NULL;
+       newtFormAddComponent(form, *okay);
+    } else {
+       *okay = makeButton((width - 18) / 3, height - buttonHeight - 1, "Ok");
+       *cancel = makeButton(((width - 18) / 3) * 2 + 9, 
+                               height - buttonHeight - 1, "Cancel");
+       newtFormAddComponents(form, *okay, *cancel, NULL);
+    }
+}
+
+static newtComponent textbox(int maxHeight, int width, char * text, int flags, 
+                            int * height) {
+    newtComponent tb;
+    int sFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
+    int i;
+    char * buf, * src, * dst;
+
+    dst = buf = alloca(strlen(text) + 1);
+    src = text; 
+    while (*src) {
+       if (*src == '\\' && *(src + 1) == 'n') {
+           src += 2;
+           *dst++ = '\n';
+       } else
+           *dst++ = *src++;
+    }
+    *dst++ = '\0';
+
+    tb = newtTextbox(1, 0, width, maxHeight, NEWT_FLAG_WRAP | sFlag);
+    newtTextboxSetText(tb, buf);
+
+    i = newtTextboxGetNumLines(tb);
+    if (i < maxHeight) {
+       newtTextboxSetHeight(tb, i);
+       maxHeight = i;
+    }
+
+    *height = maxHeight;
+
+    return tb;
+}
+
+int gauge(char * text, int height, int width, poptContext optCon, int fd, 
+               int flags) {
+    newtComponent form, scale, tb;
+    int top;
+    char * arg, * end;
+    int val;
+    FILE * f = fdopen(fd, "r");
+    char buf[3000];
+    char buf3[50];
+    int i;
+
+    setlinebuf(f);
+
+    if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+    val = strtoul(arg, &end, 10);
+    if (*end) return DLG_ERROR;
+
+    tb = textbox(height - 3, width - 2, text, flags, &top);
+
+    form = newtForm(NULL, NULL, 0);
+
+    scale = newtScale(2, height - 2, width - 4, 100);
+    newtScaleSet(scale, val);
+
+    newtFormAddComponents(form, tb, scale, NULL);
+
+    newtDrawForm(form);
+    newtRefresh();
+
+    while (fgets(buf, sizeof(buf) - 1, f)) {
+       buf[strlen(buf) - 1] = '\0';
+
+       if (!strcmp(buf, "XXX")) {
+           fgets(buf3, sizeof(buf3) - 1, f);
+           buf3[strlen(buf3) - 1] = '\0';
+           arg = buf3;
+
+           i = 0;
+           while (fgets(buf + i, sizeof(buf) - 1 - i, f)) {
+               buf[strlen(buf) - 1] = '\0';
+               if (!strcmp(buf + i, "XXX")) {
+                   *(buf + i) = '\0';
+                   break;
+               }
+               i = strlen(buf);
+           }
+
+           newtTextboxSetText(tb, buf);
+       } else {
+           arg = buf;
+       }
+
+       val = strtoul(buf, &end, 10);
+       if (!*end) {
+           newtScaleSet(scale, val);
+           newtDrawForm(form);
+           newtRefresh();
+       }
+    }
+
+    return DLG_OKAY;
+}
+
+int inputBox(char * text, int height, int width, poptContext optCon, 
+               int flags, char ** result) {
+    newtComponent form, entry, okay, cancel, answer, tb;
+    char * val;
+    int rc = DLG_OKAY;
+    int top;
+
+    val = poptGetArg(optCon);
+    tb = textbox(height - 3 - buttonHeight, width - 2,
+                       text, flags, &top);
+
+    form = newtForm(NULL, NULL, 0);
+    entry = newtEntry(1, top + 1, val, width - 2, &val, 
+                       NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
+
+    newtFormAddComponents(form, tb, entry, NULL);
+
+    addButtons(height, width, form, &okay, &cancel, flags);
+
+    answer = newtRunForm(form);
+    if (answer == cancel)
+       rc = DLG_CANCEL;
+
+    *result = val;
+
+    return rc;
+}
+
+int listBox(char * text, int height, int width, poptContext optCon,
+               int flags, char ** result) {
+    newtComponent form, okay, tb, answer, listBox;
+    newtComponent cancel = NULL;
+    char * arg, * end;
+    int listHeight;
+    int numItems = 0;
+    int allocedItems = 5;
+    int i, top;
+    int rc = DLG_OKAY;
+    char buf[80], format[20];
+    int maxTagWidth = 0;
+    int maxTextWidth = 0;
+    int noScrollFlag;
+    struct {
+       char * text;
+       char * tag;
+    } * itemInfo = malloc(allocedItems * sizeof(*itemInfo));
+
+    if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+    listHeight = strtoul(arg, &end, 10);
+    if (*end) return DLG_ERROR;
+
+    while ((arg = poptGetArg(optCon))) {
+       if (allocedItems == numItems) {
+           allocedItems += 5;
+           itemInfo = realloc(itemInfo, sizeof(*itemInfo) * allocedItems);
+       }
+
+       itemInfo[numItems].tag = arg;
+       if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+
+       if (!(flags & FLAG_NOITEM)) {
+           itemInfo[numItems].text = arg;
+       } else
+           itemInfo[numItems].text = "";
+
+       if (strlen(itemInfo[numItems].text) > maxTextWidth)
+           maxTextWidth = strlen(itemInfo[numItems].text);
+       if (strlen(itemInfo[numItems].tag) > maxTagWidth)
+           maxTagWidth = strlen(itemInfo[numItems].tag);
+
+       numItems++;
+    }
+
+    form = newtForm(NULL, NULL, 0);
+
+    tb = textbox(height - 4 - buttonHeight - listHeight, width - 2,
+                       text, flags, &top);
+
+    if (listHeight >= numItems) {
+       noScrollFlag = NEWT_FLAG_NOSCROLL;
+       i = 0;
+    } else {
+       noScrollFlag = 0;
+       i = 2;
+    }
+
+    listBox = newtListbox(3 + ((width - 10 - maxTagWidth - maxTextWidth - i) 
+                                       / 2),
+                         top + 1, listHeight, 
+                           NEWT_FLAG_RETURNEXIT | noScrollFlag);
+
+    sprintf(format, "%%-%ds  %%s", maxTagWidth);
+    for (i = 0; i < numItems; i++) {
+       sprintf(buf, format, itemInfo[i].tag, itemInfo[i].text);
+       newtListboxAddEntry(listBox, buf, (void *) i);
+    }
+
+    newtFormAddComponents(form, tb, listBox, NULL);
+
+    addButtons(height, width, form, &okay, &cancel, flags);
+
+    answer = newtRunForm(form);
+    if (answer == cancel)
+       rc = DLG_CANCEL;
+
+    i = (int) newtListboxGetCurrent(listBox);
+    *result = itemInfo[i].tag;
+
+    return rc;
+}
+
+int checkList(char * text, int height, int width, poptContext optCon,
+               int useRadio, int flags, char *** selections) {
+    newtComponent form, okay, tb, subform, answer;
+    newtComponent sb = NULL, cancel = NULL;
+    char * arg, * end;
+    int listHeight;
+    int numBoxes = 0;
+    int allocedBoxes = 5;
+    int i;
+    int numSelected;
+    int rc = DLG_OKAY;
+    char buf[80], format[20];
+    int maxWidth = 0;
+    int top;
+    struct {
+       char * text;
+       char * tag;
+       newtComponent comp;
+    } * cbInfo = malloc(allocedBoxes * sizeof(*cbInfo));
+    char * cbStates = malloc(allocedBoxes * sizeof(cbStates));
+
+    if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+    listHeight = strtoul(arg, &end, 10);
+    if (*end) return DLG_ERROR;
+
+    while ((arg = poptGetArg(optCon))) {
+       if (allocedBoxes == numBoxes) {
+           allocedBoxes += 5;
+           cbInfo = realloc(cbInfo, sizeof(*cbInfo) * allocedBoxes);
+           cbStates = realloc(cbStates, sizeof(*cbStates) * allocedBoxes);
+       }
+
+       cbInfo[numBoxes].tag = arg;
+       if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+
+       if (!(flags & FLAG_NOITEM)) {
+           cbInfo[numBoxes].text = arg;
+           if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+       } else
+           cbInfo[numBoxes].text = "";
+
+       if (!strcmp(arg, "1") || !strcasecmp(arg, "on") || 
+               !strcasecmp(arg, "yes"))
+           cbStates[numBoxes] = '*';
+       else
+           cbStates[numBoxes] = ' ';
+
+       if (strlen(cbInfo[numBoxes].tag) > maxWidth)
+           maxWidth = strlen(cbInfo[numBoxes].tag);
+
+       numBoxes++;
+    }
+
+    form = newtForm(NULL, NULL, 0);
+
+    tb = textbox(height - 3 - buttonHeight - listHeight, width - 2,
+                       text, flags, &top);
+
+    if (listHeight < numBoxes) { 
+       sb = newtVerticalScrollbar(width - 4, 
+                                  top + 1,
+                                  listHeight, NEWT_COLORSET_CHECKBOX,
+                                  NEWT_COLORSET_ACTCHECKBOX);
+       newtFormAddComponent(form, sb);
+    }
+    subform = newtForm(sb, NULL, 0);
+    newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX);
+
+    sprintf(format, "%%-%ds  %%s", maxWidth);
+    for (i = 0; i < numBoxes; i++) {
+       sprintf(buf, format, cbInfo[i].tag, cbInfo[i].text);
+
+       if (useRadio)
+           cbInfo[i].comp = newtRadiobutton(4, top + 1 + i, buf,
+                                       cbStates[i] != ' ', 
+                                       i ? cbInfo[i - 1].comp : NULL);
+       else
+           cbInfo[i].comp = newtCheckbox(4, top + 1 + i, buf,
+                             cbStates[i], NULL, cbStates + i);
+
+       newtFormAddComponent(subform, cbInfo[i].comp);
+    }
+
+    newtFormSetHeight(subform, listHeight);
+    newtFormSetWidth(subform, width - 10);
+
+    newtFormAddComponents(form, tb, subform, NULL);
+
+    addButtons(height, width, form, &okay, &cancel, flags);
+
+    answer = newtRunForm(form);
+    if (answer == cancel)
+       rc = DLG_CANCEL;
+
+    if (useRadio) {
+       answer = newtRadioGetCurrent(cbInfo[0].comp);
+       for (i = 0; i < numBoxes; i++) 
+           if (cbInfo[i].comp == answer) {
+               *selections = malloc(sizeof(char *) * 2);
+               (*selections)[0] = cbInfo[i].tag;
+               (*selections)[1] = NULL;
+               break;
+           }
+    } else {
+       numSelected = 0;
+       for (i = 0; i < numBoxes; i++) {
+           if (cbStates[i] != ' ') numSelected++;
+       }
+
+       *selections = malloc(sizeof(char *) * (numSelected + 1));
+
+       numSelected = 0;
+       for (i = 0; i < numBoxes; i++) {
+           if (cbStates[i] != ' ') 
+               (*selections)[numSelected++] = cbInfo[i].tag;
+       }
+
+       (*selections)[numSelected] = NULL;
+    }
+
+    return rc;
+}
+
+int messageBox(char * text, int height, int width, int type, int flags) {
+    newtComponent form, yes, tb, answer;
+    newtComponent no = NULL;
+    int tFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
+
+    form = newtForm(NULL, NULL, 0);
+
+    tb = newtTextbox(1, 1, width - 2, height - 3 - buttonHeight, 
+                       NEWT_FLAG_WRAP | tFlag);
+    newtTextboxSetText(tb, text);
+
+    newtFormAddComponent(form, tb);
+
+    if (type == MSGBOX_MSG) {
+       yes = makeButton((width - 8) / 2, height - 1 - buttonHeight, "Ok");
+       newtFormAddComponent(form, yes);
+    } else {
+       yes = makeButton((width - 16) / 3, height - 1 - buttonHeight, "Yes");
+       no = makeButton(((width - 16) / 3) * 2 + 9, height - 1 - buttonHeight, 
+                       "No");
+       newtFormAddComponents(form, yes, no, NULL);
+
+       if (flags & FLAG_DEFAULT_NO)
+           newtFormSetCurrent(form, no);
+    }
+
+    newtRunForm(form);
+    answer = newtFormGetCurrent(form);
+
+    if (answer == no)
+       return DLG_CANCEL;
+
+    return DLG_OKAY;
+}
+
+void useFullButtons(int state) {
+    if (state) {
+       buttonHeight = 3;
+       makeButton = newtButton;
+   } else {
+       buttonHeight = 1;
+       makeButton = newtCompactButton;
+   }
+}
diff --git a/dialogboxes.h b/dialogboxes.h
new file mode 100644 (file)
index 0000000..0cf17c2
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef H_DIALOGBOXES
+#define H_DIALOGBOXES
+
+#include "popt.h"
+
+#define MSGBOX_MSG 0 
+#define MSGBOX_YESNO 1
+
+#define FLAG_NOITEM            (1 << 0)
+#define FLAG_NOCANCEL          (1 << 1)
+#define FLAG_SCROLL_TEXT       (1 << 2)
+#define FLAG_DEFAULT_NO        (1 << 3)
+
+#define DLG_ERROR              -1
+#define DLG_OKAY               0
+#define DLG_CANCEL             1
+
+int messageBox(char * text, int height, int width, int type, int flags);
+int checkList(char * text, int height, int width, poptContext optCon,
+               int useRadio, int flags, char *** selections);
+int listBox(char * text, int height, int width, poptContext optCon,
+               int flags, char ** result);
+int inputBox(char * text, int height, int width, poptContext optCon, 
+               int flags, char ** result);
+int gauge(char * text, int height, int width, poptContext optCon, int fd, 
+               int flags);
+void useFullButtons(int state);
+
+#endif
diff --git a/newt.c b/newt.c
index ee948650d17d853059e8f616dcf89d7113e38f93..c63800c1d6939b71bb8d8bae3232cdf1fda4b519 100644 (file)
--- a/newt.c
+++ b/newt.c
@@ -326,7 +326,7 @@ int newtOpenWindow(int left, int top, int width, int height,
     currentWindow->top = top;
     currentWindow->width = width;
     currentWindow->height = height;
-    currentWindow->title = strdup(title);
+    currentWindow->title = title ? strdup(title) : NULL;
 
     currentWindow->buffer = malloc(sizeof(short) * (width + 3) * (height + 3));
 
diff --git a/newt.h b/newt.h
index 10eaf6778754ed62514d937e8714dc98d87adc57..7d9f40c10ff745d945246232377c8573722d2f94 100644 (file)
--- a/newt.h
+++ b/newt.h
@@ -177,7 +177,7 @@ void newtEntrySet(newtComponent co, char * value, int cursorAtEnd);
 void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
 
 newtComponent newtScale(int left, int top, int width, long long fullValue);
-void newtScaleSet(newtComponent co, long long amount);
+void newtScaleSet(newtComponent co, unsigned long long amount);
 
 void newtComponentAddCallback(newtComponent co, newtCallback f, void * data);
 
diff --git a/scale.c b/scale.c
index 97acd1b64f4cd3b395316917232a2c64f14a66d3..252314450fe6716b69c8866ded410dc9b74d006e 100644 (file)
--- a/scale.c
+++ b/scale.c
@@ -40,7 +40,7 @@ newtComponent newtScale(int left, int top, int width, long long fullValue) {
     return co;
 }
 
-void newtScaleSet(newtComponent co, long long amount) {
+void newtScaleSet(newtComponent co, unsigned long long amount) {
     struct scale * sc = co->data;
     int newCharsSet;
 
index beff5ad5b01db3d19fdfa75e92224eb37d473d50..1bb494b2fb89891c7a8b3599c279d66a4071076f 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include "dialogboxes.h"
 #include "newt.h"
 #include "popt.h"
 
@@ -21,400 +22,11 @@ enum mode { MODE_NONE, MODE_MSGBOX, MODE_YESNO, MODE_CHECKLIST, MODE_INPUTBOX,
 #define OPT_RADIOLIST          1006
 #define OPT_GAUGE              1007
 
-#define MSGBOX_MSG 0 
-#define MSGBOX_YESNO 1
-
-#define FLAG_NOITEM            (1 << 0)
-#define FLAG_NOCANCEL          (1 << 1)
-#define FLAG_SEPARATE_OUTPUT   (1 << 2)
-#define FLAG_SCROLL_TEXT       (1 << 3)
-#define FLAG_DEFAULT_NO        (1 << 4)
-
 static void usage(void) {
-    fprintf(stderr, "ndialog: bad parametrs (see man dialog(1) for details)\n");
+    fprintf(stderr, "whiptail: bad parametrs (see man dialog(1) for details)\n");
     exit(1);
 }
 
-/* globals -- ick */
-int buttonHeight = 1;
-newtComponent (*makeButton)(int left, int right, char * text) = 
-               newtCompactButton;
-
-void addButtons(int height, int width, newtComponent form, 
-               newtComponent * okay, newtComponent * cancel, int flags) {
-    if (flags & FLAG_NOCANCEL) {
-       *okay = makeButton((width - 8) / 2, height - buttonHeight - 1, "Ok");
-       *cancel = NULL;
-       newtFormAddComponent(form, *okay);
-    } else {
-       *okay = makeButton((width - 18) / 3, height - buttonHeight - 1, "Ok");
-       *cancel = makeButton(((width - 18) / 3) * 2 + 9, 
-                               height - buttonHeight - 1, "Cancel");
-       newtFormAddComponents(form, *okay, *cancel, NULL);
-    }
-}
-
-newtComponent textbox(int maxHeight, int width, char * text, int flags, 
-                       int * height) {
-    newtComponent tb;
-    int sFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
-    int i;
-    char * buf, * src, * dst;
-
-    dst = buf = alloca(strlen(text) + 1);
-    src = text; 
-    while (*src) {
-       if (*src == '\\' && *(src + 1) == 'n') {
-           src += 2;
-           *dst++ = '\n';
-       } else
-           *dst++ = *src++;
-    }
-    *dst++ = '\0';
-
-    tb = newtTextbox(1, 0, width, maxHeight, NEWT_FLAG_WRAP | sFlag);
-    newtTextboxSetText(tb, buf);
-
-    i = newtTextboxGetNumLines(tb);
-    if (i < maxHeight) {
-       newtTextboxSetHeight(tb, i);
-       maxHeight = i;
-    }
-
-    *height = maxHeight;
-
-    return tb;
-}
-
-
-int gauge(char * text, int height, int width, poptContext optCon, int fd, 
-               int flags) {
-    newtComponent form, scale, tb;
-    int rc;
-    int top;
-    char * arg, * end;
-    int val;
-    FILE * f = fdopen(fd, "r");
-    char buf[3000];
-    char buf3[50];
-    int i;
-
-    setlinebuf(f);
-
-    if (!(arg = poptGetArg(optCon))) usage();
-    val = strtoul(arg, &end, 10);
-    if (*end) usage();
-
-    tb = textbox(height - 3, width - 2, text, flags, &top);
-
-    form = newtForm(NULL, NULL, 0);
-
-    scale = newtScale(2, height - 2, width - 4, 100);
-    newtScaleSet(scale, val);
-
-    newtFormAddComponents(form, tb, scale, NULL);
-
-    newtDrawForm(form);
-    newtRefresh();
-
-    while (fgets(buf, sizeof(buf) - 1, f)) {
-       buf[strlen(buf) - 1] = '\0';
-
-       if (!strcmp(buf, "XXX")) {
-           fgets(buf3, sizeof(buf3) - 1, f);
-           buf3[strlen(buf3) - 1] = '\0';
-           arg = buf3;
-
-           i = 0;
-           while (fgets(buf + i, sizeof(buf) - 1 - i, f)) {
-               buf[strlen(buf) - 1] = '\0';
-               if (!strcmp(buf + i, "XXX")) {
-                   *(buf + i) = '\0';
-                   break;
-               }
-               i = strlen(buf);
-           }
-
-           newtTextboxSetText(tb, buf);
-       } else {
-           arg = buf;
-       }
-
-       val = strtoul(buf, &end, 10);
-       if (!*end) {
-           newtScaleSet(scale, val);
-           newtDrawForm(form);
-           newtRefresh();
-       }
-    }
-
-    return rc;
-}
-
-int inputBox(char * text, int height, int width, poptContext optCon, 
-               int flags) {
-    newtComponent form, entry, okay, cancel, answer, tb;
-    char * val;
-    int rc = 0;
-    int top;
-
-    val = poptGetArg(optCon);
-    tb = textbox(height - 3 - buttonHeight, width - 2,
-                       text, flags, &top);
-
-    form = newtForm(NULL, NULL, 0);
-    entry = newtEntry(1, top + 1, val, width - 2, &val, 
-                       NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
-
-    newtFormAddComponents(form, tb, entry, NULL);
-
-    addButtons(height, width, form, &okay, &cancel, flags);
-
-    answer = newtRunForm(form);
-    if (answer == cancel)
-       rc = 1;
-
-    fprintf(stderr, "%s", val);
-
-    return rc;
-}
-
-int listBox(char * text, int height, int width, poptContext optCon,
-               int flags) {
-    newtComponent form, okay, tb, answer, listBox;
-    newtComponent cancel = NULL;
-    char * arg, * end;
-    int listHeight;
-    int numItems = 0;
-    int allocedItems = 5;
-    int i, top;
-    int rc = 0;
-    char buf[80], format[20];
-    int maxTagWidth = 0;
-    int maxTextWidth = 0;
-    int noScrollFlag;
-    struct {
-       char * text;
-       char * tag;
-    } * itemInfo = malloc(allocedItems * sizeof(*itemInfo));
-
-    if (!(arg = poptGetArg(optCon))) usage();
-    listHeight = strtoul(arg, &end, 10);
-    if (*end) usage();
-
-    while ((arg = poptGetArg(optCon))) {
-       if (allocedItems == numItems) {
-           allocedItems += 5;
-           itemInfo = realloc(itemInfo, sizeof(*itemInfo) * allocedItems);
-       }
-
-       itemInfo[numItems].tag = arg;
-       if (!(arg = poptGetArg(optCon))) usage();
-
-       if (!(flags & FLAG_NOITEM)) {
-           itemInfo[numItems].text = arg;
-       } else
-           itemInfo[numItems].text = "";
-
-       if (strlen(itemInfo[numItems].text) > maxTextWidth)
-           maxTextWidth = strlen(itemInfo[numItems].text);
-       if (strlen(itemInfo[numItems].tag) > maxTagWidth)
-           maxTagWidth = strlen(itemInfo[numItems].tag);
-
-       numItems++;
-    }
-
-    form = newtForm(NULL, NULL, 0);
-
-    tb = textbox(height - 4 - buttonHeight - listHeight, width - 2,
-                       text, flags, &top);
-
-    if (listHeight >= numItems) {
-       noScrollFlag = NEWT_FLAG_NOSCROLL;
-       i = 0;
-    } else {
-       i = 2;
-    }
-
-    listBox = newtListbox(3 + ((width - 10 - maxTagWidth - maxTextWidth - i) 
-                                       / 2),
-                         top + 1, listHeight, 
-                           NEWT_FLAG_RETURNEXIT | noScrollFlag);
-
-    sprintf(format, "%%-%ds  %%s", maxTagWidth);
-    for (i = 0; i < numItems; i++) {
-       sprintf(buf, format, itemInfo[i].tag, itemInfo[i].text);
-       newtListboxAddEntry(listBox, buf, (void *) i);
-    }
-
-    newtFormAddComponents(form, tb, listBox, NULL);
-
-    addButtons(height, width, form, &okay, &cancel, flags);
-
-    answer = newtRunForm(form);
-    if (answer == cancel)
-       rc = 1;
-
-    i = (int) newtListboxGetCurrent(listBox);
-    fprintf(stderr, "%s", itemInfo[i].tag);
-
-    return rc;
-}
-
-int checkList(char * text, int height, int width, poptContext optCon,
-               int useRadio, int flags) {
-    newtComponent form, okay, tb, subform, answer;
-    newtComponent sb = NULL, cancel = NULL;
-    char * arg, * end;
-    int listHeight;
-    int numBoxes = 0;
-    int allocedBoxes = 5;
-    int i;
-    int rc = 0;
-    char buf[80], format[20];
-    int maxWidth = 0;
-    int needSpace = 0;
-    int top;
-    struct {
-       char * text;
-       char * tag;
-       newtComponent comp;
-    } * cbInfo = malloc(allocedBoxes * sizeof(*cbInfo));
-    char * cbStates = malloc(allocedBoxes * sizeof(cbStates));
-
-    if (!(arg = poptGetArg(optCon))) usage();
-    listHeight = strtoul(arg, &end, 10);
-    if (*end) usage();
-
-    while ((arg = poptGetArg(optCon))) {
-       if (allocedBoxes == numBoxes) {
-           allocedBoxes += 5;
-           cbInfo = realloc(cbInfo, sizeof(*cbInfo) * allocedBoxes);
-           cbStates = realloc(cbStates, sizeof(*cbStates) * allocedBoxes);
-       }
-
-       cbInfo[numBoxes].tag = arg;
-       if (!(arg = poptGetArg(optCon))) usage();
-
-       if (!(flags & FLAG_NOITEM)) {
-           cbInfo[numBoxes].text = arg;
-           if (!(arg = poptGetArg(optCon))) usage();
-       } else
-           cbInfo[numBoxes].text = "";
-
-       if (!strcmp(arg, "1") || !strcasecmp(arg, "on") || 
-               !strcasecmp(arg, "yes"))
-           cbStates[numBoxes] = '*';
-       else
-           cbStates[numBoxes] = ' ';
-
-       if (strlen(cbInfo[numBoxes].tag) > maxWidth)
-           maxWidth = strlen(cbInfo[numBoxes].tag);
-
-       numBoxes++;
-    }
-
-    form = newtForm(NULL, NULL, 0);
-
-    tb = textbox(height - 3 - buttonHeight - listHeight, width - 2,
-                       text, flags, &top);
-
-    if (listHeight < numBoxes) { 
-       sb = newtVerticalScrollbar(width - 4, 
-                                  top + 1,
-                                  listHeight, NEWT_COLORSET_CHECKBOX,
-                                  NEWT_COLORSET_ACTCHECKBOX);
-       newtFormAddComponent(form, sb);
-    }
-    subform = newtForm(sb, NULL, 0);
-    newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX);
-
-    sprintf(format, "%%-%ds  %%s", maxWidth);
-    for (i = 0; i < numBoxes; i++) {
-       sprintf(buf, format, cbInfo[i].tag, cbInfo[i].text);
-
-       if (useRadio)
-           cbInfo[i].comp = newtRadiobutton(4, top + 1 + i, buf,
-                                       cbStates[i] != ' ', 
-                                       i ? cbInfo[i - 1].comp : NULL);
-       else
-           cbInfo[i].comp = newtCheckbox(4, top + 1 + i, buf,
-                             cbStates[i], NULL, cbStates + i);
-
-       newtFormAddComponent(subform, cbInfo[i].comp);
-    }
-
-    newtFormSetHeight(subform, listHeight);
-    newtFormSetWidth(subform, width - 10);
-
-    newtFormAddComponents(form, tb, subform, NULL);
-
-    addButtons(height, width, form, &okay, &cancel, flags);
-
-    answer = newtRunForm(form);
-    if (answer == cancel)
-       rc = 1;
-
-    if (useRadio) {
-       answer = newtRadioGetCurrent(cbInfo[0].comp);
-       for (i = 0; i < numBoxes; i++) 
-           if (cbInfo[i].comp == answer) {
-               fprintf(stderr, "%s", cbInfo[i].tag);
-               break;
-           }
-    } else {
-       for (i = 0; i < numBoxes; i++) {
-           /* this should do proper quoting */
-           if (cbStates[i] != ' ') {
-               if (!(flags & FLAG_SEPARATE_OUTPUT)) {
-                   if (needSpace) putc(' ', stderr);
-                   fprintf(stderr, "\"%s\"", cbInfo[i].tag);
-                   needSpace = 1;
-               } else {
-                   fprintf(stderr, "%s\n", cbInfo[i].tag);
-               }
-           }
-       }
-    }
-
-    return rc;
-}
-
-int messageBox(char * text, int height, int width, int type, int flags) {
-    newtComponent form, yes, tb, answer;
-    newtComponent no = NULL;
-    int tFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
-
-    form = newtForm(NULL, NULL, 0);
-
-    tb = newtTextbox(1, 1, width - 2, height - 3 - buttonHeight, 
-                       NEWT_FLAG_WRAP | tFlag);
-    newtTextboxSetText(tb, text);
-
-    newtFormAddComponent(form, tb);
-
-    if (type == MSGBOX_MSG) {
-       yes = makeButton((width - 8) / 2, height - 1 - buttonHeight, "Ok");
-       newtFormAddComponent(form, yes);
-    } else {
-       yes = makeButton((width - 16) / 3, height - 1 - buttonHeight, "Yes");
-       no = makeButton(((width - 16) / 3) * 2 + 9, height - 1 - buttonHeight, 
-                       "No");
-       newtFormAddComponents(form, yes, no, NULL);
-
-       if (flags & FLAG_DEFAULT_NO)
-           newtFormSetCurrent(form, no);
-    }
-
-    newtRunForm(form);
-    answer = newtFormGetCurrent(form);
-
-    if (answer == no)
-       return 1;
-
-    return 0;
-}
-
 int main(int argc, char ** argv) {
     enum mode mode = MODE_NONE;
     poptContext optCon;
@@ -425,7 +37,8 @@ int main(int argc, char ** argv) {
     char * end;
     int height;
     int width;
-    int fd;
+    int fd = -1;
+    int needSpace = 0;
     int noCancel = 0;
     int noItem = 0;
     int clear = 0;
@@ -434,6 +47,8 @@ int main(int argc, char ** argv) {
     int flags = 0;
     int defaultNo = 0;
     int separateOutput = 0;
+    char * result;
+    char ** selections, ** next;
     char * title = NULL;
     char * backtitle = NULL;
     struct poptOption optionsTable[] = {
@@ -457,7 +72,7 @@ int main(int argc, char ** argv) {
            { 0, 0, 0, 0, 0 } 
     };
     
-    optCon = poptGetContext("ndialog", argc, argv, optionsTable, 0);
+    optCon = poptGetContext("whiptail", argc, argv, optionsTable, 0);
 
     while ((arg = poptGetNextOpt(optCon)) > 0) {
        optArg = poptGetOptArg(optCon);
@@ -484,8 +99,7 @@ int main(int argc, char ** argv) {
            break;
 
          case OPT_FULLBUTTONS:
-           buttonHeight = 3;
-           makeButton = newtButton;
+           useFullButtons(1);
            break;
 
          case OPT_YESNO:
@@ -541,7 +155,6 @@ int main(int argc, char ** argv) {
 
     if (noCancel) flags |= FLAG_NOCANCEL;
     if (noItem) flags |= FLAG_NOITEM;
-    if (separateOutput) flags |= FLAG_SEPARATE_OUTPUT;
     if (scrollText) flags |= FLAG_SCROLL_TEXT;
     if (defaultNo) flags |= FLAG_DEFAULT_NO;
 
@@ -555,19 +168,39 @@ int main(int argc, char ** argv) {
        break;
 
       case MODE_INPUTBOX:
-       rc = inputBox(text, height, width, optCon, flags);
+       rc = inputBox(text, height, width, optCon, flags, &result);
+       if (!rc) fprintf(stderr, "%s", result);
        break;
 
       case MODE_MENU:
-       rc = listBox(text, height, width, optCon, flags);
+       rc = listBox(text, height, width, optCon, flags, &result);
+       if (!rc) fprintf(stderr, "%s", result);
        break;
 
       case MODE_RADIOLIST:
-       rc = checkList(text, height, width, optCon, 1, flags);
+       rc = checkList(text, height, width, optCon, 1, flags, &selections);
+       if (!rc) {
+           fprintf(stderr, "%s", selections[0]);
+           free(selections);
+       }
        break;
 
       case MODE_CHECKLIST:
-       rc = checkList(text, height, width, optCon, 0, flags);
+       rc = checkList(text, height, width, optCon, 0, flags, &selections);
+
+       if (!rc) {
+           for (next = selections; *next; next++) {
+               if (!separateOutput) {
+                   if (needSpace) putc(' ', stderr);
+                   fprintf(stderr, "\"%s\"", *next);
+                   needSpace = 1;
+               } else {
+                   fprintf(stderr, "%s\n", *next);
+               }
+           }
+
+           free(selections);
+       }
        break;
 
       case MODE_GAUGE:
@@ -578,6 +211,8 @@ int main(int argc, char ** argv) {
        usage();
     }
 
+    if (rc == -1) usage();
+
     if (clear)
        newtPopWindow();
     newtFinished();
diff --git a/whiptcl.c b/whiptcl.c
new file mode 100644 (file)
index 0000000..a7c6622
--- /dev/null
+++ b/whiptcl.c
@@ -0,0 +1,296 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "dialogboxes.h"
+#include "newt.h"
+#include "popt.h"
+#include "tcl.h"
+
+enum mode { MODE_NONE, MODE_MSGBOX, MODE_YESNO, MODE_CHECKLIST, MODE_INPUTBOX,
+           MODE_RADIOLIST, MODE_MENU };
+
+#define OPT_MSGBOX             1000
+#define OPT_CHECKLIST          1001
+#define OPT_YESNO              1002
+#define OPT_INPUTBOX           1003
+#define OPT_MENU               1005
+#define OPT_RADIOLIST          1006
+
+static char * setBacktext(ClientData data, Tcl_Interp * interp, 
+                         char * name1, char * name2, int flags);
+static char * setHelptext(ClientData data, Tcl_Interp * interp,
+                         char * name1, char * name2, int flags);
+static char * setFullButtons(ClientData data, Tcl_Interp * interp, 
+                            char * name1, char * name2, int flags);
+
+static int wtFinish(ClientData clientData, Tcl_Interp * interp, int argc,
+                  char ** argv) {
+    newtFinished();
+
+    return TCL_OK;
+}
+
+static int wtInit(ClientData clientData, Tcl_Interp * interp, int argc,
+                  char ** argv) {
+    newtInit();
+    newtCls();
+
+    newtPushHelpLine("");
+
+    Tcl_TraceVar(interp, "whiptcl_backtext", 
+                TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, setBacktext, NULL);
+    Tcl_TraceVar(interp, "whiptcl_helpline", 
+                TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY, 
+                setHelptext, NULL);
+    Tcl_TraceVar(interp, "whiptcl_fullbuttons", 
+                TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY, 
+                setFullButtons, NULL);
+
+    Tcl_SetVar(interp, "whiptcl_helpline", "", TCL_GLOBAL_ONLY);
+    Tcl_SetVar(interp, "whiptcl_fullbuttons", "1", TCL_GLOBAL_ONLY);
+
+    return TCL_OK;
+}
+
+static int wtCmd(ClientData clientData, Tcl_Interp * interp, int argc,
+                  char ** argv) {
+    enum mode mode = MODE_NONE;
+    poptContext optCon;
+    int arg;
+    char * optArg;
+    char * text;
+    char * nextArg;
+    char * end;
+    int height;
+    int width;
+    int noCancel = 0;
+    int noItem = 0;
+    int scrollText = 0;
+    int rc = 0;
+    int flags = 0;
+    int defaultNo = 0;
+    char * result;
+    char ** selections, ** next;
+    char * title = NULL;
+    struct poptOption optionsTable[] = {
+           { "checklist", '\0', 0, 0, OPT_CHECKLIST },
+           { "defaultno", '\0', 0, &defaultNo, 0 },
+           { "inputbox", '\0', 0, 0, OPT_INPUTBOX },
+           { "menu", '\0', 0, 0, OPT_MENU },
+           { "msgbox", '\0', 0, 0, OPT_MSGBOX },
+           { "nocancel", '\0', 0, &noCancel, 0 },
+           { "noitem", '\0', 0, &noItem, 0 },
+           { "radiolist", '\0', 0, 0, OPT_RADIOLIST },
+           { "scrolltext", '\0', 0, &scrollText, 0 },
+           { "title", '\0', POPT_ARG_STRING, &title, 0 },
+           { "yesno", '\0', 0, 0, OPT_YESNO },
+           { 0, 0, 0, 0, 0 } 
+    };
+    
+    optCon = poptGetContext("whiptcl", argc, argv, optionsTable, 0);
+
+    while ((arg = poptGetNextOpt(optCon)) > 0) {
+       optArg = poptGetOptArg(optCon);
+
+       switch (arg) {
+         case OPT_MENU:
+           if (mode != MODE_NONE) rc = -1;
+           mode = MODE_MENU;
+           break;
+
+         case OPT_MSGBOX:
+           if (mode != MODE_NONE) rc = -1;
+           mode = MODE_MSGBOX;
+           break;
+
+         case OPT_RADIOLIST:
+           if (mode != MODE_NONE) rc = -1;
+           mode = MODE_RADIOLIST;
+           break;
+
+         case OPT_CHECKLIST:
+           if (mode != MODE_NONE) rc = -1;
+           mode = MODE_CHECKLIST;
+           break;
+
+         case OPT_YESNO:
+           if (mode != MODE_NONE) rc = -1;
+           mode = MODE_YESNO;
+           break;
+
+         case OPT_INPUTBOX:
+           if (mode != MODE_NONE) rc = -1;
+           mode = MODE_INPUTBOX;
+           break;
+       }
+    }
+    
+    if (arg < -1) {
+       /* this could buffer oveflow, bug we're not setuid so I don't care */
+       interp->result = malloc(200);
+       interp->freeProc = TCL_DYNAMIC;
+       sprintf(interp->result, "%s: %s\n", 
+               poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
+               poptStrerror(arg));
+
+       return TCL_ERROR;
+    }
+
+    if (mode == MODE_NONE) {
+       interp->result = "no dialog mode was specified";
+       return TCL_ERROR;
+    } else if (rc) {
+       interp->result = "multiple modes were specified";
+       return TCL_ERROR;
+    }
+
+    if (!(text = poptGetArg(optCon))) {
+       interp->result = "missing text parameter";
+       return TCL_ERROR;
+    }
+
+    if (!(nextArg = poptGetArg(optCon))) {
+       interp->result = "height missing";
+       return TCL_ERROR;
+    }
+    height = strtoul(nextArg, &end, 10);
+    if (*end) {
+       interp->result = "height is not a number";
+       return TCL_ERROR;
+    }
+
+    if (!(nextArg = poptGetArg(optCon))) {
+       interp->result = "width missing";
+       return TCL_ERROR;
+    }
+    width = strtoul(nextArg, &end, 10);
+    if (*end) {
+       interp->result = "width is not a number";
+       return TCL_ERROR;
+    }
+
+    width -= 2;
+    height -= 2;
+    newtOpenWindow((80 - width) / 2, (24 - height) / 2, width, height, title);
+
+    if (noCancel) flags |= FLAG_NOCANCEL;
+    if (noItem) flags |= FLAG_NOITEM;
+    if (scrollText) flags |= FLAG_SCROLL_TEXT;
+    if (defaultNo) flags |= FLAG_DEFAULT_NO;
+
+    switch (mode) {
+      case MODE_MSGBOX:
+       rc = messageBox(text, height, width, MSGBOX_MSG, flags);
+       break;
+
+      case MODE_YESNO:
+       rc = messageBox(text, height, width, MSGBOX_YESNO, flags);
+       if (rc == DLG_OKAY)
+           interp->result = "yes";
+       else 
+           interp->result = "no";
+       if (rc == DLG_ERROR) rc = 0;
+       break;
+
+      case MODE_INPUTBOX:
+       rc = inputBox(text, height, width, optCon, flags, &result);
+       if (!rc) {
+           interp->result = strdup(result);
+           interp->freeProc = TCL_DYNAMIC;
+       }
+       break;
+
+      case MODE_MENU:
+       rc = listBox(text, height, width, optCon, flags, &result);
+       if (!rc) {
+           interp->result = strdup(result);
+           interp->freeProc = TCL_DYNAMIC;
+       }
+       break;
+
+      case MODE_RADIOLIST:
+       rc = checkList(text, height, width, optCon, 1, flags, &selections);
+       if (!rc) {
+           interp->result = strdup(selections[0]);
+           interp->freeProc = TCL_DYNAMIC;
+       }
+       break;
+
+      case MODE_CHECKLIST:
+       rc = checkList(text, height, width, optCon, 0, flags, &selections);
+
+       if (!rc) {
+           for (next = selections; *next; next++) 
+               Tcl_AppendElement(interp, *next);
+
+           free(selections);
+       }
+       break;
+
+      case MODE_NONE:
+       /* this can't happen */
+    }
+
+    newtPopWindow();
+
+    if (rc == DLG_ERROR) {
+       interp->result = "bad paramter for whiptcl dialog box";
+       return TCL_ERROR;
+    } 
+
+    Tcl_SetVar(interp, "whiptcl_canceled", (rc == DLG_CANCEL) ? "1" : "0",
+               0);
+
+    return TCL_OK;
+}
+
+static char * setBacktext(ClientData data, Tcl_Interp * interp, 
+                         char * name1, char * name2, int flags) {
+    static char blankLine[81] = "                                        "
+                         "                                        ";
+
+    newtDrawRootText(0, 0, blankLine);
+    newtDrawRootText(0, 0, Tcl_GetVar(interp, "whiptcl_backtext",
+                                     TCL_GLOBAL_ONLY));
+
+    return NULL;
+}
+
+static char * setHelptext(ClientData data, Tcl_Interp * interp, 
+                         char * name1, char * name2, int flags) {
+    char * text = Tcl_GetVar(interp, "whiptcl_helpline", TCL_GLOBAL_ONLY);
+
+    if (!text)
+       text = "";
+    else if (!strlen(text))
+       text = NULL;
+
+    newtPopHelpLine();
+    newtPushHelpLine(text);
+
+    return NULL;
+}
+
+static char * setFullButtons(ClientData data, Tcl_Interp * interp, 
+                            char * name1, char * name2, int flags) {
+    char * val = Tcl_GetVar(interp, "whiptcl_fullbuttons", TCL_GLOBAL_ONLY);
+    int rc;
+    int state;
+    
+    if ((rc = Tcl_ExprBoolean(interp, val, &state))) {
+       Tcl_FreeResult(interp);
+       return "whiptcl_fullbuttons may only contain a boolean value";
+    }
+
+    useFullButtons(state);
+
+    return NULL;
+}
+
+int Whiptcl_Init(Tcl_Interp * interp) {
+    Tcl_CreateCommand(interp, "whiptcl_finish", wtFinish, NULL, NULL);
+    Tcl_CreateCommand(interp, "whiptcl_init", wtInit, NULL, NULL);
+    Tcl_CreateCommand(interp, "whiptcl_cmd", wtCmd, NULL, NULL);
+
+    return TCL_OK;
+}