* Common Library Functions
*/
#include <acess.h>
+#include <hal_proc.h>
// === CONSTANTS ===
#define RANDOM_SEED 0xACE55052
int WriteUTF8(Uint8 *str, Uint32 Val);
int DivUp(int num, int dem);
Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
+#endif
+void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
+#if 0
int rand(void);
int CheckString(char *String);
EXPORT(UnHex);
EXPORT(SwapEndian16);
EXPORT(SwapEndian32);
+EXPORT(memmove);
// === CODE ===
/**
{
char tmpBuf[64+1];
int pos=0, i;
+ Uint64 rem;
// Sanity check
if(!buf) return;
// Convert
while(num > base-1) {
- tmpBuf[pos] = cUCDIGITS[ num % base ];
- num /= (Uint)base; // Shift `num` right 1 digit
+ num = DivMod64U(num, base, &rem); // Shift `num` and get remainder
+ tmpBuf[pos] = cUCDIGITS[ rem ];
pos++;
}
- tmpBuf[pos++] = cUCDIGITS[ num % base ]; // Last digit of `num`
+ tmpBuf[pos++] = cUCDIGITS[ num ]; // Last digit of `num`
// Put in reverse
i = 0;
/**
* \brief Append a character the the vsnprintf output
*/
-#define PUTCH(c) do{\
- char ch=(c);\
- if(pos==__maxlen){return pos;}\
- if(__s){__s[pos++]=ch;}else{pos++;}\
- }while(0)
+#define PUTCH(c) _putch(c)
#define GETVAL() do {\
if(isLongLong) val = va_arg(args, Uint64);\
else val = va_arg(args, unsigned int);\
// Flags
int bPadLeft = 0;
- //Log("vsnprintf: (__s=%p, __maxlen=%i, __format='%s', ...)", __s, __maxlen, __format);
-
+ auto void _putch(char ch);
+
+ void _putch(char ch)
+ {
+ if(pos < __maxlen)
+ {
+ if(__s) __s[pos] = ch;
+ pos ++;
+ }
+ }
+
while((c = *__format++) != 0)
{
// Non control character
if(c != '%') { PUTCH(c); continue; }
-
+
c = *__format++;
- //Log("pos = %i", pos);
+ if(c == '\0') break;
// Literal %
if(c == '%') { PUTCH('%'); continue; }
if(c == 'p') {
Uint ptr = va_arg(args, Uint);
PUTCH('*'); PUTCH('0'); PUTCH('x');
- itoa(tmpBuf, ptr, 16, BITS/4, '0');
- p = tmpBuf;
- goto printString;
+ for( len = BITS/4; len --; )
+ PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
+ continue ;
}
// - Padding Side Flag
}
itoa(tmpBuf, val, 10, minSize, pad);
goto printString;
- case 'u':
+ case 'u': // Unsigned
GETVAL();
itoa(tmpBuf, val, 10, minSize, pad);
goto printString;
- case 'X':
+ case 'P': // Physical Address
+ PUTCH('0');
+ PUTCH('x');
+ if(sizeof(tPAddr) > 4) isLongLong = 1;
+ GETVAL();
+ itoa(tmpBuf, val, 16, minSize, pad);
+ goto printString;
+ case 'X': // Hex
if(BITS == 64)
isLongLong = 1; // TODO: Handle non-x86 64-bit archs
GETVAL();
itoa(tmpBuf, val, 16, minSize, pad);
goto printString;
- case 'x':
+ case 'x': // Lower case hex
GETVAL();
itoa(tmpBuf, val, 16, minSize, pad);
goto printString;
- case 'o':
+ case 'o': // Octal
GETVAL();
itoa(tmpBuf, val, 8, minSize, pad);
goto printString;
// String - Null Terminated Array
case 's':
p = va_arg(args, char*); // Get Argument
- if( !CheckString(p) ) p = "(inval)"; // Avoid #PFs
+ if( !p || !CheckString(p) ) p = "(inval)"; // Avoid #PFs
printString:
if(!p) p = "(null)";
len = strlen(p);
* \brief Copy a string to a new location
* \note Copies at most `max` chars
*/
-char *strncpy(char *__str1, const char *__str2, size_t max)
+char *strncpy(char *__str1, const char *__str2, size_t __max)
{
- while(*__str2 && max-- >= 1)
+ while(*__str2 && __max-- >= 1)
*__str1++ = *__str2++;
- if(max)
+ if(__max)
*__str1 = '\0'; // Terminate String
return __str1;
}
{
// ASCII
if( Val < 128 ) {
- *str = Val;
+ if( str ) {
+ *str = Val;
+ }
return 1;
}
// Two Byte
if( Val < 0x8000 ) {
- *str = 0xC0 | (Val >> 6);
- str ++;
- *str = 0x80 | (Val & 0x3F);
+ if( str ) {
+ *str++ = 0xC0 | (Val >> 6);
+ *str++ = 0x80 | (Val & 0x3F);
+ }
return 2;
}
// Three Byte
if( Val < 0x10000 ) {
- *str = 0xE0 | (Val >> 12);
- str ++;
- *str = 0x80 | ((Val >> 6) & 0x3F);
- str ++;
- *str = 0x80 | (Val & 0x3F);
+ if( str ) {
+ *str++ = 0xE0 | (Val >> 12);
+ *str++ = 0x80 | ((Val >> 6) & 0x3F);
+ *str++ = 0x80 | (Val & 0x3F);
+ }
return 3;
}
// Four Byte
if( Val < 0x110000 ) {
- *str = 0xF0 | (Val >> 18);
- str ++;
- *str = 0x80 | ((Val >> 12) & 0x3F);
- str ++;
- *str = 0x80 | ((Val >> 6) & 0x3F);
- str ++;
- *str = 0x80 | (Val & 0x3F);
+ if( str ) {
+ *str++ = 0xF0 | (Val >> 18);
+ *str++ = 0x80 | ((Val >> 12) & 0x3F);
+ *str++ = 0x80 | ((Val >> 6) & 0x3F);
+ *str++ = 0x80 | (Val & 0x3F);
+ }
return 4;
}
* \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
* \brief Converts a date into an Acess Timestamp
*/
-Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
+Sint64 timestamp(int sec, int min, int hrs, int day, int month, int year)
{
+ int is_leap;
Sint64 stamp;
- stamp = sec;
- stamp += mins*60;
- stamp += hrs*3600;
-
- stamp += day*3600*24;
- stamp += month*DAYS_BEFORE[month]*3600*24;
- if( (
- ((year&3) == 0 || year%100 != 0)
- || (year%100 == 0 && ((year/100)&3) == 0)
- ) && month > 1) // Leap year and after feb
- stamp += 3600*24;
+
+ if( !(0 <= sec && sec < 60) ) return 0;
+ if( !(0 <= min && min < 60) ) return 0;
+ if( !(0 <= hrs && hrs < 24) ) return 0;
+ if( !(0 <= day && day < 31) ) return 0;
+ if( !(0 <= month && month < 12) ) return 0;
+
+ stamp = DAYS_BEFORE[month] + day;
+
+ // Every 4 years
+ // - every 100 years
+ // + every 400 years
+ is_leap = (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0);
+ ASSERT(is_leap == 0 || is_leap == 1);
+
+ if( is_leap && month > 1 ) // Leap year and after feb
+ stamp += 1;
+
+ // Get seconds before the first of specified year
+ year -= 2000; // Base off Y2K
+ // base year days + total leap year days
+ stamp += year*365 + (year/400) - (year/100) + (year/4);
- stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24; // Four Year Segments
- stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
+ stamp *= 3600*24;
stamp += UNIX_TO_2K;
+ stamp += sec;
+ stamp += min*60;
+ stamp += hrs*3600;
return stamp * 1000;
}
+void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms)
+{
+ int is_leap = 0, i;
+
+ auto Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R);
+
+ Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R)
+ {
+ int sign = (N < 0) != (D < 0);
+ if(N < 0) N = -N;
+ if(D < 0) D = -D;
+ if(sign)
+ return -DivMod64U(N, D, (Uint64*)R);
+ else
+ return DivMod64U(N, D, (Uint64*)R);
+ }
+
+ // Get time
+ // TODO: Leap-seconds?
+ {
+ Sint64 rem;
+ TS = DivMod64( TS, 1000, &rem );
+ *ms = rem;
+ TS = DivMod64( TS, 60, &rem );
+ *sec = rem;
+ TS = DivMod64( TS, 60, &rem );
+ *mins = rem;
+ TS = DivMod64( TS, 24, &rem );
+ *hrs = rem;
+ }
+
+ // Adjust to Y2K
+ TS -= UNIX_TO_2K/(3600*24);
+
+ // Year (400 yr blocks) - (400/4-3) leap years
+ *year = 400 * DivMod64( TS, 365*400 + (400/4-3), &TS );
+ if( TS < 366 ) // First year in 400 is a leap
+ is_leap = 1;
+ else
+ {
+ // 100 yr blocks - 100/4-1 leap years
+ *year += 100 * DivMod64( TS, 365*100 + (100/4-1), &TS );
+ if( TS < 366 ) // First year in 100 isn't a leap
+ is_leap = 0;
+ else
+ {
+ *year += 4 * DivMod64( TS, 365*4 + 1, &TS );
+ if( TS < 366 ) // First year in 4 is a leap
+ is_leap = 1;
+ else
+ {
+ *year += DivMod64( TS, 356, &TS );
+ }
+ }
+ }
+ *year += 2000;
+
+ ASSERT(TS >= 0);
+
+ *day = 0;
+ // Month (if after the first of march, which is 29 Feb in a leap year)
+ if( is_leap && TS > DAYS_BEFORE[2] ) {
+ TS -= 1; // Shifts 29 Feb to 28 Feb
+ *day = 1;
+ }
+ // Get what month it is
+ for( i = 0; i < 12; i ++ ) {
+ if( TS < DAYS_BEFORE[i] )
+ break;
+ }
+ *month = i - 1;
+ // Get day
+ TS -= DAYS_BEFORE[i-1];
+ *day += TS; // Plus offset from leap handling above
+}
+
/**
* \fn int rand()
* \brief Pseudo random number generator
*/
int CheckString(const char *String)
{
- if( !MM_GetPhysAddr( (tVAddr)String ) )
+ tVAddr addr;
+ int bUser;
+
+ addr = (tVAddr)String;
+
+ if( !MM_GetPhysAddr( addr ) )
return 0;
// Check 1st page
- if( MM_IsUser( (tVAddr)String ) )
+ bUser = MM_IsUser( addr );
+
+ while( *(char*)addr )
{
- // Traverse String
- while( *String )
+ if( (addr & (PAGE_SIZE-1)) == 0 )
{
- if( !MM_IsUser( (tVAddr)String ) )
+ if(bUser && !MM_IsUser(addr) )
return 0;
- // Increment string pointer
- String ++;
- }
- return 1;
- }
- else if( MM_GetPhysAddr( (tVAddr)String ) )
- {
- // Traverse String
- while( *String )
- {
- if( !MM_GetPhysAddr( (tVAddr)String ) )
+ if(!bUser && !MM_GetPhysAddr(addr) )
return 0;
- // Increment string pointer
- String ++;
}
- return 1;
+ addr ++;
}
- return 0;
+ return 1;
}
/**
* \brief Check if a sized memory region is valid memory
+ * \return Boolean success
*/
int CheckMem(const void *Mem, int NumBytes)
{
- tVAddr addr = (tVAddr)Mem;
-
- if( MM_IsUser( addr ) )
- {
- while( NumBytes-- )
- {
- if( !MM_IsUser( addr ) )
- return 0;
- addr ++;
- }
- return 1;
- }
- else if( MM_GetPhysAddr( addr ) )
- {
- while( NumBytes-- )
- {
- if( !MM_GetPhysAddr( addr ) )
- return 0;
- addr ++;
- }
- return 1;
- }
- return 0;
+ return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
}
/* *
* \}
/**
* \brief Convert a string of hexadecimal digits into a byte stream
*/
-int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString)
+int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString)
{
int i;
{
return ((Val&0xFF)<<24) | ((Val&0xFF00)<<8) | ((Val>>8)&0xFF00) | ((Val>>24)&0xFF);
}
+
+void *memmove(void *__dest, const void *__src, size_t len)
+{
+ size_t block_size;
+ char *dest = __dest;
+ const char *src = __src;
+ void *ret = __dest;
+
+ if( len == 0 || dest == src )
+ return dest;
+
+ if( (tVAddr)dest > (tVAddr)src + len )
+ return memcpy(dest, src, len);
+ if( (tVAddr)dest + len < (tVAddr)src )
+ return memcpy(dest, src, len);
+
+ // NOTE: Assumes memcpy works forward
+ if( (tVAddr)dest < (tVAddr)src )
+ return memcpy(dest, src, len);
+
+ if( (tVAddr)dest < (tVAddr)src )
+ block_size = (tVAddr)src - (tVAddr)dest;
+ else
+ block_size = (tVAddr)dest - (tVAddr)src;
+
+ block_size &= ~0xF;
+
+ while(len >= block_size)
+ {
+ memcpy(dest, src, block_size);
+ len -= block_size;
+ dest += block_size;
+ src += block_size;
+ }
+ memcpy(dest, src, len);
+ return ret;
+
+}
+