xref: /freebsd/contrib/bsddialog/utility/bsddialog.c (revision a6d8be451f62d425b71a4874f7d4e133b9fb393c)
161ba55bcSBaptiste Daroussin /*-
261ba55bcSBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
361ba55bcSBaptiste Daroussin  *
4*a6d8be45SAlfonso S. Siciliano  * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
561ba55bcSBaptiste Daroussin  *
661ba55bcSBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
761ba55bcSBaptiste Daroussin  * modification, are permitted provided that the following conditions
861ba55bcSBaptiste Daroussin  * are met:
961ba55bcSBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
1061ba55bcSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
1161ba55bcSBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
1261ba55bcSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
1361ba55bcSBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
1461ba55bcSBaptiste Daroussin  *
1561ba55bcSBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1661ba55bcSBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1761ba55bcSBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1861ba55bcSBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1961ba55bcSBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2061ba55bcSBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2161ba55bcSBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2261ba55bcSBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2361ba55bcSBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2461ba55bcSBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2561ba55bcSBaptiste Daroussin  * SUCH DAMAGE.
2661ba55bcSBaptiste Daroussin  */
2761ba55bcSBaptiste Daroussin 
2861ba55bcSBaptiste Daroussin #include <getopt.h>
2961ba55bcSBaptiste Daroussin #include <limits.h>
3061ba55bcSBaptiste Daroussin #include <locale.h>
3161ba55bcSBaptiste Daroussin #include <signal.h>
3261ba55bcSBaptiste Daroussin #include <stdarg.h>
3361ba55bcSBaptiste Daroussin #include <stdlib.h>
3461ba55bcSBaptiste Daroussin #include <stdio.h>
3561ba55bcSBaptiste Daroussin #include <string.h>
3661ba55bcSBaptiste Daroussin #include <term.h>
3761ba55bcSBaptiste Daroussin 
3861ba55bcSBaptiste Daroussin #include <bsddialog.h>
3961ba55bcSBaptiste Daroussin #include <bsddialog_theme.h>
4061ba55bcSBaptiste Daroussin 
4161ba55bcSBaptiste Daroussin #include "util.h"
4261ba55bcSBaptiste Daroussin 
4361ba55bcSBaptiste Daroussin #define EXITCODE(retval) (exitcodes[retval + 1].value)
4461ba55bcSBaptiste Daroussin #define UNUSED_PAR(x) UNUSED_ ## x __attribute__((__unused__))
4561ba55bcSBaptiste Daroussin 
4661ba55bcSBaptiste Daroussin static void custom_text(struct options *opt, char *text, char *buf);
4761ba55bcSBaptiste Daroussin 
4861ba55bcSBaptiste Daroussin /* Exit codes */
4961ba55bcSBaptiste Daroussin struct exitcode {
5061ba55bcSBaptiste Daroussin 	const char *name;
5161ba55bcSBaptiste Daroussin 	int value;
5261ba55bcSBaptiste Daroussin };
5361ba55bcSBaptiste Daroussin 
5461ba55bcSBaptiste Daroussin static struct exitcode exitcodes[14] = {
5561ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_ERROR",    255 },
5661ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_OK",         0 },
5761ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_CANCEL",     1 },
5861ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_HELP",       2 },
5961ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_EXTRA",      3 },
6061ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_TIMEOUT",    4 },
6161ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_ESC",        5 },
6261ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_LEFT1",      6 },
6361ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_LEFT2",      7 },
6461ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_LEFT3",      8 },
6561ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_RIGHT1",     9 },
6661ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_RIGHT2",    10 },
6761ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_RIGHT3",    11 },
6861ba55bcSBaptiste Daroussin 	{ "BSDDIALOG_ITEM_HELP",  2 } /* like HELP by default */
6961ba55bcSBaptiste Daroussin };
7061ba55bcSBaptiste Daroussin 
7161ba55bcSBaptiste Daroussin void set_exit_code(int lib_retval, int exitcode)
7261ba55bcSBaptiste Daroussin {
7361ba55bcSBaptiste Daroussin 	exitcodes[lib_retval + 1].value = exitcode;
7461ba55bcSBaptiste Daroussin }
7561ba55bcSBaptiste Daroussin 
7661ba55bcSBaptiste Daroussin /* Error */
7761ba55bcSBaptiste Daroussin void exit_error(bool usage, const char *fmt, ...)
7861ba55bcSBaptiste Daroussin {
7961ba55bcSBaptiste Daroussin 	va_list arg_ptr;
8061ba55bcSBaptiste Daroussin 
8161ba55bcSBaptiste Daroussin 	if (bsddialog_inmode())
8261ba55bcSBaptiste Daroussin 		bsddialog_end();
8361ba55bcSBaptiste Daroussin 	printf("Error: ");
8461ba55bcSBaptiste Daroussin 	va_start(arg_ptr, fmt);
8561ba55bcSBaptiste Daroussin 	vprintf(fmt, arg_ptr);
8661ba55bcSBaptiste Daroussin 	va_end(arg_ptr);
8761ba55bcSBaptiste Daroussin 	printf(".\n\n");
8861ba55bcSBaptiste Daroussin 	if (usage) {
8961ba55bcSBaptiste Daroussin 		printf("See \'bsddialog --help\' or \'man 1 bsddialog\' ");
9061ba55bcSBaptiste Daroussin 		printf("for more information.\n");
9161ba55bcSBaptiste Daroussin 	}
9261ba55bcSBaptiste Daroussin 
9361ba55bcSBaptiste Daroussin 	exit (EXITCODE(BSDDIALOG_ERROR));
9461ba55bcSBaptiste Daroussin }
9561ba55bcSBaptiste Daroussin 
9661ba55bcSBaptiste Daroussin void error_args(const char *dialog, int argc, char **argv)
9761ba55bcSBaptiste Daroussin {
9861ba55bcSBaptiste Daroussin 	int i;
9961ba55bcSBaptiste Daroussin 
10061ba55bcSBaptiste Daroussin 	if (bsddialog_inmode())
10161ba55bcSBaptiste Daroussin 		bsddialog_end();
10261ba55bcSBaptiste Daroussin 	printf("Error: %s unexpected argument%s:", dialog, argc > 1 ? "s" : "");
10361ba55bcSBaptiste Daroussin 	for (i = 0; i < argc; i++)
10461ba55bcSBaptiste Daroussin 		printf(" \"%s\"", argv[i]);
10561ba55bcSBaptiste Daroussin 	printf(".\n\n");
10661ba55bcSBaptiste Daroussin 	printf("See \'bsddialog --help\' or \'man 1 bsddialog\' ");
10761ba55bcSBaptiste Daroussin 	printf("for more information.\n");
10861ba55bcSBaptiste Daroussin 
10961ba55bcSBaptiste Daroussin 	exit (EXITCODE(BSDDIALOG_ERROR));
11061ba55bcSBaptiste Daroussin }
11161ba55bcSBaptiste Daroussin 
11261ba55bcSBaptiste Daroussin /* init */
11361ba55bcSBaptiste Daroussin static void sigint_handler(int UNUSED_PAR(sig))
11461ba55bcSBaptiste Daroussin {
11561ba55bcSBaptiste Daroussin 	bsddialog_end();
11661ba55bcSBaptiste Daroussin 
11761ba55bcSBaptiste Daroussin 	exit(EXITCODE(BSDDIALOG_ERROR));
11861ba55bcSBaptiste Daroussin }
11961ba55bcSBaptiste Daroussin 
12061ba55bcSBaptiste Daroussin static void start_bsddialog_mode(void)
12161ba55bcSBaptiste Daroussin {
12261ba55bcSBaptiste Daroussin 	if (bsddialog_inmode())
12361ba55bcSBaptiste Daroussin 		return;
12461ba55bcSBaptiste Daroussin 	if (bsddialog_init() != BSDDIALOG_OK)
12561ba55bcSBaptiste Daroussin 		exit_error(false, bsddialog_geterror());
12661ba55bcSBaptiste Daroussin 
12761ba55bcSBaptiste Daroussin 	signal(SIGINT, sigint_handler);
12861ba55bcSBaptiste Daroussin }
12961ba55bcSBaptiste Daroussin 
13061ba55bcSBaptiste Daroussin static void getenv_exitcodes(void)
13161ba55bcSBaptiste Daroussin {
13261ba55bcSBaptiste Daroussin 	int i;
13361ba55bcSBaptiste Daroussin 	int value;
13461ba55bcSBaptiste Daroussin 	char *envvalue;
13561ba55bcSBaptiste Daroussin 
13661ba55bcSBaptiste Daroussin 	for (i = 0; i < 10; i++) {
13761ba55bcSBaptiste Daroussin 		envvalue = getenv(exitcodes[i].name);
13861ba55bcSBaptiste Daroussin 		if (envvalue == NULL || envvalue[0] == '\0')
13961ba55bcSBaptiste Daroussin 			continue;
14061ba55bcSBaptiste Daroussin 		value = (int)strtol(envvalue, NULL, 10);
14161ba55bcSBaptiste Daroussin 		exitcodes[i].value = value;
14261ba55bcSBaptiste Daroussin 		/* ITEM_HELP follows HELP without explicit setting */
14361ba55bcSBaptiste Daroussin 		if (i == BSDDIALOG_HELP + 1)
14461ba55bcSBaptiste Daroussin 			exitcodes[BSDDIALOG_ITEM_HELP + 1].value = value;
14561ba55bcSBaptiste Daroussin 	}
14661ba55bcSBaptiste Daroussin }
14761ba55bcSBaptiste Daroussin 
14861ba55bcSBaptiste Daroussin /*
14961ba55bcSBaptiste Daroussin  * bsddialog utility: TUI widgets and dialogs.
15061ba55bcSBaptiste Daroussin  */
15161ba55bcSBaptiste Daroussin int main(int argc, char *argv[argc])
15261ba55bcSBaptiste Daroussin {
15361ba55bcSBaptiste Daroussin 	bool startup;
15461ba55bcSBaptiste Daroussin 	int i, rows, cols, retval, parsed, nargc, firstoptind;
15561ba55bcSBaptiste Daroussin 	char *text, **nargv, *pn;
15661ba55bcSBaptiste Daroussin 	struct bsddialog_conf conf;
15761ba55bcSBaptiste Daroussin 	struct options opt;
15861ba55bcSBaptiste Daroussin 
15961ba55bcSBaptiste Daroussin 	setlocale(LC_ALL, "");
16061ba55bcSBaptiste Daroussin 	getenv_exitcodes();
16161ba55bcSBaptiste Daroussin 	firstoptind = optind;
16261ba55bcSBaptiste Daroussin 	pn = argv[0];
16361ba55bcSBaptiste Daroussin 	retval = BSDDIALOG_OK;
16461ba55bcSBaptiste Daroussin 
16561ba55bcSBaptiste Daroussin 	for (i = 0; i < argc; i++) {
16661ba55bcSBaptiste Daroussin 		if (strcmp(argv[i], "--version") == 0) {
16761ba55bcSBaptiste Daroussin 			printf("Version: %s\n", LIBBSDDIALOG_VERSION);
16861ba55bcSBaptiste Daroussin 			return (BSDDIALOG_OK);
16961ba55bcSBaptiste Daroussin 		}
17061ba55bcSBaptiste Daroussin 		if (strcmp(argv[i], "--help") == 0) {
17161ba55bcSBaptiste Daroussin 			usage();
17261ba55bcSBaptiste Daroussin 			return (BSDDIALOG_OK);
17361ba55bcSBaptiste Daroussin 		}
17461ba55bcSBaptiste Daroussin 	}
17561ba55bcSBaptiste Daroussin 
17661ba55bcSBaptiste Daroussin 	startup = true;
17761ba55bcSBaptiste Daroussin 	while (true) {
17861ba55bcSBaptiste Daroussin 		parsed = parseargs(argc, argv, &conf, &opt);
17961ba55bcSBaptiste Daroussin 		nargc = argc - parsed;
18061ba55bcSBaptiste Daroussin 		nargv = argv + parsed;
18161ba55bcSBaptiste Daroussin 		argc = parsed - optind;
18261ba55bcSBaptiste Daroussin 		argv += optind;
18361ba55bcSBaptiste Daroussin 
18461ba55bcSBaptiste Daroussin 		if (opt.mandatory_dialog && opt.dialogbuilder == NULL)
18561ba55bcSBaptiste Daroussin 			exit_error(true, "expected a --<dialog>");
18661ba55bcSBaptiste Daroussin 
18761ba55bcSBaptiste Daroussin 		if (opt.dialogbuilder == NULL && argc > 0)
18861ba55bcSBaptiste Daroussin 			error_args("(no --<dialog>)", argc, argv);
18961ba55bcSBaptiste Daroussin 
19061ba55bcSBaptiste Daroussin 		/* --print-maxsize or --print-version */
19161ba55bcSBaptiste Daroussin 		if (opt.mandatory_dialog == false && opt.clearscreen == false &&
19261ba55bcSBaptiste Daroussin 		    opt.savethemefile == NULL && opt.dialogbuilder == NULL) {
19361ba55bcSBaptiste Daroussin 			retval = BSDDIALOG_OK;
19461ba55bcSBaptiste Daroussin 			break;
19561ba55bcSBaptiste Daroussin 		}
19661ba55bcSBaptiste Daroussin 
19761ba55bcSBaptiste Daroussin 		/* --<dialog>, --save-theme or clear-screen */
19861ba55bcSBaptiste Daroussin 		text = NULL; /* useless inits, fix compiler warnings */
19961ba55bcSBaptiste Daroussin 		rows = BSDDIALOG_AUTOSIZE;
20061ba55bcSBaptiste Daroussin 		cols = BSDDIALOG_AUTOSIZE;
20161ba55bcSBaptiste Daroussin 		if (opt.dialogbuilder != NULL) {
20261ba55bcSBaptiste Daroussin 			if (argc < 3)
20361ba55bcSBaptiste Daroussin 				exit_error(true,
20461ba55bcSBaptiste Daroussin 				    "expected <text> <rows> <cols>");
20561ba55bcSBaptiste Daroussin 			if ((text = strdup(argv[0])) == NULL)
20661ba55bcSBaptiste Daroussin 				exit_error(false, "cannot allocate <text>");
20761ba55bcSBaptiste Daroussin 			if (opt.dialogbuilder != textbox_builder)
20861ba55bcSBaptiste Daroussin 				custom_text(&opt, argv[0], text);
20961ba55bcSBaptiste Daroussin 			rows = (int)strtol(argv[1], NULL, 10);
21061ba55bcSBaptiste Daroussin 			cols = (int)strtol(argv[2], NULL, 10);
21161ba55bcSBaptiste Daroussin 			argc -= 3;
21261ba55bcSBaptiste Daroussin 			argv += 3;
21361ba55bcSBaptiste Daroussin 		}
21461ba55bcSBaptiste Daroussin 
21561ba55bcSBaptiste Daroussin 		/* bsddialog terminal mode (first iteration) */
21661ba55bcSBaptiste Daroussin 		start_bsddialog_mode();
21761ba55bcSBaptiste Daroussin 
21861ba55bcSBaptiste Daroussin 		if (opt.screen_mode != NULL) {
21961ba55bcSBaptiste Daroussin 			opt.screen_mode = tigetstr(opt.screen_mode);
22061ba55bcSBaptiste Daroussin 			if (opt.screen_mode != NULL &&
22161ba55bcSBaptiste Daroussin 			    opt.screen_mode != (char*)-1) {
22261ba55bcSBaptiste Daroussin 				tputs(opt.screen_mode, 1, putchar);
22361ba55bcSBaptiste Daroussin 				fflush(stdout);
22461ba55bcSBaptiste Daroussin 				bsddialog_refresh();
22561ba55bcSBaptiste Daroussin 			}
22661ba55bcSBaptiste Daroussin 		}
22761ba55bcSBaptiste Daroussin 
22861ba55bcSBaptiste Daroussin 		/* theme */
22961ba55bcSBaptiste Daroussin 		if (startup)
23061ba55bcSBaptiste Daroussin 			startuptheme();
23161ba55bcSBaptiste Daroussin 		startup = false;
23261ba55bcSBaptiste Daroussin 		if ((int)opt.theme >= 0)
23361ba55bcSBaptiste Daroussin 			setdeftheme(opt.theme);
23461ba55bcSBaptiste Daroussin 		if (opt.loadthemefile != NULL)
23561ba55bcSBaptiste Daroussin 			loadtheme(opt.loadthemefile, false);
23661ba55bcSBaptiste Daroussin 		if (opt.bikeshed)
23761ba55bcSBaptiste Daroussin 			bikeshed(&conf);
23861ba55bcSBaptiste Daroussin 		if (opt.savethemefile != NULL)
23961ba55bcSBaptiste Daroussin 			savetheme(opt.savethemefile);
24061ba55bcSBaptiste Daroussin 
24161ba55bcSBaptiste Daroussin 		/* backtitle and dialog */
24261ba55bcSBaptiste Daroussin 		if (opt.dialogbuilder == NULL)
24361ba55bcSBaptiste Daroussin 			break;
24461ba55bcSBaptiste Daroussin 		if (opt.backtitle != NULL)
24561ba55bcSBaptiste Daroussin 			if (bsddialog_backtitle(&conf, opt.backtitle))
24661ba55bcSBaptiste Daroussin 				exit_error(false, bsddialog_geterror());
24761ba55bcSBaptiste Daroussin 		retval = opt.dialogbuilder(&conf, text, rows, cols, argc, argv,
24861ba55bcSBaptiste Daroussin 		    &opt);
24961ba55bcSBaptiste Daroussin 		free(text);
25061ba55bcSBaptiste Daroussin 		if (retval == BSDDIALOG_ERROR)
25161ba55bcSBaptiste Daroussin 			exit_error(false, bsddialog_geterror());
25261ba55bcSBaptiste Daroussin 		if (conf.get_height != NULL && conf.get_width != NULL)
25361ba55bcSBaptiste Daroussin 			dprintf(opt.output_fd, "DialogSize: %d, %d\n",
25461ba55bcSBaptiste Daroussin 			    *conf.get_height, *conf.get_width);
25561ba55bcSBaptiste Daroussin 		if (opt.clearscreen)
25661ba55bcSBaptiste Daroussin 			bsddialog_clear(0);
25761ba55bcSBaptiste Daroussin 		opt.clearscreen = false;
25861ba55bcSBaptiste Daroussin 		/* --and-dialog ends loop with Cancel or ESC */
25961ba55bcSBaptiste Daroussin 		if (retval == BSDDIALOG_CANCEL || retval == BSDDIALOG_ESC)
26061ba55bcSBaptiste Daroussin 			break;
26161ba55bcSBaptiste Daroussin 		argc = nargc;
26261ba55bcSBaptiste Daroussin 		argv = nargv;
26361ba55bcSBaptiste Daroussin 		if (argc <= 0)
26461ba55bcSBaptiste Daroussin 			break;
26561ba55bcSBaptiste Daroussin 		/* prepare next parseargs() call */
26661ba55bcSBaptiste Daroussin 		argc++;
26761ba55bcSBaptiste Daroussin 		argv--;
26861ba55bcSBaptiste Daroussin 		argv[0] = pn;
26961ba55bcSBaptiste Daroussin 		optind = firstoptind;
27061ba55bcSBaptiste Daroussin 	}
27161ba55bcSBaptiste Daroussin 
27261ba55bcSBaptiste Daroussin 	if (bsddialog_inmode()) {
27361ba55bcSBaptiste Daroussin 		/* --clear-screen can be a single option */
27461ba55bcSBaptiste Daroussin 		if (opt.clearscreen)
27561ba55bcSBaptiste Daroussin 			bsddialog_clear(0);
27661ba55bcSBaptiste Daroussin 		bsddialog_end();
27761ba55bcSBaptiste Daroussin 	}
27861ba55bcSBaptiste Daroussin 	/* end bsddialog terminal mode */
27961ba55bcSBaptiste Daroussin 
28061ba55bcSBaptiste Daroussin 	return (EXITCODE(retval));
28161ba55bcSBaptiste Daroussin }
28261ba55bcSBaptiste Daroussin 
28361ba55bcSBaptiste Daroussin void custom_text(struct options *opt, char *text, char *buf)
28461ba55bcSBaptiste Daroussin {
28561ba55bcSBaptiste Daroussin 	bool trim, crwrap;
28661ba55bcSBaptiste Daroussin 	int i, j;
28761ba55bcSBaptiste Daroussin 
28861ba55bcSBaptiste Daroussin 	if (strstr(text, "\\n") == NULL) {
28961ba55bcSBaptiste Daroussin 		/* "hasnl" mode */
29061ba55bcSBaptiste Daroussin 		trim = true;
29161ba55bcSBaptiste Daroussin 		crwrap = true;
29261ba55bcSBaptiste Daroussin 	} else {
29361ba55bcSBaptiste Daroussin 		trim = false;
29461ba55bcSBaptiste Daroussin 		crwrap = opt->cr_wrap;
29561ba55bcSBaptiste Daroussin 	}
29661ba55bcSBaptiste Daroussin 	if (opt->text_unchanged) {
29761ba55bcSBaptiste Daroussin 		trim = false;
29861ba55bcSBaptiste Daroussin 		crwrap = true;
29961ba55bcSBaptiste Daroussin 	}
30061ba55bcSBaptiste Daroussin 
30161ba55bcSBaptiste Daroussin 	i = j = 0;
30261ba55bcSBaptiste Daroussin 	while (text[i] != '\0') {
30361ba55bcSBaptiste Daroussin 		switch (text[i]) {
30461ba55bcSBaptiste Daroussin 		case '\\':
30561ba55bcSBaptiste Daroussin 			buf[j] = '\\';
30661ba55bcSBaptiste Daroussin 			switch (text[i+1]) {
30761ba55bcSBaptiste Daroussin 			case 'n': /* implicitly in "hasnl" mode */
30861ba55bcSBaptiste Daroussin 				buf[j] = '\n';
30961ba55bcSBaptiste Daroussin 				i++;
31061ba55bcSBaptiste Daroussin 				if (text[i+1] == '\n')
31161ba55bcSBaptiste Daroussin 					i++;
31261ba55bcSBaptiste Daroussin 				break;
31361ba55bcSBaptiste Daroussin 			case 't':
31461ba55bcSBaptiste Daroussin 				if (opt->tab_escape) {
31561ba55bcSBaptiste Daroussin 					buf[j] = '\t';
31661ba55bcSBaptiste Daroussin 				} else {
31761ba55bcSBaptiste Daroussin 					j++;
31861ba55bcSBaptiste Daroussin 					buf[j] = 't';
31961ba55bcSBaptiste Daroussin 				}
32061ba55bcSBaptiste Daroussin 				i++;
32161ba55bcSBaptiste Daroussin 				break;
32261ba55bcSBaptiste Daroussin 			}
32361ba55bcSBaptiste Daroussin 			break;
32461ba55bcSBaptiste Daroussin 		case '\n':
32561ba55bcSBaptiste Daroussin 			buf[j] = crwrap ? '\n' : ' ';
32661ba55bcSBaptiste Daroussin 			break;
32761ba55bcSBaptiste Daroussin 		case '\t':
32861ba55bcSBaptiste Daroussin 			buf[j] = opt->text_unchanged ? '\t' : ' ';
32961ba55bcSBaptiste Daroussin 			break;
33061ba55bcSBaptiste Daroussin 		default:
33161ba55bcSBaptiste Daroussin 			buf[j] = text[i];
33261ba55bcSBaptiste Daroussin 		}
33361ba55bcSBaptiste Daroussin 		i++;
33461ba55bcSBaptiste Daroussin 		if (!trim || buf[j] != ' ' || j == 0 || buf[j-1] != ' ')
33561ba55bcSBaptiste Daroussin 			j++;
33661ba55bcSBaptiste Daroussin 	}
33761ba55bcSBaptiste Daroussin 	buf[j] = '\0';
33861ba55bcSBaptiste Daroussin }
339