From: ewt Date: Mon, 18 Aug 1997 21:12:01 +0000 (+0000) Subject: split whiptail dialog stuff out; added whiptcl X-Git-Tag: r0-12~46 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=649a0152ab45c8f8ab13e2951041ea3a8cc6853e;p=thirdparty%2Fnewt.git split whiptail dialog stuff out; added whiptcl --- diff --git a/Makefile b/Makefile index ca56d8b..11e8a57 100644 --- 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 index 0000000..55a59b2 --- /dev/null +++ b/dialogboxes.c @@ -0,0 +1,405 @@ +/* simple dialog boxes, used by both whiptail and tcl dialog bindings */ + +#include +#include +#include +#include +#include + +#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 index 0000000..0cf17c2 --- /dev/null +++ b/dialogboxes.h @@ -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 ee94865..c63800c 100644 --- 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 10eaf67..7d9f40c 100644 --- 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 97acd1b..2523144 100644 --- 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; diff --git a/whiptail.c b/whiptail.c index beff5ad..1bb494b 100644 --- a/whiptail.c +++ b/whiptail.c @@ -6,6 +6,7 @@ #include #include +#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 index 0000000..a7c6622 --- /dev/null +++ b/whiptcl.c @@ -0,0 +1,296 @@ +#include +#include + +#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; +}