Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libdpv/dprompt.c
39475 views
1
/*-
2
* Copyright (c) 2013-2014 Devin Teske <[email protected]>
3
* All rights reserved.
4
*
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.
13
*
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.
25
*/
26
27
#include <sys/types.h>
28
29
#define _BSD_SOURCE /* to get dprintf() prototype in stdio.h below */
30
#include <dialog.h>
31
#include <err.h>
32
#include <libutil.h>
33
#include <stdarg.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <string_m.h>
38
#include <unistd.h>
39
40
#include "dialog_util.h"
41
#include "dialogrc.h"
42
#include "dprompt.h"
43
#include "dpv.h"
44
#include "dpv_private.h"
45
46
#define FLABEL_MAX 1024
47
48
static int fheight = 0; /* initialized by dprompt_init() */
49
static char dprompt[PROMPT_MAX + 1] = "";
50
static char *dprompt_pos = (char *)(0); /* treated numerically */
51
52
/* Display characteristics */
53
#define FM_DONE 0x01
54
#define FM_FAIL 0x02
55
#define FM_PEND 0x04
56
static uint8_t dprompt_free_mask;
57
static char *done = NULL;
58
static char *fail = NULL;
59
static char *pend = NULL;
60
int display_limit = DISPLAY_LIMIT_DEFAULT; /* Max entries to show */
61
int label_size = LABEL_SIZE_DEFAULT; /* Max width for labels */
62
int pbar_size = PBAR_SIZE_DEFAULT; /* Mini-progressbar size */
63
static int gauge_percent = 0;
64
static int done_size, done_lsize, done_rsize;
65
static int fail_size, fail_lsize, fail_rsize;
66
static int mesg_size, mesg_lsize, mesg_rsize;
67
static int pend_size, pend_lsize, pend_rsize;
68
static int pct_lsize, pct_rsize;
69
static void *gauge = NULL;
70
#define SPIN_SIZE 4
71
static char spin[SPIN_SIZE + 1] = "/-\\|";
72
static char msg[PROMPT_MAX + 1];
73
static char *spin_cp = spin;
74
75
/* Function prototypes */
76
static char spin_char(void);
77
static int dprompt_add_files(struct dpv_file_node *file_list,
78
struct dpv_file_node *curfile, int pct);
79
80
/*
81
* Returns a pointer to the current spin character in the spin string and
82
* advances the global position to the next character for the next call.
83
*/
84
static char
85
spin_char(void)
86
{
87
char ch;
88
89
if (*spin_cp == '\0')
90
spin_cp = spin;
91
ch = *spin_cp;
92
93
/* Advance the spinner to the next char */
94
if (++spin_cp >= (spin + SPIN_SIZE))
95
spin_cp = spin;
96
97
return (ch);
98
}
99
100
/*
101
* Initialize heights and widths based on various strings and environment
102
* variables (such as ENV_USE_COLOR).
103
*/
104
void
105
dprompt_init(struct dpv_file_node *file_list)
106
{
107
uint8_t nls = 0;
108
int len;
109
int max_cols;
110
int max_rows;
111
int nthfile;
112
int numlines;
113
struct dpv_file_node *curfile;
114
115
/*
116
* Initialize dialog(3) `colors' support and draw backtitle
117
*/
118
if (use_libdialog && !debug) {
119
init_dialog(stdin, stdout);
120
dialog_vars.colors = 1;
121
if (backtitle != NULL) {
122
dialog_vars.backtitle = (char *)backtitle;
123
dlg_put_backtitle();
124
}
125
}
126
127
/* Calculate width of dialog(3) or [X]dialog(1) --gauge box */
128
dwidth = label_size + pbar_size + 9;
129
130
/*
131
* Calculate height of dialog(3) or [X]dialog(1) --gauge box
132
*/
133
dheight = 5;
134
max_rows = dialog_maxrows();
135
/* adjust max_rows for backtitle and/or dialog(3) statusLine */
136
if (backtitle != NULL)
137
max_rows -= use_shadow ? 3 : 2;
138
if (use_libdialog && use_shadow)
139
max_rows -= 2;
140
/* add lines for `-p text' */
141
numlines = dialog_prompt_numlines(pprompt, 0);
142
if (debug)
143
warnx("`-p text' is %i line%s long", numlines,
144
numlines == 1 ? "" : "s");
145
dheight += numlines;
146
/* adjust dheight for various implementations */
147
if (use_dialog) {
148
dheight -= dialog_prompt_nlstate(pprompt);
149
nls = dialog_prompt_nlstate(pprompt);
150
} else if (use_xdialog) {
151
if (pprompt == NULL || *pprompt == '\0')
152
dheight++;
153
} else if (use_libdialog) {
154
if (pprompt != NULL && *pprompt != '\0')
155
dheight--;
156
}
157
/* limit the number of display items (necessary per dialog(1,3)) */
158
if (display_limit == 0 || display_limit > DPV_DISPLAY_LIMIT)
159
display_limit = DPV_DISPLAY_LIMIT;
160
/* verify fheight will fit (stop if we hit 1) */
161
for (; display_limit > 0; display_limit--) {
162
nthfile = numlines = 0;
163
fheight = (int)dpv_nfiles > display_limit ?
164
(unsigned int)display_limit : dpv_nfiles;
165
for (curfile = file_list; curfile != NULL;
166
curfile = curfile->next) {
167
nthfile++;
168
numlines += dialog_prompt_numlines(curfile->name, nls);
169
if ((nthfile % display_limit) == 0) {
170
if (numlines > fheight)
171
fheight = numlines;
172
numlines = nthfile = 0;
173
}
174
}
175
if (numlines > fheight)
176
fheight = numlines;
177
if ((dheight + fheight +
178
(int)dialog_prompt_numlines(aprompt, use_dialog) -
179
(use_dialog ? (int)dialog_prompt_nlstate(aprompt) : 0))
180
<= max_rows)
181
break;
182
}
183
/* don't show any items if we run the risk of hitting a blank set */
184
if ((max_rows - (use_shadow ? 5 : 4)) >= fheight)
185
dheight += fheight;
186
else
187
fheight = 0;
188
/* add lines for `-a text' */
189
numlines = dialog_prompt_numlines(aprompt, use_dialog);
190
if (debug)
191
warnx("`-a text' is %i line%s long", numlines,
192
numlines == 1 ? "" : "s");
193
dheight += numlines;
194
195
/* If using Xdialog(1), adjust accordingly (based on testing) */
196
if (use_xdialog)
197
dheight += dheight / 4;
198
199
/* For wide mode, long prefix (`pprompt') or append (`aprompt')
200
* strings will bump width */
201
if (wide) {
202
len = (int)dialog_prompt_longestline(pprompt, 0); /* !nls */
203
if ((len + 4) > dwidth)
204
dwidth = len + 4;
205
len = (int)dialog_prompt_longestline(aprompt, 1); /* nls */
206
if ((len + 4) > dwidth)
207
dwidth = len + 4;
208
}
209
210
/* Enforce width constraints to maximum values */
211
max_cols = dialog_maxcols();
212
if (max_cols > 0 && dwidth > max_cols)
213
dwidth = max_cols;
214
215
/* Optimize widths to sane values*/
216
if (pbar_size > dwidth - 9) {
217
pbar_size = dwidth - 9;
218
label_size = 0;
219
/* -9 = "| - [" ... "] |" */
220
}
221
if (pbar_size < 0)
222
label_size = dwidth - 8;
223
/* -8 = "| " ... " - |" */
224
else if (label_size > (dwidth - pbar_size - 9) || wide)
225
label_size = no_labels ? 0 : dwidth - pbar_size - 9;
226
/* -9 = "| " ... " - [" ... "] |" */
227
228
/* Hide labels if requested */
229
if (no_labels)
230
label_size = 0;
231
232
/* Touch up the height (now that we know dwidth) */
233
dheight += dialog_prompt_wrappedlines(pprompt, dwidth - 4, 0);
234
dheight += dialog_prompt_wrappedlines(aprompt, dwidth - 4, 1);
235
236
if (debug)
237
warnx("dheight = %i dwidth = %i fheight = %i",
238
dheight, dwidth, fheight);
239
240
/* Calculate left/right portions of % */
241
pct_lsize = (pbar_size - 4) / 2; /* -4 == printf("%-3s%%", pct) */
242
pct_rsize = pct_lsize;
243
/* If not evenly divisible by 2, increment the right-side */
244
if ((pct_rsize + pct_rsize + 4) != pbar_size)
245
pct_rsize++;
246
247
/* Initialize "Done" text */
248
if (done == NULL && (done = msg_done) == NULL) {
249
if ((done = getenv(ENV_MSG_DONE)) != NULL)
250
done_size = strlen(done);
251
else {
252
done_size = strlen(DPV_DONE_DEFAULT);
253
if ((done = malloc(done_size + 1)) == NULL)
254
errx(EXIT_FAILURE, "Out of memory?!");
255
dprompt_free_mask |= FM_DONE;
256
snprintf(done, done_size + 1, DPV_DONE_DEFAULT);
257
}
258
}
259
if (pbar_size < done_size) {
260
done_lsize = done_rsize = 0;
261
*(done + pbar_size) = '\0';
262
done_size = pbar_size;
263
} else {
264
/* Calculate left/right portions for mini-progressbar */
265
done_lsize = (pbar_size - done_size) / 2;
266
done_rsize = done_lsize;
267
/* If not evenly divisible by 2, increment the right-side */
268
if ((done_rsize + done_size + done_lsize) != pbar_size)
269
done_rsize++;
270
}
271
272
/* Initialize "Fail" text */
273
if (fail == NULL && (fail = msg_fail) == NULL) {
274
if ((fail = getenv(ENV_MSG_FAIL)) != NULL)
275
fail_size = strlen(fail);
276
else {
277
fail_size = strlen(DPV_FAIL_DEFAULT);
278
if ((fail = malloc(fail_size + 1)) == NULL)
279
errx(EXIT_FAILURE, "Out of memory?!");
280
dprompt_free_mask |= FM_FAIL;
281
snprintf(fail, fail_size + 1, DPV_FAIL_DEFAULT);
282
}
283
}
284
if (pbar_size < fail_size) {
285
fail_lsize = fail_rsize = 0;
286
*(fail + pbar_size) = '\0';
287
fail_size = pbar_size;
288
} else {
289
/* Calculate left/right portions for mini-progressbar */
290
fail_lsize = (pbar_size - fail_size) / 2;
291
fail_rsize = fail_lsize;
292
/* If not evenly divisible by 2, increment the right-side */
293
if ((fail_rsize + fail_size + fail_lsize) != pbar_size)
294
fail_rsize++;
295
}
296
297
/* Initialize "Pending" text */
298
if (pend == NULL && (pend = msg_pending) == NULL) {
299
if ((pend = getenv(ENV_MSG_PENDING)) != NULL)
300
pend_size = strlen(pend);
301
else {
302
pend_size = strlen(DPV_PENDING_DEFAULT);
303
if ((pend = malloc(pend_size + 1)) == NULL)
304
errx(EXIT_FAILURE, "Out of memory?!");
305
dprompt_free_mask |= FM_PEND;
306
snprintf(pend, pend_size + 1, DPV_PENDING_DEFAULT);
307
}
308
}
309
if (pbar_size < pend_size) {
310
pend_lsize = pend_rsize = 0;
311
*(pend + pbar_size) = '\0';
312
pend_size = pbar_size;
313
} else {
314
/* Calculate left/right portions for mini-progressbar */
315
pend_lsize = (pbar_size - pend_size) / 2;
316
pend_rsize = pend_lsize;
317
/* If not evenly divisible by 2, increment the right-side */
318
if ((pend_rsize + pend_lsize + pend_size) != pbar_size)
319
pend_rsize++;
320
}
321
322
if (debug)
323
warnx("label_size = %i pbar_size = %i", label_size, pbar_size);
324
325
dprompt_clear();
326
}
327
328
/*
329
* Clear the [X]dialog(1) `--gauge' prompt buffer.
330
*/
331
void
332
dprompt_clear(void)
333
{
334
335
*dprompt = '\0';
336
dprompt_pos = dprompt;
337
}
338
339
/*
340
* Append to the [X]dialog(1) `--gauge' prompt buffer. Syntax is like printf(3)
341
* and returns the number of bytes appended to the buffer.
342
*/
343
int
344
dprompt_add(const char *format, ...)
345
{
346
int len;
347
va_list ap;
348
349
if (dprompt_pos >= (dprompt + PROMPT_MAX))
350
return (0);
351
352
va_start(ap, format);
353
len = vsnprintf(dprompt_pos, (size_t)(PROMPT_MAX -
354
(dprompt_pos - dprompt)), format, ap);
355
va_end(ap);
356
if (len == -1)
357
errx(EXIT_FAILURE, "%s: Oops, dprompt buffer overflow",
358
__func__);
359
360
if ((dprompt_pos + len) < (dprompt + PROMPT_MAX))
361
dprompt_pos += len;
362
else
363
dprompt_pos = dprompt + PROMPT_MAX;
364
365
return (len);
366
}
367
368
/*
369
* Append active files to the [X]dialog(1) `--gauge' prompt buffer. Syntax
370
* requires a pointer to the head of the dpv_file_node linked-list. Returns the
371
* number of files processed successfully.
372
*/
373
static int
374
dprompt_add_files(struct dpv_file_node *file_list,
375
struct dpv_file_node *curfile, int pct)
376
{
377
char c;
378
char bold_code = 'b'; /* default: enabled */
379
char color_code = '4'; /* default: blue */
380
uint8_t after_curfile = curfile != NULL ? FALSE : TRUE;
381
uint8_t nls = 0;
382
char *cp;
383
char *lastline;
384
char *name;
385
const char *bg_code;
386
const char *estext;
387
const char *format;
388
enum dprompt_state dstate;
389
int estext_lsize;
390
int estext_rsize;
391
int flabel_size;
392
int hlen;
393
int lsize;
394
int nlines = 0;
395
int nthfile = 0;
396
int pwidth;
397
int rsize;
398
struct dpv_file_node *fp;
399
char flabel[FLABEL_MAX + 1];
400
char human[32];
401
char pbar[pbar_size + 16]; /* +15 for optional color */
402
char pbar_cap[sizeof(pbar)];
403
char pbar_fill[sizeof(pbar)];
404
405
406
/* Override color defaults with that of main progress bar */
407
if (use_colors || use_shadow) { /* NB: shadow enables color */
408
color_code = gauge_color[0];
409
/* NB: str[1] aka bg is unused */
410
bold_code = gauge_color[2];
411
}
412
413
/*
414
* Create mini-progressbar for current file (if applicable)
415
*/
416
*pbar = '\0';
417
if (pbar_size >= 0 && pct >= 0 && curfile != NULL &&
418
(curfile->length >= 0 || dialog_test)) {
419
snprintf(pbar, pbar_size + 1, "%*s%3u%%%*s", pct_lsize, "",
420
pct, pct_rsize, "");
421
if (use_color) {
422
/* Calculate the fill-width of progressbar */
423
pwidth = pct * pbar_size / 100;
424
/* Round up based on one-tenth of a percent */
425
if ((pct * pbar_size % 100) > 50)
426
pwidth++;
427
428
/*
429
* Make two copies of pbar. Make one represent the fill
430
* and the other the remainder (cap). We'll insert the
431
* ANSI delimiter in between.
432
*/
433
*pbar_fill = '\0';
434
*pbar_cap = '\0';
435
strncat(pbar_fill, (const char *)(pbar), dwidth);
436
*(pbar_fill + pwidth) = '\0';
437
strncat(pbar_cap, (const char *)(pbar+pwidth), dwidth);
438
439
/* Finalize the mini [color] progressbar */
440
snprintf(pbar, sizeof(pbar),
441
"\\Z%c\\Zr\\Z%c%s%s%s\\Zn", bold_code, color_code,
442
pbar_fill, "\\ZR", pbar_cap);
443
}
444
}
445
446
for (fp = file_list; fp != NULL; fp = fp->next) {
447
flabel_size = label_size;
448
name = fp->name;
449
nthfile++;
450
451
/*
452
* Support multiline filenames (where the filename is taken as
453
* the last line and the text leading up to the last line can
454
* be used as (for example) a heading/separator between files.
455
*/
456
if (use_dialog)
457
nls = dialog_prompt_nlstate(pprompt);
458
nlines += dialog_prompt_numlines(name, nls);
459
lastline = dialog_prompt_lastline(name, 1);
460
if (name != lastline) {
461
c = *lastline;
462
*lastline = '\0';
463
dprompt_add("%s", name);
464
*lastline = c;
465
name = lastline;
466
}
467
468
/* Support color codes (for dialog(1,3)) in file names */
469
if ((use_dialog || use_libdialog) && use_color) {
470
cp = name;
471
while (*cp != '\0') {
472
if (*cp == '\\' && *(cp + 1) != '\0' &&
473
*(++cp) == 'Z' && *(cp + 1) != '\0') {
474
cp++;
475
flabel_size += 3;
476
}
477
cp++;
478
}
479
if (flabel_size > FLABEL_MAX)
480
flabel_size = FLABEL_MAX;
481
}
482
483
/* If no mini-progressbar, increase label width */
484
if (pbar_size < 0 && flabel_size <= FLABEL_MAX - 2 &&
485
no_labels == FALSE)
486
flabel_size += 2;
487
488
/* If name is too long, add an ellipsis */
489
if (snprintf(flabel, flabel_size + 1, "%s", name) >
490
flabel_size) sprintf(flabel + flabel_size - 3, "...");
491
492
/*
493
* Append the label (processing the current file differently)
494
*/
495
if (fp == curfile && pct < 100) {
496
/*
497
* Add an ellipsis to current file name if it will fit.
498
* There may be an ellipsis already from truncating the
499
* label (in which case, we already have one).
500
*/
501
cp = flabel + strlen(flabel);
502
if (cp < (flabel + flabel_size))
503
snprintf(cp, flabel_size -
504
(cp - flabel) + 1, "...");
505
506
/* Append label (with spinner and optional color) */
507
dprompt_add("%s%-*s%s %c", use_color ? "\\Zb" : "",
508
flabel_size, flabel, use_color ? "\\Zn" : "",
509
spin_char());
510
} else
511
dprompt_add("%-*s%s %s", flabel_size,
512
flabel, use_color ? "\\Zn" : "", " ");
513
514
/*
515
* Append pbar/status (processing the current file differently)
516
*/
517
dstate = DPROMPT_NONE;
518
if (fp->msg != NULL)
519
dstate = DPROMPT_CUSTOM_MSG;
520
else if (pbar_size < 0)
521
dstate = DPROMPT_NONE;
522
else if (pbar_size < 4)
523
dstate = DPROMPT_MINIMAL;
524
else if (after_curfile)
525
dstate = DPROMPT_PENDING;
526
else if (fp == curfile) {
527
if (*pbar == '\0') {
528
if (fp->length < 0)
529
dstate = DPROMPT_DETAILS;
530
else if (fp->status == DPV_STATUS_RUNNING)
531
dstate = DPROMPT_DETAILS;
532
else
533
dstate = DPROMPT_END_STATE;
534
}
535
else if (dialog_test) /* status/length ignored */
536
dstate = pct < 100 ?
537
DPROMPT_PBAR : DPROMPT_END_STATE;
538
else if (fp->status == DPV_STATUS_RUNNING)
539
dstate = fp->length < 0 ?
540
DPROMPT_DETAILS : DPROMPT_PBAR;
541
else /* not running */
542
dstate = fp->length < 0 ?
543
DPROMPT_DETAILS : DPROMPT_END_STATE;
544
} else { /* before curfile */
545
if (dialog_test)
546
dstate = DPROMPT_END_STATE;
547
else
548
dstate = fp->length < 0 ?
549
DPROMPT_DETAILS : DPROMPT_END_STATE;
550
}
551
format = use_color ?
552
" [\\Z%c%s%-*s%s%-*s\\Zn]\\n" :
553
" [%-*s%s%-*s]\\n";
554
if (fp->status == DPV_STATUS_FAILED) {
555
bg_code = "\\Zr\\Z1"; /* Red */
556
estext_lsize = fail_lsize;
557
estext_rsize = fail_rsize;
558
estext = fail;
559
} else { /* e.g., DPV_STATUS_DONE */
560
bg_code = "\\Zr\\Z2"; /* Green */
561
estext_lsize = done_lsize;
562
estext_rsize = done_rsize;
563
estext = done;
564
}
565
switch (dstate) {
566
case DPROMPT_PENDING: /* Future file(s) */
567
dprompt_add(" [%-*s%s%-*s]\\n",
568
pend_lsize, "", pend, pend_rsize, "");
569
break;
570
case DPROMPT_PBAR: /* Current file */
571
dprompt_add(" [%s]\\n", pbar);
572
break;
573
case DPROMPT_END_STATE: /* Past/Current file(s) */
574
if (use_color)
575
dprompt_add(format, bold_code, bg_code,
576
estext_lsize, "", estext,
577
estext_rsize, "");
578
else
579
dprompt_add(format,
580
estext_lsize, "", estext,
581
estext_rsize, "");
582
break;
583
case DPROMPT_DETAILS: /* Past/Current file(s) */
584
humanize_number(human, pbar_size + 2, fp->read, "",
585
HN_AUTOSCALE, HN_NOSPACE | HN_DIVISOR_1000);
586
587
/* Calculate center alignment */
588
hlen = (int)strlen(human);
589
lsize = (pbar_size - hlen) / 2;
590
rsize = lsize;
591
if ((lsize+hlen+rsize) != pbar_size)
592
rsize++;
593
594
if (use_color)
595
dprompt_add(format, bold_code, bg_code,
596
lsize, "", human, rsize, "");
597
else
598
dprompt_add(format,
599
lsize, "", human, rsize, "");
600
break;
601
case DPROMPT_CUSTOM_MSG: /* File-specific message override */
602
snprintf(msg, PROMPT_MAX + 1, "%s", fp->msg);
603
if (pbar_size < (mesg_size = strlen(msg))) {
604
mesg_lsize = mesg_rsize = 0;
605
*(msg + pbar_size) = '\0';
606
mesg_size = pbar_size;
607
} else {
608
mesg_lsize = (pbar_size - mesg_size) / 2;
609
mesg_rsize = mesg_lsize;
610
if ((mesg_rsize + mesg_size + mesg_lsize)
611
!= pbar_size)
612
mesg_rsize++;
613
}
614
if (use_color)
615
dprompt_add(format, bold_code, bg_code,
616
mesg_lsize, "", msg, mesg_rsize, "");
617
else
618
dprompt_add(format, mesg_lsize, "", msg,
619
mesg_rsize, "");
620
break;
621
case DPROMPT_MINIMAL: /* Short progress bar, minimal room */
622
if (use_color)
623
dprompt_add(format, bold_code, bg_code,
624
pbar_size, "", "", 0, "");
625
else
626
dprompt_add(format, pbar_size, "", "", 0, "");
627
break;
628
case DPROMPT_NONE: /* pbar_size < 0 */
629
/* FALLTHROUGH */
630
default:
631
dprompt_add(" \\n");
632
/*
633
* NB: Leading space required for the case when
634
* spin_char() returns a single backslash [\] which
635
* without the space, changes the meaning of `\n'
636
*/
637
}
638
639
/* Stop building if we've hit the internal limit */
640
if (nthfile >= display_limit)
641
break;
642
643
/* If this is the current file, all others are pending */
644
if (fp == curfile)
645
after_curfile = TRUE;
646
}
647
648
/*
649
* Since we cannot change the height/width of the [X]dialog(1) widget
650
* after spawn, to make things look nice let's pad the height so that
651
* the `-a text' always appears in the same spot.
652
*
653
* NOTE: fheight is calculated in dprompt_init(). It represents the
654
* maximum height required to display the set of items (broken up into
655
* pieces of display_limit chunks) whose names contain the most
656
* newlines for any given set.
657
*/
658
while (nlines < fheight) {
659
dprompt_add("\n");
660
nlines++;
661
}
662
663
return (nthfile);
664
}
665
666
/*
667
* Process the dpv_file_node linked-list of named files, re-generating the
668
* [X]dialog(1) `--gauge' prompt text for the current state of transfers.
669
*/
670
void
671
dprompt_recreate(struct dpv_file_node *file_list,
672
struct dpv_file_node *curfile, int pct)
673
{
674
size_t len;
675
676
/*
677
* Re-Build the prompt text
678
*/
679
dprompt_clear();
680
if (display_limit > 0)
681
dprompt_add_files(file_list, curfile, pct);
682
683
/* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
684
if (use_xdialog) {
685
/* Replace `\n' with `\n\\n\n' in dprompt */
686
len = strlen(dprompt);
687
len += strcount(dprompt, "\\n") * 5; /* +5 chars per count */
688
if (len > PROMPT_MAX)
689
errx(EXIT_FAILURE, "%s: Oops, dprompt buffer overflow "
690
"(%zu > %i)", __func__, len, PROMPT_MAX);
691
if (replaceall(dprompt, "\\n", "\n\\n\n") < 0)
692
err(EXIT_FAILURE, "%s: replaceall()", __func__);
693
}
694
else if (use_libdialog)
695
strexpandnl(dprompt);
696
}
697
698
/*
699
* Print the [X]dialog(1) `--gauge' prompt text to a buffer.
700
*/
701
int
702
dprompt_sprint(char * restrict str, const char *prefix, const char *append)
703
{
704
705
return (snprintf(str, PROMPT_MAX, "%s%s%s%s", use_color ? "\\Zn" : "",
706
prefix ? prefix : "", dprompt, append ? append : ""));
707
}
708
709
/*
710
* Print the [X]dialog(1) `--gauge' prompt text to file descriptor fd (could
711
* be STDOUT_FILENO or a pipe(2) file descriptor to actual [X]dialog(1)).
712
*/
713
void
714
dprompt_dprint(int fd, const char *prefix, const char *append, int overall)
715
{
716
int percent = gauge_percent;
717
718
if (overall >= 0 && overall <= 100)
719
gauge_percent = percent = overall;
720
dprintf(fd, "XXX\n%s%s%s%s\nXXX\n%i\n", use_color ? "\\Zn" : "",
721
prefix ? prefix : "", dprompt, append ? append : "", percent);
722
fsync(fd);
723
}
724
725
/*
726
* Print the dialog(3) `gauge' prompt text using libdialog.
727
*/
728
void
729
dprompt_libprint(const char *prefix, const char *append, int overall)
730
{
731
int percent = gauge_percent;
732
char buf[DPV_PPROMPT_MAX + DPV_APROMPT_MAX + DPV_DISPLAY_LIMIT * 1024];
733
734
dprompt_sprint(buf, prefix, append);
735
736
if (overall >= 0 && overall <= 100)
737
gauge_percent = percent = overall;
738
gauge = dlg_reallocate_gauge(gauge, title == NULL ? "" : title,
739
buf, dheight, dwidth, percent);
740
dlg_update_gauge(gauge, percent);
741
}
742
743
/*
744
* Free allocated items initialized by dprompt_init()
745
*/
746
void
747
dprompt_free(void)
748
{
749
if ((dprompt_free_mask & FM_DONE) != 0) {
750
dprompt_free_mask ^= FM_DONE;
751
free(done);
752
done = NULL;
753
}
754
if ((dprompt_free_mask & FM_FAIL) != 0) {
755
dprompt_free_mask ^= FM_FAIL;
756
free(fail);
757
fail = NULL;
758
}
759
if ((dprompt_free_mask & FM_PEND) != 0) {
760
dprompt_free_mask ^= FM_PEND;
761
free(pend);
762
pend = NULL;
763
}
764
}
765
766