]> git.ipfire.org Git - thirdparty/newt.git/blobdiff - dialogboxes.c
install python modules to purelib and platlib
[thirdparty/newt.git] / dialogboxes.c
index 41440094a570b2e1aa3697442cc598562a942913..9658e36b1f39919d0a7c461325b789f6018b8dd7 100644 (file)
 /* 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"
 #include "popt.h"
 
+#define MAXBUF    200
+#define MAXFORMAT 20
+#define BUTTONS   4
+
 /* globals -- ick */
 static int buttonHeight = 1;
+static const char * buttonText[BUTTONS];
+
+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 const char * getButtonText(int button) {
+    const char * text;
+    if (button < 0 || button >= BUTTONS)
+       return NULL;
+
+    text = buttonText[button];
+    if (text)
+       return text;
+
+    switch (button) {
+       case 0: return dgettext(PACKAGE, "Ok");
+       case 1: return dgettext(PACKAGE, "Cancel");
+       case 2: return dgettext(PACKAGE, "Yes");
+       case 3: return dgettext(PACKAGE, "No");
+       default:
+               return NULL;
+    }
+}
+
 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,
+                             getButtonText(BUTTON_OK));
+           *cancel = NULL;
        newtFormAddComponent(form, *okay);
     } else {
-       *okay = makeButton((width - 18) / 3, height - buttonHeight - 1, "Ok");
+       *okay = makeButton((width - 18) / 3, height - buttonHeight - 1, 
+                          getButtonText(BUTTON_OK));
        *cancel = makeButton(((width - 18) / 3) * 2 + 9, 
-                               height - buttonHeight - 1, "Cancel");
+                               height - buttonHeight - 1, 
+                               getButtonText(BUTTON_CANCEL));
        newtFormAddComponents(form, *okay, *cancel, NULL);
     }
 }
 
+static void cleanNewlines(char *text)
+{
+    char *p, *q;
+
+    for (p = q = text; *p; p++, q++)
+        if (*p == '\\' && p[1] == 'n') {
+            p++;
+            *q = '\n';
+        } else
+            *q = *p;
+    *q = '\0';
+}
+
 static newtComponent textbox(int maxHeight, int width, const char * text,
                        int flags, int * height) {
     newtComponent tb;
     int sFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
     int i;
-    char * buf, * dst;
-    const char * src;
-
-    dst = buf = alloca(strlen(text) + 1);
-    src = text; 
-    while (*src) {
-       if (*src == '\\' && *(src + 1) == 'n') {
-           src += 2;
-           *dst++ = '\n';
-       } else
-           *dst++ = *src++;
-    }
-    *dst++ = '\0';
+    char *buf;
+
+    buf = alloca(strlen(text) + 1);
+    strcpy(buf, text);
+    cleanNewlines(buf);
 
     tb = newtTextbox(1, 0, width, maxHeight, NEWT_FLAG_WRAP | sFlag);
     newtTextboxSetText(tb, buf);
@@ -93,36 +142,51 @@ int gauge(const char * text, int height, int width, poptContext optCon, int fd,
     newtDrawForm(form);
     newtRefresh();
 
-    while (fgets(buf, sizeof(buf) - 1, f)) {
+    do {
+       if (!fgets(buf, sizeof(buf) - 1, f))
+           continue;
        buf[strlen(buf) - 1] = '\0';
 
        if (!strcmp(buf, "XXX")) {
-           fgets(buf3, sizeof(buf3) - 1, f);
+           while (!fgets(buf3, sizeof(buf3) - 1, f) && !feof(f))
+               ;
+           if (feof(f))
+               break;
            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")) {
+           do {
+               if (!fgets(buf + i, sizeof(buf) - 1 - i, f))
+                   continue;
+               if (!strcmp(buf + i, "XXX\n")) {
                    *(buf + i) = '\0';
                    break;
                }
                i = strlen(buf);
-           }
+           } while (!feof(f));
+
+           if (i > 0)
+               buf[strlen(buf) - 1] = '\0';
+           else
+               buf[0] = '\0';
 
+           cleanNewlines(buf);
            newtTextboxSetText(tb, buf);
-       } else {
+
+           arg = buf3;
+       } else {
            arg = buf;
        }
 
-       val = strtoul(buf, &end, 10);
+       val = strtoul(arg, &end, 10);
        if (!*end) {
            newtScaleSet(scale, val);
            newtDrawForm(form);
            newtRefresh();
        }
-    }
+    } while (!feof(f));
+
+    newtFormDestroy(form);
 
     return DLG_OKAY;
 }
