Newer
Older
Import / research / embedded / src / library / corelayer.c
/*
   Copyright (c) 2007-2013, John Ryland
 */
#include <oslayer.h>
#include <corelayer.h>


void memCopy(char *dst, const char *src, int len)
{
    int i;
    if (dst && src) {
        // TODO: Could step this up to do 64bits at a time
        if (((long)dst & 3) == ((long)src & 3)) {
            // Bring dst and src in to 4 byte alignment
            while (((long)dst & 3) != 0 && len) {
                *dst = *src;
                dst++;
                src++;
                len--;
            }
            for (i = 0; i < len/4; i++)
                ((int*)dst)[i] = ((int*)src)[i];
            for (i = i*4; i < len; i++)          // addresses for both dst and src in general
                dst[i] = src[i];
        } else {
            for (i = 0; i < len; i++)
                dst[i] = src[i];
        }
    }
}


void* memcpy(char *dst, const char *src, int len)
{
  memCopy(dst, src, len);
  return dst;
}


// Some GCC versions appear to generate code which calls this
void* memmove(char *dst, const char *src, int len)
{
  int i;
  if (dst == src)
    return dst;
  if (dst > src) {
    memCopy(dst, src, len);
  } else {
	if (dst && src) {
      // TODO: Could optimize this to copy more than a byte at a time
      for (i = 0; i < len; i++)
        dst[len-1-i] = src[len-1-i];
    }
  }
  strPrint("memmove called!\n");
  return 0;
}


int strCompare(const char *str1, const char *str2)
{
	int i = 0;
	if (!str1 || !str2)
		return -1;
	while (str1[i] && str2[i]) {
		if (str1[i] != str2[i])
			return str1[i] - str2[i];
		i++;
	}
	return str1[i] - str2[i];
}


int strLength(const char *str)
{
	int i = 0;
	if (str)
		while (str[i])
			i++;
	return i;
}


// GCC required code
unsigned __udivmodsi4(unsigned num, unsigned den, unsigned *rem_p)
{
	unsigned quot = 0, qbit = 1;

	if ( den == 0 ) {
		strPrint("Divide by 0\n");
		//__divide_error();
		return 0;
	}

#define UNTESTED_CODE_PATH
#ifdef UNTESTED_CODE_PATH
	// XXX we are assuming den is 32bits here
	unsigned int shift;
	qbit = 0;
	shift  = (den & 0xffff0000) ? 0 : 16; den <<= shift; qbit |= shift;
	shift  = (den & 0xff000000) ? 0 :  8; den <<= shift; qbit |= shift;
	shift  = (den & 0xc0000000) ? 0 :  2; den <<= shift; qbit |= shift;
	shift  = (den & 0x80000000) ? 0 :  1; den <<= shift; qbit |= shift;
	qbit = 1 << qbit;
	
#else
	// No assumption about den size, but assuming 2s complement
	while ( (int)den >= 0 ) {
		den <<= 1;
		qbit <<= 1;
	}
#endif

	while ( qbit ) {
		if ( den <= num ) {
			num -= den;
			quot += qbit;
		}
		den >>= 1;
		qbit >>= 1;
	}

	if ( rem_p )
		*rem_p = num;

	return quot;
}


// GCC required code
unsigned __udivsi3(unsigned num, unsigned den)
{
	return __udivmodsi4(num, den, 0);
}


// GCC required code
unsigned __umodsi3(unsigned num, unsigned den)
{
	unsigned v;
	(void) __udivmodsi4(num, den, &v);
	return v;
}


// GCC required code
void __stack_chk_fail(void)
{
	sysExit(-1);
}


// GCC required code (on MacOSX)
void __stack_chk_guard(void)
{
    // No idea what this function ought to do
}


// Bad, not reentrant
// What if base is > 16 ?
char strTmpBuf[64];
char *strInteger(unsigned num, unsigned base)
{
	const char *lookup = "0123456789ABCDEF";
	int i = 1;
	strTmpBuf[63] = 0;
	do {
		strTmpBuf[63-i] = lookup[num % base];
		num /= base;
		i++;
	} while (num);
	return &(strTmpBuf[63-i+1]);
}


