indent(1): Attempt to preserve some consistent style.
[freebsd-src.git] / lib / libdpv / dpv.c
blob8ac39b10f86cd852412e3ff20bd5f21652b349c7
1 /*-
2 * Copyright (c) 2013-2016 Devin Teske <dteske@FreeBSD.org>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
35 #include <ctype.h>
36 #include <dialog.h>
37 #include <err.h>
38 #include <limits.h>
39 #include <locale.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <string_m.h>
44 #include <unistd.h>
46 #include "dialog_util.h"
47 #include "dialogrc.h"
48 #include "dprompt.h"
49 #include "dpv.h"
50 #include "dpv_private.h"
51 #include "status.h"
52 #include "util.h"
54 /* Test Mechanics (Only used when dpv_config.options |= DPV_TEST_MODE) */
55 #define INCREMENT 1 /* Increment % per-pass test-mode */
56 #define XDIALOG_INCREMENT 15 /* different for slower Xdialog(1) */
57 static uint8_t increment = INCREMENT;
59 /* Debugging */
60 uint8_t debug = FALSE;
62 /* Data to process */
63 int dpv_interrupt = FALSE;
64 int dpv_abort = FALSE;
65 unsigned int dpv_nfiles = 0;
67 /* Data processing */
68 long long dpv_overall_read = 0;
69 static char pathbuf[PATH_MAX];
71 /* Extra display information */
72 uint8_t keep_tite = FALSE; /* dpv_config.keep_tite */
73 uint8_t no_labels = FALSE; /* dpv_config.options & DPV_NO_LABELS */
74 uint8_t wide = FALSE; /* dpv_config.options & DPV_WIDE_MODE */
75 char *aprompt = NULL; /* dpv_config.aprompt */
76 char *msg_done = NULL; /* dpv_config.msg_done */
77 char *msg_fail = NULL; /* dpv_config.msg_fail */
78 char *msg_pending = NULL; /* dpv_config.msg_pending */
79 char *pprompt = NULL; /* dpv_config.pprompt */
81 /* Status-Line format for when using dialog(3) */
82 static const char *status_format_custom = NULL;
83 static char status_format_default[DPV_STATUS_FORMAT_MAX];
86 * Takes a pointer to a dpv_config structure containing layout details and
87 * pointer to initial element in a linked-list of dpv_file_node structures,
88 * each presenting a file to process. Executes the `action' function passed-in
89 * as a member to the `config' structure argument.
91 int
92 dpv(struct dpv_config *config, struct dpv_file_node *file_list)
94 char c;
95 uint8_t keep_going;
96 uint8_t nls = FALSE; /* See dialog_prompt_nlstate() */
97 uint8_t no_overrun = FALSE;
98 uint8_t pprompt_nls = FALSE; /* See dialog_prompt_nlstate() */
99 uint8_t shrink_label_size = FALSE;
100 mode_t mask;
101 uint16_t options;
102 char *cp;
103 char *fc;
104 char *last;
105 char *name;
106 char *output;
107 const char *status_fmt;
108 const char *path_fmt;
109 enum dpv_display display_type;
110 enum dpv_output output_type;
111 enum dpv_status status;
112 int (*action)(struct dpv_file_node *file, int out);
113 int backslash;
114 int dialog_last_update = 0;
115 int dialog_old_nthfile = 0;
116 int dialog_old_seconds = -1;
117 int dialog_out = STDOUT_FILENO;
118 int dialog_update_usec = 0;
119 int dialog_updates_per_second;
120 int files_left;
121 int max_cols;
122 int nthfile = 0;
123 int output_out;
124 int overall = 0;
125 int pct;
126 int res;
127 int seconds;
128 int status_last_update = 0;
129 int status_old_nthfile = 0;
130 int status_old_seconds = -1;
131 int status_update_usec = 0;
132 int status_updates_per_second;
133 pid_t output_pid;
134 pid_t pid;
135 size_t len;
136 struct dpv_file_node *curfile;
137 struct dpv_file_node *first_file;
138 struct dpv_file_node *list_head;
139 struct timeval now;
140 struct timeval start;
141 char init_prompt[PROMPT_MAX + 1] = "";
143 /* Initialize globals to default values */
144 aprompt = NULL;
145 pprompt = NULL;
146 options = 0;
147 action = NULL;
148 backtitle = NULL;
149 debug = FALSE;
150 dialog_test = FALSE;
151 dialog_updates_per_second = DIALOG_UPDATES_PER_SEC;
152 display_limit = DISPLAY_LIMIT_DEFAULT;
153 display_type = DPV_DISPLAY_LIBDIALOG;
154 keep_tite = FALSE;
155 label_size = LABEL_SIZE_DEFAULT;
156 msg_done = NULL;
157 msg_fail = NULL;
158 msg_pending = NULL;
159 no_labels = FALSE;
160 output = NULL;
161 output_type = DPV_OUTPUT_NONE;
162 pbar_size = PBAR_SIZE_DEFAULT;
163 status_format_custom = NULL;
164 status_updates_per_second = STATUS_UPDATES_PER_SEC;
165 title = NULL;
166 wide = FALSE;
168 /* Process config options (overriding defaults) */
169 if (config != NULL) {
170 if (config->aprompt != NULL) {
171 if (aprompt == NULL) {
172 aprompt = malloc(DPV_APROMPT_MAX);
173 if (aprompt == NULL)
174 return (-1);
176 snprintf(aprompt, DPV_APROMPT_MAX, "%s",
177 config->aprompt);
179 if (config->pprompt != NULL) {
180 if (pprompt == NULL) {
181 pprompt = malloc(DPV_PPROMPT_MAX + 2);
182 /* +2 is for implicit "\n" appended later */
183 if (pprompt == NULL)
184 return (-1);
186 snprintf(pprompt, DPV_APROMPT_MAX, "%s",
187 config->pprompt);
190 options = config->options;
191 action = config->action;
192 backtitle = config->backtitle;
193 debug = config->debug;
194 dialog_test = ((options & DPV_TEST_MODE) != 0);
195 dialog_updates_per_second = config->dialog_updates_per_second;
196 display_limit = config->display_limit;
197 display_type = config->display_type;
198 keep_tite = config->keep_tite;
199 label_size = config->label_size;
200 msg_done = (char *)config->msg_done;
201 msg_fail = (char *)config->msg_fail;
202 msg_pending = (char *)config->msg_pending;
203 no_labels = ((options & DPV_NO_LABELS) != 0);
204 no_overrun = ((options & DPV_NO_OVERRUN) != 0);
205 output = config->output;
206 output_type = config->output_type;
207 pbar_size = config->pbar_size;
208 status_updates_per_second = config->status_updates_per_second;
209 title = config->title;
210 wide = ((options & DPV_WIDE_MODE) != 0);
212 /* Enforce some minimums (pedantic) */
213 if (display_limit < -1)
214 display_limit = -1;
215 if (label_size < -1)
216 label_size = -1;
217 if (pbar_size < -1)
218 pbar_size = -1;
220 /* For the mini-pbar, -1 means hide, zero is invalid unless
221 * only one file is given */
222 if (pbar_size == 0) {
223 if (file_list == NULL || file_list->next == NULL)
224 pbar_size = -1;
225 else
226 pbar_size = PBAR_SIZE_DEFAULT;
229 /* For the label, -1 means auto-size, zero is invalid unless
230 * specifically requested through the use of options flag */
231 if (label_size == 0 && no_labels == FALSE)
232 label_size = LABEL_SIZE_DEFAULT;
234 /* Status update should not be zero */
235 if (status_updates_per_second == 0)
236 status_updates_per_second = STATUS_UPDATES_PER_SEC;
237 } /* config != NULL */
239 /* Process the type of display we've been requested to produce */
240 switch (display_type) {
241 case DPV_DISPLAY_STDOUT:
242 debug = TRUE;
243 use_color = FALSE;
244 use_dialog = FALSE;
245 use_libdialog = FALSE;
246 use_xdialog = FALSE;
247 break;
248 case DPV_DISPLAY_DIALOG:
249 use_color = TRUE;
250 use_dialog = TRUE;
251 use_libdialog = FALSE;
252 use_xdialog = FALSE;
253 break;
254 case DPV_DISPLAY_XDIALOG:
255 snprintf(dialog, PATH_MAX, XDIALOG);
256 use_color = FALSE;
257 use_dialog = FALSE;
258 use_libdialog = FALSE;
259 use_xdialog = TRUE;
260 break;
261 default:
262 use_color = TRUE;
263 use_dialog = FALSE;
264 use_libdialog = TRUE;
265 use_xdialog = FALSE;
266 break;
267 } /* display_type */
269 /* Enforce additional minimums that require knowing our display type */
270 if (dialog_updates_per_second == 0)
271 dialog_updates_per_second = use_xdialog ?
272 XDIALOG_UPDATES_PER_SEC : DIALOG_UPDATES_PER_SEC;
274 /* Allow forceful override of use_color */
275 if (config != NULL && (config->options & DPV_USE_COLOR) != 0)
276 use_color = TRUE;
278 /* Count the number of files in provided list of dpv_file_node's */
279 if (use_dialog && pprompt != NULL && *pprompt != '\0')
280 pprompt_nls = dialog_prompt_nlstate(pprompt);
282 max_cols = dialog_maxcols();
283 if (label_size == -1)
284 shrink_label_size = TRUE;
286 /* Process file arguments */
287 for (curfile = file_list; curfile != NULL; curfile = curfile->next) {
288 dpv_nfiles++;
290 /* dialog(3) only expands literal newlines */
291 if (use_libdialog) strexpandnl(curfile->name);
293 /* Optionally calculate label size for file */
294 if (shrink_label_size) {
295 nls = FALSE;
296 name = curfile->name;
297 if (curfile == file_list)
298 nls = pprompt_nls;
299 last = (char *)dialog_prompt_lastline(name, nls);
300 if (use_dialog) {
301 c = *last;
302 *last = '\0';
303 nls = dialog_prompt_nlstate(name);
304 *last = c;
306 len = dialog_prompt_longestline(last, nls);
307 if ((int)len > (label_size - 3)) {
308 if (label_size > 0)
309 label_size += 3;
310 label_size = len;
311 /* Room for ellipsis (unless NULL) */
312 if (label_size > 0)
313 label_size += 3;
316 if (max_cols > 0 && label_size > (max_cols - pbar_size
317 - 9))
318 label_size = max_cols - pbar_size - 9;
321 if (debug)
322 warnx("label=[%s] path=[%s] size=%lli",
323 curfile->name, curfile->path, curfile->length);
324 } /* file_list */
326 /* Optionally process the contents of DIALOGRC (~/.dialogrc) */
327 if (use_dialog) {
328 res = parse_dialogrc();
329 if (debug && res == 0) {
330 warnx("Successfully read `%s' config file", DIALOGRC);
331 warnx("use_shadow = %i (Boolean)", use_shadow);
332 warnx("use_colors = %i (Boolean)", use_colors);
333 warnx("gauge_color=[%s] (FBH)", gauge_color);
335 } else if (use_libdialog) {
336 init_dialog(stdin, stdout);
337 use_shadow = dialog_state.use_shadow;
338 use_colors = dialog_state.use_colors;
339 gauge_color[0] = 48 + dlg_color_table[GAUGE_ATTR].fg;
340 gauge_color[1] = 48 + dlg_color_table[GAUGE_ATTR].bg;
341 gauge_color[2] = dlg_color_table[GAUGE_ATTR].hilite ?
342 'b' : 'B';
343 gauge_color[3] = '\0';
344 end_dialog();
345 if (debug) {
346 warnx("Finished initializing dialog(3) library");
347 warnx("use_shadow = %i (Boolean)", use_shadow);
348 warnx("use_colors = %i (Boolean)", use_colors);
349 warnx("gauge_color=[%s] (FBH)", gauge_color);
353 /* Enable mini progress bar automatically for stdin streams if unable
354 * to calculate progress (missing `lines:' syntax). */
355 if (dpv_nfiles <= 1 && file_list != NULL && file_list->length < 0 &&
356 !dialog_test)
357 pbar_size = PBAR_SIZE_DEFAULT;
359 /* If $USE_COLOR is set and non-NULL enable color; otherwise disable */
360 if ((cp = getenv(ENV_USE_COLOR)) != 0)
361 use_color = *cp != '\0' ? 1 : 0;
363 /* Print error and return `-1' if not given at least one name */
364 if (dpv_nfiles == 0) {
365 warnx("%s: no labels provided", __func__);
366 return (-1);
367 } else if (debug)
368 warnx("%s: %u label%s provided", __func__, dpv_nfiles,
369 dpv_nfiles == 1 ? "" : "s");
371 /* If only one file and pbar size is zero, default to `-1' */
372 if (dpv_nfiles <= 1 && pbar_size == 0)
373 pbar_size = -1;
375 /* Print some debugging information */
376 if (debug) {
377 warnx("%s: %s(%i) max rows x cols = %i x %i",
378 __func__, use_xdialog ? XDIALOG : DIALOG,
379 use_libdialog ? 3 : 1, dialog_maxrows(),
380 dialog_maxcols());
383 /* Xdialog(1) updates a lot slower than dialog(1) */
384 if (dialog_test && use_xdialog)
385 increment = XDIALOG_INCREMENT;
387 /* Always add implicit newline to pprompt (when specified) */
388 if (pprompt != NULL && *pprompt != '\0') {
389 len = strlen(pprompt);
391 * NOTE: pprompt = malloc(PPROMPT_MAX + 2)
392 * NOTE: (see getopt(2) section above for pprompt allocation)
394 pprompt[len++] = '\\';
395 pprompt[len++] = 'n';
396 pprompt[len++] = '\0';
399 /* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
400 if (use_xdialog && pprompt != NULL) {
401 /* Replace `\n' with `\n\\n\n' in pprompt */
402 len = strlen(pprompt);
403 len += strcount(pprompt, "\\n") * 2;
404 if (len > DPV_PPROMPT_MAX)
405 errx(EXIT_FAILURE, "%s: Oops, pprompt buffer overflow "
406 "(%zu > %i)", __func__, len, DPV_PPROMPT_MAX);
407 if (replaceall(pprompt, "\\n", "\n\\n\n") < 0)
408 err(EXIT_FAILURE, "%s: replaceall()", __func__);
410 /* libdialog requires literal newlines */
411 else if (use_libdialog && pprompt != NULL)
412 strexpandnl(pprompt);
414 /* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
415 if (use_xdialog && aprompt != NULL) {
416 /* Replace `\n' with `\n\\n\n' in aprompt */
417 len = strlen(aprompt);
418 len += strcount(aprompt, "\\n") * 2;
419 if (len > DPV_APROMPT_MAX)
420 errx(EXIT_FAILURE, "%s: Oops, aprompt buffer overflow "
421 " (%zu > %i)", __func__, len, DPV_APROMPT_MAX);
422 if (replaceall(aprompt, "\\n", "\n\\n\n") < 0)
423 err(EXIT_FAILURE, "%s: replaceall()", __func__);
425 /* libdialog requires literal newlines */
426 else if (use_libdialog && aprompt != NULL)
427 strexpandnl(aprompt);
430 * Warn user about an obscure dialog(1) bug (neither Xdialog(1) nor
431 * libdialog are affected) in the `--gauge' widget. If the first non-
432 * whitespace letter of "{new_prompt}" in "XXX\n{new_prompt}\nXXX\n"
433 * is a number, the number can sometimes be mistaken for a percentage
434 * to the overall progressbar. Other nasty side-effects such as the
435 * entire prompt not displaying or displaying improperly are caused by
436 * this bug too.
438 * NOTE: When we can use color, we have a work-around... prefix the
439 * output with `\Zn' (used to terminate ANSI and reset to normal).
441 if (use_dialog && !use_color) {
442 backslash = 0;
444 /* First, check pprompt (falls through if NULL) */
445 fc = pprompt;
446 while (fc != NULL && *fc != '\0') {
447 if (*fc == '\n') /* leading literal newline OK */
448 break;
449 if (!isspace(*fc) && *fc != '\\' && backslash == 0)
450 break;
451 else if (backslash > 0 && *fc != 'n')
452 break;
453 else if (*fc == '\\') {
454 backslash++;
455 if (backslash > 2)
456 break; /* we're safe */
458 fc++;
460 /* First non-whitespace character that dialog(1) will see */
461 if (fc != NULL && *fc >= '0' && *fc <= '9')
462 warnx("%s: WARNING! text argument to `-p' begins with "
463 "a number (not recommended)", __func__);
464 else if (fc > pprompt)
465 warnx("%s: WARNING! text argument to `-p' begins with "
466 "whitespace (not recommended)", __func__);
469 * If no pprompt or pprompt is all whitespace, check the first
470 * file name provided to make sure it is alright too.
472 if ((pprompt == NULL || *fc == '\0') && file_list != NULL) {
473 first_file = file_list;
474 fc = first_file->name;
475 while (fc != NULL && *fc != '\0' && isspace(*fc))
476 fc++;
477 /* First non-whitespace char that dialog(1) will see */
478 if (fc != NULL && *fc >= '0' && *fc <= '9')
479 warnx("%s: WARNING! File name `%s' begins "
480 "with a number (use `-p text' for safety)",
481 __func__, first_file->name);
485 dprompt_init(file_list);
486 /* Reads: label_size pbar_size pprompt aprompt dpv_nfiles */
487 /* Inits: dheight and dwidth */
489 /* Default localeconv(3) settings for dialog(3) status */
490 setlocale(LC_NUMERIC,
491 getenv("LC_ALL") == NULL && getenv("LC_NUMERIC") == NULL ?
492 LC_NUMERIC_DEFAULT : "");
494 if (!debug) {
495 /* Internally create the initial `--gauge' prompt text */
496 dprompt_recreate(file_list, (struct dpv_file_node *)NULL, 0);
498 /* Spawn [X]dialog(1) `--gauge', returning pipe descriptor */
499 if (use_libdialog) {
500 status_printf("");
501 dprompt_libprint(pprompt, aprompt, 0);
502 } else {
503 dprompt_sprint(init_prompt, pprompt, aprompt);
504 dialog_out = dialog_spawn_gauge(init_prompt, &pid);
505 dprompt_dprint(dialog_out, pprompt, aprompt, 0);
507 } /* !debug */
509 /* Seed the random(3) generator */
510 if (dialog_test)
511 srandom(0xf1eeface);
513 /* Set default/custom status line format */
514 if (dpv_nfiles > 1) {
515 snprintf(status_format_default, DPV_STATUS_FORMAT_MAX, "%s",
516 DPV_STATUS_MANY);
517 status_format_custom = config->status_many;
518 } else {
519 snprintf(status_format_default, DPV_STATUS_FORMAT_MAX, "%s",
520 DPV_STATUS_SOLO);
521 status_format_custom = config->status_solo;
524 /* Add test mode identifier to default status line if enabled */
525 if (dialog_test && (strlen(status_format_default) + 12) <
526 DPV_STATUS_FORMAT_MAX)
527 strcat(status_format_default, " [TEST MODE]");
529 /* Verify custom status format */
530 status_fmt = fmtcheck(status_format_custom, status_format_default);
531 if (status_format_custom != NULL &&
532 status_fmt == status_format_default) {
533 warnx("WARNING! Invalid status_format configuration `%s'",
534 status_format_custom);
535 warnx("Default status_format `%s'", status_format_default);
538 /* Record when we started (used to prevent updating too quickly) */
539 (void)gettimeofday(&start, (struct timezone *)NULL);
541 /* Calculate number of microseconds in-between sub-second updates */
542 if (status_updates_per_second != 0)
543 status_update_usec = 1000000 / status_updates_per_second;
544 if (dialog_updates_per_second != 0)
545 dialog_update_usec = 1000000 / dialog_updates_per_second;
548 * Process the file list [serially] (one for each argument passed)
550 files_left = dpv_nfiles;
551 list_head = file_list;
552 for (curfile = file_list; curfile != NULL; curfile = curfile->next) {
553 keep_going = TRUE;
554 output_out = -1;
555 pct = 0;
556 nthfile++;
557 files_left--;
559 if (dpv_interrupt)
560 break;
561 if (dialog_test)
562 pct = 0 - increment;
564 /* Attempt to spawn output program for this file */
565 if (!dialog_test && output != NULL) {
566 mask = umask(0022);
567 (void)umask(mask);
569 switch (output_type) {
570 case DPV_OUTPUT_SHELL:
571 output_out = shell_spawn_pipecmd(output,
572 curfile->name, &output_pid);
573 break;
574 case DPV_OUTPUT_FILE:
575 path_fmt = fmtcheck(output, "%s");
576 if (path_fmt == output)
577 len = snprintf(pathbuf,
578 PATH_MAX, output, curfile->name);
579 else
580 len = snprintf(pathbuf,
581 PATH_MAX, "%s", output);
582 if (len >= PATH_MAX) {
583 warnx("%s:%d:%s: pathbuf[%u] too small"
584 "to hold output argument",
585 __FILE__, __LINE__, __func__,
586 PATH_MAX);
587 return (-1);
589 if ((output_out = open(pathbuf,
590 O_CREAT|O_WRONLY, DEFFILEMODE & ~mask))
591 < 0) {
592 warn("%s", pathbuf);
593 return (-1);
595 break;
596 default:
597 break;
601 while (!dpv_interrupt && keep_going) {
602 if (dialog_test) {
603 usleep(50000);
604 pct += increment;
605 dpv_overall_read +=
606 (int)(random() / 512 / dpv_nfiles);
607 /* 512 limits fake readout to Megabytes */
608 } else if (action != NULL)
609 pct = action(curfile, output_out);
611 if (no_overrun || dialog_test)
612 keep_going = (pct < 100);
613 else {
614 status = curfile->status;
615 keep_going = (status == DPV_STATUS_RUNNING);
618 /* Get current time and calculate seconds elapsed */
619 gettimeofday(&now, (struct timezone *)NULL);
620 now.tv_sec = now.tv_sec - start.tv_sec;
621 now.tv_usec = now.tv_usec - start.tv_usec;
622 if (now.tv_usec < 0)
623 now.tv_sec--, now.tv_usec += 1000000;
624 seconds = now.tv_sec + (now.tv_usec / 1000000.0);
626 /* Update dialog (be it dialog(3), dialog(1), etc.) */
627 if ((dialog_updates_per_second != 0 &&
629 seconds != dialog_old_seconds ||
630 now.tv_usec - dialog_last_update >=
631 dialog_update_usec ||
632 nthfile != dialog_old_nthfile
633 )) || pct == 100
635 /* Calculate overall progress (rounding up) */
636 overall = (100 * nthfile - 100 + pct) /
637 dpv_nfiles;
638 if (((100 * nthfile - 100 + pct) * 10 /
639 dpv_nfiles % 100) > 50)
640 overall++;
642 dprompt_recreate(list_head, curfile, pct);
644 if (use_libdialog && !debug) {
645 /* Update dialog(3) widget */
646 dprompt_libprint(pprompt, aprompt,
647 overall);
648 } else {
649 /* stdout, dialog(1), or Xdialog(1) */
650 dprompt_dprint(dialog_out, pprompt,
651 aprompt, overall);
652 fsync(dialog_out);
654 dialog_old_seconds = seconds;
655 dialog_old_nthfile = nthfile;
656 dialog_last_update = now.tv_usec;
659 /* Update the status line */
660 if ((use_libdialog && !debug) &&
661 status_updates_per_second != 0 &&
663 keep_going != TRUE ||
664 seconds != status_old_seconds ||
665 now.tv_usec - status_last_update >=
666 status_update_usec ||
667 nthfile != status_old_nthfile
670 status_printf(status_fmt, dpv_overall_read,
671 (dpv_overall_read / (seconds == 0 ? 1 :
672 seconds) * 1.0),
673 1, /* XXX until we add parallelism XXX */
674 files_left);
675 status_old_seconds = seconds;
676 status_old_nthfile = nthfile;
677 status_last_update = now.tv_usec;
681 if (!dialog_test && output_out >= 0) {
682 close(output_out);
683 waitpid(output_pid, (int *)NULL, 0);
686 if (dpv_abort)
687 break;
689 /* Advance head of list when we hit the max display lines */
690 if (display_limit > 0 && nthfile % display_limit == 0)
691 list_head = curfile->next;
694 if (!debug) {
695 if (use_libdialog)
696 end_dialog();
697 else {
698 close(dialog_out);
699 waitpid(pid, (int *)NULL, 0);
701 if (!keep_tite && !dpv_interrupt)
702 printf("\n");
703 } else
704 warnx("%s: %lli overall read", __func__, dpv_overall_read);
706 if (dpv_interrupt || dpv_abort)
707 return (-1);
708 else
709 return (0);
713 * Free allocated items initialized by dpv()
715 void
716 dpv_free(void)
718 dialogrc_free();
719 dprompt_free();
720 dialog_maxsize_free();
721 if (aprompt != NULL) {
722 free(aprompt);
723 aprompt = NULL;
725 if (pprompt != NULL) {
726 free(pprompt);
727 pprompt = NULL;
729 status_free();