Author: Kev <klmitch@mit.edu>
authorKevin L. Mitchell <klmitch@mit.edu>
Thu, 13 Apr 2000 19:20:53 +0000 (19:20 +0000)
committerKevin L. Mitchell <klmitch@mit.edu>
Thu, 13 Apr 2000 19:20:53 +0000 (19:20 +0000)
Log message:

* config/aclocal.m4 (unet_CHECK_TYPE_SIZES): check size of void *,
too, for ircd_snprintf.c

* include/ircd_snprintf.h: documentation for ircd_(v)snprintf, in
comments; mostly descended from the Linux manpage for printf, but
also documenting the extensions.

* ircd/ircd_snprintf.c: NULL dest is equivalent to going to a
client; make 'q' be the same as 'L'; remove __inline__; only
define EXTENSION if HAVE_LONG_LONG is defined

git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@161 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
config/aclocal.m4
include/ircd_snprintf.h
ircd/ircd_snprintf.c

index 4dc058b18ffab03acd628dffd2e90de966399fa1..f54b16e7058816d30bafb5fc4d95bd9b447ca858 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2000-04-13  Kevin L. Mitchell  <klmitch@mit.edu>
 
+       * config/aclocal.m4 (unet_CHECK_TYPE_SIZES): check size of void *,
+       too, for ircd_snprintf.c
+
+       * include/ircd_snprintf.h: documentation for ircd_(v)snprintf, in
+       comments; mostly descended from the Linux manpage for printf, but
+       also documenting the extensions.
+
+       * ircd/ircd_snprintf.c: NULL dest is equivalent to going to a
+       client; make 'q' be the same as 'L'; remove __inline__; only
+       define EXTENSION if HAVE_LONG_LONG is defined
+
        * include/handlers.h: declare m_gline()
 
        * ircd/parse.c: gline can be called by users, but it only lists
 #
 # ChangeLog for ircu2.10.11
 #
-# $Id: ChangeLog,v 1.78 2000-04-13 15:58:22 kev Exp $
+# $Id: ChangeLog,v 1.79 2000-04-13 19:20:52 kev Exp $
 #
 # Insert new changes at beginning of the change list.
 #
