Newer
Older
uwuboot / source / util.c
/*
 *   This file is part of fastboot 3DS
 *   Copyright (C) 2017 derrek, profi200
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "util.h"

void wait(u32 cycles)
{
	cycles >>= 2;
	while(cycles)
	{
		__asm("nop");
		cycles--;
	}
}

int mysscanf(const char *s, const char *fmt, ...)
{
	va_list args;
	va_start(args, fmt);


	int ret = 0;
	const char *const oldS = s;
	while(*fmt && *s)
	{
		if(*fmt == '%')
		{
			bool longInt = false;
			bool number = false;
			if(*++fmt == 'l')
			{
				longInt = true;
				fmt++;
			}

			switch(*fmt)
			{
				case 'd':
					if(!longInt) *va_arg(args, int*) = atoi(s);
					else *va_arg(args, long int*) = atol(s);
					number = true;
					ret++;
					break;
				case 'u':
					if(!longInt) *va_arg(args, unsigned int*) = (unsigned int)strtoul(s, NULL, 0);
					else *va_arg(args, unsigned long int*) = strtoul(s, NULL, 0);
					number = true;
					ret++;
					break;
				case 'c':
					*va_arg(args, char*) = *s++;
					ret++;
					break;
				case 'n':
					if(!longInt) *va_arg(args, int*) = (int)(s - oldS);
					else *va_arg(args, long int*) = (long int)(s - oldS);
					break;
				default: ;
			}
			if(number) while(*s >= '0' && *s <= '9') s++;
			fmt++;
		}
		else
		{
			if(*fmt != *s) break;
			fmt++;
			s++;
		}
	}

	va_end(args);

	return ret;
}

// case insensitive string compare function
int strnicmp(const char *str1, const char *str2, u32 len)
{
	int diff;
	
	if(len == 0)
		return 0;
	
	for(;; str1++, str2++)
	{	
		if(len != 0) len --;
		else return 0;
		diff = tolower(*str1) - tolower(*str2);
		if(diff != 0 || *str1 == '\0')
			return diff;
	}
	
	return 0;
}

// custom safe strncpy, string is always 0-terminated for buflen > 0
void strncpy_s(char *dest, const char *src, u32 nchars, const u32 buflen)
{
	char c;

	if(!buflen)
		return;
		
	if(buflen > 1)
	{
		if(nchars >= buflen)
			nchars = buflen - 1;
		
		while(nchars--)
		{
			c = *src++;
			
			if(c == '\0')
				break;
			
			*dest++ = c;
		}
	}
	
	*dest = '\0';
}

// custom safe memcpy
void memcpy_s(void *dstBuf, size_t dstBufSize, size_t dstBufOffset,
				void *srcBuf, size_t srcBufSize, size_t srcBufOffset, bool reverse)
{
	size_t dstRemaining, srcRemaining, actualSize;
	
	if(dstBufOffset >= dstBufSize)
		return;
	if(srcBufOffset >= srcBufSize)
		return;
	
	dstRemaining = dstBufSize - dstBufOffset;
	srcRemaining = srcBufSize - srcBufOffset;
	
	actualSize = min(dstRemaining, srcRemaining);
	
	if(reverse)
	{
		u8 *src = srcBuf + srcBufOffset + actualSize - 1;
		u8 *dst = dstBuf + dstBufOffset + actualSize - 1;
		
		do {
			*dst = *src;
			dst--;
			src--;
			actualSize --;
		} while(actualSize);
	}
	else
		memcpy(dstBuf+dstBufOffset, srcBuf+srcBufOffset, actualSize);
}

u32 getleu32(const void* ptr)
{
	const u8* p = (const u8*)ptr;
	
	return (u32)((p[0]<<0) | (p[1]<<8) | (p[2]<<16) | (p[3]<<24));
}

u32 swap32(u32 val)
{
	return ((val>>24) |
	        (val>>8  & 0x0000FF00) |
	        (val<<8  & 0x00FF0000) |
	        (val<<24));
}