/*
从rotpV3平台拷贝过来的函数，考虑到cpu特性和应用，没有全部拷贝过来，只拷贝了常用的几个函数
** Description: 字符串相关的工具函数
**
*/

#include <stdarg.h>
#include <ctype.h>
#include "stdio.h"
#include "string.h"
#include "macro_common.h"

/*lint -save -e713 -e715 -e732 -e737 -e415 -e661 -e530*/
static void dopr (char *buffer, size_t maxlen, const char *format,
                  va_list args);
static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
		    const char *value, int flags, int min, int max);
static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
		    long value, int base, int min, int max, int flags);
static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );

/*
 * dopr(): poor man's version of doprintf
 */

/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS   1
#define DP_S_MIN     2
#define DP_S_DOT     3
#define DP_S_MAX     4
#define DP_S_MOD     5
#define DP_S_CONV    6
#define DP_S_DONE    7

/* format flags - Bits */
#define DP_F_MINUS 	(1 << 0)
#define DP_F_PLUS  	(1 << 1)
#define DP_F_SPACE 	(1 << 2)
#define DP_F_NUM   	(1 << 3)
#define DP_F_ZERO  	(1 << 4)
#define DP_F_UP    	(1 << 5)
#define DP_F_UNSIGNED 	(1 << 6)

/* Conversion Flags */
#define DP_C_SHORT   1
#define DP_C_LONG    2

