10e3d5408SPeter Wemm /****************************************************************************
2*21817992SBaptiste Daroussin * Copyright 2018-2021,2023 Thomas E. Dickey *
3e1865124SBaptiste Daroussin * Copyright 1998-2012,2013 Free Software Foundation, Inc. *
40e3d5408SPeter Wemm * *
50e3d5408SPeter Wemm * Permission is hereby granted, free of charge, to any person obtaining a *
60e3d5408SPeter Wemm * copy of this software and associated documentation files (the *
70e3d5408SPeter Wemm * "Software"), to deal in the Software without restriction, including *
80e3d5408SPeter Wemm * without limitation the rights to use, copy, modify, merge, publish, *
90e3d5408SPeter Wemm * distribute, distribute with modifications, sublicense, and/or sell *
100e3d5408SPeter Wemm * copies of the Software, and to permit persons to whom the Software is *
110e3d5408SPeter Wemm * furnished to do so, subject to the following conditions: *
120e3d5408SPeter Wemm * *
130e3d5408SPeter Wemm * The above copyright notice and this permission notice shall be included *
140e3d5408SPeter Wemm * in all copies or substantial portions of the Software. *
150e3d5408SPeter Wemm * *
160e3d5408SPeter Wemm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
170e3d5408SPeter Wemm * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
180e3d5408SPeter Wemm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
190e3d5408SPeter Wemm * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
200e3d5408SPeter Wemm * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
210e3d5408SPeter Wemm * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
220e3d5408SPeter Wemm * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
230e3d5408SPeter Wemm * *
240e3d5408SPeter Wemm * Except as contained in this notice, the name(s) of the above copyright *
250e3d5408SPeter Wemm * holders shall not be used in advertising or otherwise to promote the *
260e3d5408SPeter Wemm * sale, use or other dealings in this Software without prior written *
270e3d5408SPeter Wemm * authorization. *
280e3d5408SPeter Wemm ****************************************************************************/
290e3d5408SPeter Wemm
300e3d5408SPeter Wemm /****************************************************************************
3173f0a83dSXin LI * Author: Thomas E. Dickey 1997-on *
320e3d5408SPeter Wemm ****************************************************************************/
330e3d5408SPeter Wemm
340e3d5408SPeter Wemm #include <curses.priv.h>
350e3d5408SPeter Wemm #include <ctype.h>
360e3d5408SPeter Wemm
37*21817992SBaptiste Daroussin MODULE_ID("$Id: safe_sprintf.c,v 1.37 2023/09/30 10:42:42 tom Exp $")
380e3d5408SPeter Wemm
390e3d5408SPeter Wemm #if USE_SAFE_SPRINTF
400e3d5408SPeter Wemm
417a69bbfbSPeter Wemm typedef enum {
427a69bbfbSPeter Wemm Flags, Width, Prec, Type, Format
437a69bbfbSPeter Wemm } PRINTF;
440e3d5408SPeter Wemm
45aae38d10SBaptiste Daroussin #define VA_INTGR(type) ival = (int) va_arg(ap, type)
460e3d5408SPeter Wemm #define VA_FLOAT(type) fval = va_arg(ap, type)
470e3d5408SPeter Wemm #define VA_POINT(type) pval = (void *)va_arg(ap, type)
480e3d5408SPeter Wemm
490e3d5408SPeter Wemm /*
500e3d5408SPeter Wemm * Scan a variable-argument list for printf to determine the number of
510e3d5408SPeter Wemm * characters that would be emitted.
520e3d5408SPeter Wemm */
530e3d5408SPeter Wemm static int
_nc_printf_length(const char * fmt,va_list ap)540e3d5408SPeter Wemm _nc_printf_length(const char *fmt, va_list ap)
550e3d5408SPeter Wemm {
560e3d5408SPeter Wemm size_t length = BUFSIZ;
570e3d5408SPeter Wemm char *buffer;
580e3d5408SPeter Wemm char *format;
590e3d5408SPeter Wemm int len = 0;
604a1a9510SRong-En Fan size_t fmt_len;
614a1a9510SRong-En Fan char fmt_arg[BUFSIZ];
620e3d5408SPeter Wemm
630e3d5408SPeter Wemm if (fmt == 0 || *fmt == '\0')
644a1a9510SRong-En Fan return 0;
654a1a9510SRong-En Fan fmt_len = strlen(fmt) + 1;
664a1a9510SRong-En Fan if ((format = typeMalloc(char, fmt_len)) == 0)
670e3d5408SPeter Wemm return -1;
680e3d5408SPeter Wemm if ((buffer = typeMalloc(char, length)) == 0) {
690e3d5408SPeter Wemm free(format);
700e3d5408SPeter Wemm return -1;
710e3d5408SPeter Wemm }
720e3d5408SPeter Wemm
730e3d5408SPeter Wemm while (*fmt != '\0') {
740e3d5408SPeter Wemm if (*fmt == '%') {
750e3d5408SPeter Wemm static char dummy[] = "";
760e3d5408SPeter Wemm PRINTF state = Flags;
770e3d5408SPeter Wemm char *pval = dummy; /* avoid const-cast */
780e3d5408SPeter Wemm double fval = 0.0;
790e3d5408SPeter Wemm int done = FALSE;
800e3d5408SPeter Wemm int ival = 0;
810e3d5408SPeter Wemm int prec = -1;
820e3d5408SPeter Wemm int type = 0;
830e3d5408SPeter Wemm int used = 0;
840e3d5408SPeter Wemm int width = -1;
850e3d5408SPeter Wemm size_t f = 0;
860e3d5408SPeter Wemm
870e3d5408SPeter Wemm format[f++] = *fmt;
880e3d5408SPeter Wemm while (*++fmt != '\0' && len >= 0 && !done) {
890e3d5408SPeter Wemm format[f++] = *fmt;
900e3d5408SPeter Wemm
9139f2269fSPeter Wemm if (isdigit(UChar(*fmt))) {
920e3d5408SPeter Wemm int num = *fmt - '0';
930e3d5408SPeter Wemm if (state == Flags && num != 0)
940e3d5408SPeter Wemm state = Width;
950e3d5408SPeter Wemm if (state == Width) {
960e3d5408SPeter Wemm if (width < 0)
970e3d5408SPeter Wemm width = 0;
980e3d5408SPeter Wemm width = (width * 10) + num;
990e3d5408SPeter Wemm } else if (state == Prec) {
1000e3d5408SPeter Wemm if (prec < 0)
1010e3d5408SPeter Wemm prec = 0;
1020e3d5408SPeter Wemm prec = (prec * 10) + num;
1030e3d5408SPeter Wemm }
1040e3d5408SPeter Wemm } else if (*fmt == '*') {
1050e3d5408SPeter Wemm VA_INTGR(int);
1060e3d5408SPeter Wemm if (state == Flags)
1070e3d5408SPeter Wemm state = Width;
1080e3d5408SPeter Wemm if (state == Width) {
1090e3d5408SPeter Wemm width = ival;
1100e3d5408SPeter Wemm } else if (state == Prec) {
1110e3d5408SPeter Wemm prec = ival;
1120e3d5408SPeter Wemm }
11373f0a83dSXin LI _nc_SPRINTF(fmt_arg,
11473f0a83dSXin LI _nc_SLIMIT(sizeof(fmt_arg))
11573f0a83dSXin LI "%d", ival);
1164a1a9510SRong-En Fan fmt_len += strlen(fmt_arg);
11706bfebdeSXin LI if ((format = _nc_doalloc(format, fmt_len)) == 0) {
11873f0a83dSXin LI free(buffer);
1194a1a9510SRong-En Fan return -1;
1204a1a9510SRong-En Fan }
12173f0a83dSXin LI --f;
12273f0a83dSXin LI _nc_STRCPY(&format[f], fmt_arg, fmt_len - f);
1230e3d5408SPeter Wemm f = strlen(format);
12439f2269fSPeter Wemm } else if (isalpha(UChar(*fmt))) {
1250e3d5408SPeter Wemm done = TRUE;
1260e3d5408SPeter Wemm switch (*fmt) {
1270e3d5408SPeter Wemm case 'Z': /* FALLTHRU */
1280e3d5408SPeter Wemm case 'h': /* FALLTHRU */
1290e3d5408SPeter Wemm case 'l': /* FALLTHRU */
1300e3d5408SPeter Wemm done = FALSE;
1310e3d5408SPeter Wemm type = *fmt;
1320e3d5408SPeter Wemm break;
1330e3d5408SPeter Wemm case 'i': /* FALLTHRU */
1340e3d5408SPeter Wemm case 'd': /* FALLTHRU */
1350e3d5408SPeter Wemm case 'u': /* FALLTHRU */
1360e3d5408SPeter Wemm case 'x': /* FALLTHRU */
1370e3d5408SPeter Wemm case 'X': /* FALLTHRU */
1380e3d5408SPeter Wemm if (type == 'l')
1390e3d5408SPeter Wemm VA_INTGR(long);
1400e3d5408SPeter Wemm else if (type == 'Z')
1410e3d5408SPeter Wemm VA_INTGR(size_t);
1420e3d5408SPeter Wemm else
1430e3d5408SPeter Wemm VA_INTGR(int);
1440e3d5408SPeter Wemm used = 'i';
1450e3d5408SPeter Wemm break;
1460e3d5408SPeter Wemm case 'f': /* FALLTHRU */
1470e3d5408SPeter Wemm case 'e': /* FALLTHRU */
1480e3d5408SPeter Wemm case 'E': /* FALLTHRU */
1490e3d5408SPeter Wemm case 'g': /* FALLTHRU */
1500e3d5408SPeter Wemm case 'G': /* FALLTHRU */
1510e3d5408SPeter Wemm VA_FLOAT(double);
1520e3d5408SPeter Wemm used = 'f';
1530e3d5408SPeter Wemm break;
1540e3d5408SPeter Wemm case 'c':
1550e3d5408SPeter Wemm VA_INTGR(int);
1560e3d5408SPeter Wemm used = 'i';
1570e3d5408SPeter Wemm break;
1580e3d5408SPeter Wemm case 's':
1590e3d5408SPeter Wemm VA_POINT(char *);
1600e3d5408SPeter Wemm if (prec < 0)
161aae38d10SBaptiste Daroussin prec = (int) strlen(pval);
1620e3d5408SPeter Wemm if (prec > (int) length) {
163aae38d10SBaptiste Daroussin length = length + (size_t) prec;
1640e3d5408SPeter Wemm buffer = typeRealloc(char, length, buffer);
1650e3d5408SPeter Wemm if (buffer == 0) {
1660e3d5408SPeter Wemm free(format);
1670e3d5408SPeter Wemm return -1;
1680e3d5408SPeter Wemm }
1690e3d5408SPeter Wemm }
1700e3d5408SPeter Wemm used = 'p';
1710e3d5408SPeter Wemm break;
1720e3d5408SPeter Wemm case 'p':
1730e3d5408SPeter Wemm VA_POINT(void *);
1740e3d5408SPeter Wemm used = 'p';
1750e3d5408SPeter Wemm break;
1760e3d5408SPeter Wemm case 'n':
1770e3d5408SPeter Wemm VA_POINT(int *);
1780e3d5408SPeter Wemm used = 0;
1790e3d5408SPeter Wemm break;
1800e3d5408SPeter Wemm default:
1810e3d5408SPeter Wemm break;
1820e3d5408SPeter Wemm }
1830e3d5408SPeter Wemm } else if (*fmt == '.') {
1840e3d5408SPeter Wemm state = Prec;
1850e3d5408SPeter Wemm } else if (*fmt == '%') {
1860e3d5408SPeter Wemm done = TRUE;
1870e3d5408SPeter Wemm used = 'p';
1880e3d5408SPeter Wemm }
1890e3d5408SPeter Wemm }
1900e3d5408SPeter Wemm format[f] = '\0';
1910e3d5408SPeter Wemm switch (used) {
1920e3d5408SPeter Wemm case 'i':
19373f0a83dSXin LI _nc_SPRINTF(buffer, _nc_SLIMIT(length) format, ival);
1940e3d5408SPeter Wemm break;
1950e3d5408SPeter Wemm case 'f':
19673f0a83dSXin LI _nc_SPRINTF(buffer, _nc_SLIMIT(length) format, fval);
1970e3d5408SPeter Wemm break;
1980e3d5408SPeter Wemm default:
19973f0a83dSXin LI _nc_SPRINTF(buffer, _nc_SLIMIT(length) format, pval);
2000e3d5408SPeter Wemm break;
2010e3d5408SPeter Wemm }
2020e3d5408SPeter Wemm len += (int) strlen(buffer);
2030e3d5408SPeter Wemm } else {
2040e3d5408SPeter Wemm fmt++;
2050e3d5408SPeter Wemm len++;
2060e3d5408SPeter Wemm }
2070e3d5408SPeter Wemm }
2080e3d5408SPeter Wemm
2090e3d5408SPeter Wemm free(buffer);
2100e3d5408SPeter Wemm free(format);
2110e3d5408SPeter Wemm return len;
2120e3d5408SPeter Wemm }
2130e3d5408SPeter Wemm #endif
2140e3d5408SPeter Wemm
2155ca44d1cSRong-En Fan #define my_buffer _nc_globals.safeprint_buf
2165ca44d1cSRong-En Fan #define my_length _nc_globals.safeprint_used
2175ca44d1cSRong-En Fan
2180e3d5408SPeter Wemm /*
2190e3d5408SPeter Wemm * Wrapper for vsprintf that allocates a buffer big enough to hold the result.
2200e3d5408SPeter Wemm */
2217a69bbfbSPeter Wemm NCURSES_EXPORT(char *)
NCURSES_SP_NAME(_nc_printf_string)22206bfebdeSXin LI NCURSES_SP_NAME(_nc_printf_string) (NCURSES_SP_DCLx
22306bfebdeSXin LI const char *fmt,
22406bfebdeSXin LI va_list ap)
2250e3d5408SPeter Wemm {
226*21817992SBaptiste Daroussin char *result = NULL;
2274a1a9510SRong-En Fan
228*21817992SBaptiste Daroussin if (SP_PARM != NULL && fmt != NULL) {
2290e3d5408SPeter Wemm #if USE_SAFE_SPRINTF
23006bfebdeSXin LI va_list ap2;
23106bfebdeSXin LI int len;
23206bfebdeSXin LI
23306bfebdeSXin LI begin_va_copy(ap2, ap);
23406bfebdeSXin LI len = _nc_printf_length(fmt, ap2);
23506bfebdeSXin LI end_va_copy(ap2);
2360e3d5408SPeter Wemm
2375ca44d1cSRong-En Fan if ((int) my_length < len + 1) {
238aae38d10SBaptiste Daroussin my_length = (size_t) (2 * (len + 1));
2395ca44d1cSRong-En Fan my_buffer = typeRealloc(char, my_length, my_buffer);
2404a1a9510SRong-En Fan }
241*21817992SBaptiste Daroussin if (my_buffer != NULL) {
2425ca44d1cSRong-En Fan *my_buffer = '\0';
2434a1a9510SRong-En Fan if (len >= 0) {
2445ca44d1cSRong-En Fan vsprintf(my_buffer, fmt, ap);
2450e3d5408SPeter Wemm }
2465ca44d1cSRong-En Fan result = my_buffer;
2474a1a9510SRong-En Fan }
2480e3d5408SPeter Wemm #else
2495ca44d1cSRong-En Fan #define MyCols _nc_globals.safeprint_cols
2505ca44d1cSRong-En Fan #define MyRows _nc_globals.safeprint_rows
2510e3d5408SPeter Wemm
25206bfebdeSXin LI if (screen_lines(SP_PARM) > MyRows || screen_columns(SP_PARM) > MyCols) {
25306bfebdeSXin LI if (screen_lines(SP_PARM) > MyRows)
25406bfebdeSXin LI MyRows = screen_lines(SP_PARM);
25506bfebdeSXin LI if (screen_columns(SP_PARM) > MyCols)
25606bfebdeSXin LI MyCols = screen_columns(SP_PARM);
25706bfebdeSXin LI my_length = (size_t) (MyRows * (MyCols + 1)) + 1;
258*21817992SBaptiste Daroussin if (my_length < 80)
259*21817992SBaptiste Daroussin my_length = 80;
2605ca44d1cSRong-En Fan my_buffer = typeRealloc(char, my_length, my_buffer);
2610e3d5408SPeter Wemm }
2620e3d5408SPeter Wemm
263*21817992SBaptiste Daroussin if (my_buffer != NULL) {
2640e3d5408SPeter Wemm # if HAVE_VSNPRINTF
265*21817992SBaptiste Daroussin /* SUSv2, 1997 */
266*21817992SBaptiste Daroussin int used;
267*21817992SBaptiste Daroussin
268*21817992SBaptiste Daroussin do {
269*21817992SBaptiste Daroussin va_list ap2;
270*21817992SBaptiste Daroussin
271*21817992SBaptiste Daroussin begin_va_copy(ap2, ap);
272*21817992SBaptiste Daroussin used = vsnprintf(my_buffer, my_length, fmt, ap2);
273*21817992SBaptiste Daroussin end_va_copy(ap2);
274*21817992SBaptiste Daroussin if (used < (int) my_length)
275*21817992SBaptiste Daroussin break;
276*21817992SBaptiste Daroussin my_length = (size_t) ((3 * used) / 2);
277*21817992SBaptiste Daroussin my_buffer = typeRealloc(char, my_length, my_buffer);
278*21817992SBaptiste Daroussin } while (my_buffer != NULL);
2790e3d5408SPeter Wemm # else
280*21817992SBaptiste Daroussin /* ISO/ANSI C, 1989 */
281*21817992SBaptiste Daroussin vsprintf(my_buffer, fmt, ap);
2820e3d5408SPeter Wemm # endif
2835ca44d1cSRong-En Fan result = my_buffer;
2840e3d5408SPeter Wemm }
2850e3d5408SPeter Wemm #endif
286*21817992SBaptiste Daroussin } else if (my_buffer != NULL) { /* see _nc_freeall() */
2875ca44d1cSRong-En Fan free(my_buffer);
288*21817992SBaptiste Daroussin my_buffer = NULL;
2895ca44d1cSRong-En Fan my_length = 0;
2904a1a9510SRong-En Fan }
2914a1a9510SRong-En Fan return result;
2920e3d5408SPeter Wemm }
29306bfebdeSXin LI
29406bfebdeSXin LI #if NCURSES_SP_FUNCS
29506bfebdeSXin LI NCURSES_EXPORT(char *)
_nc_printf_string(const char * fmt,va_list ap)29606bfebdeSXin LI _nc_printf_string(const char *fmt, va_list ap)
29706bfebdeSXin LI {
29806bfebdeSXin LI return NCURSES_SP_NAME(_nc_printf_string) (CURRENT_SCREEN, fmt, ap);
29906bfebdeSXin LI }
30006bfebdeSXin LI #endif
301