@@ -130,7 +194,8 @@ int gauge(const char * text, int height, int width, poptContext optCon, int fd,
 int inputBox(const char * text, int height, int width, poptContext optCon, 
                int flags, char ** result) {
     newtComponent form, entry, okay, cancel, answer, tb;
-    char * val;
+    const char * val;
+    int pFlag = (flags & FLAG_PASSWORD) ? NEWT_FLAG_PASSWORD : 0;
     int rc = DLG_OKAY;
     int top;
 
@@ -140,66 +205,113 @@ 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);
 
     addButtons(height, width, form, &okay, &cancel, flags);
 
     answer = newtRunForm(form);
+    *result = NULL;
     if (answer == cancel)
        rc = DLG_CANCEL;
+    else if (answer == NULL)
+       rc = DLG_ESCAPE;
+    else
+       *result = strdup(val);
 
-    *result = val;
+    newtFormDestroy(form);
 
     return rc;
 }
 
-int listBox(const char * text, int height, int width, poptContext optCon,
-               int flags, char ** result) {
-    newtComponent form, okay, tb, answer, listBox;
+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, int listHeight, poptContext optCon,
+               int flags, const char *default_item, char ** result) {
+    newtComponent form = NULL, okay, tb, answer, listBox;
     newtComponent cancel = NULL;
     const char * arg;
-    char * end;
-    int listHeight;
     int numItems = 0;
     int allocedItems = 5;
     int i, top;
-    int rc = DLG_OKAY;
-    char buf[80], format[20];
+    int rc = DLG_ERROR;
+    char buf[MAXBUF];
     int maxTagWidth = 0;
     int maxTextWidth = 0;
+    int defItem = -1;
     int scrollFlag;
+    int lineWidth, textWidth, tagWidth;
     struct {
        const char * text;
        const char * tag;
     } * itemInfo = malloc(allocedItems * sizeof(*itemInfo));
+    void * tmp;
 
-    if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
-    listHeight = strtoul(arg, &end, 10);
-    if (*end) return DLG_ERROR;
+    if (itemInfo == NULL)
+       goto error;
 
     while ((arg = poptGetArg(optCon))) {
        if (allocedItems == numItems) {
            allocedItems += 5;
-           itemInfo = realloc(itemInfo, sizeof(*itemInfo) * allocedItems);
+           tmp = realloc(itemInfo, sizeof(*itemInfo) * allocedItems);
+           if (tmp == NULL)
+               goto error;
+           itemInfo = tmp;
        }
 
        itemInfo[numItems].tag = arg;
-       if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+       if (default_item && (strcmp(default_item, arg) == 0)) {
+               defItem = numItems;
+       }
+       if (!(arg = poptGetArg(optCon)))
+           goto error;
 
        if (!(flags & FLAG_NOITEM)) {
            itemInfo[numItems].text = arg;
        } else
            itemInfo[numItems].text = "";
 
-       if (strlen(itemInfo[numItems].text) > (unsigned int)maxTextWidth)
-           maxTextWidth = strlen(itemInfo[numItems].text);
-       if (strlen(itemInfo[numItems].tag) > (unsigned int)maxTagWidth)
-           maxTagWidth = strlen(itemInfo[numItems].tag);
+       if (wstrlen(itemInfo[numItems].text,-1) > (unsigned int)maxTextWidth)
+           maxTextWidth = wstrlen(itemInfo[numItems].text,-1);
+       if (wstrlen(itemInfo[numItems].tag,-1) > (unsigned int)maxTagWidth)
+           maxTagWidth = wstrlen(itemInfo[numItems].tag,-1);
 
        numItems++;
     }
+    if (numItems == 0)
+       goto error;
+
+    if (flags & FLAG_NOTAGS) {
+           maxTagWidth = 0;
+    }
 
     form = newtForm(NULL, NULL, 0);
 
@@ -214,44 +326,88 @@ 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 + 1, SLtt_Screen_Cols - 6);
+    listBox = newtListbox( (width - lineWidth) / 2 , top + 1, listHeight,
+                          NEWT_FLAG_RETURNEXIT | scrollFlag);
 
-    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);
+    textWidth = maxTextWidth;
+    tagWidth = maxTagWidth;
+    if (maxTextWidth == 0) {
+        tagWidth = lineWidth;
+    } else {
+       tagWidth++;
+       while (textWidth + tagWidth + i > lineWidth) {
+           if (textWidth >= tagWidth && textWidth > 0)
+               textWidth--;
+           else if (tagWidth > 0)
+               tagWidth--;
+           else
+               break;
+       }
     }
 