void strPrint(const char *str)
{
	//if (str)
	//	fsWrite(STDOUT_FILENO, str, strLength(str));

	if (str) {
		char strBuf[1024];
		int i = 0;
		while (*str) {
			if ( *str == '\n' )
				strBuf[i++] = '\r';
			strBuf[i++] = *str++;
			if ( i == 1022 )
				fsWrite(STDOUT_FILENO, strBuf, 1024), i = 0;
		}
		fsWrite(STDOUT_FILENO, strBuf, i);
	}
}


void strNPrint(const char *str, int n)
{
	//if (str && n)
	//	fsWrite(STDOUT_FILENO, str, n);

	if (str && n) {
		char strBuf[1024];
		int i = 0;
		while (n--) {
			if ( *str == '\n' )
				strBuf[i++] = '\r';
			strBuf[i++] = *str++;
			if ( i == 1022 )
				fsWrite(STDOUT_FILENO, strBuf, 1024), i = 0;
		}
		fsWrite(STDOUT_FILENO, strBuf, i);
	}
}


/*
	// Currently supported format identifiers

		%d %i     Decimal signed integer.
		%o        Octal integer.
		%x %X     Hex integer.
		%u        Unsigned integer.
		%c        Character.
		%s        String. See below.
		//    %f        double
		//    %e %E     double.
		//    %g %G     double.
		%p        pointer.
		%n        Number of characters written by this printf.
		No argument expected.
		%%        %. No argument expected.
 */
#define PRINTF_BUF_SIZE	    2048


#ifdef ARCH_MacOSX64
#  include <stdarg.h>
#  define my_va_list                    va_list
#  define my_va_start(args, first)      va_start(args, first)
#  define my_va_arg(args, type)         va_arg(args, type)
#else
#  define my_va_list                    char*
#  define my_va_start(args, first)      args = (char*)&first + sizeof(first)
#  define my_va_arg(args, type)         *(type*)(args); args += sizeof(type)
#endif


char outputBuffer[PRINTF_BUF_SIZE]; // For some reason this needs to be out here
// Some how when it is on the stack it goes out of scope before it should. Weird
void strPrintf(const char *str, ...)
{
	int i = 0, x = 0;
    my_va_list ap;
    my_va_start(ap, str);

	while (str[i]) {
		if (str[i] == '%') {
			i++;
			if (str[i] == '%') {
				outputBuffer[x] = str[i];
				x++;
			} else if (str[i] == 'i' || str[i] == 'd' || str[i] == 'u' || str[i] == 'o' ||
					str[i] == 'x' || str[i] == 'X' || str[i] == 'p' || str[i] == 'n' ||
					str[i] == 's')
			{
				int num, base = 10, t = 0;
				char *tmp;
				if (str[i] != 's') {
					if (str[i] == 'n') {
						num = x;
					} else {
						num = my_va_arg(ap, int);
					}
					if (str[i] == 'o') {
						outputBuffer[x] = '0'; x++;
						base = 8;
					}
					if (str[i] == 'x' || str[i] == 'X') {
						outputBuffer[x] = '0'; x++;
						outputBuffer[x] = str[i]; x++;
						base = 16;
					}
					if (str[i] == 'p') {
						outputBuffer[x] = '('; x++;
						outputBuffer[x] = '0'; x++;
						outputBuffer[x] = 'X'; x++;
						base = 16;
					}
					tmp = strInteger(num, base);
				} else {
				    tmp = my_va_arg(ap, char*);
				}
				while (tmp[t]) {
					outputBuffer[x] = tmp[t];
					t++;
					x++;
				}
				if (str[i] == 'p') {
					outputBuffer[x] = ')'; x++;
				}
			} else if (str[i] == 'c') {
				int ch = my_va_arg(ap, int);
				outputBuffer[x] = (char)ch;
				x++;
			} else {
				// unrecognized / unsupported format identifier
			}
		} else {
			outputBuffer[x] = str[i];
			x++;
		}

		// Flush what is buffered so far
		if ( x >= (PRINTF_BUF_SIZE / 2) ) {
			strNPrint(outputBuffer, x);
			x = 0;
		}

		i++;
	}

	strNPrint(outputBuffer, x);
}