pputf.cxx (6379B)
1 /* 2 * 3 * C++ Portable Types Library (PTypes) 4 * Version 2.1.1 Released 27-Jun-2007 5 * 6 * Copyright (C) 2001-2007 Hovik Melikyan 7 * 8 * http://www.melikyan.com/ptypes/ 9 * 10 */ 11 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <stdarg.h> 16 17 #include "ptypes.h" 18 #include "pstreams.h" 19 #include "pinet.h" // for ipaddress type 20 #include "ptime.h" // for dttotm() 21 22 #ifndef PTYPES_ST 23 #include "pasync.h" // for mutex locking in logfile::vputf() 24 #endif 25 26 27 namespace ptypes { 28 29 30 // %t and %T formats 31 const char* const shorttimefmt = "%d-%b-%Y %X"; 32 const char* const longtimefmt = "%a %b %d %X %Y"; 33 34 35 static cset fmtopts = " #+~-0-9."; 36 37 38 enum fmt_type_t 39 { 40 FMT_NONE, 41 FMT_CHAR, 42 FMT_SHORT, 43 FMT_INT, 44 FMT_LONG, 45 FMT_LARGE, 46 FMT_STR, 47 FMT_PTR, 48 FMT_DOUBLE, 49 FMT_LONG_DOUBLE, 50 FMT_IPADDR, 51 FMT_TIME, 52 FMT_LONGTIME 53 }; 54 55 56 void outstm::vputf(const char* fmt, va_list va) 57 { 58 const char* p = fmt; 59 while (*p != 0) 60 { 61 // write out raw data between format specifiers 62 const char* e = strchr(p, '%'); 63 if (e == 0) 64 e = p + strlen(p); 65 if (e > p) 66 write(p, e - p); 67 68 if (*e != '%') 69 break; 70 71 e++; 72 if (*e == '%') 73 { 74 // write out a single '%' 75 put('%'); 76 p = e + 1; 77 continue; 78 } 79 80 // build a temporary buffer for the conversion specification 81 char fbuf[128]; 82 fbuf[0] = '%'; 83 char* f = fbuf + 1; 84 bool modif = false; 85 86 // formatting flags and width specifiers 87 while (*e & fmtopts && uint(f - fbuf) < sizeof(fbuf) - 5) 88 { 89 *f++ = *e++; 90 modif = true; 91 } 92 93 // prefixes 94 fmt_type_t fmt_type = FMT_NONE; 95 switch(*e) 96 { 97 case 'h': 98 fmt_type = FMT_SHORT; 99 *f++ = *e++; 100 break; 101 case 'L': 102 fmt_type = FMT_LONG_DOUBLE; 103 *f++ = *e++; 104 break; 105 case 'l': 106 e++; 107 if (*e == 'l') 108 { 109 #if defined(_MSC_VER) || defined(__BORLANDC__) 110 *f++ = 'I'; 111 *f++ = '6'; 112 *f++ = '4'; 113 #else 114 *f++ = 'l'; 115 *f++ = 'l'; 116 #endif 117 e++; 118 fmt_type = FMT_LARGE; 119 } 120 else 121 { 122 *f++ = 'l'; 123 fmt_type = FMT_LONG; 124 } 125 break; 126 } 127 128 // format specifier 129 switch(*e) 130 { 131 case 'c': 132 fmt_type = FMT_CHAR; 133 *f++ = *e++; 134 break; 135 case 'd': 136 case 'i': 137 case 'o': 138 case 'u': 139 case 'x': 140 case 'X': 141 if (fmt_type < FMT_SHORT || fmt_type > FMT_LARGE) 142 fmt_type = FMT_INT; 143 *f++ = *e++; 144 break; 145 case 'e': 146 case 'E': 147 case 'f': 148 case 'g': 149 case 'G': 150 if (fmt_type != FMT_LONG_DOUBLE) 151 fmt_type = FMT_DOUBLE; 152 *f++ = *e++; 153 break; 154 case 's': 155 fmt_type = FMT_STR; 156 *f++ = *e++; 157 break; 158 case 'p': 159 fmt_type = FMT_PTR; 160 *f++ = *e++; 161 break; 162 case 'a': 163 fmt_type = FMT_IPADDR; 164 *f++ = *e++; 165 break; 166 case 't': 167 fmt_type = FMT_TIME; 168 *f++ = *e++; 169 break; 170 case 'T': 171 fmt_type = FMT_LONGTIME; 172 *f++ = *e++; 173 break; 174 } 175 176 if (fmt_type == FMT_NONE) 177 break; 178 179 *f = 0; 180 181 // some formatters are processed here 'manually', 182 // while others are passed to snprintf 183 char buf[4096]; 184 int s = 0; 185 switch(fmt_type) 186 { 187 case FMT_NONE: 188 break; // to avoid compiler warning 189 case FMT_CHAR: 190 if (modif) 191 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,int)); 192 else 193 put(char(va_arg(va,int))); 194 break; 195 case FMT_SHORT: 196 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,int)); 197 break; 198 case FMT_INT: 199 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,int)); 200 break; 201 case FMT_LONG: 202 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,long)); 203 break; 204 case FMT_LARGE: 205 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,large)); 206 break; 207 case FMT_STR: 208 if (modif) 209 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,char*)); 210 else 211 put(va_arg(va,const char*)); 212 break; 213 case FMT_PTR: 214 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,void*)); 215 break; 216 case FMT_DOUBLE: 217 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,double)); 218 break; 219 case FMT_LONG_DOUBLE: 220 s = snprintf(buf, sizeof(buf), fbuf, va_arg(va,long double)); 221 break; 222 223 case FMT_IPADDR: 224 { 225 ipaddress ip = va_arg(va,long); 226 s = snprintf(buf, sizeof(buf), "%d.%d.%d.%d", 227 uint(ip[0]), uint(ip[1]), uint(ip[2]), uint(ip[3])); 228 } 229 break; 230 231 case FMT_TIME: 232 case FMT_LONGTIME: 233 { 234 const char* const fmt = (fmt_type == FMT_TIME) ? shorttimefmt : longtimefmt; 235 struct tm t; 236 datetime dt = va_arg(va,large); 237 if (dt < 0) 238 dt = 0; 239 s = strftime(buf, sizeof(buf), fmt, dttotm(dt, t)); 240 } 241 break; 242 } 243 if (s > 0) 244 write(buf, s); 245 246 p = e; 247 } 248 } 249 250 251 void outstm::putf(const char* fmt, ...) 252 { 253 va_list va; 254 va_start(va, fmt); 255 vputf(fmt, va); 256 va_end(va); 257 } 258 259 260 void fdxstm::putf(const char* fmt, ...) 261 { 262 va_list va; 263 va_start(va, fmt); 264 out.vputf(fmt, va); 265 va_end(va); 266 } 267 268 269 void logfile::vputf(const char* fmt, va_list va) 270 { 271 #ifndef PTYPES_ST 272 scopelock sl(lock); 273 #endif 274 outfile::vputf(fmt, va); 275 } 276 277 278 void logfile::putf(const char* fmt, ...) 279 { 280 va_list va; 281 va_start(va, fmt); 282 vputf(fmt, va); 283 va_end(va); 284 } 285 286 287 }