index 8cd86808b12772f529065a74b02cb27f8e207e50..875251f9364d3005fbf12d408a0d4eead3327e34 100644 (file)
@@ -234,6 +234,7 @@ AC_DEFUN(unet_CHECK_TYPE_SIZES,
 AC_CHECK_SIZEOF(short)
 AC_CHECK_SIZEOF(int)
 AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(void *)
 if test "$ac_cv_sizeof_int" = 2 ; then
   AC_CHECK_TYPE(int16_t, int)
   AC_CHECK_TYPE(u_int16_t, unsigned int)
index 824c5940c4602cb96d444900112414821bbfae56..28bcc5cce4eb5c5e262cc63af80e5ceeca0eb6ac 100644 (file)
@@ -47,4 +47,230 @@ extern int ircd_snprintf(struct Client *dest, char *buf, size_t buf_len,
 extern int ircd_vsnprintf(struct Client *dest, char *buf, size_t buf_len,
                          const char *format, va_list args);
 
+/*
+** ircd_(v)snprintf
+**
+**   These functions are intended to be a complete replacement for
+** sprintf and sprintf_irc.  They are a (nearly) complete
+** reimplementation, and of course they're snprintf clones, making it
+** more difficult for accidental buffer overflows to crop up.
+**
+**   First off, what's missing?  These functions support all ANSI C
+** conversion specifiers and selected ones from ISO 9x, with the
+** exception of all floating-point conversions.  The floating-point
+** conversions are tricky, and will likely be dependent on the
+** representation of a floating-point number on a particular
+** architecture.  While that representation is likely to conform to
+** some standard, it is not currently used in ircu, so seemed like a
+** good thing to omit, given the difficulty of implementing it.
+**
+**   There are two more things missing from this implementation that
+** would be required by ANSI; the first is support for multibyte
+** character strings, and the second is support for locales, neither
+** of which have any relevance for ircu, so again omission seemed to
+** be a good policy.  Additionally, %#x always causes '0x' (or '0X')
+** to be printed, even if the number is zero.
+**
+**   These functions also have some extensions not seen in a
+** standards-compliant implementation; technically, the ISO 9x
+** extensions fall into this category, for instance.  The ISO 9x
+** extensions supported are type extensions--%ju, %tu, and %zu, for
+** instance; %qu and %hhu are also supported.  The extensions added
+** for use in ircu are %Tu, which takes a time_t, and the new %C
+** conversion, which inserts either a numeric or a nick, dependant on
+** the <dest> parameter.  The GNU %m extension, which inserts the
+** strerror() string corresponding to the current value of errno, is
+** also supported, as is a special %v extension, which essentially
+** does a recursive call to ircd_snprintf.
+**
+**   The following description is descended from the Linux manpage for
+** the printf family of functions.
+**
+**   The format string is composed of zero or more directives:
+** ordinary characters (not %), which are copied unchanged to the
+** output stream; and conversion specifications, each of which results
+** in fetching zero or more subsequent arguments.  Each conversion
+** specification is introduced by the character %.  The arguments must
+** correspond properly (after type promotion) with the conversion
+** specifier.  After the %, the following appear in sequence:
+**
+** * Zero or more of the following flags:
+**
+**   # specifying that the value should be converted to an
+**     "alternate form."  For c, d, i, n, p, s, and u conversions,
+**     this option has no effect.  For o conversions, the precision
+**     of the number is increased to force the first character of the
+**     output string to a zero (except if a zero value is printed
+**     with an explicit precision of zero).  For x and X conversions,
+**     the string '0x' (or '0X' for X conversions) is prepended to
+**     it.  For e, E, f, g, and G conversions, the result will always
+**     contain a decimal point, even if no digits follow it
+**     (normally, a decimal point appears in the results of those
+**     conversions only if a digit follows).  For g and G
+**     conversions, trailing zeros are not removed from the result as
+**     they would otherwise be.
+**
+**   0 specifying zero padding.  For all conversions except n, the
+**     converted value is padded on the left with zeros rather than
+**     blanks.  If a precision is given with a numeric conversion (d,
+**     i, o, u, i, x, and X), the 0 flag is ignored.
+**
+**   - (a negative field width flag) indicates the converted value is
+**     to be left adjusted on the field boundary.  Except for n
+**     conversions, the converted value is padded on the right with
+**     blanks, rather than on the left with blanks or zeros.  A -
+**     overrides a 0 if both are given.
+**
+**  ' '        (a space) specifying that a blank should be left before a
+**     positive number produced by a signed conversion (d, e, E, f,
+**     g, G, or i).
+**
+**   + specifying that a sign always be placed before a number
+**     produced by a signed conversion.  A + overrides a space if
+**     both are used.
+**
+** * An optional decimal digit string specifying a minimum field
+**   width.  If the converted value has fewer characters than the
+**   field width, it will be padded with spaces on the left (or right,
+**   if the left-adjustment flag has been given) to fill out the field
+**   width.
+**
+** * An optional precision, in the form of a period (`.') followed by
+**   an optional digit string.  If  the digit string is omitted, the
+**   precision is taken as zero.  This gives the minimum number of
+**   digits to appear for d, i, o, u, x, and X conversions, the number
+**   of digits to appear after the decimal-point for e, E, and f
+**   conversions, the maximum number of significant digits for g and G
+**   conversions, or the maximum number of characters to be printed
+**   from a string for s conversions.
+**
+** * The optional character h, specifying that a following d, i, o, u,
+**   x, or X conversion corresponds to a short int or unsigned short
+**   int argument, or that a following n conversion corresponds to a
+**   pointer to a short int argument.  If the h character is given
+**   again, char is used instead of short int.
+**
+** * The optional character l (ell) specifying that a following d, i,
+**   o, u, x, or X conversion applies to a pointer to a long int or
+**   unsigned long int argument, or that a following n conversion
+**   corresponds to a pointer to a long int argument.
+**
+** * The character L specifying that a following e, E, f, g, or G
+**   conversion corresponds to a long double argument, or a following
+**   d, i, o, u, x, or X conversion corresponds to a long long
+**   argument.  Note that long long is not specified in ANSI C and
+**   therefore not portable to all architectures.
+**
+** * The optional character q.  This is equivalent to L.
+**
+** * A j character specifying that the following integer (d, i, o, u,
+**   x, or X) conversion corresponds to an intmax_t argument.
+**
+** * A t character specifying that the following integer (d, i, o, u,
+**   x, or X) conversion corresponds to a ptrdiff_t argument.
+**
+** * A z character specifying that the following integer (d, i, o, u,
+**   x, or X) conversion corresponds to a size_t argument.
+**
+** * A T character specifying that the following integer (d, i, o, u,
+**   x, or X) conversion corresponds to a time_t argument.
+**
+** * A character that specifies the type of conversion to be applied.
+**
+**   A field width or precision, or both, may be indicated by an
+** asterisk `*' instead of a digit string.  In this case, an int
+** argument supplies the field width or precision.  A negative field
+** width is treated as a left adjustment flag followed by a positive
+** field width; a negative precision is treated as though it were
+** missing.
+**
+** The conversion specifiers and their meanings are:
+**
+** diouxX      The int (or appropriate variant) argument is converted
+**             to signed decimal (d and i), unsigned octal (o),
+**             unsigned decimal (u), or unsigned hexadecimal (x and
+**             X) notation.  The letters abcdef are used for x
+**             conversions; the letters ABCDEF are used for X
+**             conversions.  The precision, if any, gives the minimum
+**             number of digits that must appear; if the converted
+**             value requires fewer digits, it is padded on the left
+**             with zeros.
+**
+** eE          [NOT IMPLEMENTED] The double argument is rounded and
+**             converted in the style [-]d.dddedd where there is one
+**             digit before the decimal-point character and the
+**             number of digits after it is equal to the precision;
+**             if the precision is missing, it is taken as 6; if the
+**             precision is zero, no decimal-point character appears.
+**             An E conversion uses the letter E (rather than e) to
+**             introduce the exponent.  The exponent always contains
+**             at least two digits; if the value is zero, the
+**             exponent is 00.
+**
+** f           [NOT IMPLEMENTED] The double argument is rounded and
+**             converted to  decimal notation in the style
+**             [-]ddd.ddd, where the number of digits after the
+**             decimal-point character is equal to the precision
+**             specification.  If the precision is missing, it is
+**             taken as 6; if the precision is explicitly zero, no
+**             decimal-point character appears.  If a decimal point
+**             appears, at least one digit appears before it.
+**
+** g           [NOT IMPLEMENTED] The double argument is converted in
+**             style f or e (or E for G conversions).  The precision
+**             specifies the number of significant digits.  If the
+**             precision is missing, 6 digits are given; if the
+**             precision is zero, it is treated as 1.  Style e is
+**             used if the exponent from its conversion is less than
+**             -4 or greater than or equal to the precision.
+**             Trailing zeros are removed from the fractional part of
+**             the result; a decimal point appears only if it is
+**             followed by at least one digit.
+**
+** c           The int argument is converted to an unsigned char, and
+**             the resulting character is written.
+**
+** s           The "char *" argument is expected to be a pointer to
+**             an array of character type (pointer to a string).
+**             Characters from the array are written up to (but not
+**             including) a terminating NUL character; if a precision
+**             is specified, no more than the number specified are
+**             written.  If a precision is given, no null character
+**             need be present; if the precision is not specified, or
+**             is greater than the size of the array, the array must
+**             contain a terminating NUL character.
+**
+** p           The "void *" pointer argument is printed in
+**             hexadecimal (as if by %#x or %#lx).
+**
+** n           The number of characters written so far is stored into
+**             the integer indicated by the ``int *'' (or variant)
+**             pointer argument.  No argument is converted.
+**
+** m           The error message associated with the current value of
+**             errno is printed as if by %s.
+**
+** C           The client argument identifier is printed under the
+**             control of the <dest> argument; if <dest> is NULL or
+**             is a user, the client's name (nickname or server name)
+**             is printed; otherwise, the client's network numeric is
+**             printed.
+**
+** v           The argument given must be a pointer to a struct
+**             VarData with vd_format and vd_args must be initialized
+**             appropriately.  On return, vd_chars will contain the
+**             number of characters added to the buffer, and
+**             vd_overflow will contain the number of characters that
+**             could not be added due to buffer overflow or due to a
+**             precision.
+**
+** %           A `%' is written.  No argument is converted.  The
+**             complete conversion specification is `%%'.
+**
+**   In no case does a non-existent or small field width cause
+** truncation of a field; if the result of a conversion is wider than
+** the field width, the field is expanded to contain the conversion
+** result.
+*/
+
 #endif /* INCLUDED_ircd_snprintf_h */
index 646dc160cd489ed19c48f92efa21538e91e19f90..6c9e43db5b54d597c01d73694872eb5ddd7b66a4 100644 (file)
 #include <string.h>
 #include <time.h>
 
-/* for testing purposes */
-#ifndef SIZEOF_VOID_P
-# warning SIZEOF_VOID_P not defined yet!
-# define SIZEOF_VOID_P 4
-# define SIZEOF_LONG   4
-#endif
-
 /* Inhibit complaints when we use GCC extensions */
-#ifdef __GNUC__
+#if defined(__GNUC__) && defined(HAVE_LONG_LONG)
 # define EXTENSION __extension__
 #else
 # define EXTENSION
@@ -1411,7 +1404,7 @@ static char *HEX[] = {
 };
 
 /* Add a character to the buffer */
-static __inline__ void
+static void
 addc(struct BufData *buf_p, int c)
 {
   int overflow = 0;
@@ -1432,7 +1425,7 @@ addc(struct BufData *buf_p, int c)
 }
 
 /* Add a string to the buffer */
-static __inline__ void
+static void
 adds(struct BufData *buf_p, int s_len, const char *s)
 {
   int overflow = 0;
@@ -1460,7 +1453,7 @@ adds(struct BufData *buf_p, int s_len, const char *s)
 }
 
 /* Add padding */
-static __inline__ void
+static void
 do_pad(struct BufData *buf_p, int padlen, char *pad)
 {
   /* do chunks of PAD_LENGTH first */
@@ -1472,7 +1465,7 @@ do_pad(struct BufData *buf_p, int padlen, char *pad)
 }
 
 /* Find string length up to maxlen */
-static __inline__ int
+static int
 my_strnlen(const char *str, int maxlen)
 {
   int len = 0;
@@ -1604,21 +1597,13 @@ doprintf(struct Client *dest, struct BufData *buf_p, const char *fmt,
        if (state <= OPT) {
          state = OPT;
          if (fld_s.flags & TYPE_LONG) /* We support 'll' */
-           fld_s.flags |= TYPE_QUAD;
+           fld_s.flags |= TYPE_QUAD | TYPE_LONGDOUBLE;
          else if (!(fld_s.flags & TYPE_MASK))
            fld_s.flags |= TYPE_LONG;
        }
        continue;
 
-      case 'q': /* it's a quad */
-       if (state <= OPT) {
-         state = OPT;
-         if (!(fld_s.flags & TYPE_MASK))
-           fld_s.flags |= TYPE_QUAD;
-       }
-       continue;
-
-      case 'L': /* it's a quad or long double */
+      case 'q':  case 'L': /* it's a quad or long double */
        if (state <= OPT) {
          state = OPT;
          if (!(fld_s.flags & TYPE_MASK))
@@ -2005,7 +1990,7 @@ doprintf(struct Client *dest, struct BufData *buf_p, const char *fmt,
       char *str1 = 0, *str2 = 0;
       int slen1 = 0, slen2 = 0, plen = 0;
 
-      if (IsServer(dest)) {
+      if (dest && IsServer(dest)) {
        if (IsServer(cptr))
          str1 = cptr->yxx;
        else {