+    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 + 1 >= MAXBUF)
+                      break;
+                  buf[len++] = ' ';
+          }
+          buf[len] = '\0';
+          w = textWidth;
+          mystrncpyw(buf + len, itemInfo[i].text, MAXBUF-len, &w);
+           newtListboxAddEntry(listBox, buf, (void *)(long) i);
+       }
+     } else {
+        for (i = 0; i < numItems; i++) {
+           snprintf(buf, MAXBUF, "%s", itemInfo[i].text);
+           newtListboxAddEntry(listBox, buf, (void *)(long) i);
+      }
+   }
+
+    if (defItem != -1)
+       newtListboxSetCurrent (listBox, defItem);
+
     newtFormAddComponents(form, tb, listBox, NULL);
 
     addButtons(height, width, form, &okay, &cancel, flags);
 
     answer = newtRunForm(form);
+    *result = NULL;
     if (answer == cancel)
        rc = DLG_CANCEL;
+    else if (answer == NULL)
+       rc = DLG_ESCAPE;
+    else {
+       i = (long) newtListboxGetCurrent(listBox);
+       *result = strdup(itemInfo[i].tag);
+       if (*result == NULL)
+           goto error;
+       rc = DLG_OKAY;
+    }
 
-    i = (int) newtListboxGetCurrent(listBox);
-    *result = itemInfo[i].tag;
+error:
+    if (form)
+       newtFormDestroy(form);
+    free(itemInfo);
 
     return rc;
 }
 
