summaryrefslogtreecommitdiffstats
path: root/gnu
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1998-09-26 12:29:57 +0000
committerjkh <jkh@FreeBSD.org>1998-09-26 12:29:57 +0000
commita27c9f956a0dc8fc5170dd5f24a69c844ace1f6a (patch)
treecc3c4a47bc43b04a02d8fc9f79f886747f06cc6a /gnu
parent968dcc7cb58ee3c99fbd00e5fd281241ee1fc152 (diff)
downloadFreeBSD-src-a27c9f956a0dc8fc5170dd5f24a69c844ace1f6a.zip
FreeBSD-src-a27c9f956a0dc8fc5170dd5f24a69c844ace1f6a.tar.gz
Add some new functionality which I promised to add over a year a go and
shamefully dropped on the floor. I need to add it now since it does a minor number bump, but otherwise the current functionality of libdialog is unchanged (in all its evil glory) and the change is non-intrusive. Submitted by: "Anatoly A. Orehovsky" <tolik@mpeks.tomsk.su>
Diffstat (limited to 'gnu')
-rw-r--r--gnu/lib/libdialog/Makefile6
-rw-r--r--gnu/lib/libdialog/dialog.h46
-rw-r--r--gnu/lib/libdialog/tree.c940
-rw-r--r--gnu/lib/libdialog/tree.h46
4 files changed, 1035 insertions, 3 deletions
diff --git a/gnu/lib/libdialog/Makefile b/gnu/lib/libdialog/Makefile
index 167098e..784401f 100644
--- a/gnu/lib/libdialog/Makefile
+++ b/gnu/lib/libdialog/Makefile
@@ -1,14 +1,14 @@
# Makefile for libdialog
-# $Id$
+# $Id: Makefile,v 1.21 1997/02/22 15:42:35 peter Exp $
LIB= dialog
MAN3= dialog.3
SHLIB_MAJOR= 3
-SHLIB_MINOR= 0
+SHLIB_MINOR= 1
SRCS= kernel.c rc.c checklist.c inputbox.c menubox.c msgbox.c \
lineedit.c radiolist.c textbox.c yesno.c prgbox.c raw_popen.c \
- fselect.c ui_objects.c dir.c notify.c help.c gauge.c
+ fselect.c ui_objects.c dir.c notify.c help.c gauge.c tree.c
CFLAGS+= -I${.CURDIR} -Wall -Wstrict-prototypes -DLOCALE
diff --git a/gnu/lib/libdialog/dialog.h b/gnu/lib/libdialog/dialog.h
index 76011b4..b9d911c 100644
--- a/gnu/lib/libdialog/dialog.h
+++ b/gnu/lib/libdialog/dialog.h
@@ -158,4 +158,50 @@ char *get_helpline(void);
void restore_helpline(char *helpline);
void dialog_gauge(char *title, char *prompt, int y, int x, int height, int width, int perc);
+/*
+ * Display a tree menu from file
+ *
+ * filename - file with like find(1) output
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set (must be freed later)
+ * 1 - Cancel
+ */
+int dialog_ftree(unsigned char *filename, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result);
+
+/*
+ * Display a tree menu from array
+ *
+ * names - array with like find(1) output
+ * size - size of array
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set (must be freed later)
+ * 1 - Cancel
+ */
+
+int dialog_tree(unsigned char **names, int size, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result);
+
#endif /* _DIALOG_H_INCLUDE */
diff --git a/gnu/lib/libdialog/tree.c b/gnu/lib/libdialog/tree.c
new file mode 100644
index 0000000..957beb5
--- /dev/null
+++ b/gnu/lib/libdialog/tree.c
@@ -0,0 +1,940 @@
+/*
+ * tree.c -- implements the 'tree' interface element for libdialog
+ *
+ * Author: Anatoly A. Orehovsky (tolik@mpeks.tomsk.su)
+ *
+ * Copyright (c) 1997, Anatoly A. Orehovsky
+ *
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <dialog.h>
+#include "dialog.priv.h"
+#include <ncurses.h>
+
+/* static utils for make tree */
+struct leaf {
+ unsigned char *name; /* name of leaf */
+ unsigned char *branches; /* branches that going by leaf */
+ unsigned char slip; /* slip of leaf*/
+ int shift; /* shift relative root of tree */
+};
+
+static int mk_slip(struct leaf array[], int arr_size,
+ int number, int shift);
+
+/* make tree from file
+ *
+ * filename - name of file with like find(1) output
+ * p_names - pointer to array of strings
+ * p_size - pointer to size of array
+ * FS - fields separator
+ * p_array - pointer to array of leafs
+ *
+ * return values:
+ * 0 - ok and names by p_names, size by p_size, array by p_array set
+ * -1 - memory allocation error (errno set)
+ */
+
+static int mk_ftree(char *filename,
+ unsigned char ***p_names, int *p_size, unsigned char FS,
+ struct leaf **p_array);
+
+/* make tree from array
+ *
+ * names - array of strings
+ * size - size of array
+ * FS - fields separator
+ * p_array - pointer to array of leafs
+ *
+ * return values:
+ * 0 - ok and array by p_array set
+ * -1 - memory allocation error (errno set)
+ */
+
+static int mk_tree(unsigned char **names, int size, unsigned char FS,
+ struct leaf **p_array);
+
+/* free memory from tree (leafs)
+ *
+ * return values:
+ * nothing
+ */
+
+static void free_leafs(struct leaf *array, int size);
+
+/* free memory from source data for tree (names)
+ *
+ * return values:
+ * if 0 <= choice <= size - pointer to name from names,
+ * and memory for name not released (must be freed later)
+ * else - NULL (recomended choice -1 for it)
+ */
+
+static unsigned char *free_names(unsigned char **names,
+ int size, int choice);
+
+/* end of static utils for make tree */
+
+/* static utils for ftree */
+
+/* control struct for queue */
+struct queue {
+ int size; /* size of queue */
+ struct m_queue *first; /* begin of queue */
+ struct m_queue *last; /* end of queue */
+};
+
+/* queue member */
+struct m_queue {
+ void *pointer; /* queue member */
+ struct m_queue *next; /* next queue member */
+};
+
+/* init struct queue by zeros */
+static void init_queue(struct queue *queue);
+
+/* add pointer to queue */
+/* return - pointer or NULL if error */
+static void *p2_queue(struct queue *queue, void *pointer);
+
+/* get first from queue */
+/* return - pointer or NULL if queue is empty */
+static void *first_queue(struct queue *queue);
+
+/* make zero terminated array from queue */
+/* return - pointer to array or NULL if error */
+static void **q2arr(struct queue *queue, int depth);
+
+/* end of static utils for ftree */
+
+static void print_item(WINDOW *win, struct leaf item, int choice, int selected);
+
+static void print_position(WINDOW *win, int x, int y,
+ int cur_pos, int size);
+
+static int menu_width, item_x;
+
+static int dialog_treemenu(unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ int item_no, struct leaf items[],
+ int *result,
+ int *ch, int *sc);
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+static
+int dialog_treemenu(unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ int item_no, struct leaf items[],
+ int *result,
+ int *ch, int *sc)
+{
+ int i, j, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0,
+ l, scroll = 0, max_choice, redraw_menu = FALSE;
+ WINDOW *dialog, *menu;
+
+ if (ch) /* restore menu item info */
+ choice = *ch;
+ if (sc)
+ scroll = *sc;
+
+ max_choice = MIN(menu_height, item_no);
+
+ item_x = 0;
+ /* Find length of longest item in order to center menu */
+ for (i = 0; i < item_no; i++) {
+ l = strlen(items[i].name) + strlen(items[i].branches) * 4 + 4;
+ item_x = MAX(item_x, l);
+ }
+
+ if (height < 0)
+ height = strheight(prompt)+menu_height+4+2;
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i,j);
+ width = MAX(width,item_x+4)+4;
+ }
+ width = MAX(width,24);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = (COLS - width)/2;
+ y = (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
+ exit(1);
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+ print_autowrap(dialog, prompt, height-1, width-2, width, 1, 2, TRUE, FALSE);
+
+ menu_width = width-6;
+ getyx(dialog, cur_y, cur_x);
+ box_y = cur_y + 1;
+ box_x = (width - menu_width)/2 - 1;
+
+ /* create new window for the menu */
+ menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1);
+ if (menu == NULL) {
+ endwin();
+ fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", menu_height,menu_width,y+box_y+1,x+box_x+1);
+ exit(1);
+ }
+ keypad(menu, TRUE);
+
+ /* draw a box around the menu items */
+ draw_box(dialog, box_y, box_x, menu_height+2, menu_width+2, menubox_border_attr, menubox_attr);
+
+ item_x = 1;
+
+ /* Print the menu */
+ for (i = 0; i < max_choice; i++)
+ print_item(menu, items[(scroll+i)], i, i == choice);
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, item_x, cur_x, cur_y);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+
+ display_helpline(dialog, height-1, width);
+
+ x = width/2-11;
+ y = height-2;
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+
+ wrefresh(dialog);
+
+ while (key != ESC) {
+ key = wgetch(dialog);
+ /* Check if key pressed matches first character of any item tag in menu */
+
+ if (key == KEY_UP || key == KEY_DOWN || key == '-' || key == '+') {
+ if (key == KEY_UP || key == '-') {
+ if (!choice) {
+ if (scroll) {
+#ifdef BROKEN_WSCRL
+ /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation
+ violation when scrolling windows of height = 4, so scrolling is not
+ used for now */
+ scroll--;
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ /* Reprint menu to scroll down */
+ for (i = 0; i < max_choice; i++)
+ print_item(menu, items[(scroll+i)], i, i == choice);
+
+#else
+
+ /* Scroll menu down */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (menu_height > 1) {
+ /* De-highlight current first item before scrolling down */
+ print_item(menu, items[scroll], 0, FALSE);
+ scrollok(menu, TRUE);
+ wscrl(menu, -1);
+ scrollok(menu, FALSE);
+ }
+ scroll--;
+ print_item(menu, items[scroll], 0, TRUE);
+#endif
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, item_x, cur_x, cur_y);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice - 1;
+ }
+ else if (key == KEY_DOWN || key == '+')
+ if (choice == max_choice - 1) {
+ if (scroll+choice < item_no-1) {
+#ifdef BROKEN_WSCRL
+ /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation
+ violation when scrolling windows of height = 4, so scrolling is not
+ used for now */
+ scroll++;
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ /* Reprint menu to scroll up */
+ for (i = 0; i < max_choice; i++)
+ print_item(menu, items[(scroll+i)], i, i == choice);
+
+#else
+
+ /* Scroll menu up */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (menu_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ print_item(menu, items[(scroll+max_choice-1)], max_choice-1, FALSE);
+ scrollok(menu, TRUE);
+ scroll(menu);
+ scrollok(menu, FALSE);
+ }
+ scroll++;
+ print_item(menu, items[(scroll+max_choice-1)], max_choice-1, TRUE);
+#endif
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, item_x, cur_x, cur_y);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice + 1;
+
+ if (i != choice) {
+ /* De-highlight current item */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ print_item(menu, items[(scroll+choice)], choice, FALSE);
+
+ /* Highlight new item */
+ choice = i;
+ print_item(menu, items[(scroll+choice)], choice, TRUE);
+ wnoutrefresh(menu);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+
+ /* save info about menu item position */
+ if (ch)
+ *ch = choice;
+ if (sc)
+ *sc = scroll;
+
+ switch (key) {
+ case KEY_PPAGE:
+ case 'b' :
+ if (scroll > menu_height) { /* can we go up? */
+ scroll -= (menu_height);
+ } else {
+ scroll = 0;
+ }
+ redraw_menu = TRUE;
+ break;
+ case KEY_NPAGE:
+ case ' ' :
+ if (scroll + menu_height >= item_no-1 - menu_height) { /* can we go down a full page? */
+ scroll = item_no - menu_height;
+ if (scroll < 0) scroll = 0;
+ } else {
+ scroll += menu_height;
+ }
+ redraw_menu = TRUE;
+ break;
+ case KEY_HOME:
+ case 'g' :
+ scroll = 0;
+ choice = 0;
+ redraw_menu = TRUE;
+ break;
+ case KEY_END:
+ case 'G' :
+ scroll = item_no - menu_height;
+ if (scroll < 0) scroll = 0;
+ choice = max_choice - 1;
+ redraw_menu = TRUE;
+ break;
+ case 'O':
+ case 'o':
+ delwin(dialog);
+ *result = scroll+choice;
+ return 0;
+ case 'C':
+ case 'c':
+ delwin(dialog);
+ return 1;
+ case KEY_BTAB:
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ if (!button) {
+ button = 1; /* Indicates "Cancel" button is selected */
+ print_button(dialog, " OK ", y, x, FALSE);
+ print_button(dialog, "Cancel", y, x+14, TRUE);
+ }
+ else {
+ button = 0; /* Indicates "OK" button is selected */
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+ }
+ wrefresh(dialog);
+ break;
+ case '\r':
+ case '\n':
+ delwin(dialog);
+ if (!button)
+ *result = scroll+choice;
+ return button;
+ case ESC:
+ break;
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+ if (redraw_menu) {
+ for (i = 0; i < max_choice; i++) {
+ print_item(menu, items[(scroll+i)],
+ i, i == choice);
+ }
+ wnoutrefresh(menu);
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, item_x, cur_x, cur_y);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ redraw_menu = FALSE;
+ }
+ }
+
+ delwin(dialog);
+ return -1; /* ESC pressed */
+}
+/* End of dialog_treemenu() */
+
+
+/*
+ * Print menu item
+ */
+static void print_item(WINDOW *win, struct leaf item, int choice, int selected)
+{
+ int i, j = menu_width - 2;
+ char *branches = item.branches;
+
+ /* Clear 'residue' of last item */
+ wattrset(win, menubox_attr);
+ wmove(win, choice, 0);
+ for (i = 0; i < menu_width; i++)
+ waddch(win, ' ');
+ wmove(win, choice, item_x);
+
+ while(*branches && j)
+ {
+ switch (*branches++) {
+ case ' ' : waddch(win, ' ');
+ break;
+ case '|' : waddch(win, ACS_VLINE);
+ }
+
+ j--;
+ i = 3;
+ while(i-- && j)
+ {
+ waddch(win, ' ');
+ j--;
+ }
+ }
+
+ if (j)
+ {
+ switch (item.slip) {
+ case '+' : waddch(win, ACS_LTEE);
+ break;
+ case '`' : waddch(win, ACS_LLCORNER);
+ }
+ j--;
+ }
+
+ i = 3;
+ while(i-- && j)
+ {
+ waddch(win, ACS_HLINE);
+ j--;
+ }
+
+ wattrset(win, selected ? item_selected_attr : item_attr);
+ if (j)
+ waddnstr(win, item.name, j);
+}
+/* End of print_item() */
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW *win, int x, int y,
+ int cur_pos, int size)
+{
+ int percent;
+
+ wattrset(win, position_indicator_attr);
+ percent = cur_pos == size - 1 ? 100 : (cur_pos * 100)/(size - 1);
+ wmove(win, y + 1, x - 6);
+ wprintw(win, "(%3d%%)", percent);
+}
+/* End of print_position() */
+
+/*
+ * Display a tree menu from file
+ *
+ * filename - file with like find(1) output
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set (must be freed later)
+ * 1 - Cancel
+ */
+
+int dialog_ftree(unsigned char *filename, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result)
+{
+ int retcode, choice, size;
+ struct leaf *items;
+ unsigned char **names;
+
+ if (mk_ftree(filename, &names, &size, FS, &items))
+ {
+ perror("dialog_ftree");
+ end_dialog();
+ exit(-1);
+ }
+
+ if (!size)
+ {
+ fprintf(stderr, "\ndialog_ftree: file %s is empty\n", filename);
+ end_dialog();
+ exit(-1);
+ }
+
+ retcode = dialog_treemenu(title, prompt, height, width, menu_height,
+ size, items, &choice, NULL, NULL);
+
+ free_leafs(items, size);
+
+ if (!retcode)
+ *result = free_names(names, size, choice);
+ else
+ (void)free_names(names, size, -1);
+
+ return retcode;
+}
+/* End of dialog_ftree() */
+
+/*
+ * Display a tree menu from array
+ *
+ * names - array with like find(1) output
+ * size - size of array
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set (must be freed later)
+ * 1 - Cancel
+ */
+
+int dialog_tree(unsigned char **names, int size, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result)
+{
+ int retcode, choice;
+ struct leaf *items;
+
+ if (!size)
+ {
+ fprintf(stderr, "\ndialog_tree: source array is empty\n");
+ end_dialog();
+ exit(-1);
+ }
+
+ if (mk_tree(names, size, FS, &items))
+ {
+ perror("dialog_tree");
+ end_dialog();
+ exit(-1);
+ }
+
+ retcode = dialog_treemenu(title, prompt, height, width, menu_height,
+ size, items, &choice, NULL, NULL);
+
+ free_leafs(items, size);
+
+ if (!retcode)
+ *result = names[choice];
+
+ return retcode;
+}
+/* End of dialog_tree() */
+
+/* utils for ftree */
+
+/* init struct queue by zeros */
+static void
+init_queue(struct queue *queue)
+{
+ bzero((void *)queue, sizeof(struct queue));
+}
+
+/* add pointer to queue */
+/* return - pointer or NULL if error */
+static void *
+p2_queue(struct queue *queue, void *pointer)
+{
+ if (!queue)
+ return NULL;
+
+ if (!queue->first)
+ {
+ if (!(queue->first = queue->last =
+ calloc(1, sizeof(struct m_queue))))
+ return NULL;
+
+ }
+ else
+ {
+ if (!(queue->last->next =
+ calloc(1, sizeof(struct m_queue))))
+ return NULL;
+
+ queue->last = queue->last->next;
+ }
+
+ queue->size++;
+ return queue->last->pointer = pointer;
+}
+
+/* get first from queue */
+/* return - pointer or NULL if queue is empty */
+static void *
+first_queue(struct queue *queue)
+{
+ void *retval;
+ struct m_queue *new_first;
+
+ if (!queue ||
+ !queue->first ||
+ !queue->size)
+ return NULL;
+
+ retval = queue->first->pointer;
+ new_first = queue->first->next;
+ free(queue->first);
+ queue->first = new_first;
+ queue->size--;
+
+ return retval;
+
+}
+
+/* make zero terminated array from queue */
+/* return - pointer to array or NULL if error */
+static void **
+q2arr(struct queue *queue, int depth)
+{
+ void **mono, **end;
+
+ if (!queue ||
+ !queue->first ||
+ !queue->size)
+ return NULL;
+
+ /* memory allocation for array */
+ if (!(mono = end = malloc(depth * sizeof(void *) + 1)))
+ return NULL;
+
+ while(depth--)
+ {
+ if (!(*end++ = first_queue(queue)))
+ break;
+ }
+
+ *end = NULL;
+
+ return mono;
+
+}
+
+/* end of utils for ftree */
+
+/* utils for make tree */
+
+/* if error - return -1 */
+static
+int
+mk_slip(struct leaf array[], int arr_size, int number, int shift)
+{
+ int t_number;
+ int t_shift;
+
+ if (number > arr_size - 1)
+ return number - 1;
+
+ t_shift = shift;
+
+ if (!(array[number].branches = calloc(1, t_shift + 1)))
+ return -1;
+
+ (void)memset(array[number].branches, ' ', t_shift);
+
+ t_number = number;
+
+ while (array[number].shift < array[t_number + 1].shift)
+ {
+ t_number = mk_slip(array, arr_size, t_number + 1, t_shift + 1);
+ if (t_number < 0)
+ return -1;
+ if (t_number == arr_size - 1)
+ break;
+ }
+
+ if (array[number].shift == array[t_number + 1].shift)
+ array[number].slip = '+';
+
+ if ((array[number].shift > array[t_number + 1].shift) ||
+ t_number == arr_size - 1)
+ array[number].slip = '`';
+
+ return t_number;
+
+} /* mk_slip() */
+
+/* make tree from file
+ *
+ * filename - name of file with like find(1) output
+ * p_names - pointer to array of strings
+ * p_size - pointer to size of array
+ * FS - fields separator
+ * p_array - pointer to array of leafs
+ *
+ * return values:
+ * 0 - ok and names by p_names, size by p_size, array by p_array set
+ * -1 - memory allocation error (errno set)
+ */
+
+static
+int
+mk_ftree(char *filename,
+ unsigned char ***p_names, int *p_size, unsigned char FS,
+ struct leaf **p_array)
+{
+ int NR; /* number of input records */
+ struct queue queue;
+ unsigned char *string;
+ unsigned char **names;
+
+ FILE *input_file;
+
+ if (!(input_file = fopen(filename, "r")))
+ return -1;
+
+ init_queue(&queue);
+
+ if (!(string = malloc(BUFSIZ)))
+ return -1;
+
+ /* read input file into queue */
+ while(fgets(string, BUFSIZ, input_file))
+ {
+ if (strchr(string, '\n'))
+ *strchr(string, '\n') = '\0';
+
+ if (!(string = realloc(string, strlen(string) + 1)))
+ return -1;
+
+ if (!p2_queue(&queue, string))
+ return -1;
+
+ if (!(string = malloc(BUFSIZ)))
+ return -1;
+ } /* read input file into queue */
+
+ if (fclose(input_file) == EOF)
+ return -1;
+
+ if (!(NR = queue.size))
+ {
+ *p_size = 0;
+ return 0;
+ }
+
+ /* make array from queue */
+ if (!(names = (unsigned char **)q2arr(&queue, NR)))
+ return -1;
+
+ *p_names = names;
+ *p_size = NR;
+
+ /* make tree from array */
+ return mk_tree(names, NR, FS, p_array);
+
+} /* mk_ftree */
+
+/* make tree from array
+ *
+ * names - array of strings
+ * size - size of array
+ * FS - fields separator
+ * p_array - pointer to array of leafs
+ *
+ * return values:
+ * 0 - ok and array by p_array set
+ * -1 - memory allocation error (errno set)
+ */
+
+static
+int
+mk_tree(unsigned char **names, int size, unsigned char FS,
+ struct leaf **p_array)
+{
+ int i;
+ struct leaf *array;
+
+ /* make array of leafs */
+ if (!(array = calloc(size, sizeof(struct leaf))))
+ return -1;
+
+ /* init leafs */
+ for (i = 0; i < size; i++)
+ {
+ unsigned char *in_string, *name;
+ int shift = 0;
+
+ in_string = name = names[i];
+ while(*in_string)
+ {
+ if (*in_string == FS)
+ if (!i && !*(in_string + 1))
+ name = in_string;
+ else
+ {
+ shift++;
+ name = in_string + 1;
+ }
+ in_string++;
+ }
+ array[i].name = name;
+ array[i].shift = shift;
+ array[i].slip = '\0';
+ array[i].branches = NULL;
+ } /* init leafs */
+
+ /* make slips */
+ for (i = 0;i < size; i++)
+ {
+ i = mk_slip(array, size, i, 0);
+ if (i < 0)
+ return -1;
+ } /* make slips */
+
+ /* make branches */
+ for (i = 1;i < size; i++)
+ {
+ unsigned char *src = array[i - 1].branches;
+ unsigned char *dst = array[i].branches;
+
+ while(*src && *dst)
+ *dst++ = *src++;
+
+ if (*dst)
+ switch (array[i - 1].slip) {
+ case '+' : *dst = '|';
+ break;
+ case '`' : *dst = ' ';
+ }
+ } /* make branches */
+
+ *p_array = array;
+ return 0;
+
+} /* mk_tree() */
+
+/* free memory from tree (leafs)
+ *
+ * return values:
+ * nothing
+ */
+
+static
+void
+free_leafs(struct leaf *array, int size)
+{
+ struct leaf *p_array = array;
+
+ while (size--)
+ free(array++->branches);
+
+ free(p_array);
+} /* free_leafs() */
+
+/* free memory from source data for tree (names)
+ *
+ * return values:
+ * if 0 <= choice <= size - pointer to name from names,
+ * and memory for name not released (must be freed later)
+ * else - NULL (recomended choice -1 for it)
+ */
+
+static
+unsigned char *
+free_names(unsigned char **names, int size, int choice)
+{
+ unsigned char *retval = NULL;
+
+ while (size--)
+ {
+ if (!choice--)
+ retval = *names++;
+ else
+ free(*names++);
+ }
+ free(names);
+ return retval;
+} /* free_names() */
+
+/* end of utils for make tree */
diff --git a/gnu/lib/libdialog/tree.h b/gnu/lib/libdialog/tree.h
new file mode 100644
index 0000000..e78b3d5
--- /dev/null
+++ b/gnu/lib/libdialog/tree.h
@@ -0,0 +1,46 @@
+/*
+ * Display a tree menu from file
+ *
+ * filename - file with like find(1) output
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set (must be freed later)
+ * 1 - Cancel
+ */
+
+int dialog_ftree(unsigned char *filename, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result);
+
+/*
+ * Display a tree menu from array
+ *
+ * names - array with like find(1) output
+ * size - size of array
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set (must be freed later)
+ * 1 - Cancel
+ */
+
+int dialog_tree(unsigned char **names, int size, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result);
OpenPOWER on IntegriCloud