unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

ircsprintf.c (5129B)

      1 /*
      2  * Unreal Internet Relay Chat Daemon, src/ircsprintf.c
      3  *
      4  * (C) Copyright 2013
      5  *
      6  * Author: Falcon Darkstar Momot based upon earlier code by Carlo Wood in 1997:
      7  * 1024/624ACAD5 1997/01/26 Carlo Wood, Run on IRC <carlo@runaway.xs4all.nl>
      8  * Key fingerprint = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
      9  *
     10  * This program is free software; you can redistribute it and/or modify
     11  * it under the terms of the GNU General Public License as published by
     12  * the Free Software Foundation; either version 2, or (at your option)
     13  * any later version.
     14  *
     15  * This program is distributed in the hope that it will be useful,
     16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  * GNU General Public License for more details.
     19  *
     20  * You should have received a copy of the GNU General Public License
     21  * along with this program; if not, write to the Free Software
     22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     23  *
     24  * $Id$
     25  */
     26 #include "ircsprintf.h"
     27 #include <stdio.h>
     28 
     29 /** Optimized version of vsnprintf() for us.
     30  * ircvsnprintf is optimized for the formats: %s, %c, %d, %i, %u, %lu and %lld.
     31  * If you only use these format string types then this function is significantly
     32  * faster than regular vsnprintf().
     33  * When it encounters any other format type or things like padding, precision,
     34  * etc. then it will resort to calling vsnprintf(), so no problem.
     35  */
     36 char *ircvsnprintf(char *str, size_t size, const char *format, va_list vl)
     37 {
     38 	char *str_begin = str;
     39 	char c;
     40 	const char *end = str+size-1; /* for comparison, not dereferencing.  It is the last position a null can go. */
     41 	char scratch_buffer[32]; /* large enough for 64 bit integer as a string */
     42 
     43 	if (!size) return str;
     44 
     45 	while (str!=end && (c = *format++))
     46 	{
     47 		if (c == '%')
     48 		{
     49 			c = *format++;
     50 			if (c == 's')
     51 			{
     52 				/* %s - string */
     53 				const char *p1 = va_arg(vl, const char *);
     54 				while (str!=end && *p1) *str++ = *p1++;
     55 				continue;
     56 			}
     57 			else if (c == 'c')
     58 			{
     59 				/* %c - single character */
     60 				*str++ = (char)va_arg(vl, int);
     61 				continue;
     62 			}
     63 			else if (c == 'd' || c == 'i')
     64 			{
     65 				/* %d and %i - integer */
     66 				char *t;
     67 				int v = va_arg(vl, int);
     68 				int i = 0;
     69 				size_t len;
     70 				if (v==0)
     71 				{
     72 					*str++ = '0';
     73 					continue;
     74 				}
     75 				t = scratch_buffer + sizeof(scratch_buffer);
     76 				if (v<0)
     77 				{
     78 					*str++ = '-';
     79 					if (str==end) break;
     80 					while (v)
     81 					{
     82 						*--t = '0' - (v%10);
     83 						v/=10;
     84 					}
     85 				} else {
     86 					while (v)
     87 					{
     88 						*--t = (v%10) + '0';
     89 						v/=10;
     90 					}
     91 				}
     92 
     93 				len = sizeof(scratch_buffer)-(t-scratch_buffer);
     94 				if ((str+len)>end) break;
     95 				for (i = 0; i < len; i++)
     96 					*str++=t[i];
     97 				continue;
     98 			}
     99 			else if (c == 'l')
    100 			{
    101 				if (format[0] == 'l' && format[1] == 'd')
    102 				{
    103 					/* %lld - long long */
    104 					char *t;
    105 					long long v = va_arg(vl, long long);
    106 					int i = 0;
    107 					size_t len;
    108 
    109 					format += 2;
    110 
    111 					if (v==0)
    112 					{
    113 						*str++ = '0';
    114 						continue;
    115 					}
    116 					t = scratch_buffer + sizeof(scratch_buffer);
    117 					if (v<0)
    118 					{
    119 						*str++ = '-';
    120 						if (str==end) break;
    121 						while (v)
    122 						{
    123 							*--t = '0' - (v%10);
    124 							v/=10;
    125 						}
    126 					} else {
    127 						while (v)
    128 						{
    129 							*--t = (v%10) + '0';
    130 							v/=10;
    131 						}
    132 					}
    133 
    134 					len = sizeof(scratch_buffer)-(t-scratch_buffer);
    135 					if ((str+len)>end) break;
    136 					for (i = 0; i < len; i++)
    137 						*str++=t[i];
    138 					continue;
    139 				}
    140 				if (*format == 'u')
    141 				{
    142 					/* %lu - unsigned long */
    143 					char *t;
    144 					unsigned long v = va_arg(vl, unsigned long);
    145 					int i = 0;
    146 					size_t len;
    147 
    148 					format++;
    149 					if (v==0)
    150 					{
    151 						*str++ = '0';
    152 						continue;
    153 					}
    154 
    155 					t = scratch_buffer + sizeof(scratch_buffer);
    156 					while (v)
    157 					{
    158 						*--t = (v%10) + '0';
    159 						v/=10;
    160 					}
    161 
    162 					len = sizeof(scratch_buffer)-(t-scratch_buffer);
    163 					if ((str+len)>end) break;
    164 					for (i = 0; i < len; i++)
    165 						*str++=t[i];
    166 					continue;
    167 				}
    168 			}
    169 			else if (c == 'u')
    170 			{
    171 				/* %u - unsigned integer */
    172 				char *t;
    173 				unsigned int v = va_arg(vl, unsigned int);
    174 				int i = 0;
    175 				size_t len;
    176 				if (v==0)
    177 				{
    178 					*str++ = '0';
    179 					continue;
    180 				}
    181 
    182 				t = scratch_buffer + sizeof(scratch_buffer);
    183 				while (v)
    184 				{
    185 					*--t = (v%10) + '0';
    186 					v/=10;
    187 				}
    188 
    189 				len = sizeof(scratch_buffer)-(t-scratch_buffer);
    190 				if ((str+len)>end) break;
    191 				for (i = 0; i < len; i++)
    192 					*str++=t[i];
    193 				continue;
    194 			}
    195 			else if (c == '%')
    196 			{
    197 				/* %% - literal percent character */
    198 				*str++ = '%';
    199 				continue;
    200 			}
    201 			else if (!c)
    202 				break; /* A % at the end of the format string (illegal, skipped) */
    203 			
    204 			/* The default case, when we cannot handle the % format:
    205 			 * Stop what we are doing and pass control to the real vsnprintf()
    206 			 */
    207 			format -= 2;
    208 			vsnprintf(str, (size_t)(end-str+1), format, vl);
    209 			return str_begin;
    210 		}
    211 		*str++ = c;
    212 	}
    213 	*str = 0;
    214 	return str_begin;
    215 }
    216 
    217 char *ircsnprintf(char *str, size_t size, const char *format, ...) {
    218 	va_list vl;
    219 	char *ret;
    220 	va_start(vl, format);
    221 	ret = ircvsnprintf(str, size, format, vl);
    222 	va_end(vl);
    223 	return ret;
    224 }