100#define P_INPUT_C(c, n) (P_INPUT){ .choices = c }, n, P_CHOICE
101#define P_INPUT_CS(choices) P_INPUT_C(choices, sizeof(choices))
103#define P_INPUT_P(out, size) (P_INPUT){ .output = (out) }, size, P_PROMPT
104#define P_INPUT_PS(out) P_INPUT_P(out, sizeof(out))
109#define P_VERBOSE "\x02"
110#define P_WARNING "\x03"
111#define P_ERROR "\x04"
112#define P_HEADER "\x05"
113#define P_SECTION "\x06"
114#define P_CHOICE "\x07"
115#define P_PROMPT "\x08"
116#define P_MIDDLE "\x11"
124 PRINT_SKIPPED_BECAUSE_QUIET_OR_VERBOSE_NOT_ENABLED__SUCCESS = 0,
125 PRINT_REPEAT_PROGRESS_PERCENT__SUCCESS = 0,
126 PRINT_FIRST_CHOICE_INDEX__SUCCESS = 0,
127 PRINT_INVALID_FORMAT_ARGS__ERROR = -1,
128 PRINT_CHOICE_COLLECTION_SHOULD_CONTAIN_2_OR_MORE_CHOICES__ERROR = -2,
129 PRINT_PROMPT_BUFFER_SIZE_SHOULD_BE_2_OR_MORE__ERROR = -2,
130 PRINT_INVALID_INPUT_TYPE__ERROR = -3,
133void print_stream_in(FILE *);
134void print_stream_out(FILE *);
135void print_stream_err(FILE *);
138#if defined(_MSC_VER) && !defined(__clang__)
139#define P_RESTRICT __restrict
141#define P_RESTRICT __restrict__
143#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
144#define P_RESTRICT restrict
147#error "Please compile with C99 or later standard"
150enum p_return print(
const char *P_RESTRICT, ...);
151enum p_return progress_bar(
int percent,
const char *P_RESTRICT, ...);
152enum p_return input(P_INPUT,
size_t,
const char *P_RESTRICT, ...);
155bool print_yN(
const char *P_RESTRICT);
157bool print_Yn(
const char *P_RESTRICT);
159bool print_yn(
const char *P_RESTRICT);
161#define pinfo(...) print(P_INFO __VA_ARGS__)
162#define pinfom(...) print(P_INFO P_MIDDLE __VA_ARGS__)
163#define pinfol(...) print(P_INFO P_LAST __VA_ARGS__)
165#define pwarning(...) print(P_WARNING __VA_ARGS__)
166#define pwarningm(...) print(P_WARNING P_MIDDLE __VA_ARGS__)
167#define pwarningl(...) print(P_WARNING P_LAST __VA_ARGS__)
169#define pwarn(...) pwarning(__VA_ARGS__)
170#define pwarnm(...) pwarningm(__VA_ARGS__)
171#define pwarnl(...) pwarningl(__VA_ARGS__)
173#define pverbose(...) print(P_VERBOSE __VA_ARGS__)
174#define pverbosem(...) print(P_VERBOSE P_MIDDLE __VA_ARGS__)
175#define pverbosel(...) print(P_VERBOSE P_LAST __VA_ARGS__)
177#define pverb(...) pverbose(__VA_ARGS__)
178#define pverbm(...) pverbosem(__VA_ARGS__)
179#define pverbl(...) pverbosel(__VA_ARGS__)
181#define perr(...) print(P_ERROR __VA_ARGS__)
182#define perrm(...) print(P_ERROR P_MIDDLE __VA_ARGS__)
183#define perrl(...) print(P_ERROR P_LAST __VA_ARGS__)
185#define pchoice(choices, n, ...) input(P_INPUT_C(choices, n) __VA_ARGS__)
186#define pchoice_s(choices, ...) input(P_INPUT_CS(choices) __VA_ARGS__)
187#define pinput(out, size, ...) input(P_INPUT_P(out, size) __VA_ARGS__)
188#define pinput_s(out, ...) input(P_INPUT_PS(out) __VA_ARGS__)
190#define ppercent(pct, ...) progress_bar(pct, __VA_ARGS__)
191#define pproport(prp, ...) progress_bar((100 * prp), __VA_ARGS__)
192#define pproportc(prp, ...) progress_bar((int)(100 * prp), __VA_ARGS__)
194#define pheader(...) print(P_HEADER __VA_ARGS__)
196#define psection(...) print(P_SECTION __VA_ARGS__)
197#define psection_end() print(NULL)
206#ifndef PRINT_TO_DEV_STR
207#define PRINT_TO_DEV_STR "_TO_DEV_: "
211#define pdev(...) perr(PRINT_TO_DEV_STR __VA_ARGS__)
216#ifdef PRINT_EXTERN_FORCE
217extern bool print_force;
219#ifdef PRINT_EXTERN_VERBOSE
220extern bool print_verbose;
222#ifdef PRINT_EXTERN_QUIET
223extern bool print_quiet;
225#ifdef PRINT_EXTERN_NODETAIL
226extern bool print_nodetail;
231#if defined(PRINT_IMPLEMENTATION) && !defined(_PRINT_IMPLEMENTED)
232#define _PRINT_IMPLEMENTED
235#if defined(_MSC_VER) && !defined(__clang__)
236#define P_RESTRICT __restrict
238#define P_RESTRICT __restrict__
240#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
241#define P_RESTRICT restrict
244#error "Please compile with C99 or later standard"
254#ifndef WIN32_LEAN_AND_MEAN
255#define WIN32_LEAN_AND_MEAN
256#define PRINT_UNDEF_WIN32_LEAN_AND_MEAN
259#ifdef PRINT_UNDEF_WIN32_LEAN_AND_MEAN
260#undef WIN32_LEAN_AND_MEAN
261#undef PRINT_UNDEF_WIN32_LEAN_AND_MEAN
263#define fputc_unlocked _fputc_nolock
264#define fwrite_unlocked _fwrite_nolock
265#define flockfile _lock_file
266#define funlockfile _unlock_file
270#include <sys/param.h>
279#ifndef PRINT_TERMINAL_WIDTH
280#define PRINT_TERMINAL_WIDTH 80
283static int terminal_environment(
void)
285 static int is_terminal = -1;
286 if (is_terminal == -1) {
288 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
290 is_terminal = (hStdout != INVALID_HANDLE_VALUE &&
291 GetConsoleMode(hStdout, &dwMode));
293 is_terminal = isatty(STDOUT_FILENO);
300static void terminal_init(
void)
303 HWND consoleWnd = GetConsoleWindow();
304 DWORD consoleProcessId = 0;
307 GetWindowThreadProcessId(consoleWnd, &consoleProcessId);
309 if (consoleProcessId == GetCurrentProcessId()) {
310 char path[MAX_PATH] = { 0 };
311 char dir[MAX_PATH] = { 0 };
312 char name[MAX_PATH] = { 0 };
314 if (GetModuleFileNameA(NULL, path, MAX_PATH)) {
315 char *slash = strrchr(path,
'\\');
317 size_t dirLen = (size_t)(slash - path);
318 memcpy(dir, path, dirLen);
320 strcpy(name, slash + 1);
330 "cmd.exe /k \"cd /d \"%s\" && \"%s\"\"",
333 snprintf(cmd,
sizeof(cmd),
334 "cmd.exe /k \"%s\"", name);
337 STARTUPINFOA si = { 0 };
338 PROCESS_INFORMATION pi = { 0 };
341 if (CreateProcessA(NULL, cmd, NULL, NULL, FALSE,
342 CREATE_NEW_CONSOLE, NULL,
343 dir[0] ? dir : NULL, &si,
345 CloseHandle(pi.hProcess);
346 CloseHandle(pi.hThread);
353 SetConsoleOutputCP(CP_UTF8);
354 SetConsoleCP(CP_UTF8);
356 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
357 if (hOut != INVALID_HANDLE_VALUE) {
359 if (GetConsoleMode(hOut, &dwMode)) {
360 dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
361 SetConsoleMode(hOut, dwMode);
368static void terminal_mode_raw(
void)
371 HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
372 DWORD mode, mask = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT;
373 if (GetConsoleMode(hStdin, &mode))
374 SetConsoleMode(hStdin, mode & ~mask);
378 tcgetattr(STDIN_FILENO, &term);
379 term.c_lflag &= ~((tcflag_t)(ICANON | ECHO));
380 tcsetattr(STDIN_FILENO, TCSANOW, &term);
384static void terminal_mode_restore(
void)
387 HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
389 GetConsoleMode(hStdin, &mode);
390 SetConsoleMode(hStdin, mode | (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
393 tcgetattr(STDIN_FILENO, &term);
394 term.c_lflag |= (ICANON | ECHO);
395 tcsetattr(STDIN_FILENO, TCSANOW, &term);
455enum box_type { BOX_NORMAL, BOX_FANCY, BOX_TYPE_COUNT };
458 const char *codes[COLOR_TYPE_COUNT];
459 const char *icons[ICON_TYPE_COUNT];
469 const char boxes[BOX_TYPE_COUNT][BOX_CHAR_COUNT][
sizeof(
"╔")];
470 const char progress_filled_char[
sizeof(
"■")];
471 const char progress_empty_char[
sizeof(
"·")];
472 const char ansi_escape_start[
sizeof(
"\x1b")];
473 char ansi_carriage_return[
sizeof(
"\r")];
476 [T_NONE] = { COLOR_RESET, ICON_NONE,
false },
477 [T_INFO] = { COLOR_BLUE, ICON_INFO,
false },
478 [T_VERBOSE] = { COLOR_GRAY, ICON_DOT,
true },
479 [T_WARNING] = { COLOR_YELLOW, ICON_WARNING,
true },
480 [T_ERROR] = { COLOR_RED, ICON_ERROR,
true },
481 [T_HEADER] = { COLOR_BRIGHT_CYAN, ICON_NONE,
false },
482 [T_SECTION] = { COLOR_CYAN, ICON_NONE,
false },
483 [T_CHOICE] = { COLOR_BLUE, ICON_INFO,
true },
484 [T_PROMPT] = { COLOR_BLUE, ICON_INFO,
true },
485 [T_PROGRESS] = { COLOR_BLUE, ICON_ARROW,
false },
487#define PCOL(t) p.map[(t)].color
488#define PCOLSIZ(t) (PCOL(t) <= COLOR_UNDER ? 4 : 5)
490 [COLOR_RESET] =
"\x1b[0m",
491 [COLOR_UNDER] =
"\x1b[4m",
492 [COLOR_RED] =
"\x1b[31m",
493 [COLOR_GREEN] =
"\x1b[32m",
494 [COLOR_YELLOW] =
"\x1b[33m",
495 [COLOR_BLUE] =
"\x1b[34m",
496 [COLOR_CYAN] =
"\x1b[36m",
497 [COLOR_GRAY] =
"\x1b[90m",
498 [COLOR_BRIGHT_BLUE] =
"\x1b[94m",
499 [COLOR_BRIGHT_CYAN] =
"\x1b[96m",
501#define PICO(t) p.map[(t)].icon
502#define PICOSIZ(t) (PICO(t) >= ICON_ERROR ? 3 : PICO(t))
505 [ICON_WARNING] =
"!",
511#define BOXSIZ (sizeof(p.boxes[BOX_NORMAL][0]) - 1)
513 {
"┌",
"├",
"└",
"┐",
"─",
"│",
"┤",
"┘" },
514 {
"╔",
"╠",
"╚",
"╗",
"═",
"║",
"╣",
"╝" },
516 .progress_filled_char =
"■",
517 .progress_empty_char =
"·",
518 .ansi_escape_start =
"\x1b",
519 .ansi_carriage_return =
"\r",
520 .width = PRINT_TERMINAL_WIDTH,
523static bool print_force;
524static bool print_verbose;
525static bool print_quiet;
526static bool print_nodetail;
528static bool in_section;
529static bool content_printed;
532void print_stream_in(FILE *in)
537void print_stream_out(FILE *out)
542void print_stream_err(FILE *err)
547static void print_section_end(
void)
553static void print_init(
void)
556 if (!terminal_environment()) {
557 p.ansi_carriage_return[0] =
'\n';
558 print_nodetail =
true;
561 print_stream_in(stdin);
562 print_stream_out(stdout);
563 print_stream_err(stderr);
564 atexit(print_section_end);
568static void terminal_read_input(
char *buf,
size_t buf_sz)
577 for (
int c; (c = fgetc(p.in)) != EOF && c !=
'\n' && c !=
'\r';) {
578 if (c ==
'\b' || c == 0x7F) {
580 while (i && ((buf[i - 1] & 0xC0) == 0x80))
583 fwrite(
"\b \b", 1, 3, p.out);
589 if (i < buf_sz - 1 && (c >= 0x20 && c <= 0x7E)) {
598 terminal_mode_restore();
601bool print_yN(
const char *P_RESTRICT prompt)
606 char result[2] = { 0 };
607 pinput_s(result,
"%s [y/N]", prompt);
608 return result[0] ==
'y' || result[0] ==
'Y';
611bool print_Yn(
const char *P_RESTRICT prompt)
616 char result[2] = { 0 };
617 pinput_s(result,
"%s [Y/n]", prompt);
618 return !(result[0] ==
'n' || result[0] ==
'N');
621bool print_yn(
const char *P_RESTRICT prompt)
626 char result[2] = { 0 };
628 pinput_s(result,
"%s [y/n]", prompt);
629 if (result[0] ==
'y' || result[0] ==
'Y')
631 else if (result[0] ==
'n' || result[0] ==
'N')
637#define ouputc(c) fputc_unlocked((c), out)
638#define oprintf(...) fprintf(out, __VA_ARGS__)
639#define ouwrite(buf, size) fwrite_unlocked((buf), 1, (size), out)
640#define ouwico(t) ouwrite(p.icons[PICO(t)], PICOSIZ(t))
641#define ouwcol(t) ouwrite(p.codes[PCOL(t)], PCOLSIZ(t))
642#define ouwbox(bt, bpart) ouwrite(p.boxes[(bt)][bpart], BOXSIZ)
644static int last_percentage = -1;
646enum p_return print(
const char *P_RESTRICT fmt, ...)
653 char p_buf[BUFSIZ] = { 0 };
656 enum p_location loc = LOC_FIRST;
657 enum p_type type = T_NONE;
666 unsigned char c = (
unsigned char)*fmt;
667 if (c >= T_INFO && c <= T_SECTION) {
668 type = (
enum p_type)c;
670 }
else if (c == 0x11) {
673 }
else if (c == 0x12) {
684 if ((print_quiet && !p.map[type].required) ||
685 (type == T_VERBOSE && !print_verbose))
686 return PRINT_SKIPPED_BECAUSE_QUIET_OR_VERBOSE_NOT_ENABLED__SUCCESS;
688 if (!in_section && type != T_HEADER && type != T_SECTION)
691 if (last_percentage != -1 && content_printed) {
693 last_percentage = -1;
698 va_start(v_args, fmt);
699 p_bufsiz = vsnprintf(p_buf,
sizeof(p_buf), fmt, v_args);
703 pdev(
"Failed to format print string");
704 return PRINT_INVALID_FORMAT_ARGS__ERROR;
709 simple = print_nodetail || (print_quiet && p.map[type].required);
710 const size_t available = p.width - 3 - (!PICO(type) ? 0 : 2);
711 size_t p_buflen = (size_t)p_bufsiz;
712 if (p_buflen > available) {
713 pdev(
"Print string too long, doing a simple print");
719 if (type == T_HEADER) {
725 ouwrite(p_buf, p_buflen);
738 ouwbox(BOX_FANCY, BOX_TOP_LEFT);
741 for (iwlrp = 0; iwlrp < p.width - 2; iwlrp++)
742 ouwbox(BOX_FANCY, BOX_HORIZONTAL);
744 ouwbox(BOX_FANCY, BOX_TOP_RIGHT);
748 const size_t l_pad = (p.width - 2 - p_buflen) / 2;
749 const size_t r_pad = p.width - 2 - p_buflen - l_pad;
752 ouwbox(BOX_FANCY, BOX_VERTICAL);
753 for (iwlrp = 0; iwlrp < l_pad; iwlrp++)
755 ouwrite(p_buf, p_buflen);
756 for (iwlrp = 0; iwlrp < r_pad; iwlrp++)
758 ouwbox(BOX_FANCY, BOX_VERTICAL);
763 ouwbox(BOX_FANCY, BOX_BOTTOM_LEFT);
764 for (iwlrp = 0; iwlrp < p.width - 2; iwlrp++)
765 ouwbox(BOX_FANCY, BOX_HORIZONTAL);
767 ouwbox(BOX_FANCY, BOX_BOTTOM_RIGHT);
771 }
else if (type == T_SECTION) {
772 if (in_section && (!fmt || content_printed)) {
775 ouwbox(BOX_NORMAL, BOX_BOTTOM_LEFT);
778 for (iw = 0; iw < p.width - 2; iw++)
779 ouwbox(BOX_NORMAL, BOX_HORIZONTAL);
781 ouwbox(BOX_NORMAL, BOX_BOTTOM_RIGHT);
787 content_printed =
false;
794 ouwrite(p_buf, p_buflen);
798 content_printed =
false;
803 size_t r_dashes = p.width - 2 - l_dashes - p_buflen - 2;
806 ouwbox(BOX_NORMAL, BOX_TOP_LEFT);
812 ouwbox(BOX_NORMAL, BOX_HORIZONTAL);
816 ouwrite(p.codes[COLOR_UNDER], PCOLSIZ(COLOR_UNDER));
817 ouwrite(p_buf, p_buflen);
824 ouwbox(BOX_NORMAL, BOX_HORIZONTAL);
826 ouwbox(BOX_NORMAL, BOX_TOP_RIGHT);
831 content_printed =
false;
834 ouwrite(p_buf, p_buflen);
836 content_printed =
true;
841 ouwbox(BOX_NORMAL, BOX_VERTICAL);
846 if (loc != LOC_FIRST)
847 ouwbox(BOX_NORMAL, loc);
854 ouwrite(p_buf, p_buflen);
855 size_t padding = available - p_buflen;
859 ouwbox(BOX_NORMAL, BOX_VERTICAL);
862 content_printed =
true;
867 return PRINT_SUCCESS;
870enum p_return progress_bar(
int percent,
const char *P_RESTRICT fmt, ...)
878 return PRINT_SKIPPED_BECAUSE_QUIET_OR_VERBOSE_NOT_ENABLED__SUCCESS;
883#define CLAMP(val, min_val, max_val) (min(max((val), (min_val)), (max_val)))
884 int p_percent = CLAMP(percent, 0, 100);
885 if (p_percent == last_percentage ||
886 (p_percent == 100 && last_percentage == -1))
887 return PRINT_REPEAT_PROGRESS_PERCENT__SUCCESS;
889 last_percentage = p_percent;
890 if (last_percentage == 100)
891 last_percentage = -1;
893 char p_buf[BUFSIZ] = { 0 };
898 va_start(v_args, fmt);
899 p_bufsiz = vsnprintf(p_buf,
sizeof(p_buf), fmt, v_args);
903 pdev(
"Failed to format progress bar string");
904 return PRINT_INVALID_FORMAT_ARGS__ERROR;
908 bool simple = print_nodetail;
909 const size_t available = p.width - 3 - (!PICO(T_PROGRESS) ? 0 : 2);
910 size_t p_buflen = (size_t)p_bufsiz;
911 if (p_buflen > available) {
912 pdev(
"Progress bar string too long, doing a simple print");
918 const int digits = p_percent < 10 ? 1 : (p_percent < 100 ? 2 : 3);
922 ouwrite(p.ansi_carriage_return, 1);
924 ouwrite(p_buf, p_buflen);
926 if (p_percent == 100) {
927 ouwrite(
"100%\n", 5);
930 ouputc(
'0' + p_percent / 10);
931 ouputc(
'0' + p_percent % 10);
936 content_printed =
true;
940 const size_t meta_width = (size_t)digits + 2 + 1 + 1 + 1;
941 const size_t bar_width = available - p_buflen - meta_width - 1;
942 const size_t filled_width = bar_width * (size_t)p_percent / 100;
943 const size_t empty_width = bar_width - filled_width;
946 ouwrite(p.ansi_carriage_return, 1);
949 ouwbox(BOX_NORMAL, BOX_VERTICAL);
951 if (!repeat || p_percent == 100)
954 ouwrite(p.codes[COLOR_BRIGHT_BLUE], PCOLSIZ(COLOR_BRIGHT_BLUE));
960 ouwrite(p_buf, p_buflen);
964 for (ifew = 0; ifew < filled_width; ifew++)
965 ouwrite(p.progress_filled_char, 3);
967 for (ifew = 0; ifew < empty_width; ifew++)
968 ouwrite(p.progress_empty_char, 2);
971 if (p_percent == 100) {
975 ouputc(
'0' + p_percent / 10);
976 ouputc(
'0' + p_percent % 10);
981 ouwbox(BOX_NORMAL, BOX_VERTICAL);
983 if (p_percent == 100)
987 content_printed =
true;
991 return PRINT_SUCCESS;
994enum p_return input(P_INPUT in,
size_t size,
const char *P_RESTRICT fmt, ...)
1000 pdev(
"Input format string is NULL");
1001 return PRINT_INVALID_FORMAT_ARGS__ERROR;
1004 enum p_type type = T_NONE;
1006 unsigned char c = (
unsigned char)*fmt;
1007 if (c >= 0x07 && c <= 0x08) {
1008 type = (
enum p_type)c;
1014 if (type != T_CHOICE && type != T_PROMPT) {
1015 pdev(
"Invalid input type");
1016 return PRINT_INVALID_INPUT_TYPE__ERROR;
1024 if (last_percentage != -1 && content_printed) {
1026 last_percentage = -1;
1029 char p_buf[BUFSIZ] = { 0 };
1034 va_start(v_args, fmt);
1035 p_bufsiz = vsnprintf(p_buf,
sizeof(p_buf), fmt, v_args);
1039 pdev(
"Failed to format input string");
1040 return PRINT_INVALID_FORMAT_ARGS__ERROR;
1044 bool simple = print_nodetail;
1045 const size_t available = p.width - 3 - (!PICO(type) ? 0 : 2);
1046 size_t p_buflen = (size_t)p_bufsiz;
1047 if (p_buflen > available) {
1048 pdev(
"Input string too long, doing a simple print");
1054 if (type == T_CHOICE) {
1055 const char **choices = in.choices;
1056 size_t c_count = size;
1060 pdev(
"Not enough choices (<2)");
1061 return PRINT_CHOICE_COLLECTION_SHOULD_CONTAIN_2_OR_MORE_CHOICES__ERROR;
1064 choices[c_count] = NULL;
1067 for (c = 0; c < c_count; c++) {
1069 oprintf(
"%zu: %s\n", c + 1, choices[c]);
1071 const int label_chars = snprintf(
1072 NULL, 0,
"%zu: %s", c + 1, choices[c]);
1073 const size_t label_len =
1074 (label_chars < 0) ? 0 :
1075 (size_t)label_chars;
1076 const size_t padding =
1077 label_len < available ?
1078 available - label_len + 2 :
1082 ouwbox(BOX_NORMAL, BOX_VERTICAL);
1084 oprintf(
" %zu: %s%*s", c + 1, choices[c],
1087 ouwbox(BOX_NORMAL, BOX_VERTICAL);
1093 char i_buffer[PRINT_TERMINAL_WIDTH] = { 0 };
1098 ouwbox(BOX_NORMAL, BOX_VERTICAL);
1105 ouwrite(p_buf, p_buflen);
1107 oprintf(
"%zu", c_count);
1111 terminal_read_input(i_buffer,
sizeof(i_buffer));
1114 char *endptr = NULL;
1115 unsigned long selected = strtoul(i_buffer, &endptr, 10);
1116 if (endptr == i_buffer || *endptr !=
'\0' ||
1117 errno == ERANGE || selected > INT_MAX)
1122 snprintf(NULL, 0,
"%s (1-%zu): %s",
1123 p_buf, c_count, i_buffer);
1124 const size_t p_len =
1125 (p_chars < 0) ? 0 : (size_t)p_chars;
1126 size_t p_padding = p_len < available ?
1133 ouwbox(BOX_NORMAL, BOX_VERTICAL);
1139 if (selected >= 1 && selected <= c_count) {
1140 content_printed =
true;
1142 return (
int)selected - 1 +
1143 PRINT_FIRST_CHOICE_INDEX__SUCCESS;
1147 pwarn(
"Please enter a number between 1 and %zu",
1151 }
else if (type == T_PROMPT) {
1152 char *result = in.output;
1153 const size_t rsz = size;
1156 pdev(
"Output buffer size is too small");
1157 return PRINT_PROMPT_BUFFER_SIZE_SHOULD_BE_2_OR_MORE__ERROR;
1162 ouwbox(BOX_NORMAL, BOX_VERTICAL);
1169 ouwrite(p_buf, p_buflen);
1173 terminal_read_input(result, rsz);
1177 const size_t p_len = p_buflen + 2 + strlen(result);
1179 p_len < available ? available - p_len : 0;
1184 ouwbox(BOX_NORMAL, BOX_VERTICAL);
1189 content_printed =
true;
1193 return PRINT_SUCCESS;