view cos/kernel/snprintf.c @ 407:9eb1fc6aad6c

Minor improvements
author Windel Bouwman
date Fri, 20 Feb 2015 15:47:54 +0100
parents 8012221dd740
children
line wrap: on
line source

/*
 * snprintf.c
 */
#include "kernel.h"

/*
 * NOTE! This ctype does not handle EOF like the standard C
 * library is required to.
 */

#define _U	0x01	/* upper */
#define _L	0x02	/* lower */
#define _D	0x04	/* digit */
#define _C	0x08	/* cntrl */
#define _P	0x10	/* punct */
#define _S	0x20	/* white space (space/lf/tab) */
#define _X	0x40	/* hex digit */
#define _SP	0x80	/* hard space (0x20) */

uint8_t _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */

#define __ismask(x) (_ctype[(int)(uint8_t)(x)])

#define isalnum(c)	((__ismask(c)&(_U|_L|_D)) != 0)
#define isalpha(c)	((__ismask(c)&(_U|_L)) != 0)
#define iscntrl(c)	((__ismask(c)&(_C)) != 0)
#define isdigit(c)	((__ismask(c)&(_D)) != 0)
#define isgraph(c)	((__ismask(c)&(_P|_U|_L|_D)) != 0)
#define islower(c)	((__ismask(c)&(_L)) != 0)
#define isprint(c)	((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
#define ispunct(c)	((__ismask(c)&(_P)) != 0)
#define isspace(c)	((__ismask(c)&(_S)) != 0)
#define isupper(c)	((__ismask(c)&(_U)) != 0)
#define isxdigit(c)	((__ismask(c)&(_D|_X)) != 0)

#define isascii(c) (((unsigned char)(c))<=0x7f)
#define toascii(c) (((unsigned char)(c))&0x7f)

static inline uint8_t tolower(uint8_t c)
{
	if (isupper(c))
		c += 'a'-'A';
	return c;
}

static inline uint8_t toupper(uint8_t c)
{
	if (islower(c))
		c -= 'a'-'A';
	return c;
}

#define MORE_THAN_YOU_WANT	1<<30
#define MAX_STDOUT_CHARS	255

static char hexmap[] = {
    '0', '1', '2', '3', '4', '5', '6', '7',
    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};

/* string print function. Supports the formats:
  %p, %x: 64 bits hex number
  %d: signed integer
  %u: unsigned integer
*/
void va_snprintf(char *b, int l, const char *fmt, va_list pvar)
{
   int i;
   int64_t s64;
   uint64_t u64;
   char *t;
   char d[20]; // For storing the decimal value in chars.

   if ((fmt == 0) || (b == 0) || (l < 1))
   {
	   return;
   }

   while ((l > 0) && (*fmt != 0))
   {
      if (*fmt == '%') 
      {
         if ((--l) == 0)
         {
            break;
         }

         fmt++;
         switch (*fmt) 
         {
            case 's':		/* string */
               t = va_arg(pvar, char *);
               while ((l > 0) && (*t != 0))
               {
                   *b++ = *t++;
                   l--;
               }
               break;

            case 'c':		/* single character */
               *b++ = (char)va_arg(pvar, int);
               l--;
               break;

            case 'x':
            case 'p':
               /* Pointer and hex uint64_t */
               /* 16 digit, unsigned 64-bit hex integer */
               if (l < 18) 
               {
                  l = 0;
                  break;
               }

               *b++ = '0';
               *b++ = 'x';

               u64 = va_arg(pvar, uint64_t);
               for (i = 15; i >= 0; i--)
               {
                  b[i] = hexmap[u64 & 0x0f];
                  u64 >>= 4;
               }
               b += 16;
               l -= 16;
               break;

            case 'd':		/* signed integer */
               s64 = va_arg(pvar, int);
               if (s64 < 0) 
               {
                  u64 = (uint64_t)(-s64);
                  *b++ = '-';
                  if ((--l) == 0)
                  {
                     break;
                  }
               }
               else 
               {
                  u64 = s64;
               }
               goto u2;

            case 'u':		/* unsigned integer */
               u64 = va_arg(pvar, unsigned int);
               u2:
               i = 19;
               do 
               {
                   d[i] = (u64 % 10) + '0';
                   u64 /= 10;
                   i--;
               }
               while ((u64 != 0) && (i >= 0));

               // Now print the characters:
               while (++i < 20)
               {
                  *b++ = d[i];
                  if ((--l) == 0)
                  {
                     break;
                  }
               }
               break;

            default:
               *b++ = *fmt;
         }
      } 
      else 
      {
          *b++ = *fmt;
          l--;
      }

      fmt++;
   }

   *b = 0; // Add a 0 terminate
}

void snprintf(char *str, int len, char *fmt, ...)
{
    va_list pvar;
    va_start(pvar, fmt);
    va_snprintf(str, len, fmt, pvar);
    va_end(pvar);
}

void
printf(const char* fmt, ...)
{
    static char buf[MAX_STDOUT_CHARS];

    va_list args;
    va_start(args, fmt);
    va_snprintf(buf, MAX_STDOUT_CHARS, fmt, args);
    va_end(args);

    print_string(buf);
}