#define char_to_int(p) (p - '0')
#define chisdigit(ch) (((ch)>='0')&&((ch)<='9'))
static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
{
	char ch;
	long value;
	char *strvalue;
	int min;
	int max;
	int state;
	int flags;
	int cflags;
	size_t currlen;

	state = DP_S_DEFAULT;
	currlen = flags = cflags = min = 0;
	max = -1;
	ch = *format++;
	while (state != DP_S_DONE) 
	{
	  	if ((ch == '\0') || (currlen >= maxlen))
	  	{
			state = DP_S_DONE;
	  	}
	    switch(state) 
		{
		    case DP_S_DEFAULT:
				if (ch == '%')
				{
					state = DP_S_FLAGS;
				}
				else
				{
					dopr_outch (buffer, &currlen, maxlen, ch);
				}
				ch = *format++;
				
				break;
		    case DP_S_FLAGS:
				switch (ch) 
				{
					case '-':
						flags |= DP_F_MINUS;
						ch = *format++;
						break;
					case '+':
						flags |= DP_F_PLUS;
						ch = *format++;
						break;
					case ' ':
						flags |= DP_F_SPACE;
						ch = *format++;
						break;
					case '#':
						flags |= DP_F_NUM;
						ch = *format++;
						break;
					case '0':
						flags |= DP_F_ZERO;
						ch = *format++;
						break;
					default:
						state = DP_S_MIN;
						break;
				}
				break;
		    case DP_S_MIN:
				if(chisdigit(ch))
				{
					min = 10*min + char_to_int (ch);
					ch = *format++;
				}
				else if (ch == '*') 
				{
					min = va_arg (args, int);
					ch = *format++;
					state = DP_S_DOT;
				}
				else 
				{
					state = DP_S_DOT;
				}
				break;
		    case DP_S_DOT:
				if (ch == '.') 
				{
					state = DP_S_MAX;
					ch = *format++;
				} 
				else 
				{
					state = DP_S_MOD;
				}
				break;
		    case DP_S_MAX:
				if (chisdigit((int) ch)) 
				{
					if (max < 0)
					{
						max = 0;
					}
					max = 10*max + char_to_int (ch);
					ch = *format++;
				} 
				else if(ch == '*') 
				{
					max = va_arg (args, int);
					ch = *format++;
					state = DP_S_MOD;
				} 
				else 
				{
					state = DP_S_MOD;
				}
				break;
			case DP_S_MOD:
				/* Currently, we don't support Long Long, bummer */
				switch (ch) 
				{
					case 'h':
						cflags = DP_C_SHORT;
						ch = *format++;
						break;
					case 'l':
						cflags = DP_C_LONG;
						ch = *format++;
						break;
					default:
						break;
				}
				state = DP_S_CONV;
				break;
			case DP_S_CONV:
				switch (ch) 
				{
					case 'd':
					case 'i':
						if (cflags == DP_C_SHORT)
						{
#if ( defined(OTP_COMPILER) && OTP_COMPILER == TORNADO_2_2 )
							value = va_arg (args, int);
#else
							value = va_arg (args, int);
#endif
						}
						else if (cflags == DP_C_LONG)
						{
							value = va_arg (args, long int);
						}
						else
						{
							value = va_arg (args, int);
						}
						fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
						break;
					case 'o':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
						{
#if ( defined(OTP_COMPILER) && OTP_COMPILER == TORNADO_2_2 )
							value = va_arg (args, int);
#else
							value = va_arg (args, unsigned int);
#endif
						}
						else if (cflags == DP_C_LONG)
						{
							value = va_arg (args, unsigned long int);
						}
						else
						{
							value = va_arg (args, unsigned int);
						}
						fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
						break;
					case 'u':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
						{
#if ( defined(OTP_COMPILER) && OTP_COMPILER == TORNADO_2_2 )
							value = va_arg (args, int);
#else
							 value = va_arg (args, unsigned int);
#endif
						}
						else if (cflags == DP_C_LONG)
						{
							value = va_arg (args, unsigned long int);
						}
						else
						{
							value = va_arg (args, unsigned int);
						}
						fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
						break;
					/*lint -save -e616 -e825*/	
					case 'X':
						flags |= DP_F_UP;
					case 'x':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
						{
#if ( defined(OTP_COMPILER) && OTP_COMPILER == TORNADO_2_2 )
							value = va_arg (args, int);
#else
							value = va_arg (args, unsigned int);
#endif
						}
						else if (cflags == DP_C_LONG)
						{
							value = va_arg (args, unsigned long int);
						}
						else
						{
							value = va_arg (args, unsigned int);
						}
						fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
						break;
					/*lint -restore*/
					case 'c':
						dopr_outch (buffer, &currlen, maxlen,(char) va_arg (args, int));
						break;
					case 's':
						strvalue = va_arg (args, char *);
						if (max < 0)
						{
							max = maxlen; /* ie, no max */
						}
						fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
						break;
					case 'p':
						strvalue = va_arg (args, void *);
						fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
						break;
					case 'n':
						if (cflags == DP_C_SHORT) 
						{
							short int *num;
							num = va_arg (args, short int *);
							*num = currlen;

						} 
						else if (cflags == DP_C_LONG) 
						{
							long int *num;
							num = va_arg (args, long int *);
							*num = currlen;
						} 
						else 
						{
							int *num;
							num = va_arg (args, int *);
							*num = currlen;
						}
						break;
					case '%':
						dopr_outch (buffer, &currlen, maxlen, ch);
						break;
					case 'w':
						/* not supported yet, treat as next char */
						ch = *format++;
						break;
					default:
						/* Unknown, skip */
						break;
				}
				ch = *format++;
				state = DP_S_DEFAULT;
				flags = cflags = min = 0;
				max = -1;
				break;
			case DP_S_DONE:
				break;
			default:			/* hmm? */
				break;			/* some picky compilers need this */
		}
	}
	if (currlen < maxlen - 1)
	{
		buffer[currlen] = '\0';
	}
	else
	{
		buffer[maxlen - 1] = '\0';
	}
}

static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
		    const char *value, int flags, int min, int max)
{
  int padlen;			/* amount to pad */
  int cnt = 0;

  if (value == 0)
	value = "<NULL>";

  /*lint -save -e64*/
  padlen = min - strlen(value);
  /*lint -restore*/
  if (padlen < 0)
    padlen = 0;
  if (flags & DP_F_MINUS)
    padlen = -padlen; /* Left Justify */

  while ((padlen > 0) && (cnt < max)) {
    dopr_outch (buffer, currlen, maxlen, ' ');
    --padlen;
    ++cnt;
  }
  while (*value && (cnt < max)) {
    dopr_outch (buffer, currlen, maxlen, *value++);
    ++cnt;
  }
  while ((padlen < 0) && (cnt < max)) {
    dopr_outch (buffer, currlen, maxlen, ' ');
    ++padlen;
    ++cnt;
  }
}

/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */

