mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-04 05:25:45 +01:00 
			
		
		
		
	Add Posix functions for porting compatibility. Fix compliance issues with ISO/IEC 9899:199409 New Functions: setenv(), fparseln(), GetFileNameFromPath(), rename(), realpath(), setprogname(), getprogname(), strlcat(), strlcpy(), strsep(), setitimer(), getitimer(), timegm(), getopt(), basename(), mkstemp(), ffs(), vsnprintf(), snprintf(), getpass(), usleep(), select(), writev(), strcasecmp(), getcwd(), chdir(), tcgetpgrp(), getpgrp(), gettimeofday(), bcopy(), git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12061 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			495 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			495 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*  $NetBSD: vsnprintf_ss.c,v 1.2.2.1 2007/05/07 19:49:09 pavel Exp $ */
 | 
						|
 | 
						|
/*-
 | 
						|
 * Copyright (c) 1990, 1993
 | 
						|
 *  The Regents of the University of California.  All rights reserved.
 | 
						|
 *
 | 
						|
 * This code is derived from software contributed to Berkeley by
 | 
						|
 * Chris Torek.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 3. Neither the name of the University nor the names of its contributors
 | 
						|
 *    may be used to endorse or promote products derived from this software
 | 
						|
 *    without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | 
						|
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 */
 | 
						|
#include  <LibConfig.h>
 | 
						|
#include <sys/EfiCdefs.h>
 | 
						|
#if defined(LIBC_SCCS) && !defined(lint)
 | 
						|
#if 0
 | 
						|
static char sccsid[] = "@(#)vsnprintf.c 8.1 (Berkeley) 6/4/93";
 | 
						|
#else
 | 
						|
__RCSID("$NetBSD: vsnprintf_ss.c,v 1.2.2.1 2007/05/07 19:49:09 pavel Exp $");
 | 
						|
#endif
 | 
						|
#endif /* LIBC_SCCS and not lint */
 | 
						|
 | 
						|
#include "namespace.h"
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <inttypes.h>
 | 
						|
#include <assert.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <string.h>
 | 
						|
#include "reentrant.h"
 | 
						|
#include "extern.h"
 | 
						|
#include "local.h"
 | 
						|
 | 
						|
#ifdef __weak_alias
 | 
						|
__weak_alias(vsnprintf_ss,_vsnprintf_ss)
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * vsnprintf_ss: scaled down version of printf(3).
 | 
						|
 *
 | 
						|
 * this version based on vfprintf() from libc which was derived from
 | 
						|
 * software contributed to Berkeley by Chris Torek.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * macros for converting digits to letters and vice versa
 | 
						|
 */
 | 
						|
#define to_digit(c) ((c) - '0')
 | 
						|
#define is_digit(c) ((unsigned)to_digit(c) <= 9)
 | 
						|
#define to_char(n)  (char)((n) + '0')
 | 
						|
 | 
						|
/*
 | 
						|
 * flags used during conversion.
 | 
						|
 */
 | 
						|
#define ALT   0x001   /* alternate form */
 | 
						|
#define HEXPREFIX 0x002   /* add 0x or 0X prefix */
 | 
						|
#define LADJUST   0x004   /* left adjustment */
 | 
						|
#define LONGDBL   0x008   /* long double; unimplemented */
 | 
						|
#define LONGINT   0x010   /* long integer */
 | 
						|
#define QUADINT   0x020   /* quad integer */
 | 
						|
#define SHORTINT  0x040   /* short integer */
 | 
						|
#define MAXINT    0x080   /* intmax_t */
 | 
						|
#define PTRINT    0x100   /* intptr_t */
 | 
						|
#define SIZEINT   0x200   /* size_t */
 | 
						|
#define ZEROPAD   0x400   /* zero (as opposed to blank) pad */
 | 
						|
#define FPT   0x800   /* Floating point number */
 | 
						|
 | 
						|
  /*
 | 
						|
   * To extend shorts properly, we need both signed and unsigned
 | 
						|
   * argument extraction methods.
 | 
						|
   */
 | 
						|
#define SARG() \
 | 
						|
  ((INT64)(flags&MAXINT ? va_arg(ap, intmax_t) : \
 | 
						|
      flags&PTRINT ? va_arg(ap, intptr_t) : \
 | 
						|
      flags&SIZEINT ? va_arg(ap, ssize_t) : /* XXX */ \
 | 
						|
      flags&QUADINT ? va_arg(ap, quad_t) : \
 | 
						|
      flags&LONGINT ? va_arg(ap, long) : \
 | 
						|
      flags&SHORTINT ? (short)va_arg(ap, int) : \
 | 
						|
      va_arg(ap, int)))
 | 
						|
 | 
						|
