From 12020a9e6dcfc2213e8bbb0fec259c1ed1202f30 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 10 Apr 2011 09:33:22 -0700 Subject: [PATCH] Keep doprnt.c around for now, as we might revamp and reuse it. --- admin/ChangeLog | 5 - admin/MAINTAINERS | 2 + lisp/ChangeLog | 5 - lisp/emacs-lisp/find-gc.el | 2 +- src/ChangeLog | 5 +- src/doprnt.c | 279 +++++++++++++++++++++++++++++++++++++ 6 files changed, 285 insertions(+), 13 deletions(-) create mode 100644 src/doprnt.c diff --git a/admin/ChangeLog b/admin/ChangeLog index f58a7592f6c..853c1941a92 100644 --- a/admin/ChangeLog +++ b/admin/ChangeLog @@ -1,8 +1,3 @@ -2011-04-07 Paul Eggert - - Remove the doprnt implementation, as Emacs now uses vsnprintf. - * MAINTAINERS: Remove src/doprnt.c. - 2011-03-07 Chong Yidong * Version 23.3 released. diff --git a/admin/MAINTAINERS b/admin/MAINTAINERS index 8fb6f59b45f..1d988a25626 100644 --- a/admin/MAINTAINERS +++ b/admin/MAINTAINERS @@ -145,6 +145,7 @@ src/config.in src/data.c src/dispnew.c src/doc.c +src/doprnt.c src/ecrt0.c src/emacs.c src/epaths.in @@ -214,3 +215,4 @@ src/xmenu.c src/xrdb.c src/xselect.c src/xterm.c + diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 13776503dfb..51f8066077d 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,8 +1,3 @@ -2011-04-10 Paul Eggert - - Remove the doprnt implementation, as Emacs now uses vsnprintf. - * emacs-lisp/find-gc.el (find-gc-source-files): Remove doprnt.c. - 2011-04-10 Leo Liu * emacs-lisp/tabulated-list.el (tabulated-list-print-entry): Fix diff --git a/lisp/emacs-lisp/find-gc.el b/lisp/emacs-lisp/find-gc.el index c9ca03c5e47..1de38625243 100644 --- a/lisp/emacs-lisp/find-gc.el +++ b/lisp/emacs-lisp/find-gc.el @@ -60,7 +60,7 @@ Each entry has the form (FUNCTION . FUNCTIONS-IT-CALLS).") "alloc.c" "data.c" "doc.c" "editfns.c" "callint.c" "eval.c" "fns.c" "print.c" "lread.c" "abbrev.c" "syntax.c" "unexcoff.c" - "bytecode.c" "process.c" "callproc.c" + "bytecode.c" "process.c" "callproc.c" "doprnt.c" "x11term.c" "x11fns.c")) diff --git a/src/ChangeLog b/src/ChangeLog index d3a387d1e63..e9e9abd4876 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -38,8 +38,9 @@ * eval.c (verror): Initial buffer size is 4000 (not 200) bytes. - Remove the doprnt implementation, as Emacs now uses vsnprintf. - * doprnt.c: Remove. + Remove invocations of doprnt, as Emacs now uses vsnprintf. + But keep the doprint source code for now, as we might revamp it + and use it again (Bug#8435). * lisp.h (doprnt): Remove. * Makefile.in (base_obj): Remove doprnt.o. * deps.mk (doprnt.o): Remove. diff --git a/src/doprnt.c b/src/doprnt.c new file mode 100644 index 00000000000..36eb272caae --- /dev/null +++ b/src/doprnt.c @@ -0,0 +1,279 @@ +/* Output like sprintf to a buffer of specified size. + Also takes args differently: pass one pointer to an array of strings + in addition to the format string which is separate. + Copyright (C) 1985, 2001-2011 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + + +#include +#include +#include +#include + +#ifdef STDC_HEADERS +#include +#endif + +#include + +#include "lisp.h" + +/* Since we use the macro CHAR_HEAD_P, we have to include this, but + don't have to include others because CHAR_HEAD_P does not contains + 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. + Output goes in BUFFER, which has room for BUFSIZE chars. + If the output does not fit, truncate it to fit. + Returns the number of bytes stored into BUFFER. + ARGS points to the vector of arguments, and NARGS says how many. + A double counts as two arguments. + String arguments are passed as C strings. + Integers are passed as C integers. */ + +EMACS_INT +doprnt (char *buffer, register int 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.. */ + + /* Use this for sprintf unless we need something really big. */ + char tembuf[DBL_MAX_10_EXP + 100]; + + /* Size of sprintf_buffer. */ + unsigned size_allocated = sizeof (tembuf); + + /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */ + char *sprintf_buffer = tembuf; + + /* Buffer we have got with malloc. */ + char *big_buffer = 0; + + register int tem; + char *string; + char fixed_buffer[20]; /* Default buffer for small formatting. */ + char *fmtcpy; + int minlen; + char charbuf[MAX_MULTIBYTE_LENGTH + 1]; /* Used for %c. */ + + if (format_end == 0) + format_end = format + strlen (format); + + if ((format_end - format + 1) < sizeof (fixed_buffer)) + fmtcpy = fixed_buffer; + else + fmtcpy = (char *) 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 */ + { + unsigned size_bound = 0; + EMACS_INT width; /* Columns occupied by STRING. */ + + fmt++; + /* Copy this one %-spec into fmtcpy. */ + string = fmtcpy; + *string++ = '%'; + while (1) + { + *string++ = *fmt; + if ('0' <= *fmt && *fmt <= '9') + { + /* Get an idea of how much space we might need. + This might be a field width or a precision; e.g. + %1.1000f and %1000.1f both might need 1000+ bytes. + Parse the width or precision, checking for overflow. */ + unsigned n = *fmt - '0'; + while ('0' <= fmt[1] && fmt[1] <= '9') + { + if (n * 10 + fmt[1] - '0' < n) + error ("Format width or precision too large"); + n = n * 10 + fmt[1] - '0'; + *string++ = *++fmt; + } + + if (size_bound < n) + size_bound = n; + } + else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+') + ; + else + break; + fmt++; + } + *string = 0; + + /* Make the size bound large enough to handle floating point formats + with large numbers. */ + if (size_bound + DBL_MAX_10_EXP + 50 < size_bound) + error ("Format width or precision too large"); + size_bound += DBL_MAX_10_EXP + 50; + + /* Make sure we have that much. */ + if (size_bound > size_allocated) + { + if (big_buffer) + big_buffer = (char *) xrealloc (big_buffer, size_bound); + else + big_buffer = (char *) xmalloc (size_bound); + sprintf_buffer = big_buffer; + size_allocated = size_bound; + } + minlen = 0; + switch (*fmt++) + { + default: + error ("Invalid format operation %%%c", fmt[-1]); + +/* case 'b': */ + case 'd': + case 'o': + case 'x': + if (sizeof (int) == sizeof (EMACS_INT)) + ; + else if (sizeof (long) == sizeof (EMACS_INT)) + /* Insert an `l' the right place. */ + string[1] = string[0], + string[0] = string[-1], + string[-1] = 'l', + string++; + else + abort (); + sprintf (sprintf_buffer, fmtcpy, va_arg(ap, char *)); + /* Now copy into final output, truncating as nec. */ + string = sprintf_buffer; + goto doit; + + case 'f': + case 'e': + case 'g': + { + double d = va_arg(ap, double); + sprintf (sprintf_buffer, fmtcpy, d); + /* Now copy into final output, truncating as nec. */ + string = sprintf_buffer; + goto doit; + } + + case 'S': + string[-1] = 's'; + case 's': + if (fmtcpy[1] != 's') + minlen = atoi (&fmtcpy[1]); + string = va_arg (ap, char *); + tem = strlen (string); + width = strwidth (string, tem); + goto doit1; + + /* Copy string into final output, truncating if no room. */ + doit: + /* Coming here means STRING contains ASCII only. */ + width = tem = strlen (string); + doit1: + /* We have already calculated: + TEM -- length of STRING, + WIDTH -- columns occupied by STRING when displayed, and + MINLEN -- minimum columns of the output. */ + if (minlen > 0) + { + while (minlen > width && bufsize > 0) + { + *bufptr++ = ' '; + bufsize--; + minlen--; + } + minlen = 0; + } + if (tem > bufsize) + { + /* Truncate the string at character boundary. */ + tem = bufsize; + while (!CHAR_HEAD_P (string[tem - 1])) tem--; + memcpy (bufptr, string, tem); + /* We must calculate WIDTH again. */ + width = strwidth (bufptr, tem); + } + else + memcpy (bufptr, string, tem); + bufptr += tem; + bufsize -= tem; + if (minlen < 0) + { + while (minlen < - width && bufsize > 0) + { + *bufptr++ = ' '; + bufsize--; + minlen++; + } + minlen = 0; + } + continue; + + case 'c': + { + /* Sometimes for %c we pass a char, which would widen + to int. Sometimes we pass XFASTINT() or XINT() + values, which would be EMACS_INT. Let's hope that + both are passed the same way, otherwise we'll need + to rewrite callers. */ + EMACS_INT chr = va_arg(ap, EMACS_INT); + tem = CHAR_STRING ((int) chr, (unsigned char *) charbuf); + string = charbuf; + string[tem] = 0; + width = strwidth (string, tem); + if (fmtcpy[1] != 'c') + minlen = atoi (&fmtcpy[1]); + goto doit1; + } + + case '%': + fmt--; /* Drop thru and this % will be treated as normal */ + } + } + + { + /* Just some character; Copy it if the whole multi-byte form + fit in the buffer. */ + char *save_bufptr = bufptr; + + do { *bufptr++ = *fmt++; } + while (--bufsize > 0 && !CHAR_HEAD_P (*fmt)); + if (!CHAR_HEAD_P (*fmt)) + { + bufptr = save_bufptr; + break; + } + } + }; + + /* If we had to malloc something, free it. */ + xfree (big_buffer); + + *bufptr = 0; /* Make sure our string end with a '\0' */ + return bufptr - buffer; +} -- 2.39.2