-/* Output like sprintf to a buffer of specified size.
+/* Output like sprintf to a buffer of specified size. -*- coding: utf-8 -*-
Also takes args differently: pass one pointer to the end
of the format string in addition to the format string itself.
- Copyright (C) 1985, 2001-2011 Free Software Foundation, Inc.
+ Copyright (C) 1985, 2001-2015 Free Software Foundation, Inc.
This file is part of GNU Emacs.
of the (`int') argument, suitable for display in an Emacs buffer.
. For %s and %c, when field width is specified (e.g., %25s), it accounts for
- the diplay width of each character, according to char-width-table. That
+ the display width of each character, according to char-width-table. That
is, it does not assume that each character takes one column on display.
. If the size of the buffer is not enough to produce the formatted string in
could include embedded null characters.
. It signals an error if the length of the formatted string is about to
- overflow MOST_POSITIVE_FIXNUM, to avoid producing strings longer than what
+ overflow ptrdiff_t or size_t, to avoid producing strings longer than what
Emacs can handle.
OTOH, this function supports only a small subset of the standard C formatted
support features beyond those in `Fformat', which is used by `error' on the
Lisp level. */
-/* This function supports the following %-sequences in the `format'
- argument:
+/* In the FORMAT argument this function supports ` and ' as directives
+ that output left and right quotes as per ‘text-quoting style’. It
+ also supports the following %-sequences:
%s means print a string argument.
%S is silently treated as %s, for loose compatibility with `Fformat'.
#include <config.h>
#include <stdio.h>
-#include <ctype.h>
-#include <setjmp.h>
#include <float.h>
#include <unistd.h>
#include <limits.h>
another macro. */
#include "character.h"
-#ifndef DBL_MAX_10_EXP
-#define DBL_MAX_10_EXP 308 /* IEEE double */
-#endif
-
/* Generate output from a format-spec FORMAT,
terminated at position FORMAT_END.
(*FORMAT_END is not part of the format, but must exist and be readable.)
doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
const char *format_end, va_list ap)
{
- const char *fmt = format; /* Pointer into format string */
- register char *bufptr = buffer; /* Pointer into output buffer.. */
+ const char *fmt = format; /* Pointer into format string. */
+ char *bufptr = buffer; /* Pointer into output buffer. */
/* Use this for sprintf unless we need something really big. */
char tembuf[DBL_MAX_10_EXP + 100];
/* Buffer we have got with malloc. */
char *big_buffer = NULL;
- register size_t tem;
+ enum text_quoting_style quoting_style = text_quoting_style ();
+ ptrdiff_t tem = -1;
char *string;
char fixed_buffer[20]; /* Default buffer for small formatting. */
char *fmtcpy;
if (format_end == 0)
format_end = format + strlen (format);
- if (format_end - format < sizeof (fixed_buffer) - 1)
- fmtcpy = fixed_buffer;
- else
- SAFE_ALLOCA (fmtcpy, char *, format_end - format + 1);
+ fmtcpy = (format_end - format < sizeof (fixed_buffer) - 1
+ ? fixed_buffer
+ : SAFE_ALLOCA (format_end - format + 1));
bufsize--;
/* Loop until end of format string or buffer full. */
while (fmt < format_end && bufsize > 0)
{
- if (*fmt == '%') /* Check for a '%' character */
+ char const *fmt0 = fmt;
+ char fmtchar = *fmt++;
+ if (fmtchar == '%')
{
ptrdiff_t size_bound = 0;
- EMACS_INT width; /* Columns occupied by STRING on display. */
+ ptrdiff_t width; /* Columns occupied by STRING on display. */
enum {
pDlen = sizeof pD - 1,
pIlen = sizeof pI - 1,
int maxmlen = max (max (1, pDlen), max (pIlen, pMlen));
int mlen;
- fmt++;
/* Copy this one %-spec into fmtcpy. */
string = fmtcpy;
*string++ = '%';
{
if (big_buffer)
xfree (big_buffer);
- big_buffer = (char *) xmalloc (size_bound);
+ big_buffer = xmalloc (size_bound);
sprintf_buffer = big_buffer;
size_allocated = size_bound;
}
case no_modifier:
{
int v = va_arg (ap, int);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
case long_modifier:
{
long v = va_arg (ap, long);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
case pD_modifier:
signed_pD_modifier:
{
ptrdiff_t v = va_arg (ap, ptrdiff_t);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
case pI_modifier:
{
EMACS_INT v = va_arg (ap, EMACS_INT);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
case pM_modifier:
{
intmax_t v = va_arg (ap, intmax_t);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
}
case no_modifier:
{
unsigned v = va_arg (ap, unsigned);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
case long_modifier:
{
unsigned long v = va_arg (ap, unsigned long);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
case pD_modifier:
case pI_modifier:
{
EMACS_UINT v = va_arg (ap, EMACS_UINT);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
case pM_modifier:
{
uintmax_t v = va_arg (ap, uintmax_t);
- sprintf (sprintf_buffer, fmtcpy, v);
+ tem = sprintf (sprintf_buffer, fmtcpy, v);
}
break;
}
case 'e':
case 'g':
{
- double d = va_arg(ap, double);
- sprintf (sprintf_buffer, fmtcpy, d);
+ double d = va_arg (ap, double);
+ tem = sprintf (sprintf_buffer, fmtcpy, d);
/* Now copy into final output, truncating as necessary. */
string = sprintf_buffer;
goto doit;
/* Copy string into final output, truncating if no room. */
doit:
+ eassert (0 <= tem);
/* Coming here means STRING contains ASCII only. */
- tem = strlen (string);
if (STRING_BYTES_BOUND < tem)
error ("Format width or precision too large");
width = tem;
{
/* Truncate the string at character boundary. */
tem = bufsize;
- while (!CHAR_HEAD_P (string[tem - 1])) tem--;
- /* If the multibyte sequence of this character is
- too long for the space we have left in the
- buffer, truncate before it. */
- if (tem > 0
- && BYTES_BY_CHAR_HEAD (string[tem - 1]) > bufsize)
- tem--;
- if (tem > 0)
- memcpy (bufptr, string, tem);
+ do
+ {
+ tem--;
+ if (CHAR_HEAD_P (string[tem]))
+ {
+ if (BYTES_BY_CHAR_HEAD (string[tem]) <= bufsize - tem)
+ tem = bufsize;
+ break;
+ }
+ }
+ while (tem != 0);
+
+ memcpy (bufptr, string, tem);
bufptr[tem] = 0;
/* Trigger exit from the loop, but make sure we
return to the caller a value which will indicate
bufsize = 0;
continue;
}
- else
- memcpy (bufptr, string, tem);
+ memcpy (bufptr, string, tem);
bufptr += tem;
bufsize -= tem;
if (minlen < 0)
case 'c':
{
- int chr = va_arg(ap, int);
+ int chr = va_arg (ap, int);
tem = CHAR_STRING (chr, (unsigned char *) charbuf);
string = charbuf;
string[tem] = 0;
}
}
- {
- /* Just some character; Copy it if the whole multi-byte form
- fit in the buffer. */
- char *save_bufptr = bufptr;
-
- do { *bufptr++ = *fmt++; }
- while (fmt < format_end && --bufsize > 0 && !CHAR_HEAD_P (*fmt));
- if (!CHAR_HEAD_P (*fmt))
- {
- /* Truncate, but return value that will signal to caller
- that the buffer was too small. */
- *save_bufptr = 0;
- break;
- }
- }
- };
+ char const *src;
+ ptrdiff_t srclen;
+ if (quoting_style == CURVE_QUOTING_STYLE && fmtchar == '`')
+ src = uLSQM, srclen = sizeof uLSQM - 1;
+ else if (quoting_style == CURVE_QUOTING_STYLE && fmtchar == '\'')
+ src = uRSQM, srclen = sizeof uRSQM - 1;
+ else if (quoting_style == STRAIGHT_QUOTING_STYLE && fmtchar == '`')
+ src = "'", srclen = 1;
+ else
+ {
+ while (fmt < format_end && !CHAR_HEAD_P (*fmt))
+ fmt++;
+ src = fmt0, srclen = fmt - fmt0;
+ }
+
+ if (bufsize < srclen)
+ {
+ /* Truncate, but return value that will signal to caller
+ that the buffer was too small. */
+ do
+ *bufptr++ = '\0';
+ while (--bufsize != 0);
+ }
+ else
+ {
+ do
+ *bufptr++ = *src++;
+ while (--srclen != 0);
+ }
+ }
/* If we had to malloc something, free it. */
xfree (big_buffer);
/* Format to an unbounded buffer BUF. This is like sprintf, except it
is not limited to returning an 'int' so it doesn't have a silly 2
GiB limit on typical 64-bit hosts. However, it is limited to the
- Emacs-style formats that doprnt supports.
+ Emacs-style formats that doprnt supports, and it requotes ` and '
+ as per ‘text-quoting-style’.
Return the number of bytes put into BUF, excluding the terminating
'\0'. */
return nbytes;
}
-/* Format to a buffer BUF of positive size BUFSIZE. This is like
- snprintf, except it is not limited to returning an 'int' so it
- doesn't have a silly 2 GiB limit on typical 64-bit hosts. However,
- it is limited to the Emacs-style formats that doprnt supports, and
- BUFSIZE must be positive.
-
- Return the number of bytes put into BUF, excluding the terminating
- '\0'. Unlike snprintf, always return a nonnegative value less than
- BUFSIZE; if the output is truncated, return BUFSIZE - 1, which is
- the length of the truncated output. */
-ptrdiff_t
-esnprintf (char *buf, ptrdiff_t bufsize, char const *format, ...)
-{
- ptrdiff_t nbytes;
- va_list ap;
- va_start (ap, format);
- nbytes = doprnt (buf, bufsize, format, 0, ap);
- va_end (ap);
- return nbytes;
-}
+#if HAVE_MODULES || (defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT)
/* Format to buffer *BUF of positive size *BUFSIZE, reallocating *BUF
and updating *BUFSIZE if the buffer is too small, and otherwise
return nbytes;
}
+#endif
+
/* Act like exprintf, except take a va_list. */
ptrdiff_t
evxprintf (char **buf, ptrdiff_t *bufsize,
if (nbytes < *bufsize - 1)
return nbytes;
if (*buf != nonheapbuf)
- xfree (*buf);
+ {
+ xfree (*buf);
+ *buf = NULL;
+ }
*buf = xpalloc (NULL, bufsize, 1, bufsize_max, 1);
}
}