* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id$
*/
+/** @file
+ * @brief IRC-specific printf() clone implementation.
+ * @version $Id$
+ */
+#include "config.h"
+
#include "client.h"
+#include "channel.h"
+#include "ircd_log.h"
#include "ircd_snprintf.h"
#include "struct.h"
+/* #include <assert.h> -- Now using assert in ircd_log.h */
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
/* Inhibit complaints when we use GCC extensions */
-#if defined(__GNUC__) && defined(HAVE_LONG_LONG)
+#if defined(__GNUC__) && SIZEOF_LONG_LONG
# define EXTENSION __extension__
#else
+/** Fallback (empty) definition of EXTENSION. */
# define EXTENSION
#endif
/* Find the largest type */
-#ifdef HAVE_LONG_LONG
+#if SIZEOF_LONG_LONG
EXTENSION typedef long long _large_t;
EXTENSION typedef unsigned long long _ularge_t;
# define SIZEOF__LARGE_T SIZEOF_LONG_LONG
# define HAVE_POINTER_T
# endif
#else
+/** Fallback definition of the largest integer type. */
typedef long _large_t;
+/** Fallback definition of the largest unsigned integer type. */
typedef unsigned long _ularge_t;
+/** Fallback definition of SIZEOF__LARGE_T. */
# define SIZEOF__LARGE_T SIZEOF_LONG
#endif
/* Select something for _pointer_t */
#ifndef HAVE_POINTER_T
# if SIZEOF_LONG == SIZEOF_VOID_P
+/** Unsigned integer type large enough to hold a pointer. */
typedef unsigned long _pointer_t;
# elif SIZEOF_INT == SIZEOF_VOID_P
typedef unsigned int _pointer_t;
# endif
#endif /* HAVE_POINTER_T */
-/* rough length sufficient to hold an octal number, since those can be large */
+/** rough length sufficient to hold an octal number, since those can be large */
#define INTBUF_LEN (SIZEOF__LARGE_T * 3)
+/** Return minimum of \a i1 and \a i2. */
#define SNP_MIN(i1, i2) ((i1) < (i2) ? (i1) : (i2))
+/** Return maximum of \a i1 and \a i2. */
#define SNP_MAX(i1, i2) ((i1) > (i2) ? (i1) : (i2))
+/** Indicate total number of bytes "pseudo-output" in buffer. */
#define TOTAL(buf_p) ((buf_p)->buf_loc + \
SNP_MAX((buf_p)->buf_overflow, (buf_p)->overflow))
-#define WIDTH_MAX 999 /* keep from overflowing width */
+#define WIDTH_MAX 999 /**< keep from overflowing width */
-/* data about the buffer */
+/** data about the output buffer */
struct BufData {
- char *buf; /* pointer to buffer */
- size_t buf_size; /* maximum size of buffer */
- size_t buf_overflow; /* how much buffer has been overflowed */
- size_t buf_loc; /* where we are in the buffer */
- size_t limit; /* max # of chars to convert */
- size_t overflow; /* how much we overflowed the limit */
+ char *buf; /**< pointer to buffer */
+ size_t buf_size; /**< maximum size of buffer */
+ size_t buf_overflow; /**< how much buffer has been overflowed */
+ size_t buf_loc; /**< where we are in the buffer */
+ short limit; /**< max # of chars to convert */
+ size_t overflow; /**< how much we overflowed the limit */
};
+/** initializer for BufData */
#define BUFDATA_INIT { 0, 0, 0, 0, 0, 0 }
-/* data about the fields */
+/** data about format fields */
struct FieldData {
- unsigned int flags; /* flags describing argument */
- short base; /* base for integer conversions */
- short width; /* width of field */
- short prec; /* precision of field */
+ unsigned int flags; /**< flags describing argument */
+ short base; /**< base for integer conversions */
+ short width; /**< width of field */
+ short prec; /**< precision of field */
union {
- _ularge_t v_int; /* an integer value */
- long double v_float; /* a floating point value -- NOT SUPPORTED */
- void *v_ptr; /* a pointer value */
- } value; /* value of a field */
+ _ularge_t v_int; /**< an integer value */
+ long double v_float; /**< a floating point value -- NOT SUPPORTED */
+ void *v_ptr; /**< a pointer value */
+ } value; /**< value of a field */
};
+/** initializer for FieldData */
#define FIELDDATA_INIT { 0, 0, 0, 0, { 0 } }
/* Specifier flags */
-#define FLAG_MINUS 0x00000001 /* found a '-' flag */
-#define FLAG_PLUS 0x00000002 /* found a '+' flag */
-#define FLAG_SPACE 0x00000004 /* found a ' ' flag */
-#define FLAG_ALT 0x00000008 /* found a '#' flag */
-#define FLAG_ZERO 0x00000010 /* found a '0' flag */
+#define FLAG_MINUS 0x00000001 /**< found a '-' flag */
+#define FLAG_PLUS 0x00000002 /**< found a '+' flag */
+#define FLAG_SPACE 0x00000004 /**< found a ' ' flag */
+#define FLAG_ALT 0x00000008 /**< found a '#' flag */
+#define FLAG_ZERO 0x00000010 /**< found a '0' flag */
+#define FLAG_COLON 0x00000020 /**< found a ':' flag */
-#define FLAG_RESERVED2 0x00000020 /* reserved for future expansion */
-#define FLAG_RESERVED1 0x00000040
-#define FLAG_RESERVED0 0x00000080
+#define FLAG_RESERVED1 0x00000040 /**< reserved for future expansion */
+#define FLAG_RESERVED0 0x00000080 /**< reserved for future expansion */
/* integer types */
-#define TYPE_CHAR 0x00000100 /* number is a char */
-#define TYPE_SHORT 0x00000200 /* number is a short */
-#define TYPE_LONG 0x00000400 /* number is a long */
-#define TYPE_QUAD 0x00000800 /* number is a quad */
+#define TYPE_CHAR 0x00000100 /**< number is a char */
+#define TYPE_SHORT 0x00000200 /**< number is a short */
+#define TYPE_LONG 0x00000400 /**< number is a long */
+#define TYPE_QUAD 0x00000800 /**< number is a quad */
/* special integer types */
-#define TYPE_INTMAX 0x00001000 /* number is an intmax_t */
-#define TYPE_PTRDIFF 0x00002000 /* number is a ptrdiff_t */
-#define TYPE_SIZE 0x00004000 /* number is a size_t */
-#define TYPE_TIME 0x00008000 /* number is a time_t */
-#define TYPE_POINTER 0x00010000 /* number is a pointer_t */
+#define TYPE_INTMAX 0x00001000 /**< number is an intmax_t */
+#define TYPE_PTRDIFF 0x00002000 /**< number is a ptrdiff_t */
+#define TYPE_SIZE 0x00004000 /**< number is a size_t */
+#define TYPE_TIME 0x00008000 /**< number is a time_t */
+#define TYPE_POINTER 0x00010000 /**< number is a pointer_t */
/* floating point types */
-#define TYPE_LONGDOUBLE 0x00020000 /* number is a long double */
+#define TYPE_LONGDOUBLE 0x00020000 /**< number is a long double */
-#define TYPE_RESERVED1 0x00040000 /* reserved for future expansion */
-#define TYPE_RESERVED0 0x00080000
+#define TYPE_RESERVED1 0x00040000 /**< reserved for future expansion */
+#define TYPE_RESERVED0 0x00080000 /**< reserved for future expansion */
-/* Mask to get just the type data */
+/** Mask to get just the type data */
#define TYPE_MASK (TYPE_CHAR | TYPE_SHORT | TYPE_LONG | TYPE_QUAD | \
TYPE_INTMAX | TYPE_PTRDIFF | TYPE_SIZE | TYPE_TIME | \
TYPE_POINTER | TYPE_LONGDOUBLE)
/* type of argument to extract */
-#define ARG_INT 0x00100000 /* argument is an integer */
-#define ARG_FLOAT 0x00200000 /* argument is a float */
-#define ARG_PTR 0x00300000 /* argument is a pointer */
-
-#define ARG_RESERVED11 0x00400000 /* reserved for future expansion */
-#define ARG_RESERVED10 0x00500000
-#define ARG_RESERVED9 0x00600000
-#define ARG_RESERVED8 0x00700000
-#define ARG_RESERVED7 0x00800000
-#define ARG_RESERVED6 0x00900000
-#define ARG_RESERVED5 0x00a00000
-#define ARG_RESERVED4 0x00b00000
-#define ARG_RESERVED3 0x00c00000
-#define ARG_RESERVED2 0x00d00000
-#define ARG_RESERVED1 0x00e00000
-#define ARG_RESERVED0 0x00f00000
+#define ARG_INT 0x00100000 /**< argument is an integer */
+#define ARG_FLOAT 0x00200000 /**< argument is a float */
+#define ARG_PTR 0x00300000 /**< argument is a pointer */
+
+#define ARG_RESERVED11 0x00400000 /**< reserved for future expansion */
+#define ARG_RESERVED10 0x00500000 /**< reserved for future expansion */
+#define ARG_RESERVED9 0x00600000 /**< reserved for future expansion */
+#define ARG_RESERVED8 0x00700000 /**< reserved for future expansion */
+#define ARG_RESERVED7 0x00800000 /**< reserved for future expansion */
+#define ARG_RESERVED6 0x00900000 /**< reserved for future expansion */
+#define ARG_RESERVED5 0x00a00000 /**< reserved for future expansion */
+#define ARG_RESERVED4 0x00b00000 /**< reserved for future expansion */
+#define ARG_RESERVED3 0x00c00000 /**< reserved for future expansion */
+#define ARG_RESERVED2 0x00d00000 /**< reserved for future expansion */
+#define ARG_RESERVED1 0x00e00000 /**< reserved for future expansion */
+#define ARG_RESERVED0 0x00f00000 /**< reserved for future expansion */
/* Mask to get just the argument data */
-#define ARG_MASK 0x00f00000
+#define ARG_MASK 0x00f00000 /**< masks off non-argument bits */
/* type of conversion to perform */
-#define CONV_INT 0x01000000 /* convert integers */
-#define CONV_FLOAT 0x02000000 /* convert floats */
-#define CONV_CHAR 0x03000000 /* convert chars */
-#define CONV_STRING 0x04000000 /* convert strings */
-#define CONV_VARARGS 0x05000000 /* convert a %v */
-#define CONV_CLIENT 0x06000000 /* convert a struct Client */
-
-#define CONV_RESERVED8 0x07000000 /* reserved for future expansion */
-#define CONV_RESERVED7 0x08000000
-#define CONV_RESERVED6 0x09000000
-#define CONV_RESERVED5 0x0a000000
-#define CONV_RESERVED4 0x0b000000
-#define CONV_RESERVED3 0x0c000000
-#define CONV_RESERVED2 0x0d000000
-#define CONV_RESERVED1 0x0e000000
-#define CONV_RESERVED0 0x0f000000
+#define CONV_INT 0x01000000 /**< convert integers */
+#define CONV_FLOAT 0x02000000 /**< convert floats */
+#define CONV_CHAR 0x03000000 /**< convert chars */
+#define CONV_STRING 0x04000000 /**< convert strings */
+#define CONV_VARARGS 0x05000000 /**< convert a %v */
+#define CONV_CLIENT 0x06000000 /**< convert a struct Client */
+#define CONV_CHANNEL 0x07000000 /**< convert a struct Channel */
+
+#define CONV_RESERVED7 0x08000000 /**< reserved for future expansion */
+#define CONV_RESERVED6 0x09000000 /**< reserved for future expansion */
+#define CONV_RESERVED5 0x0a000000 /**< reserved for future expansion */
+#define CONV_RESERVED4 0x0b000000 /**< reserved for future expansion */
+#define CONV_RESERVED3 0x0c000000 /**< reserved for future expansion */
+#define CONV_RESERVED2 0x0d000000 /**< reserved for future expansion */
+#define CONV_RESERVED1 0x0e000000 /**< reserved for future expansion */
+#define CONV_RESERVED0 0x0f000000 /**< reserved for future expansion */
/* Mask to get just the conversion data */
-#define CONV_MASK 0x0f000000
+#define CONV_MASK 0x0f000000 /**< masks off non-conversion bits */
/* Value information flags */
-#define INFO_RESERVED0 0x10000000 /* reserved for future expansion */
-#define INFO_UPPERCASE 0x20000000 /* use uppercase characters */
-#define INFO_UNSIGNED 0x40000000 /* number is unsigned */
-#define INFO_NEGATIVE 0x80000000 /* number is negative */
+#define INFO_RESERVED0 0x10000000 /**< reserved for future expansion */
+#define INFO_UPPERCASE 0x20000000 /**< use uppercase characters */
+#define INFO_UNSIGNED 0x40000000 /**< number is unsigned */
+#define INFO_NEGATIVE 0x80000000 /**< number is negative */
-#define BASE_OCTAL 9 /* octal base; bits-per-char * 3 */
-#define BASE_DECIMAL -1000 /* decimal base; 10 ** 3 */
-#define BASE_HEX 12 /* hexadecimal base; bits-per-char * 3 */
+#define BASE_OCTAL 9 /**< octal base; bits-per-char * 3 */
+#define BASE_DECIMAL -1000 /**< decimal base; 10 ** 3 */
+#define BASE_HEX 12 /**< hexadecimal base; bits-per-char * 3 */
/* padding... 1 2 3 4 5 */
/* 12345678901234567890123456789012345678901234567890 */
+/** Predefined space padding. */
static char spaces[] = " ";
+/** Predefined zero padding. */
static char zeros[] = "00000000000000000000000000000000000000000000000000";
+/** Length of predefined padding strings. */
#define PAD_LENGTH (sizeof(spaces) - 1)
/*
* course, a reason for this; check out how they're built in doprintf.
*/
-/* string table for octal values */
+/** string table for octal values */
static char *octal[] = {
"", "1", "2", "3", "4", "5", "6", "7",
"01", "11", "21", "31", "41", "51", "61", "71",
"077", "177", "277", "377", "477", "577", "677", "777"
};
-/* string table for decimal values */
+/** string table for decimal values */
static char *decimal[] = {
"", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"01", "11", "21", "31", "41", "51", "61", "71", "81", "91",
"099", "199", "299", "399", "499", "599", "699", "799", "899", "999"
};
-/* string table for lower-case hexadecimal values */
+/** string table for lower-case hexadecimal values */
static char *hex[] = {
"", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "a", "b", "c", "d", "e", "f",
"8ff", "9ff", "aff", "bff", "cff", "dff", "eff", "fff"
};
-/* string table for upper-case hexadecimal values */
+/** string table for upper-case hexadecimal values */
static char *HEX[] = {
"", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "A", "B", "C", "D", "E", "F",
"8FF", "9FF", "AFF", "BFF", "CFF", "DFF", "EFF", "FFF"
};
-/* Add a character to the buffer */
+/** Append a single character to an output buffer.
+ * @param[in,out] buf_p Buffer to append to.
+ * @param[in] c Character to append.
+ */
static void
addc(struct BufData *buf_p, int c)
{
buf_p->buf[buf_p->buf_loc++] = c;
}
-/* Add a string to the buffer */
+/** Append a string to an output buffer.
+ * @param[in,out] buf_p Buffer to append to.
+ * @param[in] s_len Length of string to append.
+ * @param[in] s String to append.
+ */
static void
adds(struct BufData *buf_p, int s_len, const char *s)
{
int overflow = 0;
- while (*s && s_len) { /* while the string exists and has non-zero length */
+ /* while the string exists and has non-zero length */
+ while (s_len && *s)
+ {
/* poor man's inlining; see addc(), above */
if (buf_p->limit == 0) { /* We've gone past the limit... */
buf_p->overflow++;
}
}
-/* Add padding */
+/** Add certain padding to an output buffer.
+ * @param[in,out] buf_p Buffer to append to.
+ * @param[in] padlen Length of padding to add.
+ * @param[in] pad Padding string (at least PAD_LENGTH bytes long).
+ */
static void
do_pad(struct BufData *buf_p, int padlen, char *pad)
{
adds(buf_p, padlen, pad);
}
-/* Find string length up to maxlen */
+/** Return length of string, up to a maximum.
+ * @param[in] str String to find length for.
+ * @param[in] maxlen Maximum value to return.
+ * @return Minimum of \a maxlen and length of \a str.
+ */
static int
my_strnlen(const char *str, int maxlen)
{
return len;
}
-/* the function that actually puts it all together */
+/** Workhorse printing function.
+ * @param[in] dest Client to format the message.
+ * @param[in,out] buf_p Description of output buffer.
+ * @param[in] fmt Message format string.
+ * @param[in] vp Variable-length argument list for format string.
+ */
static void
doprintf(struct Client *dest, struct BufData *buf_p, const char *fmt,
va_list vp)
fld_s.flags |= FLAG_ALT;
continue;
+ case ':': /* Deal with the colon flag */
+ if (state == FLAG)
+ fld_s.flags |= FLAG_COLON;
+ continue;
+
case '0': /* Deal with a zero flag */
if (state == FLAG) {
fld_s.flags |= FLAG_ZERO;
case 's': /* convert a string */
fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
- TYPE_MASK);
+ FLAG_COLON | TYPE_MASK);
fld_s.flags |= ARG_PTR | CONV_STRING;
break;
case 'd': case 'i':
+ fld_s.flags &= ~(FLAG_COLON);
fld_s.flags |= ARG_INT | CONV_INT;
break;
fld_s.base = BASE_HEX;
/*FALLTHROUGH*/
case 'u': /* Unsigned int */
- fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE);
+ fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_COLON);
fld_s.flags |= INFO_UNSIGNED | ARG_INT | CONV_INT;
break;
case 'c': /* character */
fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
- TYPE_MASK);
+ FLAG_COLON | TYPE_MASK);
fld_s.flags |= INFO_UNSIGNED | ARG_INT | TYPE_CHAR | CONV_CHAR;
fld_s.prec = -1;
break;
case 'p': /* display a pointer */
- fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | TYPE_MASK);
+ fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_COLON | TYPE_MASK);
fld_s.flags |= (FLAG_ALT | FLAG_ZERO | TYPE_POINTER | ARG_PTR |
CONV_INT | INFO_UNSIGNED);
fld_s.prec = (SIZEOF_VOID_P * 2); /* number of characters */
*((char *)va_arg(vp, int *)) = TOTAL(buf_p);
else if (fld_s.flags & TYPE_SHORT) /* eg, %hn */
*((short *)va_arg(vp, int *)) = TOTAL(buf_p);
-#ifdef HAVE_LONG_LONG
else if (fld_s.flags & TYPE_QUAD) /* eg, %qn */
- *((my_quad_t *)va_arg(vp, my_quad_t *)) = TOTAL(buf_p);
-#endif /* HAVE_LONG_LONG */
+ *((int64_t *)va_arg(vp, int64_t *)) = TOTAL(buf_p);
else if (fld_s.flags & TYPE_LONG) /* eg, %ln */
*((long *)va_arg(vp, long *)) = TOTAL(buf_p);
else if (fld_s.flags & TYPE_INTMAX) /* eg, %jn */
case 'm': /* write out a string describing an errno error */
fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
- TYPE_MASK);
+ FLAG_COLON | TYPE_MASK);
fld_s.flags |= CONV_STRING;
fld_s.value.v_ptr = (void *)strerror(errno);
break;
case 'v': /* here's the infamous %v... */
fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
- TYPE_MASK);
+ FLAG_COLON | TYPE_MASK);
fld_s.flags |= ARG_PTR | CONV_VARARGS;
break;
case 'C': /* convert a client name... */
- fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
- TYPE_MASK);
+ fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ZERO | TYPE_MASK);
fld_s.flags |= ARG_PTR | CONV_CLIENT;
break;
+ case 'H': /* convert a channel name... */
+ fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
+ FLAG_COLON | TYPE_MASK);
+ fld_s.flags |= ARG_PTR | CONV_CHANNEL;
+ break;
+
default: /* Unsupported, display a message and the entire format */
adds(buf_p, -1, "(Unsupported: %");
adds(buf_p, fmt - fstart + 1, fstart);
if (fld_s.flags & TYPE_CHAR) /* eg, %hhu */
fld_s.value.v_int = (unsigned char)va_arg(vp, unsigned int);
else if (fld_s.flags & TYPE_SHORT) /* eg, %hu */
- fld_s.value.v_int = (short)va_arg(vp, unsigned int);
-#ifdef HAVE_LONG_LONG
+ fld_s.value.v_int = (unsigned short)va_arg(vp, unsigned int);
else if (fld_s.flags & TYPE_QUAD) /* eg, %qu */
- fld_s.value.v_int = va_arg(vp, _large_t);
-#endif
+ fld_s.value.v_int = va_arg(vp, uint64_t);
else if (fld_s.flags & TYPE_LONG) /* eg, %lu */
fld_s.value.v_int = va_arg(vp, unsigned long);
else if (fld_s.flags & TYPE_INTMAX) /* eg, %ju */
signed_int = (char)va_arg(vp, unsigned int);
else if (fld_s.flags & TYPE_SHORT) /* eg, %hd */
signed_int = (short)va_arg(vp, unsigned int);
-#ifdef HAVE_LONG_LONG
else if (fld_s.flags & TYPE_QUAD) /* eg, %qd */
- signed_int = va_arg(vp, _large_t);
-#endif
+ signed_int = va_arg(vp, int64_t);
else if (fld_s.flags & TYPE_LONG) /* eg, %ld */
signed_int = va_arg(vp, long);
else if (fld_s.flags & TYPE_INTMAX) /* eg, %jd */
char intbuf[INTBUF_LEN], **table = 0, *tstr;
int ibuf_loc = INTBUF_LEN, ilen, zlen = 0, plen = 0, elen = 0;
- if (fld_s.prec < 0) /* default precision is 1 */
- fld_s.prec = 1;
-
if (fld_s.base == BASE_OCTAL) /* select string table to use */
table = octal;
else if (fld_s.base == BASE_DECIMAL)
elen = 2; /* account for the length of 0x */
}
+ if (fld_s.prec < 0) { /* default precision is 1 */
+ if ((fld_s.flags & (FLAG_MINUS | FLAG_ZERO)) == FLAG_ZERO &&
+ fld_s.width) {
+ fld_s.prec = fld_s.width - elen;
+ fld_s.width = 0;
+ } else
+ fld_s.prec = 1;
+ }
+
/* If there's a sign flag, account for it */
if (fld_s.flags & (FLAG_PLUS | FLAG_SPACE | INFO_NEGATIVE))
elen++;
} else if ((fld_s.flags & CONV_MASK) == CONV_STRING ||
fld_s.value.v_ptr == 0) { /* spaces or null pointers */
int slen, plen;
- char *str = fld_s.value.v_ptr;
+ char *str = (char*) fld_s.value.v_ptr;
if (!str) /* NULL pointers print "(null)" */
str = "(null)";
do_pad(buf_p, plen, spaces); /* post-padding */
} else if ((fld_s.flags & CONV_MASK) == CONV_VARARGS) {
struct BufData buf_s = BUFDATA_INIT;
- struct VarData *vdata = fld_s.value.v_ptr;
+ struct VarData *vdata = (struct VarData*) fld_s.value.v_ptr;
int plen, tlen;
buf_s.buf = buf_p->buf + buf_p->buf_loc;
vdata->vd_chars = buf_s.buf_loc; /* return relevant data */
vdata->vd_overflow = SNP_MAX(buf_s.buf_overflow, buf_s.overflow);
} else if ((fld_s.flags & CONV_MASK) == CONV_CLIENT) {
- struct Client *cptr = fld_s.value.v_ptr;
- char *str1 = 0, *str2 = 0;
- int slen1 = 0, slen2 = 0, plen = 0;
-
- if (dest && IsServer(dest)) {
- if (IsServer(cptr))
- str1 = cptr->yxx;
+ struct Client *cptr = (struct Client*) fld_s.value.v_ptr;
+ const char *str1 = 0, *str2 = 0, *str3 = 0;
+ int slen1 = 0, slen2 = 0, slen3 = 0, elen = 0, plen = 0;
+
+ /* &me is used if it's not a definite server */
+ if (dest && (IsServer(dest) || IsMe(dest))) {
+ if (IsServer(cptr) || IsMe(cptr))
+ str1 = cli_yxx(cptr);
else {
- str1 = cptr->user->server->yxx;
- str2 = cptr->yxx;
+ str1 = cli_yxx(cli_user(cptr)->server);
+ str2 = cli_yxx(cptr);
}
- } else
- str1 = cptr->name;
+ fld_s.flags &= ~(FLAG_ALT | FLAG_COLON);
+ } else {
+ str1 = *cli_name(cptr) ? cli_name(cptr) : "*";
+ if (!IsServer(cptr) && !IsMe(cptr) && fld_s.flags & FLAG_ALT) {
+ assert(0 != cli_user(cptr));
+ assert(0 != *(cli_name(cptr)));
+ str2 = cli_user(cptr)->username;
+ str3 = cli_user(cptr)->host;
+ } else
+ fld_s.flags &= ~FLAG_ALT;
+ }
- slen1 = my_strnlen(str1, fld_s.prec);
- if (str2 && (fld_s.prec < 0 || fld_s.prec - slen1 > 0))
- slen2 = my_strnlen(str2, fld_s.prec < 0 ? -1 : fld_s.prec - slen1);
- plen = (fld_s.width - (slen1 + slen2) <= 0 ? 0 :
- fld_s.width - (slen1 + slen2));
+ if (fld_s.flags & FLAG_COLON)
+ elen++; /* account for : */
+
+ slen1 = my_strnlen(str1, fld_s.prec < 0 ? -1 : fld_s.prec - elen);
+ if (fld_s.flags & FLAG_ALT)
+ elen++; /* account for ! */
+ if (str2 && (fld_s.prec < 0 || fld_s.prec - (slen1 + elen) > 0))
+ slen2 = my_strnlen(str2, fld_s.prec < 0 ? -1 : fld_s.prec -
+ (slen1 + elen));
+ if (fld_s.flags & FLAG_ALT)
+ elen++; /* account for @ */
+ if (str3 && (fld_s.prec < 0 || fld_s.prec - (slen1 + slen2 + elen) > 0))
+ slen3 = my_strnlen(str3, fld_s.prec < 0 ? -1 : fld_s.prec -
+ (slen1 + slen2 + elen));
+ plen = (fld_s.width - (slen1 + slen2 + slen3 + elen) <= 0 ? 0 :
+ fld_s.width - (slen1 + slen2 + slen3 + elen));
if (plen > 0 && !(fld_s.flags & FLAG_MINUS))
do_pad(buf_p, plen, spaces); /* pre-padding */
+ if (fld_s.flags & FLAG_COLON)
+ addc(buf_p, ':');
adds(buf_p, slen1, str1);
+ if (fld_s.flags & FLAG_ALT)
+ addc(buf_p, '!');
if (str2)
adds(buf_p, slen2, str2);
+ if (fld_s.flags & FLAG_ALT)
+ addc(buf_p, '@');
+ if (str3)
+ adds(buf_p, slen3, str3);
+
+ if (plen > 0 && (fld_s.flags & FLAG_MINUS))
+ do_pad(buf_p, plen, spaces); /* post-padding */
+ } else if ((fld_s.flags & CONV_MASK) == CONV_CHANNEL) {
+ struct Channel *chan = (struct Channel *)fld_s.value.v_ptr;
+ char *str = chan->chname;
+ int slen, plen;
+
+ slen = my_strnlen(str, fld_s.prec); /* str lengths and pad lengths */
+ plen = (fld_s.width - slen <= 0 ? 0 : fld_s.width - slen);
+
+ if (plen > 0 && !(fld_s.flags & FLAG_MINUS))
+ do_pad(buf_p, plen, spaces); /* pre-padding */
+
+ adds(buf_p, slen, str); /* add the string */
if (plen > 0 && (fld_s.flags & FLAG_MINUS))
do_pad(buf_p, plen, spaces); /* post-padding */
} /* for (; *fmt; fmt++) { */
}
+/* ircd_snprintf() has a big Doxygen comment in the header file. */
int
ircd_snprintf(struct Client *dest, char *buf, size_t buf_len,
const char *format, ...)
return TOTAL(&buf_s);
}
+/** Like ircd_snprintf() but with a va_list argument list.
+ * @param[in] dest Client receiving of message.
+ * @param[out] buf Output buffer for formatted message.
+ * @param[in] buf_len Number of bytes that can be written to \a buf.
+ * @param[in] format Format string for message.
+ * @param[in] args Variable-length argument list for format string.
+ * @return Number of bytes that would be written to \a buf without truncation.
+ */
int
ircd_vsnprintf(struct Client *dest, char *buf, size_t buf_len,
const char *format, va_list args)