#define UARG() \
 | 
						|
  ((UINT64)(flags&MAXINT ? va_arg(ap, uintmax_t) : \
 | 
						|
      flags&PTRINT ? va_arg(ap, uintptr_t) : \
 | 
						|
      flags&SIZEINT ? va_arg(ap, size_t) : \
 | 
						|
      flags&QUADINT ? va_arg(ap, u_quad_t) : \
 | 
						|
      flags&LONGINT ? va_arg(ap, unsigned long) : \
 | 
						|
      flags&SHORTINT ? (u_short)va_arg(ap, int) : \
 | 
						|
      va_arg(ap, u_int)))
 | 
						|
 | 
						|
#define PUTCHAR(C) do {         \
 | 
						|
  if (sbuf < tailp)       \
 | 
						|
    *sbuf++ = (C);        \
 | 
						|
} while (/*CONSTCOND*/0)
 | 
						|
 | 
						|
int
 | 
						|
vsnprintf_ss(char *sbuf, size_t slen, const char *fmt0, va_list ap)
 | 
						|
{
 | 
						|
  const char *fmt;  /* format string */
 | 
						|
  int ch;     /* character from fmt */
 | 
						|
  int n;      /* handy integer (short term usage) */
 | 
						|
  char *cp;   /* handy char pointer (short term usage) */
 | 
						|
  int flags;    /* flags as above */
 | 
						|
  int ret;    /* return value accumulator */
 | 
						|
  int width;    /* width from format (%8d), or 0 */
 | 
						|
  int prec;   /* precision from format (%.3d), or -1 */
 | 
						|
  char sign;    /* sign prefix (' ', '+', '-', or \0) */
 | 
						|
 | 
						|
  u_quad_t _uquad;  /* integer arguments %[diouxX] */
 | 
						|
  enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
 | 
						|
  int dprec;    /* a copy of prec if [diouxX], 0 otherwise */
 | 
						|
  int realsz;   /* field size expanded by dprec */
 | 
						|
  int size;   /* size of converted field or string */
 | 
						|
  const char *xdigs;  /* digits for [xX] conversion */
 | 
						|
  char bf[128];     /* space for %c, %[diouxX] */
 | 
						|
  char *tailp;    /* tail pointer for snprintf */
 | 
						|
 | 
						|
  static const char xdigs_lower[16] = "0123456789abcdef";
 | 
						|
  static const char xdigs_upper[16] = "0123456789ABCDEF";
 | 
						|
 | 
						|
 | 
						|
  _DIAGASSERT(n == 0 || sbuf != NULL);
 | 
						|
  _DIAGASSERT(fmt != NULL);
 | 
						|
 | 
						|
  tailp = sbuf + slen;
 | 
						|
 | 
						|
  cp = NULL;  /* XXX: shutup gcc */
 | 
						|
  size = 0; /* XXX: shutup gcc */
 | 
						|
 | 
						|
  fmt = fmt0;
 | 
						|
  ret = 0;
 | 
						|
 | 
						|
  xdigs = NULL;   /* XXX: shut up gcc warning */
 | 
						|
 | 
						|
  /*
 | 
						|
   * Scan the format for conversions (`%' character).
 | 
						|
   */
 | 
						|
  for (;;) {
 | 
						|
    while (*fmt != '%' && *fmt) {
 | 
						|
      ret++;
 | 
						|
      PUTCHAR(*fmt++);
 | 
						|
    }
 | 
						|
    if (*fmt == 0)
 | 
						|
      goto done;
 | 
						|
 | 
						|
    fmt++;    /* skip over '%' */
 | 
						|
 | 
						|
    flags = 0;
 | 
						|
    dprec = 0;
 | 
						|
    width = 0;
 | 
						|
    prec = -1;
 | 
						|
    sign = '\0';
 | 
						|
 | 
						|
rflag:    ch = *fmt++;
 | 
						|
reswitch: switch (ch) {
 | 
						|
    case ' ':
 | 
						|
      /*
 | 
						|
       * ``If the space and + flags both appear, the space
 | 
						|
       * flag will be ignored.''
 | 
						|
       *  -- ANSI X3J11
 | 
						|
       */
 | 
						|
      if (!sign)
 | 
						|
        sign = ' ';
 | 
						|
      goto rflag;
 | 
						|
    case '#':
 | 
						|
      flags |= ALT;
 | 
						|
      goto rflag;
 | 
						|
    case '*':
 | 
						|
      /*
 | 
						|
       * ``A negative field width argument is taken as a
 | 
						|
       * - flag followed by a positive field width.''
 | 
						|
       *  -- ANSI X3J11
 | 
						|
       * They don't exclude field widths read from args.
 | 
						|
       */
 | 
						|
      if ((width = va_arg(ap, int)) >= 0)
 | 
						|
        goto rflag;
 | 
						|
      width = -width;
 | 
						|
      /* FALLTHROUGH */
 | 
						|
    case '-':
 | 
						|
      flags |= LADJUST;
 | 
						|
      goto rflag;
 | 
						|
    case '+':
 | 
						|
      sign = '+';
 | 
						|
      goto rflag;
 | 
						|
    case '.':
 | 
						|
      if ((ch = *fmt++) == '*') {
 | 
						|
        n = va_arg(ap, int);
 | 
						|
        prec = n < 0 ? -1 : n;
 | 
						|
        goto rflag;
 | 
						|
      }
 | 
						|
      n = 0;
 | 
						|
      while (is_digit(ch)) {
 | 
						|
        n = 10 * n + to_digit(ch);
 | 
						|
        ch = *fmt++;
 | 
						|
      }
 | 
						|
      prec = n < 0 ? -1 : n;
 | 
						|
      goto reswitch;
 | 
						|
    case '0':
 | 
						|
      /*
 | 
						|
       * ``Note that 0 is taken as a flag, not as the
 | 
						|
       * beginning of a field width.''
 | 
						|
       *  -- ANSI X3J11
 | 
						|
       */
 | 
						|
      flags |= ZEROPAD;
 | 
						|
      goto rflag;
 | 
						|
    case '1': case '2': case '3': case '4':
 | 
						|
    case '5': case '6': case '7': case '8': case '9':
 | 
						|
      n = 0;
 | 
						|
      do {
 | 
						|
        n = 10 * n + to_digit(ch);
 | 
						|
        ch = *fmt++;
 | 
						|
      } while (is_digit(ch));
 | 
						|
      width = n;
 | 
						|
      goto reswitch;
 | 
						|
    case 'h':
 | 
						|
      flags |= SHORTINT;
 | 
						|
      goto rflag;
 | 
						|
    case 'j':
 | 
						|
      flags |= MAXINT;
 | 
						|
      goto rflag;
 | 
						|
    case 'l':
 | 
						|
      if (*fmt == 'l') {
 | 
						|
        fmt++;
 | 
						|
        flags |= QUADINT;
 | 
						|
      } else {
 | 
						|
        flags |= LONGINT;
 | 
						|
      }
 | 
						|
      goto rflag;
 | 
						|
    case 'q':
 | 
						|
      flags |= QUADINT;
 | 
						|
      goto rflag;
 | 
						|
    case 't':
 | 
						|
      flags |= PTRINT;
 | 
						|
      goto rflag;
 | 
						|
    case 'z':
 | 
						|
      flags |= SIZEINT;
 | 
						|
      goto rflag;
 | 
						|
    case 'c':
 | 
						|
      *(cp = bf) = va_arg(ap, int);
 | 
						|
      size = 1;
 | 
						|
      sign = '\0';
 | 
						|
      break;
 | 
						|
    case 'D':
 | 
						|
      flags |= LONGINT;
 | 
						|
      /*FALLTHROUGH*/
 | 
						|
    case 'd':
 | 
						|
    case 'i':
 | 
						|
      _uquad = SARG();
 | 
						|
      if ((quad_t)_uquad < 0) {
 | 
						|
        _uquad = -_uquad;
 | 
						|
        sign = '-';
 | 
						|
      }
 | 
						|
      base = DEC;
 | 
						|
      goto number;
 | 
						|
    case 'n':
 | 
						|
      if (flags & MAXINT)
 | 
						|
        *va_arg(ap, intmax_t *) = ret;
 | 
						|
      else if (flags & PTRINT)
 | 
						|
        *va_arg(ap, intptr_t *) = ret;
 | 
						|
      else if (flags & SIZEINT)
 | 
						|
        *va_arg(ap, ssize_t *) = ret;
 | 
						|
      else if (flags & QUADINT)
 | 
						|
        *va_arg(ap, quad_t *) = ret;
 | 
						|
      else if (flags & LONGINT)
 | 
						|
        *va_arg(ap, long *) = (long)ret;
 | 
						|
      else if (flags & SHORTINT)
 | 
						|
        *va_arg(ap, short *) = (short)ret;
 | 
						|
      else
 | 
						|
        *va_arg(ap, int *) = ret;
 | 
						|
      continue; /* no output */
 | 
						|
    case 'O':
 | 
						|
      flags |= LONGINT;
 | 
						|
      /*FALLTHROUGH*/
 | 
						|
    case 'o':
 | 
						|
      _uquad = UARG();
 | 
						|
      base = OCT;
 | 
						|
      goto nosign;
 | 
						|
    case 'p':
 | 
						|
      /*
 | 
						|
       * ``The argument shall be a pointer to void.  The
 | 
						|
       * value of the pointer is converted to a sequence
 | 
						|
       * of printable characters, in an implementation-
 | 
						|
       * defined manner.''
 | 
						|
       *  -- ANSI X3J11
 | 
						|
       */
 | 
						|
      /* NOSTRICT */
 | 
						|
      _uquad = (u_long)va_arg(ap, void *);
 | 
						|
      base = HEX;
 | 
						|
      xdigs = xdigs_lower;
 | 
						|
      flags |= HEXPREFIX;
 | 
						|
      ch = 'x';
 | 
						|
      goto nosign;
 | 
						|
    case 's':
 | 
						|
      if ((cp = va_arg(ap, char *)) == NULL)
 | 
						|
        /*XXXUNCONST*/
 | 
						|
        cp = __UNCONST("(null)");
 | 
						|
      if (prec >= 0) {
 | 
						|
        /*
 | 
						|
         * can't use strlen; can only look for the
 | 
						|
         * NUL in the first `prec' characters, and
 | 
						|
         * strlen() will go further.
 | 
						|
         */
 | 
						|
        char *p = memchr(cp, 0, (size_t)prec);
 | 
						|
 | 
						|
        if (p != NULL) {
 | 
						|
          size = p - cp;
 | 
						|
          if (size > prec)
 | 
						|
            size = prec;
 | 
						|
        } else
 | 
						|
          size = prec;
 | 
						|
      } else
 | 
						|
        size = strlen(cp);
 | 
						|
      sign = '\0';
 | 
						|
      break;
 | 
						|
    case 'U':
 | 
						|
      flags |= LONGINT;
 | 
						|
      /*FALLTHROUGH*/
 | 
						|
    case 'u':
 | 
						|
      _uquad = UARG();
 | 
						|
      base = DEC;
 | 
						|
      goto nosign;
 | 
						|
    case 'X':
 | 
						|
      xdigs = xdigs_upper;
 | 
						|
      goto hex;
 | 
						|
    case 'x':
 | 
						|
      xdigs = xdigs_lower;
 | 
						|
hex:      _uquad = UARG();
 | 
						|
      base = HEX;
 | 
						|
      /* leading 0x/X only if non-zero */
 | 
						|
      if (flags & ALT && _uquad != 0)
 | 
						|
        flags |= HEXPREFIX;
 | 
						|
 | 
						|
      /* unsigned conversions */
 | 
						|
nosign:     sign = '\0';
 | 
						|
      /*
 | 
						|
       * ``... diouXx conversions ... if a precision is
 | 
						|
       * specified, the 0 flag will be ignored.''
 | 
						|
       *  -- ANSI X3J11
 | 
						|
       */
 | 
						|
number:     if ((dprec = prec) >= 0)
 | 
						|
        flags &= ~ZEROPAD;
 | 
						|
 | 
						|
      /*
 | 
						|
       * ``The result of converting a zero value with an
 | 
						|
       * explicit precision of zero is no characters.''
 | 
						|
       *  -- ANSI X3J11
 | 
						|
       */
 | 
						|
      cp = bf + sizeof(bf);
 | 
						|
      if (_uquad != 0 || prec != 0) {
 | 
						|
        /*
 | 
						|
         * Unsigned mod is hard, and unsigned mod
 | 
						|
         * by a constant is easier than that by
 | 
						|
         * a variable; hence this switch.
 | 
						|
         */
 | 
						|
        switch (base) {
 | 
						|
        case OCT:
 | 
						|
          do {
 | 
						|
            *--cp = to_char(_uquad & 7);
 | 
						|
            _uquad >>= 3;
 | 
						|
          } while (_uquad);
 | 
						|
          /* handle octal leading 0 */
 | 
						|
          if (flags & ALT && *cp != '0')
 | 
						|
            *--cp = '0';
 | 
						|
          break;
 | 
						|
 | 
						|
        case DEC:
 | 
						|
          /* many numbers are 1 digit */
 | 
						|
          while (_uquad >= 10) {
 | 
						|
            *--cp = to_char(_uquad % 10);
 | 
						|
            _uquad /= 10;
 | 
						|
          }
 | 
						|
          *--cp = to_char(_uquad);
 | 
						|
          break;
 | 
						|
 | 
						|
        case HEX:
 | 
						|
          do {
 | 
						|
            *--cp = xdigs[(size_t)_uquad & 15];
 | 
						|
            _uquad >>= 4;
 | 
						|
          } while (_uquad);
 | 
						|
          break;
 | 
						|
 | 
						|
        default:
 | 
						|
          /*XXXUNCONST*/
 | 
						|
          cp = __UNCONST("bug bad base");
 | 
						|
          size = strlen(cp);
 | 
						|
          goto skipsize;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      size = bf + sizeof(bf) - cp;
 | 
						|
    skipsize:
 | 
						|
      break;
 | 
						|
    default:  /* "%?" prints ?, unless ? is NUL */
 | 
						|
      if (ch == '\0')
 | 
						|
        goto done;
 | 
						|
      /* pretend it was %c with argument ch */
 | 
						|
      cp = bf;
 | 
						|
      *cp = ch;
 | 
						|
      size = 1;
 | 
						|
      sign = '\0';
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * All reasonable formats wind up here.  At this point, `cp'
 | 
						|
     * points to a string which (if not flags&LADJUST) should be
 | 
						|
     * padded out to `width' places.  If flags&ZEROPAD, it should
 | 
						|
     * first be prefixed by any sign or other prefix; otherwise,
 | 
						|
     * it should be blank padded before the prefix is emitted.
 | 
						|
     * After any left-hand padding and prefixing, emit zeroes
 | 
						|
     * required by a decimal [diouxX] precision, then print the
 | 
						|
     * string proper, then emit zeroes required by any leftover
 | 
						|
     * floating precision; finally, if LADJUST, pad with blanks.
 | 
						|
     *
 | 
						|
     * Compute actual size, so we know how much to pad.
 | 
						|
     * size excludes decimal prec; realsz includes it.
 | 
						|
     */
 | 
						|
    realsz = dprec > size ? dprec : size;
 | 
						|
    if (sign)
 | 
						|
      realsz++;
 | 
						|
    else if (flags & HEXPREFIX)
 | 
						|
      realsz+= 2;
 | 
						|
 | 
						|
    /* adjust ret */
 | 
						|
    ret += width > realsz ? width : realsz;
 | 
						|
 | 
						|
    /* right-adjusting blank padding */
 | 
						|
    if ((flags & (LADJUST|ZEROPAD)) == 0) {
 | 
						|
      n = width - realsz;
 | 
						|
      while (n-- > 0)
 | 
						|
        PUTCHAR(' ');
 | 
						|
    }
 | 
						|
 | 
						|
    /* prefix */
 | 
						|
    if (sign) {
 | 
						|
      PUTCHAR(sign);
 | 
						|
    } else if (flags & HEXPREFIX) {
 | 
						|
      PUTCHAR('0');
 | 
						|
      PUTCHAR(ch);
 | 
						|
    }
 | 
						|
 | 
						|
    /* right-adjusting zero padding */
 | 
						|
    if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) {
 | 
						|
      n = width - realsz;
 | 
						|
      while (n-- > 0)
 | 
						|
        PUTCHAR('0');
 | 
						|
    }
 | 
						|
 | 
						|
    /* leading zeroes from decimal precision */
 | 
						|
    n = dprec - size;
 | 
						|
    while (n-- > 0)
 | 
						|
      PUTCHAR('0');
 | 
						|
 | 
						|
    /* the string or number proper */
 | 
						|
    while (size--)
 | 
						|
      PUTCHAR(*cp++);
 | 
						|
    /* left-adjusting padding (always blank) */
 | 
						|
    if (flags & LADJUST) {
 | 
						|
      n = width - realsz;
 | 
						|
      while (n-- > 0)
 | 
						|
        PUTCHAR(' ');
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
done:
 | 
						|
  if (sbuf == tailp)
 | 
						|
    sbuf[-1] = '\0';
 | 
						|
  else
 | 
						|
    *sbuf = '\0';
 | 
						|
  return (ret);
 | 
						|
  /* NOTREACHED */
 | 
						|
}
 |