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 }