150276Speter/****************************************************************************
2174993Srafan * Copyright (c) 1998-2003,2007 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Thomas E. Dickey <dickey@clark.net> 1997                        *
3150276Speter ****************************************************************************/
3250276Speter
3350276Speter#include <curses.priv.h>
3450276Speter#include <ctype.h>
3550276Speter
36174993SrafanMODULE_ID("$Id: safe_sprintf.c,v 1.20 2007/04/21 22:28:06 tom Exp $")
3750276Speter
3850276Speter#if USE_SAFE_SPRINTF
3950276Speter
4076726Spetertypedef enum {
4176726Speter    Flags, Width, Prec, Type, Format
4276726Speter} PRINTF;
4350276Speter
4450276Speter#define VA_INTGR(type) ival = va_arg(ap, type)
4550276Speter#define VA_FLOAT(type) fval = va_arg(ap, type)
4650276Speter#define VA_POINT(type) pval = (void *)va_arg(ap, type)
4750276Speter
4850276Speter/*
4950276Speter * Scan a variable-argument list for printf to determine the number of
5050276Speter * characters that would be emitted.
5150276Speter */
5250276Speterstatic int
5350276Speter_nc_printf_length(const char *fmt, va_list ap)
5450276Speter{
5576726Speter    size_t length = BUFSIZ;
5676726Speter    char *buffer;
5776726Speter    char *format;
5876726Speter    int len = 0;
59166124Srafan    size_t fmt_len;
60166124Srafan    char fmt_arg[BUFSIZ];
6150276Speter
6276726Speter    if (fmt == 0 || *fmt == '\0')
63166124Srafan	return 0;
64166124Srafan    fmt_len = strlen(fmt) + 1;
65166124Srafan    if ((format = typeMalloc(char, fmt_len)) == 0)
6676726Speter	  return -1;
6776726Speter    if ((buffer = typeMalloc(char, length)) == 0) {
6876726Speter	free(format);
6976726Speter	return -1;
7076726Speter    }
7150276Speter
7276726Speter    while (*fmt != '\0') {
7376726Speter	if (*fmt == '%') {
7476726Speter	    static char dummy[] = "";
7576726Speter	    PRINTF state = Flags;
7676726Speter	    char *pval = dummy;	/* avoid const-cast */
7776726Speter	    double fval = 0.0;
7876726Speter	    int done = FALSE;
7976726Speter	    int ival = 0;
8076726Speter	    int prec = -1;
8176726Speter	    int type = 0;
8276726Speter	    int used = 0;
8376726Speter	    int width = -1;
8476726Speter	    size_t f = 0;
8550276Speter
8676726Speter	    format[f++] = *fmt;
8776726Speter	    while (*++fmt != '\0' && len >= 0 && !done) {
8876726Speter		format[f++] = *fmt;
8950276Speter
9097049Speter		if (isdigit(UChar(*fmt))) {
9176726Speter		    int num = *fmt - '0';
9276726Speter		    if (state == Flags && num != 0)
9376726Speter			state = Width;
9476726Speter		    if (state == Width) {
9576726Speter			if (width < 0)
9676726Speter			    width = 0;
9776726Speter			width = (width * 10) + num;
9876726Speter		    } else if (state == Prec) {
9976726Speter			if (prec < 0)
10076726Speter			    prec = 0;
10176726Speter			prec = (prec * 10) + num;
10276726Speter		    }
10376726Speter		} else if (*fmt == '*') {
10476726Speter		    VA_INTGR(int);
10576726Speter		    if (state == Flags)
10676726Speter			state = Width;
10776726Speter		    if (state == Width) {
10876726Speter			width = ival;
10976726Speter		    } else if (state == Prec) {
11076726Speter			prec = ival;
11176726Speter		    }
112166124Srafan		    sprintf(fmt_arg, "%d", ival);
113166124Srafan		    fmt_len += strlen(fmt_arg);
114166124Srafan		    if ((format = realloc(format, fmt_len)) == 0) {
115166124Srafan			return -1;
116166124Srafan		    }
117166124Srafan		    strcpy(&format[--f], fmt_arg);
11876726Speter		    f = strlen(format);
11997049Speter		} else if (isalpha(UChar(*fmt))) {
12076726Speter		    done = TRUE;
12176726Speter		    switch (*fmt) {
12276726Speter		    case 'Z':	/* FALLTHRU */
12376726Speter		    case 'h':	/* FALLTHRU */
12476726Speter		    case 'l':	/* FALLTHRU */
12576726Speter			done = FALSE;
12676726Speter			type = *fmt;
12776726Speter			break;
12876726Speter		    case 'i':	/* FALLTHRU */
12976726Speter		    case 'd':	/* FALLTHRU */
13076726Speter		    case 'u':	/* FALLTHRU */
13176726Speter		    case 'x':	/* FALLTHRU */
13276726Speter		    case 'X':	/* FALLTHRU */
13376726Speter			if (type == 'l')
13476726Speter			    VA_INTGR(long);
13576726Speter			else if (type == 'Z')
13676726Speter			    VA_INTGR(size_t);
13776726Speter			else
13876726Speter			    VA_INTGR(int);
13976726Speter			used = 'i';
14076726Speter			break;
14176726Speter		    case 'f':	/* FALLTHRU */
14276726Speter		    case 'e':	/* FALLTHRU */
14376726Speter		    case 'E':	/* FALLTHRU */
14476726Speter		    case 'g':	/* FALLTHRU */
14576726Speter		    case 'G':	/* FALLTHRU */
14676726Speter			VA_FLOAT(double);
14776726Speter			used = 'f';
14876726Speter			break;
14976726Speter		    case 'c':
15076726Speter			VA_INTGR(int);
15176726Speter			used = 'i';
15276726Speter			break;
15376726Speter		    case 's':
15476726Speter			VA_POINT(char *);
15576726Speter			if (prec < 0)
15676726Speter			    prec = strlen(pval);
15776726Speter			if (prec > (int) length) {
15876726Speter			    length = length + prec;
15976726Speter			    buffer = typeRealloc(char, length, buffer);
16076726Speter			    if (buffer == 0) {
16176726Speter				free(format);
16276726Speter				return -1;
16376726Speter			    }
16450276Speter			}
16576726Speter			used = 'p';
16676726Speter			break;
16776726Speter		    case 'p':
16876726Speter			VA_POINT(void *);
16976726Speter			used = 'p';
17076726Speter			break;
17176726Speter		    case 'n':
17276726Speter			VA_POINT(int *);
17376726Speter			used = 0;
17476726Speter			break;
17576726Speter		    default:
17676726Speter			break;
17776726Speter		    }
17876726Speter		} else if (*fmt == '.') {
17976726Speter		    state = Prec;
18076726Speter		} else if (*fmt == '%') {
18176726Speter		    done = TRUE;
18276726Speter		    used = 'p';
18350276Speter		}
18476726Speter	    }
18576726Speter	    format[f] = '\0';
18676726Speter	    switch (used) {
18776726Speter	    case 'i':
18876726Speter		sprintf(buffer, format, ival);
18976726Speter		break;
19076726Speter	    case 'f':
19176726Speter		sprintf(buffer, format, fval);
19276726Speter		break;
19376726Speter	    default:
19476726Speter		sprintf(buffer, format, pval);
19576726Speter		break;
19676726Speter	    }
19776726Speter	    len += (int) strlen(buffer);
19876726Speter	} else {
19976726Speter	    fmt++;
20076726Speter	    len++;
20150276Speter	}
20276726Speter    }
20350276Speter
20476726Speter    free(buffer);
20576726Speter    free(format);
20676726Speter    return len;
20750276Speter}
20850276Speter#endif
20950276Speter
210174993Srafan#define my_buffer _nc_globals.safeprint_buf
211174993Srafan#define my_length _nc_globals.safeprint_used
212174993Srafan
21350276Speter/*
21450276Speter * Wrapper for vsprintf that allocates a buffer big enough to hold the result.
21550276Speter */
21676726SpeterNCURSES_EXPORT(char *)
217166124Srafan_nc_printf_string(const char *fmt, va_list ap)
21850276Speter{
219166124Srafan    char *result = 0;
220166124Srafan
221166124Srafan    if (fmt != 0) {
22250276Speter#if USE_SAFE_SPRINTF
223166124Srafan	int len = _nc_printf_length(fmt, ap);
22450276Speter
225174993Srafan	if ((int) my_length < len + 1) {
226174993Srafan	    my_length = 2 * (len + 1);
227174993Srafan	    my_buffer = typeRealloc(char, my_length, my_buffer);
228166124Srafan	}
229174993Srafan	if (my_buffer != 0) {
230174993Srafan	    *my_buffer = '\0';
231166124Srafan	    if (len >= 0) {
232174993Srafan		vsprintf(my_buffer, fmt, ap);
233166124Srafan	    }
234174993Srafan	    result = my_buffer;
235166124Srafan	}
23650276Speter#else
237174993Srafan#define MyCols _nc_globals.safeprint_cols
238174993Srafan#define MyRows _nc_globals.safeprint_rows
23950276Speter
240174993Srafan	if (screen_lines > MyRows || screen_columns > MyCols) {
241174993Srafan	    if (screen_lines > MyRows)
242174993Srafan		MyRows = screen_lines;
243174993Srafan	    if (screen_columns > MyCols)
244174993Srafan		MyCols = screen_columns;
245174993Srafan	    my_length = (MyRows * (MyCols + 1)) + 1;
246174993Srafan	    my_buffer = typeRealloc(char, my_length, my_buffer);
24750276Speter	}
24850276Speter
249174993Srafan	if (my_buffer != 0) {
25050276Speter# if HAVE_VSNPRINTF
251174993Srafan	    vsnprintf(my_buffer, my_length, fmt, ap);	/* GNU extension */
25250276Speter# else
253174993Srafan	    vsprintf(my_buffer, fmt, ap);	/* ANSI */
25450276Speter# endif
255174993Srafan	    result = my_buffer;
256166124Srafan	}
257166124Srafan#endif
258174993Srafan    } else if (my_buffer != 0) {	/* see _nc_freeall() */
259174993Srafan	free(my_buffer);
260174993Srafan	my_buffer = 0;
261174993Srafan	my_length = 0;
26276726Speter    }
263166124Srafan    return result;
26450276Speter}
265