diff options
author | jkh <jkh@FreeBSD.org> | 1998-09-26 12:29:57 +0000 |
---|---|---|
committer | jkh <jkh@FreeBSD.org> | 1998-09-26 12:29:57 +0000 |
commit | a27c9f956a0dc8fc5170dd5f24a69c844ace1f6a (patch) | |
tree | cc3c4a47bc43b04a02d8fc9f79f886747f06cc6a /gnu/lib/libdialog | |
parent | 968dcc7cb58ee3c99fbd00e5fd281241ee1fc152 (diff) | |
download | FreeBSD-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/lib/libdialog')
-rw-r--r-- | gnu/lib/libdialog/Makefile | 6 | ||||
-rw-r--r-- | gnu/lib/libdialog/dialog.h | 46 | ||||
-rw-r--r-- | gnu/lib/libdialog/tree.c | 940 | ||||
-rw-r--r-- | gnu/lib/libdialog/tree.h | 46 |
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); |