static bool handle_input(DIALOG_CALLBACK * cb) { MY_OBJ *obj = (MY_OBJ *) cb; bool result; int status; char buf[MY_LEN]; if (dialog_state.pipe_input == 0) { status = -1; } else if ((status = read_data(buf, dialog_state.pipe_input)) > 0) { if (isMarker(buf)) { /* * Historically, next line should be percentage, but one of the * worse-written clones of 'dialog' assumes the number is missing. * (Gresham's Law applied to software). */ if ((status = read_data(buf, dialog_state.pipe_input)) > 0) { obj->prompt_buf[0] = '\0'; if (decode_percent(buf)) obj->percent = atoi(buf); else strcpy(obj->prompt_buf, buf); /* Rest is message text */ while ((status = read_data(buf, dialog_state.pipe_input)) > 0 && !isMarker(buf)) { if (strlen(obj->prompt_buf) + strlen(buf) < sizeof(obj->prompt_buf) - 1) { strcat(obj->prompt_buf, buf); } } if (obj->prompt != obj->prompt_buf) free(obj->prompt); obj->prompt = obj->prompt_buf; } } else if (decode_percent(buf)) { obj->percent = atoi(buf); } } else { if (feof(dialog_state.pipe_input) || (ferror(dialog_state.pipe_input) && errno != EINTR)) { delink(obj); dlg_remove_callback(cb); } } if (status > 0) { result = TRUE; repaint_text(obj); } else { result = FALSE; } return result; }
void dlg_free_gauge(void *objptr) { MY_OBJ *obj = (MY_OBJ *) objptr; curs_set(1); if (valid(obj)) { delink(obj); obj->obj.keep_win = FALSE; dlg_remove_callback(&(obj->obj)); } }
/* * Display a gauge, or progress meter. Starts at percent% and reads stdin. If * stdin is not XXX, then it is interpreted as a percentage, and the display is * updated accordingly. Otherwise the next line is the percentage, and * subsequent lines up to another XXX are used for the new prompt. Note that * the size of the window never changes, so the prompt can not get any larger * than the height and width specified. */ int dialog_gauge(const char *title, const char *cprompt, int height, int width, int percent) { int fkey; int ch, result; void *objptr = dlg_allocate_gauge(title, cprompt, height, width, percent); MY_OBJ *obj = (MY_OBJ *) objptr; dlg_add_callback_ref((DIALOG_CALLBACK **) & obj, my_cleanup); dlg_update_gauge(obj, percent); dlg_trace_win(obj->obj.win); do { ch = dlg_getc(obj->obj.win, &fkey); #ifdef KEY_RESIZE if (fkey && ch == KEY_RESIZE) { MY_OBJ *oldobj = obj; dlg_mouse_free_regions(); obj = dlg_allocate_gauge(title, cprompt, height, width, oldobj->percent); /* avoid breaking new window in dlg_remove_callback */ oldobj->obj.caller = 0; oldobj->obj.input = 0; oldobj->obj.keep_win = FALSE; /* remove the old version of the gauge */ dlg_clear(); dlg_remove_callback(&(oldobj->obj)); refresh(); dlg_add_callback_ref((DIALOG_CALLBACK **) & obj, my_cleanup); dlg_update_gauge(obj, obj->percent); } #endif } while (valid(obj) && handle_my_getc(&(obj->obj), ch, fkey, &result)); dlg_free_gauge(obj); return (DLG_EXIT_OK); }
int dlg_getc_callbacks(int ch, int fkey, int *result) { int code = FALSE; DIALOG_CALLBACK *p, *q; if ((p = dialog_state.getc_callbacks) != 0) { if (check_inputs() >= 0) { do { q = p->next; if (p->input_ready) { if (!(p->handle_getc(p, ch, fkey, result))) { dlg_remove_callback(p); } } } while ((p = q) != 0); } code = (dialog_state.getc_callbacks != 0); } return code; }
/* * If we have callbacks active, purge the list of all that are not marked * to keep in the background. If any remain, run those in a background * process. */ void dlg_killall_bg(int *retval) { DIALOG_CALLBACK *cb; int pid; #ifdef HAVE_TYPE_UNIONWAIT union wait wstatus; #else int wstatus; #endif if ((cb = dialog_state.getc_callbacks) != 0) { while (cb != 0) { if (cb->keep_bg) { cb = cb->next; } else { dlg_remove_callback(cb); cb = dialog_state.getc_callbacks; } } if (dialog_state.getc_callbacks != 0) { refresh(); fflush(stdout); fflush(stderr); reset_shell_mode(); if ((pid = fork()) != 0) { _exit(pid > 0 ? DLG_EXIT_OK : DLG_EXIT_ERROR); } else if (pid == 0) { /* child */ if ((pid = fork()) != 0) { /* * Echo the process-id of the grandchild so a shell script * can read that, and kill that process. We'll wait around * until then. Our parent has already left, leaving us * temporarily orphaned. */ if (pid > 0) { /* parent */ fprintf(stderr, "%d\n", pid); fflush(stderr); } /* wait for child */ #ifdef HAVE_WAITPID while (-1 == waitpid(pid, &wstatus, 0)) { #ifdef EINTR if (errno == EINTR) continue; #endif /* EINTR */ #ifdef ERESTARTSYS if (errno == ERESTARTSYS) continue; #endif /* ERESTARTSYS */ break; } #else while (wait(&wstatus) != pid) /* do nothing */ ; #endif _exit(WEXITSTATUS(wstatus)); } else if (pid == 0) { if (!dialog_vars.cant_kill) (void) signal(SIGHUP, finish_bg); (void) signal(SIGINT, finish_bg); (void) signal(SIGQUIT, finish_bg); (void) signal(SIGSEGV, finish_bg); while (dialog_state.getc_callbacks != 0) { int fkey = 0; dlg_getc_callbacks(ERR, fkey, retval); napms(1000); } } } } } }
/* * Read a character from the given window. Handle repainting here (to simplify * things in the calling application). Also, if input-callback(s) are set up, * poll the corresponding files and handle the updates, e.g., for displaying a * tailbox. */ int dlg_getc(WINDOW *win, int *fkey) { WINDOW *save_win = win; int ch = ERR; int before_chr; int before_fkey; int result; bool done = FALSE; bool literal = FALSE; DIALOG_CALLBACK *p = 0; int interval = (dialog_vars.timeout_secs * 1000); time_t expired = time((time_t *) 0) + dialog_vars.timeout_secs; time_t current; if (may_handle_inputs()) wtimeout(win, WTIMEOUT_VAL); else if (interval > 0) wtimeout(win, interval); while (!done) { bool handle_others = FALSE; /* * If there was no pending file-input, check the keyboard. */ ch = really_getch(win, fkey); if (literal) { done = TRUE; continue; } before_chr = ch; before_fkey = *fkey; ch = dlg_lookup_key(win, ch, fkey); dlg_trace_chr(ch, *fkey); current = time((time_t *) 0); /* * If we acquired a fkey value, then it is one of dialog's builtin * codes such as DLGK_HELPFILE. */ if (!*fkey || *fkey != before_fkey) { switch (ch) { case CHR_LITERAL: literal = TRUE; keypad(win, FALSE); continue; case CHR_REPAINT: (void) touchwin(win); (void) wrefresh(curscr); break; case ERR: /* wtimeout() in effect; check for file I/O */ if (interval > 0 && current >= expired) { dlg_exiterr("timeout"); } if (!valid_file(stdin) || !valid_file(dialog_state.screen_output)) { ch = ESC; done = TRUE; } else if (check_inputs()) { if (handle_inputs(win)) dlg_raise_window(win); else done = TRUE; } else { done = (interval <= 0); } break; case DLGK_HELPFILE: if (dialog_vars.help_file) { int yold, xold; getyx(win, yold, xold); dialog_helpfile("HELP", dialog_vars.help_file, 0, 0); dlg_raise_window(win); wmove(win, yold, xold); } continue; case DLGK_FIELD_PREV: /* FALLTHRU */ case KEY_BTAB: /* FALLTHRU */ case DLGK_FIELD_NEXT: /* FALLTHRU */ case TAB: /* Handle tab/backtab as a special case for traversing between * the nominal "current" window, and other windows having * callbacks. If the nominal (control) window closes, we'll * close the windows with callbacks. */ if (dialog_state.getc_callbacks != 0 && (isBeforeChr(TAB) || isBeforeFkey(KEY_BTAB))) { p = (isBeforeChr(TAB) ? next_callback(p) : prev_callback(p)); if ((dialog_state.getc_redirect = p) != 0) { win = p->win; } else { win = save_win; } dlg_raise_window(win); break; } /* FALLTHRU */ default: #ifdef NO_LEAKS if (isBeforeChr(DLG_CTRL('P'))) { /* for testing, ^P closes the connection */ close(0); close(1); close(2); break; } #endif handle_others = TRUE; break; #ifdef HAVE_DLG_TRACE case CHR_TRACE: dlg_trace_win(win); break; #endif } } else { handle_others = TRUE; } if (handle_others) { if ((p = dialog_state.getc_redirect) != 0) { if (!(p->handle_getc(p, ch, *fkey, &result))) { done = (p->win == save_win) && (!p->keep_win); dlg_remove_callback(p); dialog_state.getc_redirect = 0; win = save_win; } } else { done = TRUE; } } } if (literal) keypad(win, TRUE); return ch; }