-int checkList(const char * text, int height, int width, poptContext optCon,
-               int useRadio, int flags, char *** selections) {
-    newtComponent form, okay, tb, subform, answer;
+int checkList(const char * text, int height, int width, int listHeight,
+             poptContext optCon, int useRadio, int flags, char *** selections) {
+    newtComponent form = NULL, okay, tb, subform, answer;
     newtComponent sb = NULL, cancel = NULL;
     const char * arg;
-    char * end;
-    int listHeight;
     int numBoxes = 0;
     int allocedBoxes = 5;
     int i;
     int numSelected;
-    int rc = DLG_OKAY;
-    char buf[80], format[20];
+    int rc = DLG_ERROR;
+    char buf[MAXBUF], format[MAXFORMAT];
     int maxWidth = 0;
     int top;
     struct {
@@ -259,25 +415,35 @@ int checkList(const char * text, int height, int width, poptContext optCon,
        const char * tag;
        newtComponent comp;
     } * cbInfo = malloc(allocedBoxes * sizeof(*cbInfo));
-    char * cbStates = malloc(allocedBoxes * sizeof(cbStates));
+    char * cbStates = malloc(allocedBoxes * sizeof(*cbStates));
+    void * tmp;
 
-    if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
-    listHeight = strtoul(arg, &end, 10);
-    if (*end) return DLG_ERROR;
+    if (cbInfo == NULL || cbStates == NULL)
+       goto error;
 
     while ((arg = poptGetArg(optCon))) {
        if (allocedBoxes == numBoxes) {
            allocedBoxes += 5;
-           cbInfo = realloc(cbInfo, sizeof(*cbInfo) * allocedBoxes);
-           cbStates = realloc(cbStates, sizeof(*cbStates) * allocedBoxes);
+
+           tmp = realloc(cbInfo, sizeof(*cbInfo) * allocedBoxes);
+           if (tmp == NULL)
+               goto error;
+           cbInfo = tmp;
+
+           tmp = realloc(cbStates, sizeof(*cbStates) * allocedBoxes);
+           if (tmp == NULL)
+               goto error;
+           cbStates = tmp;
        }
 
        cbInfo[numBoxes].tag = arg;
-       if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+       if (!(arg = poptGetArg(optCon)))
+           goto error;
 
        if (!(flags & FLAG_NOITEM)) {
            cbInfo[numBoxes].text = arg;
-           if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+           if (!(arg = poptGetArg(optCon)))
+               goto error;
        } else
            cbInfo[numBoxes].text = "";
 
@@ -287,8 +453,8 @@ int checkList(const char * text, int height, int width, poptContext optCon,
        else
            cbStates[numBoxes] = ' ';
 
-       if (strlen(cbInfo[numBoxes].tag) > (unsigned int)maxWidth)
-           maxWidth = strlen(cbInfo[numBoxes].tag);
+       if (wstrlen(cbInfo[numBoxes].tag,-1) > (unsigned int)maxWidth)
+           maxWidth = wstrlen(cbInfo[numBoxes].tag,-1);
 
        numBoxes++;
     }
@@ -308,18 +474,23 @@ int checkList(const char * text, int height, int width, poptContext optCon,
     subform = newtForm(sb, NULL, 0);
     newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX);
 
-    sprintf(format, "%%-%ds  %%s", maxWidth);
+    if (flags & FLAG_NOTAGS)
+       snprintf(format, MAXFORMAT, "%%.0s%%s");
+    else
+       snprintf(format, MAXFORMAT, "%%-%ds  %%s", maxWidth);
+
     for (i = 0; i < numBoxes; i++) {
-       sprintf(buf, format, cbInfo[i].tag, cbInfo[i].text);
+       snprintf(buf, MAXBUF, format, cbInfo[i].tag, cbInfo[i].text);
 
        if (useRadio)
-           cbInfo[i].comp = newtRadiobutton(4, top + 1 + i, buf,
+           cbInfo[i].comp = newtRadiobutton(2, top + 1 + i, buf,
                                        cbStates[i] != ' ', 
                                        i ? cbInfo[i - 1].comp : NULL);
        else
-           cbInfo[i].comp = newtCheckbox(4, top + 1 + i, buf,
+           cbInfo[i].comp = newtCheckbox(2, top + 1 + i, buf,
                              cbStates[i], NULL, cbStates + i);
 
+       newtCheckboxSetFlags(cbInfo[i].comp, NEWT_FLAG_RETURNEXIT, NEWT_FLAGS_SET);
        newtFormAddComponent(subform, cbInfo[i].comp);
     }
 
@@ -331,41 +502,58 @@ int checkList(const char * text, int height, int width, poptContext optCon,
     addButtons(height, width, form, &okay, &cancel, flags);
 
     answer = newtRunForm(form);
+    *selections = NULL;
     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 if (answer == NULL)
+       rc = DLG_ESCAPE;
+    else {
+       if (useRadio) {
+           answer = newtRadioGetCurrent(cbInfo[0].comp);
+           *selections = malloc(sizeof(char *) * 2);
+           if (*selections == NULL)
+               goto error;
+           (*selections)[0] = (*selections)[1] = NULL;
+           for (i = 0; i < numBoxes; i++)
+               if (cbInfo[i].comp == answer) {
+                   (*selections)[0] = strdup(cbInfo[i].tag);
+                   break;
+               }
+       } else {
+           numSelected = 0;
+           for (i = 0; i < numBoxes; i++) {
+               if (cbStates[i] != ' ') numSelected++;
            }
-    } else {
-       numSelected = 0;
-       for (i = 0; i < numBoxes; i++) {
-           if (cbStates[i] != ' ') numSelected++;
-       }
 
-       *selections = malloc(sizeof(char *) * (numSelected + 1));
+           *selections = malloc(sizeof(char *) * (numSelected + 1));
+           if (*selections == NULL)
+               goto error;
 
-       numSelected = 0;
-       for (i = 0; i < numBoxes; i++) {
-           if (cbStates[i] != ' ') 
-               (*selections)[numSelected++] = cbInfo[i].tag;
+           numSelected = 0;
+           for (i = 0; i < numBoxes; i++) {
+               if (cbStates[i] != ' ')
+                   (*selections)[numSelected++] = strdup(cbInfo[i].tag);
+           }
+
+           (*selections)[numSelected] = NULL;
        }
 
-       (*selections)[numSelected] = NULL;
+       rc = DLG_OKAY;
     }
 
+error:
+    free(cbInfo);
+    free(cbStates);
+    if (form)
+       newtFormDestroy(form);
+
     return rc;
 }
 
 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);
@@ -380,13 +568,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, 
+                         getButtonText(BUTTON_OK));
        newtFormAddComponent(form, yes);
        break;
     default:
-       yes = makeButton((width - 16) / 3, height - 1 - buttonHeight, "Yes");
+       yes = makeButton((width - 16) / 3, height - 1 - buttonHeight, 
+                        getButtonText(BUTTON_YES));
        no = makeButton(((width - 16) / 3) * 2 + 9, height - 1 - buttonHeight, 
-                       "No");
+                        getButtonText(BUTTON_NO));
        newtFormAddComponents(form, yes, no, NULL);
 
        if (flags & FLAG_DEFAULT_NO)
@@ -394,21 +585,22 @@ 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);
 
        if (answer == no)
-           return DLG_CANCEL;
+           rc = DLG_CANCEL;
     }
     else {
        newtDrawForm(form);
        newtRefresh();
     }
-       
 
+    newtFormDestroy(form);
 
-    return DLG_OKAY;
+    return rc;
 }
 
 void useFullButtons(int state) {
@@ -420,3 +612,9 @@ void useFullButtons(int state) {
        makeButton = newtCompactButton;
    }
 }
+
+void setButtonText(const char * text, int button) {
+    if (button < 0 || button >= BUTTONS)
+       return;
+    buttonText[button] = text;
+}