Logo Search packages:      
Sourcecode: leafnode version File versions

snprintf.c

/*
 * poor man's snprintf() - for systems which don't have their own
 *
 * This version of snprintf() currently supports only %s, %c, %d, %u,
 * %ld, %lu, %li, %i. It supports the 0, + and width modifiers only for decimal
 * output (%[l]{d|u|i}).
 *
 * Copyright (c) Cornelius Krasel 2000.
 * Modified by Matthias Andree <matthias.andree@gmx.de>.
 * Modifications (C)opyright 2002 - 2003.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "leafnode.h"

#ifndef HAVE_WORKING_SNPRINTF

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/** format unsigned value u into p */
static void fmtu(char *p, unsigned long u) {
    unsigned int len = 0;
    unsigned long i = u, ni;
    unsigned char b[22];
    do {
      ni = i / 10;
      b[len++] = i - 10*ni;
      i = ni;
    } while (i);

    while (len) {
      *p++  = "0123456789"[b[--len]];
    }
    *p = '\0';
}

/** format signed value s into p, prefix asign if its nonzero and the
 * value is positive. asign is usually '+' or ' '. */
static inline void fmts(char *p, long s, char asign) {
    if (s < 0) {
      *p++ = '-';
      fmtu(p, -s);
    } else {
      if (asign)
          *p++ = asign;
      fmtu(p, s);
    }
}

int
ln_vsnprintf(char *str, size_t n, const char *format, va_list ap)
{
    const char *p;
    char *q;
    int flag = 0;
    size_t width = 0;
    char fill = ' ';
    int lflag = 0;            /* checking for longs */
    int asign = 0;            /* always show sign */
    size_t i = 1;       /* because the terminating \0 also counts */
    size_t len, olen;
    char buf[30];       /* buffer for converting longs and ints */

    char *s;
    char c;

    p = format;
    q = str;
    while (p && *p) {
      if ((*p == '%') && !flag) {
          /* swallow the %, switch to % mode and initialize */
          lflag = 0;
          flag = 1;
          asign = 0; /* can be 0, '+' or later ' ' (' ' is unimplemented) */
          fill = ' ';
          width = 0;
          p++;
      } else if (flag) {
          /* % mode */
          switch (*p) {
          case 's': case 'm': {
                if (*p == 's')
                  s = va_arg(ap, char *);
                else
                  s = strerror(errno);
                olen = len = strlen(s);
                if (len > (n - i))
                  len = n - i;
                *q = '\0';
                strncat(q, s, len);
                p++;
                q += len;
                i += olen;
                flag = 0;
                break;
            }
          case 'u':{
                unsigned long u;
                if (lflag) {
                  u = va_arg(ap, unsigned long);
                } else {
                  u = (unsigned long)va_arg(ap, unsigned int);
                }
                fmtu(buf, u);
                goto printdec;
            }
          case 'd': case 'i': {
                long l;
                if (lflag) {
                  l = va_arg(ap, long);
                } else {
                  l = (long)va_arg(ap, int);
                }
                fmts(buf, l, asign);
printdec:
                olen = len = strlen(buf);
                if (width) {
                  int off = !!asign;
                  if (len < width) {
                      switch (fill) {
                        case ' ':
                            memmove(buf + width - len, buf, len + 1);
                            memset(buf, fill, width - len);
                            break;
                        case '0':
                            memmove(buf + off + width - len, buf + off, len + 1 - off);
                            memset(buf + off, fill, width - len);
                            break;
                        default:
                            abort();
                      }
                   }
                   olen = len = strlen(buf);
                }
                if (len > (n - i))
                  len = n - i;
                *q = '\0';
                strncat(q, buf, len);
                q += len;
                i += olen;
                flag = 0;
                p++;
                break;
            }
          case 'l':{
                /* next argument will be long */
                lflag = 1;
                p++;
                break;
            }
          case 'c':{
                c = va_arg(ap, int);
                flag = 0;
                if (i < n)
                  *q++ = c;
                i++;
                p++;
                break;
            }
          case '%':{
                flag = 0;
                if (i < n)
                  *q++ = *p++;
                i++;
                break;
            }
          case '0':
                 if (fill == ' ' && width == 0)
                   fill='0';
                 else
                   width *= 10;
                 p++;
                 break;
          case '1': case '2': case '3': case '4': case '5':
          case '6': case '7': case '8': case '9':
                 width = width * 10 + *p - '0';
                 p++;
                 break;
          case '+':
                 asign = '+';
                 p++;
                 break;
          default:
                 abort();
                 break;
          }
      } else {
          if (i < n) {
            *q++ = *p;
          }
          p++;
          i++;
      }
    }
    va_end(ap);
    *q = '\0';
    return (i - 1);
}

int
ln_snprintf(char *str, size_t n, const char *format, ...)
{
    int r;
    va_list ap;

    va_start(ap, format);
    r = ln_vsnprintf(str, n, format, ap);
    va_end(ap);
    return r;
}

#endif

Generated by  Doxygen 1.6.0   Back to index