138451Smsmith/*- 238451Smsmith * Copyright (c) 1986, 1988, 1991, 1993 338451Smsmith * The Regents of the University of California. All rights reserved. 438451Smsmith * (c) UNIX System Laboratories, Inc. 538451Smsmith * All or some portions of this file are derived from material licensed 638451Smsmith * to the University of California by American Telephone and Telegraph 738451Smsmith * Co. or Unix System Laboratories, Inc. and are reproduced herein with 838451Smsmith * the permission of UNIX System Laboratories, Inc. 938451Smsmith * 1038451Smsmith * Redistribution and use in source and binary forms, with or without 1138451Smsmith * modification, are permitted provided that the following conditions 1238451Smsmith * are met: 1338451Smsmith * 1. Redistributions of source code must retain the above copyright 1438451Smsmith * notice, this list of conditions and the following disclaimer. 1538451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1638451Smsmith * notice, this list of conditions and the following disclaimer in the 1738451Smsmith * documentation and/or other materials provided with the distribution. 1838451Smsmith * 4. Neither the name of the University nor the names of its contributors 1938451Smsmith * may be used to endorse or promote products derived from this software 2038451Smsmith * without specific prior written permission. 2138451Smsmith * 2238451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2338451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2438451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2538451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2638451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2738451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2838451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2938451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3038451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3138451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3238451Smsmith * SUCH DAMAGE. 3338451Smsmith * 3438451Smsmith * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 3538451Smsmith */ 3638451Smsmith 3784221Sdillon#include <sys/cdefs.h> 3884221Sdillon__FBSDID("$FreeBSD: stable/11/stand/libsa/printf.c 346477 2019-04-21 03:43:27Z kevans $"); 3984221Sdillon 4038451Smsmith/* 4138451Smsmith * Standaloneified version of the FreeBSD kernel printf family. 4238451Smsmith */ 4338451Smsmith 4438451Smsmith#include <sys/types.h> 45113159Speter#include <sys/stddef.h> 46113159Speter#include <sys/stdint.h> 47103949Smike#include <limits.h> 4855137Speter#include <string.h> 4938451Smsmith#include "stand.h" 5038451Smsmith 5138451Smsmith/* 5238451Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both 5338451Smsmith * ANSI and traditional C compilers. 5438451Smsmith */ 5538451Smsmith#include <machine/stdarg.h> 5638451Smsmith 57113159Speter#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) 58113159Speter 59266878Shselaskytypedef void (kvprintf_fn_t)(int, void *); 60266878Shselasky 61156518Sjkimstatic char *ksprintn (char *buf, uintmax_t num, int base, int *len, int upper); 62266878Shselaskystatic int kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap); 6338451Smsmith 64266878Shselaskystatic void 65266878Shselaskyputchar_wrapper(int cc, void *arg) 66266878Shselasky{ 67266879Shselasky 68266878Shselasky putchar(cc); 69266878Shselasky} 70266878Shselasky 7138451Smsmithint 7238451Smsmithprintf(const char *fmt, ...) 7338451Smsmith{ 7438451Smsmith va_list ap; 7538451Smsmith int retval; 7638451Smsmith 7738451Smsmith va_start(ap, fmt); 78266878Shselasky retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap); 7938451Smsmith va_end(ap); 8038451Smsmith return retval; 8138451Smsmith} 8238451Smsmith 83334935Sianint 8438451Smsmithvprintf(const char *fmt, va_list ap) 8538451Smsmith{ 86266879Shselasky 87334935Sian return (kvprintf(fmt, putchar_wrapper, NULL, 10, ap)); 8838451Smsmith} 8938451Smsmith 9038451Smsmithint 9138451Smsmithsprintf(char *buf, const char *cfmt, ...) 9238451Smsmith{ 9338451Smsmith int retval; 9438451Smsmith va_list ap; 9538451Smsmith 9638451Smsmith va_start(ap, cfmt); 9738451Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 9838451Smsmith buf[retval] = '\0'; 9938451Smsmith va_end(ap); 10038451Smsmith return retval; 10138451Smsmith} 10238451Smsmith 103266878Shselaskystruct print_buf { 104266878Shselasky char *buf; 105266878Shselasky size_t size; 106266878Shselasky}; 107266878Shselasky 108266878Shselaskystatic void 109266878Shselaskysnprint_func(int ch, void *arg) 110266878Shselasky{ 111266878Shselasky struct print_buf *pbuf = arg; 112266878Shselasky 113266878Shselasky if (pbuf->size < 2) { 114266878Shselasky /* 115266878Shselasky * Reserve last buffer position for the terminating 116266878Shselasky * character: 117266878Shselasky */ 118266878Shselasky return; 119266878Shselasky } 120266878Shselasky *(pbuf->buf)++ = ch; 121266878Shselasky pbuf->size--; 122266878Shselasky} 123266878Shselasky 124266878Shselaskyint 125346477Skevansasprintf(char **buf, const char *cfmt, ...) 126346477Skevans{ 127346477Skevans int retval; 128346477Skevans struct print_buf arg; 129346477Skevans va_list ap; 130346477Skevans 131346477Skevans *buf = NULL; 132346477Skevans va_start(ap, cfmt); 133346477Skevans retval = kvprintf(cfmt, NULL, NULL, 10, ap); 134346477Skevans va_end(ap); 135346477Skevans if (retval <= 0) 136346477Skevans return (-1); 137346477Skevans 138346477Skevans arg.size = retval + 1; 139346477Skevans arg.buf = *buf = malloc(arg.size); 140346477Skevans if (*buf == NULL) 141346477Skevans return (-1); 142346477Skevans 143346477Skevans va_start(ap, cfmt); 144346477Skevans retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 145346477Skevans va_end(ap); 146346477Skevans 147346477Skevans if (arg.size >= 1) 148346477Skevans *(arg.buf)++ = 0; 149346477Skevans return (retval); 150346477Skevans} 151346477Skevans 152346477Skevansint 153266878Shselaskysnprintf(char *buf, size_t size, const char *cfmt, ...) 154266878Shselasky{ 155266878Shselasky int retval; 156266878Shselasky va_list ap; 157266878Shselasky struct print_buf arg; 158266878Shselasky 159266878Shselasky arg.buf = buf; 160266878Shselasky arg.size = size; 161266878Shselasky 162266878Shselasky va_start(ap, cfmt); 163266878Shselasky retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 164266878Shselasky va_end(ap); 165266878Shselasky 166266878Shselasky if (arg.size >= 1) 167266878Shselasky *(arg.buf)++ = 0; 168266878Shselasky return retval; 169266878Shselasky} 170266878Shselasky 171334935Sianint 172334935Sianvsnprintf(char *buf, size_t size, const char *cfmt, va_list ap) 173334935Sian{ 174334935Sian struct print_buf arg; 175334935Sian int retval; 176334935Sian 177334935Sian arg.buf = buf; 178334935Sian arg.size = size; 179334935Sian 180334935Sian retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); 181334935Sian 182334935Sian if (arg.size >= 1) 183334935Sian *(arg.buf)++ = 0; 184334935Sian 185334935Sian return (retval); 186334935Sian} 187334935Sian 188334935Sianint 18940805Smsmithvsprintf(char *buf, const char *cfmt, va_list ap) 19040805Smsmith{ 19140805Smsmith int retval; 19240805Smsmith 19340805Smsmith retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 19440805Smsmith buf[retval] = '\0'; 195334935Sian 196334935Sian return (retval); 19740805Smsmith} 19840805Smsmith 19938451Smsmith/* 200113159Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 201113159Speter * order; return an optional length and a pointer to the last character 202113159Speter * written in the buffer (i.e., the first character of the string). 203113159Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 20438451Smsmith */ 20538451Smsmithstatic char * 206156518Sjkimksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 207113159Speter{ 208156518Sjkim char *p, c; 20938451Smsmith 210113159Speter p = nbuf; 211113159Speter *p = '\0'; 21238451Smsmith do { 213156518Sjkim c = hex2ascii(num % base); 214156518Sjkim *++p = upper ? toupper(c) : c; 215113159Speter } while (num /= base); 21638451Smsmith if (lenp) 217113159Speter *lenp = p - nbuf; 21838451Smsmith return (p); 21938451Smsmith} 22038451Smsmith 22138451Smsmith/* 22238451Smsmith * Scaled down version of printf(3). 22338451Smsmith * 22438451Smsmith * Two additional formats: 22538451Smsmith * 22638451Smsmith * The format %b is supported to decode error registers. 22738451Smsmith * Its usage is: 22838451Smsmith * 22938451Smsmith * printf("reg=%b\n", regval, "<base><arg>*"); 23038451Smsmith * 23138451Smsmith * where <base> is the output base expressed as a control character, e.g. 23238451Smsmith * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 23338451Smsmith * the first of which gives the bit number to be inspected (origin 1), and 23438451Smsmith * the next characters (up to a control character, i.e. a character <= 32), 23538451Smsmith * give the name of the register. Thus: 23638451Smsmith * 237277560Sdanfe * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE"); 23838451Smsmith * 23938451Smsmith * would produce output: 24038451Smsmith * 24138451Smsmith * reg=3<BITTWO,BITONE> 24238451Smsmith * 24338451Smsmith * XXX: %D -- Hexdump, takes pointer and separator string: 24438451Smsmith * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 24538451Smsmith * ("%*D", len, ptr, " " -> XX XX XX XX ... 24638451Smsmith */ 24738451Smsmithstatic int 248266878Shselaskykvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap) 24938451Smsmith{ 250266878Shselasky#define PCHAR(c) {int cc=(c); if (func) (*func)(cc, arg); else *d++ = cc; retval++; } 251113159Speter char nbuf[MAXNBUF]; 252113159Speter char *d; 253113159Speter const char *p, *percent, *q; 254300078Simp uint16_t *S; 25538451Smsmith u_char *up; 25638451Smsmith int ch, n; 257113159Speter uintmax_t num; 258113159Speter int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 259209837Sjkim int cflag, hflag, jflag, tflag, zflag; 260156518Sjkim int dwidth, upper; 26138451Smsmith char padc; 262209837Sjkim int stop = 0, retval = 0; 26338451Smsmith 264113159Speter num = 0; 26538451Smsmith if (!func) 26638451Smsmith d = (char *) arg; 26738451Smsmith else 26838451Smsmith d = NULL; 26938451Smsmith 27038451Smsmith if (fmt == NULL) 27138451Smsmith fmt = "(fmt null)\n"; 27238451Smsmith 27338451Smsmith if (radix < 2 || radix > 36) 27438451Smsmith radix = 10; 27538451Smsmith 27638451Smsmith for (;;) { 27738451Smsmith padc = ' '; 27838451Smsmith width = 0; 279209837Sjkim while ((ch = (u_char)*fmt++) != '%' || stop) { 280113159Speter if (ch == '\0') 281113159Speter return (retval); 28238451Smsmith PCHAR(ch); 28338451Smsmith } 284113159Speter percent = fmt - 1; 285113159Speter qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 286156518Sjkim sign = 0; dot = 0; dwidth = 0; upper = 0; 287209837Sjkim cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 28838451Smsmithreswitch: switch (ch = (u_char)*fmt++) { 28938451Smsmith case '.': 29038451Smsmith dot = 1; 29138451Smsmith goto reswitch; 29238451Smsmith case '#': 29338451Smsmith sharpflag = 1; 29438451Smsmith goto reswitch; 29538451Smsmith case '+': 29638451Smsmith sign = 1; 29738451Smsmith goto reswitch; 29838451Smsmith case '-': 29938451Smsmith ladjust = 1; 30038451Smsmith goto reswitch; 30138451Smsmith case '%': 30238451Smsmith PCHAR(ch); 30338451Smsmith break; 30438451Smsmith case '*': 30538451Smsmith if (!dot) { 30638451Smsmith width = va_arg(ap, int); 30738451Smsmith if (width < 0) { 30838451Smsmith ladjust = !ladjust; 30938451Smsmith width = -width; 31038451Smsmith } 31138451Smsmith } else { 31238451Smsmith dwidth = va_arg(ap, int); 31338451Smsmith } 31438451Smsmith goto reswitch; 31538451Smsmith case '0': 31638451Smsmith if (!dot) { 31738451Smsmith padc = '0'; 31838451Smsmith goto reswitch; 31938451Smsmith } 32038451Smsmith case '1': case '2': case '3': case '4': 32138451Smsmith case '5': case '6': case '7': case '8': case '9': 32238451Smsmith for (n = 0;; ++fmt) { 32338451Smsmith n = n * 10 + ch - '0'; 32438451Smsmith ch = *fmt; 32538451Smsmith if (ch < '0' || ch > '9') 32638451Smsmith break; 32738451Smsmith } 32838451Smsmith if (dot) 32938451Smsmith dwidth = n; 33038451Smsmith else 33138451Smsmith width = n; 33238451Smsmith goto reswitch; 33338451Smsmith case 'b': 334209837Sjkim num = (u_int)va_arg(ap, int); 33538451Smsmith p = va_arg(ap, char *); 336156518Sjkim for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 33738451Smsmith PCHAR(*q--); 33838451Smsmith 339113159Speter if (num == 0) 34038451Smsmith break; 34138451Smsmith 34238451Smsmith for (tmp = 0; *p;) { 34338451Smsmith n = *p++; 344113159Speter if (num & (1 << (n - 1))) { 34538451Smsmith PCHAR(tmp ? ',' : '<'); 34638451Smsmith for (; (n = *p) > ' '; ++p) 34738451Smsmith PCHAR(n); 34838451Smsmith tmp = 1; 34938451Smsmith } else 35038451Smsmith for (; *p > ' '; ++p) 35138451Smsmith continue; 35238451Smsmith } 35338451Smsmith if (tmp) 35438451Smsmith PCHAR('>'); 35538451Smsmith break; 35638451Smsmith case 'c': 35738451Smsmith PCHAR(va_arg(ap, int)); 35838451Smsmith break; 35938451Smsmith case 'D': 36038451Smsmith up = va_arg(ap, u_char *); 36138451Smsmith p = va_arg(ap, char *); 36238451Smsmith if (!width) 36338451Smsmith width = 16; 36438451Smsmith while(width--) { 36538451Smsmith PCHAR(hex2ascii(*up >> 4)); 36638451Smsmith PCHAR(hex2ascii(*up & 0x0f)); 36738451Smsmith up++; 36838451Smsmith if (width) 36938451Smsmith for (q=p;*q;q++) 37038451Smsmith PCHAR(*q); 37138451Smsmith } 37238451Smsmith break; 37338451Smsmith case 'd': 374113159Speter case 'i': 375113159Speter base = 10; 37638451Smsmith sign = 1; 377113159Speter goto handle_sign; 378209837Sjkim case 'h': 379209837Sjkim if (hflag) { 380209837Sjkim hflag = 0; 381209837Sjkim cflag = 1; 382209837Sjkim } else 383209837Sjkim hflag = 1; 384209837Sjkim goto reswitch; 385113159Speter case 'j': 386113159Speter jflag = 1; 387113159Speter goto reswitch; 38838451Smsmith case 'l': 389113159Speter if (lflag) { 390113159Speter lflag = 0; 391113159Speter qflag = 1; 392113159Speter } else 393113159Speter lflag = 1; 39438451Smsmith goto reswitch; 39538451Smsmith case 'n': 396113159Speter if (jflag) 397113159Speter *(va_arg(ap, intmax_t *)) = retval; 398113159Speter else if (qflag) 399113159Speter *(va_arg(ap, quad_t *)) = retval; 400113159Speter else if (lflag) 401113159Speter *(va_arg(ap, long *)) = retval; 402113159Speter else if (zflag) 403113159Speter *(va_arg(ap, size_t *)) = retval; 404209837Sjkim else if (hflag) 405209837Sjkim *(va_arg(ap, short *)) = retval; 406209837Sjkim else if (cflag) 407209837Sjkim *(va_arg(ap, char *)) = retval; 408113159Speter else 409113159Speter *(va_arg(ap, int *)) = retval; 410113159Speter break; 41138451Smsmith case 'o': 41238451Smsmith base = 8; 413113159Speter goto handle_nosign; 41438451Smsmith case 'p': 41538451Smsmith base = 16; 416113159Speter sharpflag = (width == 0); 417113159Speter sign = 0; 418113159Speter num = (uintptr_t)va_arg(ap, void *); 41938451Smsmith goto number; 420113159Speter case 'q': 421113159Speter qflag = 1; 422113159Speter goto reswitch; 423113159Speter case 'r': 424113159Speter base = radix; 425113159Speter if (sign) 426113159Speter goto handle_sign; 427113159Speter goto handle_nosign; 42838451Smsmith case 's': 42938451Smsmith p = va_arg(ap, char *); 43038451Smsmith if (p == NULL) 43138451Smsmith p = "(null)"; 43238451Smsmith if (!dot) 43338451Smsmith n = strlen (p); 43438451Smsmith else 43538451Smsmith for (n = 0; n < dwidth && p[n]; n++) 43638451Smsmith continue; 43738451Smsmith 43838451Smsmith width -= n; 43938451Smsmith 44038451Smsmith if (!ladjust && width > 0) 44138451Smsmith while (width--) 44238451Smsmith PCHAR(padc); 44338451Smsmith while (n--) 44438451Smsmith PCHAR(*p++); 44538451Smsmith if (ladjust && width > 0) 44638451Smsmith while (width--) 44738451Smsmith PCHAR(padc); 44838451Smsmith break; 449300078Simp case 'S': /* Assume console can cope with wide chars */ 450300078Simp for (S = va_arg(ap, uint16_t *); *S != 0; S++) 451300078Simp PCHAR(*S); 452300078Simp break; 453113159Speter case 't': 454113159Speter tflag = 1; 455113159Speter goto reswitch; 45638451Smsmith case 'u': 45738451Smsmith base = 10; 458113159Speter goto handle_nosign; 459156518Sjkim case 'X': 460156518Sjkim upper = 1; 46138451Smsmith case 'x': 46238451Smsmith base = 16; 463113159Speter goto handle_nosign; 464113159Speter case 'y': 465113159Speter base = 16; 466113159Speter sign = 1; 467113159Speter goto handle_sign; 468113159Speter case 'z': 469113159Speter zflag = 1; 470113159Speter goto reswitch; 471113159Speterhandle_nosign: 472113159Speter sign = 0; 473113159Speter if (jflag) 474113159Speter num = va_arg(ap, uintmax_t); 475113159Speter else if (qflag) 476113159Speter num = va_arg(ap, u_quad_t); 477113159Speter else if (tflag) 478113159Speter num = va_arg(ap, ptrdiff_t); 479113159Speter else if (lflag) 480113159Speter num = va_arg(ap, u_long); 481113159Speter else if (zflag) 482113159Speter num = va_arg(ap, size_t); 483209837Sjkim else if (hflag) 484209837Sjkim num = (u_short)va_arg(ap, int); 485209837Sjkim else if (cflag) 486209837Sjkim num = (u_char)va_arg(ap, int); 487113159Speter else 488113159Speter num = va_arg(ap, u_int); 489113159Speter goto number; 490113159Speterhandle_sign: 491113159Speter if (jflag) 492113159Speter num = va_arg(ap, intmax_t); 493113159Speter else if (qflag) 494113159Speter num = va_arg(ap, quad_t); 495113159Speter else if (tflag) 496113159Speter num = va_arg(ap, ptrdiff_t); 497113159Speter else if (lflag) 498113159Speter num = va_arg(ap, long); 499113159Speter else if (zflag) 500185037Sdelphij num = va_arg(ap, ssize_t); 501209837Sjkim else if (hflag) 502209837Sjkim num = (short)va_arg(ap, int); 503209837Sjkim else if (cflag) 504209837Sjkim num = (char)va_arg(ap, int); 505113159Speter else 506113159Speter num = va_arg(ap, int); 507113159Speternumber: 508113159Speter if (sign && (intmax_t)num < 0) { 50938451Smsmith neg = 1; 510113159Speter num = -(intmax_t)num; 51138451Smsmith } 512209837Sjkim p = ksprintn(nbuf, num, base, &n, upper); 513209837Sjkim tmp = 0; 514113159Speter if (sharpflag && num != 0) { 51538451Smsmith if (base == 8) 51638451Smsmith tmp++; 51738451Smsmith else if (base == 16) 51838451Smsmith tmp += 2; 51938451Smsmith } 52038451Smsmith if (neg) 52138451Smsmith tmp++; 52238451Smsmith 523209837Sjkim if (!ladjust && padc == '0') 524209837Sjkim dwidth = width - tmp; 525209949Sjkim width -= tmp + imax(dwidth, n); 526209837Sjkim dwidth -= n; 527209837Sjkim if (!ladjust) 528209837Sjkim while (width-- > 0) 529209837Sjkim PCHAR(' '); 53038451Smsmith if (neg) 53138451Smsmith PCHAR('-'); 532113159Speter if (sharpflag && num != 0) { 53338451Smsmith if (base == 8) { 53438451Smsmith PCHAR('0'); 53538451Smsmith } else if (base == 16) { 53638451Smsmith PCHAR('0'); 53738451Smsmith PCHAR('x'); 53838451Smsmith } 53938451Smsmith } 540209837Sjkim while (dwidth-- > 0) 541209837Sjkim PCHAR('0'); 54238451Smsmith 54338451Smsmith while (*p) 54438451Smsmith PCHAR(*p--); 54538451Smsmith 546209837Sjkim if (ladjust) 547209837Sjkim while (width-- > 0) 548209837Sjkim PCHAR(' '); 54938451Smsmith 55038451Smsmith break; 55138451Smsmith default: 552113159Speter while (percent < fmt) 553113159Speter PCHAR(*percent++); 554209837Sjkim /* 555277560Sdanfe * Since we ignore a formatting argument it is no 556209837Sjkim * longer safe to obey the remaining formatting 557209837Sjkim * arguments as the arguments will no longer match 558209837Sjkim * the format specs. 559209837Sjkim */ 560209837Sjkim stop = 1; 56138451Smsmith break; 56238451Smsmith } 56338451Smsmith } 56438451Smsmith#undef PCHAR 56538451Smsmith} 566