static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
		    long value, int base, int min, int max, int flags)
{
  char signvalue = 0;
  unsigned long uvalue;
  char convert[20];
  int place = 0;
  int spadlen = 0; /* amount to space pad */
  int zpadlen = 0; /* amount to zero pad */
  char *chars = ((flags & DP_F_UP)
		 ? "0123456789ABCDEF"
		 : "0123456789abcdef");

  if (max < 0)
    max = 0;

  uvalue = value;

  if (!(flags & DP_F_UNSIGNED)) {
    if (value < 0) {
      signvalue = '-';
      uvalue = -value;
    } else if (flags & DP_F_PLUS) {	/* Do a sign (+/i) */
      signvalue = '+';
    } else if (flags & DP_F_SPACE) {
      signvalue = ' ';
    }
  }

  do {
    convert[place++] = chars[uvalue % (unsigned) base];
    uvalue = (uvalue / (unsigned)base );
  } while(uvalue && (place < 20));
  if (place == 20)
    place--;
  convert[place] = 0;

  zpadlen = max - place;
  spadlen = (min - MAX (max, place)) - (signvalue ? 1 : 0);
  if (zpadlen < 0)
    zpadlen = 0;
  if (spadlen < 0)
    spadlen = 0;
  if (flags & DP_F_ZERO) {
    zpadlen = MAX(zpadlen, spadlen);
    spadlen = 0;
  }
  if (flags & DP_F_MINUS)
    spadlen = -spadlen; /* Left Justifty */

  /* Spaces */
  while (spadlen > 0) {
    dopr_outch (buffer, currlen, maxlen, ' ');
    --spadlen;
  }

  /* Sign */
  if (signvalue)
    dopr_outch (buffer, currlen, maxlen, signvalue);

  /* Zeros */
  if (zpadlen > 0) {
    while (zpadlen > 0) {
      dopr_outch (buffer, currlen, maxlen, '0');
      --zpadlen;
    }
  }

  /* Digits */
  while (place > 0)
    dopr_outch (buffer, currlen, maxlen, convert[--place]);

  /* Left Justified spaces */
  while (spadlen < 0) {
    dopr_outch (buffer, currlen, maxlen, ' ');
    ++spadlen;
  }
}

static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
{
  if (*currlen < maxlen)
    buffer[(*currlen)++] = c;
}

/*
	王炯从snprintf.c拷贝过来
*/
unsigned int otp_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
	if(count==0)
	{
		return 0;
	}
	
  str[0] = 0;
  dopr(str, count, fmt, args);
  /*lint -save -e64*/
  return(strlen(str));
  /*lint -restore*/
}


/*
	王炯从snprintf.c拷贝过来
	向str中打印字符串，最多只打印count-1个字符。
	如果打印了count-1个字符，则第count个字符为'\0'。
*/
unsigned int otp_snprintf (char *str, unsigned int count, const char *fmt, ...)
{
	int len;
  va_list ap;
  
	if(count==0 || !str )
	{
		return 0;
	}
	
  va_start(ap, fmt);
  len = otp_vsnprintf(str, count, fmt, ap);
  va_end(ap);
  
  return len;
}

/*
	把输入的字符串转换成小写。
	该函数会转换str中的所有大写字母为小写，非大写字母保持不变。
	遇到'\0'会结束转换,达到了缓冲区长度count也会结束转换
	输入参数:
		str,	需要转换的字符串指针，
		count,	str的缓冲区长度。
	返回
		str的值
*/
char * otp_strtolower (char *str, int count)
{
	int i=0;
	if( !str )
	{
		return str;
	}
	while( i<count && str[i]!='\0' )
	{
		str[i]= (char)tolower(str[i]);
		i++;
	}
	return str;
}

/*
	把输入的字符串转换成大写。
	该函数会转换str中的所有小写字母为大写，非小写字母保持不变。
	遇到'\0'会结束转换,达到了缓冲区长度count也会结束转换
	输入参数:
		str,	需要转换的字符串指针，
		count,	str的缓冲区长度。
	返回
		str的值
*/
char * otp_strtoupper (char *str, int count)
{
	int i=0;
	if( !str )
	{
		return str;
	}
	while( i<count && str[i]!='\0' )
	{
		str[i]= (char)toupper(str[i]);
		i++;
	}
	return str;
}

/*lint -restore*/



