\f
int stdout_needs_newline;
+void debug_backtrace(void);
+
static void
std_handle_out_external(FILE * stream, Lisp_Object lstream,
const Extbyte * extptr, Extcount extlen,
return;
}
if (stream) {
- {
- fwrite(extptr, 1, extlen, stream);
- if (must_flush)
- fflush(stream);
- }
+ fwrite(extptr, 1, extlen, stream);
+ if (must_flush) fflush(stream);
} else
Lstream_write(XLSTREAM(lstream), extptr, extlen);
fwrite(extptr, 1, extlen, termscript);
fflush(termscript);
}
- stdout_needs_newline = extlen ? (extptr[extlen - 1] != '\n') : 1;
+ stdout_needs_newline = extptr[extlen - 1] != '\n';
}
}
+
+#define SXE_VSNPRINT_VA(ret__,sbuf__,buf__,size__,spec__,tries__,type__,fmt__,args__) \
+ do { \
+ --tries__; \
+ ret__ = vsnprintf((char*)buf__,size__,fmt__,args__); \
+ if ( ret__ == 0 ) { \
+ /* Nothing to write */ \
+ break; \
+ } else if ( ret__ < 0 ) { \
+ XMALLOC_UNBIND(buf__,size__,spec__); \
+ size__ *= 2; \
+ XMALLOC_OR_ALLOCA(buf__,size__,type__); \
+ } else if ( (size_t)ret__ > (size_t)size__ ) { \
+ /* We need more space, so we need to allocate it */ \
+ XMALLOC_UNBIND(buf__,size__,spec__); \
+ size__ = ret__ + 1; \
+ XMALLOC_OR_ALLOCA(buf__,size__,type__); \
+ ret__ = -1; \
+ } \
+ } while( ret__ < 0 && tries__ > 0 )
+
+
+int write_fmt_str(Lisp_Object stream, const char* fmt, ...)
+{
+ char *kludge;
+ va_list args;
+ int bufsize, retval, tries = 3;
+ /* write_fmt_str is used for small prints usually... */
+ char buffer[64+1];
+ int speccount = specpdl_depth();
+
+ va_start(args, fmt);
+ kludge = buffer;
+ bufsize = sizeof(buffer);
+
+ SXE_VSNPRINT_VA(retval,buffer,kludge,bufsize,speccount,tries,char,fmt,args);
+
+ if (retval>0)
+ write_c_string(kludge,stream);
+
+ XMALLOC_UNBIND(kludge, bufsize, speccount);
+ va_end(args);
+
+ if (retval < 0)
+ error("Error attempting to write write format string '%s'",
+ fmt);
+ return retval;
+}
+
+int write_fmt_string(Lisp_Object stream, const char *fmt, ...)
+{
+ char *kludge;
+ va_list args;
+ int bufsize, retval, tries = 3;
+ /* write_va is used for small prints usually... */
+ char buffer[128+1];
+ int speccount = specpdl_depth();
+
+ va_start(args, fmt);
+ kludge = buffer;
+ bufsize = sizeof(buffer);
+
+ SXE_VSNPRINT_VA(retval,buffer,kludge,bufsize,speccount,tries,char,fmt,args);
+ if (retval>0)
+ write_c_string(kludge,stream);
+ XMALLOC_UNBIND(kludge, bufsize, speccount);
+ va_end(args);
+
+ if (retval < 0)
+ error("Error attempting to write write format string '%s'",
+ fmt);
+ return retval;
+}
+
/* #### The following function should be replaced a call to the
emacs_doprnt_*() functions. This is the only way to ensure that
I18N3 works properly (many implementations of the *printf()
static int std_handle_out_va(FILE * stream, const char *fmt, va_list args)
{
- Bufbyte buffer[16384],
- *kludge = buffer;
- Extbyte *extptr = NULL;
- Extcount extlen = 0;
- int retval,
- bufsize = sizeof(buffer),
- tries = 3;
- int speccount = specpdl_depth();
+ int retval, tries = 3;
+ size_t bufsize;
+ int use_fprintf;
+ Bufbyte *kludge;
+ Bufbyte buffer[1024]; /* Tax stack lightly, used to be 16KiB */
+ int speccount = specpdl_depth();
- do {
- assert(tries != 0);
- retval = vsnprintf((char *)kludge, bufsize, fmt, args);
- if ( retval == 0 ) {
- /* Nothing to write!! */
- return retval;
- } else if ( retval < 0 ) {
- bufsize *= 2;
- XMALLOC_UNBIND(kludge, bufsize, speccount);
- XMALLOC_OR_ALLOCA(kludge,bufsize,Bufbyte);
- retval = 0;
- } else if ( retval > bufsize ) {
- /* We need more space, so we need to allocate it
- */
- bufsize = retval + 1;
- XMALLOC_OR_ALLOCA(kludge,bufsize,Bufbyte);
- retval = 0;
- }
- } while( retval == 0 );
+ bufsize = sizeof(buffer);
+ kludge = buffer;
- extlen = retval;
+ SXE_VSNPRINT_VA(retval,buffer,kludge,bufsize,speccount,tries,Bufbyte,fmt,args);
- if (initialized && !inhibit_non_essential_printing_operations &&
- ! fatal_error_in_progress ) {
- TO_EXTERNAL_FORMAT(DATA, (kludge, strlen((char *)kludge)),
- ALLOCA, (extptr, extlen), Qnative);
- std_handle_out_external(stream, Qnil, extptr, extlen, 1, 1);
- } else if (fatal_error_in_progress || !inhibit_non_essential_printing_operations)
- fprintf(stream,"%s",(char*)kludge);
+ if (retval == 0)
+ /* nothing to write */
+ return retval;
+
+ use_fprintf = ! initialized ||fatal_error_in_progress ||
+ inhibit_non_essential_printing_operations;
+
+ if (retval > 0) {
+ if (use_fprintf) {
+ fprintf(stream,"%s",(char*)kludge);
+ } else {
+ Extbyte *extptr = NULL;
+ Extcount extlen = retval;
+
+ TO_EXTERNAL_FORMAT(DATA, (kludge, strlen((char *)kludge)),
+ ALLOCA, (extptr, extlen), Qnative);
+ std_handle_out_external(stream, Qnil, extptr, extlen, 1, 1);
+ }
+ } else {
+ if (use_fprintf) {
+ fprintf(stream,"Error attempting to write format string '%s'",
+ fmt);
+ } else {
+ const Extbyte *msg = "Error attempting to write format string";
+ std_handle_out_external(stream, Qnil, msg, strlen(msg), 1, 1);
+ }
+ }
XMALLOC_UNBIND(kludge, bufsize, speccount);
return retval;
}
+
/* Output portably to stderr or its equivalent; call GETTEXT on the
format string. Automatically flush when done. */
int retval;
va_list args;
va_start(args, fmt);
- retval =
- std_handle_out_va
- (stdout, initialized
- && !fatal_error_in_progress ? GETTEXT(fmt) : fmt, args);
+ retval = std_handle_out_va(stdout,
+ (initialized && !fatal_error_in_progress
+ ? GETTEXT(fmt) : fmt),
+ args);
va_end(args);
return retval;
}
va_start(args, fmt);
stderr_out("\nSXEmacs: ");
- std_handle_out_va(stderr, GETTEXT(fmt), args);
+ std_handle_out_va(stderr,
+ (initialized && !fatal_error_in_progress
+ ? GETTEXT(fmt) : fmt),
+ args);
stderr_out("\n");
va_end(args);
Lisp_Object coding_system, int must_flush)
{
Extcount extlen;
- const Extbyte *extptr;
+ const Extbyte *extptr = NULL;
/* #### yuck! sometimes this function is called with string data,
and the following call may gc. */
Bufbyte *puta = (Bufbyte *) alloca(len);
memcpy(puta, str + offset, len);
- if (initialized && !inhibit_non_essential_printing_operations)
+ if (initialized && !inhibit_non_essential_printing_operations) {
TO_EXTERNAL_FORMAT(DATA, (puta, len),
ALLOCA, (extptr, extlen),
coding_system);
- else {
+ }
+ if( extptr == NULL ) {
extptr = (Extbyte *) puta;
extlen = (Bytecount) len;
}
}
+
if (stream) {
std_handle_out_external(stream, Qnil, extptr, extlen,
stream == stdout
|| stream == stderr, must_flush);
- } else {
+ } else if(con != NULL) {
assert(CONSOLE_TTY_P(con));
std_handle_out_external(0, CONSOLE_TTY_DATA(con)->outstream,
extptr, extlen,
CONSOLE_TTY_DATA(con)->is_stdio,
must_flush);
+ } else {
+ error("Error attempting to write write '%s' with no stream nor console", str);
+ debug_backtrace();
+ abort();
}
}
output_string(stream, str, Qnil, 0, size);
}
+
+void write_hex_ptr(void* value, Lisp_Object stream)
+{
+ char buf[sizeof(value)*2+1];
+ int n = snprintf(buf,sizeof(buf),"0x%p",value);
+ assert(n>=0 && (size_t)n<sizeof(buf));
+ write_c_string(buf,stream);
+}
+
void write_c_string(const char *str, Lisp_Object stream)
{
/* This function can GC */
write_string_1((const Bufbyte *)str, strlen(str), stream);
}
-static void write_fmt_string(Lisp_Object stream, const char *fmt, ...)
-{
- va_list va;
- char bigbuf[666];
-
- va_start(va, fmt);
- vsprintf(bigbuf, fmt, va);
- va_end(va);
- write_c_string(bigbuf, stream);
-}
\f
DEFUN("write-char", Fwrite_char, 1, 2, 0, /*
Output character CHARACTER to stream STREAM.
Lisp_Object Vfloat_output_format;
+void float_to_string(char *buf, fpfloat data, int maxlen);
+
/*
* This buffer should be at least as large as the max string size of the
* largest float, printed in the biggest notation. This is undoubtedly
* I assume that IEEE-754 format numbers can take 329 bytes for the worst
* case of -1e307 in 20d float_output_format. What is one to do (short of
* re-writing _doprnt to be more sane)?
- * -wsr
+ * -wsr
*/
-void float_to_string(char *buf, fpfloat data)
+void float_to_string(char *buf, fpfloat data, int maxlen)
{
Bufbyte *cp, c;
- int width;
+ int width, sz;
if (NILP(Vfloat_output_format) || !STRINGP(Vfloat_output_format)) {
lose:
#if fpfloat_double_p
- sprintf(buf, "%.16g", data);
+ sz = snprintf(buf, maxlen, "%.16g", data);
#elif fpfloat_long_double_p
- sprintf(buf, "%.16Lg", data);
+ sz = snprintf(buf, maxlen, "%.16Lg", data);
#endif
+ assert(sz>=0 && sz<maxlen);
} else { /* oink oink */
/* Check that the spec we have is fully valid.
if (cp[1] != 0)
goto lose;
- sprintf(buf, (char *)XSTRING_DATA(Vfloat_output_format), data);
+ sz = snprintf(buf, maxlen,
+ (char *)XSTRING_DATA(Vfloat_output_format), data);
+ assert(sz>=0 && sz < maxlen);
}
/* added by jwz: don't allow "1.0" to print as "1"; that destroys
{
Bufbyte *s = (Bufbyte *) buf; /* don't use signed chars here!
isdigit() can't hack them! */
- if (*s == '-')
+ if (*s == '-') {
s++;
+ maxlen--;
+ assert(maxlen>0);
+ }
for (; *s; s++)
/* if there's a non-digit, then there is a decimal point, or
it's in exponential notation, both of which are ok. */
if (!isdigit(*s))
goto DONE_LABEL;
/* otherwise, we need to hack it. */
+ maxlen-=2;
+ assert(maxlen>0);
*s++ = '.';
*s++ = '0';
*s = 0;
/* Some machines print "0.4" as ".4". I don't like that. */
if (buf[0] == '.' || (buf[0] == '-' && buf[1] == '.')) {
+ assert(maxlen>0);
int i;
for (i = strlen(buf) + 1; i >= 0; i--)
buf[i + 1] = buf[i];
#endif /* HAVE_FPFLOAT */
/* Print NUMBER to BUFFER.
- This is equivalent to sprintf (buffer, "%ld", number), only much faster.
+ This is equivalent to snprintf (buffer, maxlen, "%ld", number), only much faster.
BUFFER should accept 24 bytes. This should suffice for the longest
numbers on 64-bit machines, including the `-' sign and the trailing
'\0'. Returns a pointer to the trailing '\0'. */
-char *long_to_string(char *buffer, long number)
+char *long_to_string(char *buffer, long number, int maxlen)
{
#if (SIZEOF_LONG != 4) && (SIZEOF_LONG != 8)
/* Huh? */
- sprintf(buffer, "%ld", number);
+ int sz = snprintf(buffer, maxlen, "%ld", number);
+ assert(sz>=0 && sz < maxlen);
return buffer + strlen(buffer);
#else /* (SIZEOF_LONG == 4) || (SIZEOF_LONG == 8) */
char *p = buffer;
*p++ = '-';
number = -number;
}
-#define FROB(figure) do { \
- if (force || number >= figure) \
- *p++ = number / figure + '0', number %= figure, force = 1; \
- } while (0)
+#define FROB(figure) \
+ do { \
+ if (force || number >= figure) { \
+ *p++ = number / figure + '0'; \
+ number %= figure; \
+ force = 1; \
+ --maxlen; \
+ assert(maxlen>0); \
+ } \
+ } while (0)
#if SIZEOF_LONG == 8
FROB(1000000000000000000L);
FROB(100000000000000000L);
int escapeflag)
{
struct lcrecord_header *header = (struct lcrecord_header *)XPNTR(obj);
- char buf[200];
if (print_readably)
error("printing unreadable object #<%s 0x%x>",
LHEADER_IMPLEMENTATION(&header->lheader)->name,
header->uid);
- sprintf(buf, "#<%s 0x%x>",
- LHEADER_IMPLEMENTATION(&header->lheader)->name, header->uid);
- write_c_string(buf, printcharfun);
+ write_fmt_string(printcharfun, "#<%s 0x%x>",
+ LHEADER_IMPLEMENTATION(&header->lheader)->name, header->uid);
}
void
internal_object_printer(Lisp_Object obj, Lisp_Object printcharfun,
int escapeflag)
{
- char buf[200];
- sprintf(buf, "#<INTERNAL OBJECT (SXEmacs bug?) (%s) 0x%lx>",
- XRECORD_LHEADER_IMPLEMENTATION(obj)->name,
- (unsigned long)XPNTR(obj));
- write_c_string(buf, printcharfun);
+ write_fmt_string(printcharfun, "#<INTERNAL OBJECT (SXEmacs bug?) (%s) 0x%lx>",
+ XRECORD_LHEADER_IMPLEMENTATION(obj)->name,
+ (unsigned long)XPNTR(obj));
}
enum printing_badness {
enum printing_badness badness)
{
char buf[666];
+ ssize_t len;
switch (badness) {
case BADNESS_INTEGER_OBJECT:
- sprintf(buf, "%s %d object %ld", badness_string, type,
- (EMACS_INT) val);
+ len = snprintf(buf, sizeof(buf), "%s %d object %ld", badness_string, type,
+ (EMACS_INT) val);
break;
case BADNESS_POINTER_OBJECT:
- sprintf(buf, "%s %d object %p", badness_string, type, val);
+ len = snprintf(buf, sizeof(buf), "%s %d object %p", badness_string, type, val);
break;
case BADNESS_NO_TYPE:
- sprintf(buf, "%s object %p", badness_string, val);
+ len = snprintf(buf, sizeof(buf), "%s object %p", badness_string, val);
break;
default:
+ len = snprintf(buf, sizeof(buf), "%s unknown badness %d",
+ badness_string, badness);
break;
}
+ assert(len >= 0 && (size_t)len < sizeof(buf));
/* Don't abort or signal if called from debug_print() or already
crashing */
output. */
#endif
- /* Try out custom printing */
- if (UNLIKELY(!(bool)inhibit_autoloads && !(bool)nodumpfile) &&
+ /* Try out custom printing */
+ if (UNLIKELY(!(bool)inhibit_autoloads && !(bool)nodumpfile) &&
!EQ(Qnil, Vcustom_object_printer) &&
- !EQ(Qnil, apply1(Vcustom_object_printer,
- Fcons(obj, Fcons(printcharfun, Qnil))))) {
- return;
+ !EQ(Qnil, apply1(Vcustom_object_printer,
+ Fcons(obj, Fcons(printcharfun, Qnil))))) {
+ return;
}
/* Detect circularities and truncate them.
if (EQ(obj, being_printed[i])) {
char buf[32];
*buf = '#';
- long_to_string(buf + 1, i);
+ long_to_string(buf + 1, i, sizeof(buf)-1);
write_c_string(buf, printcharfun);
return;
}
/* ASCII Decimal representation uses 2.4 times as many bits as
machine binary. */
char buf[3 * sizeof(EMACS_INT) + 5];
- long_to_string(buf, XINT(obj));
+ long_to_string(buf, XINT(obj),sizeof(buf));
write_c_string(buf, printcharfun);
break;
}
Bufbyte str[MAX_EMCHAR_LEN];
Bytecount len;
int extlen;
- const Extbyte *extptr;
+ const Extbyte *extptr = NULL;
CHECK_CHAR_COERCE_INT(character);
len = set_charptr_emchar(str, XCHAR(character));
TO_EXTERNAL_FORMAT(DATA, (str, len),
ALLOCA, (extptr, extlen), Qterminal);
- memcpy(alternate_do_string + alternate_do_pointer, extptr, extlen);
- alternate_do_pointer += extlen;
- alternate_do_string[alternate_do_pointer] = 0;
+ if ( extptr != NULL ) {
+ memcpy(alternate_do_string + alternate_do_pointer, extptr, extlen);
+ alternate_do_pointer += extlen;
+ alternate_do_string[alternate_do_pointer] = 0;
+ } else {
+ /* Better bad transcoding than nothing I guess... */
+ memcpy(alternate_do_string + alternate_do_pointer, str, len);
+ alternate_do_pointer += len;
+ alternate_do_string[alternate_do_pointer] = 0;
+ }
return character;
}
*/
(char_or_string, stdout_p, device))
{
- FILE *file = 0;
- struct console *con = 0;
+ FILE *file = NULL;
+ struct console *con = NULL;
if (NILP(device)) {
if (!NILP(stdout_p))
/* Debugging kludge -- unbuffered */
/* This function provided for the benefit of the debugger. */
-void debug_backtrace(void);
void debug_backtrace(void)
{
/* This function can GC */