#include <time.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#if defined(__linux)
#include <sys/time.h>
#endif
#if defined(__MACH__)
#include <mach/mach_time.h>
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
#include "gravity_utils.h"
#include "gravity_memory.h"
#define SWP(x,y) (x^=y, y^=x, x^=y)
nanotime_t nanotime (void) {
nanotime_t value;
#if defined(_WIN32)
static LARGE_INTEGER win_frequency;
static BOOL flag = QueryPerformanceFrequency(&s_frequency);
LARGE_INTEGER t;
if (!QueryPerformanceCounter(&t)) return 0;
value = (t.QuadPart / win_frequency.QuadPart) * 1000000000;
value += (t.QuadPart % win_frequency.QuadPart) * 1000000000 / win_frequency.QuadPart;
#elif defined(__MACH__)
mach_timebase_info_data_t info;
kern_return_t r;
nanotime_t t;
t = mach_absolute_time();
r = mach_timebase_info(&info);
if (r != 0) return 0;
value = (t / info.denom) * info.numer;
value += (t % info.denom) * info.numer / info.denom;
#elif defined(__linux)
struct timespec ts;
int r;
r = clock_gettime(CLOCK_MONOTONIC, &ts);
if (r != 0) return 0;
value = ts.tv_sec * (nanotime_t)1000000000 + ts.tv_nsec;
#else
struct timeval tv;
int r;
r = gettimeofday(&tv, 0);
if (r != 0) return 0;
value = tv.tv_sec * (nanotime_t)1000000000 + tv.tv_usec * 1000;
#endif
return value;
}
double microtime (nanotime_t tstart, nanotime_t tend) {
nanotime_t t = tend - tstart;
return ((double)t / 1000.0f);
}
double millitime (nanotime_t tstart, nanotime_t tend) {
nanotime_t t = tend - tstart;
return ((double)t / 1000000.0f);
}
uint64_t file_size (const char *path) {
#ifdef WIN32
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
if (GetFileAttributesExA(path, GetFileExInfoStandard, (void*)&fileInfo) == 0) return -1;
return (uint64_t)(((__int64)fileInfo.nFileSizeHigh) << 32 ) + fileInfo.nFileSizeLow;
#else
struct stat sb;
if (stat(path, &sb) > 0) return -1;
return (uint64_t)sb.st_size;
#endif
}
const char *file_read(const char *path, size_t *len) {
int fd = 0;
off_t fsize = 0;
size_t fsize2 = 0;
char *buffer = NULL;
fsize = (size_t) file_size(path);
if (fsize < 0) goto abort_read;
fd = open(path, O_RDONLY);
if (fd < 0) goto abort_read;
buffer = (char *)mem_alloc((size_t)fsize + 1);
if (buffer == NULL) goto abort_read;
buffer[fsize] = 0;
fsize2 = read(fd, buffer, fsize);
if (fsize != fsize2) goto abort_read;
if (len) *len = fsize;
close(fd);
return (const char *)buffer;
abort_read:
if (buffer) mem_free((void *)buffer);
if (fd >= 0) close(fd);
return NULL;
}
bool file_exists (const char *path) {
#ifdef WIN32
BOOL isDirectory;
DWORD attributes = GetFileAttributesA(path);
if (attributes == INVALID_FILE_ATTRIBUTES)
isDirectory = (GetLastError() == ERROR_BAD_NETPATH);
else
isDirectory = (FILE_ATTRIBUTE_DIRECTORY & attributes);
if (isDirectory) {
if (PathIsNetworkPathA(path)) return true;
if (PathIsUNCA(path)) return true;
}
if (PathFileExistsA(path) == 1) return true;
#else
if (access(path, F_OK)==0) return true;
#endif
return false;
}
const char *file_buildpath (const char *filename, const char *dirpath) {
size_t len1 = strlen(filename);
size_t len2 = strlen(dirpath);
size_t len = len1+len2+2;
char *full_path = (char *)mem_alloc(len);
if (!full_path) return NULL;
if ((len2) && (dirpath[len2-1] != '/'))
snprintf(full_path, len, "%s/%s", dirpath, filename);
else
snprintf(full_path, len, "%s%s", dirpath, filename);
return (const char *)full_path;
}
bool file_write (const char *path, const char *buffer, size_t len) {
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (fd < 0) return false;
ssize_t nwrite = write(fd, buffer, len);
close(fd);
return (nwrite == len);
}
bool is_directory (const char *path) {
#ifdef WIN32
DWORD dwAttrs;
dwAttrs = GetFileAttributesA(path);
if (dwAttrs == INVALID_FILE_ATTRIBUTES) return false;
if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) return true;
#else
struct stat buf;
if (lstat(path, &buf) < 0) return false;
if (S_ISDIR(buf.st_mode)) return true;
#endif
return false;
}
DIRREF directory_init (const char *dirpath) {
#ifdef WIN32
WIN32_FIND_DATA findData;
WCHAR path[MAX_PATH];
WCHAR dirpathW[MAX_PATH];
HANDLE hFind;
MultiByteToWideChar(CP_UTF8, 0, dirpath, -1, dirpathW, MAX_PATH);
PathCombine(path, dirpathW, _T("*"));
return FindFirstFile(path, &findData);
#else
return opendir(dirpath);
#endif
}
const char *directory_read (DIRREF ref) {
if (ref == NULL) return NULL;
while (1) {
#ifdef WIN32
WIN32_FIND_DATA findData;
if (FindNextFile(ref, &findData) == 0) {
FindClose(dref);
return NULL;
}
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
if (findData.cFileName == NULL) continue;
if (findData.cFileName[0] == '.') continue;
return (const char *)findData.cFileName;
#else
struct dirent *d;
if ((d = readdir(ref)) == NULL) {
closedir(ref);
return NULL;
}
if (d->d_name[0] == 0) continue;
if (d->d_name[0] == '.') continue;
return (const char *)d->d_name;
#endif
}
return NULL;
}
int string_nocasencmp(const char *s1, const char *s2, size_t n) {
while(n > 0 && tolower((unsigned char)*s1) == tolower((unsigned char)*s2)) {
if(*s1 == '\0') return 0;
s1++;
s2++;
n--;
}
if(n == 0) return 0;
return tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
}
int string_casencmp(const char *s1, const char *s2, size_t n) {
while(n > 0 && ((unsigned char)*s1) == ((unsigned char)*s2)) {
if(*s1 == '\0') return 0;
s1++;
s2++;
n--;
}
if(n == 0) return 0;
return ((unsigned char)*s1) - ((unsigned char)*s2);
}
int string_cmp (const char *s1, const char *s2) {
if (!s1) return 1;
return strcmp(s1, s2);
}
const char *string_dup (const char *s1) {
size_t len = (size_t)strlen(s1);
char *s = (char *)mem_alloc(len + 1);
memcpy(s, s1, len);
return s;
}
const char *string_ndup (const char *s1, size_t n) {
char *s = (char *)mem_alloc(n + 1);
memcpy(s, s1, n);
return s;
}
char *string_unescape (const char *s1, uint32_t *s1len, char *buffer) {
uint32_t len = *s1len;
uint32_t orig_len = len;
for (uint32_t i=0, j=0; i<orig_len; ++i, ++j) {
char c = s1[i];
if ((c == '\\') && (i+1<orig_len)) {
c = s1[i+1];
switch (c) {
case '"':
case '\\':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
++i; --len; break;
default:
c = s1[i]; break;
}
}
buffer[j] = c;
}
*s1len = len;
return buffer;
}
void string_reverse (char *p) {
char *q = p;
while(q && *q) ++q;
for(--q; p < q; ++p, --q) SWP(*p, *q);
}
uint32_t string_size (const char *p) {
if (!p) return 0;
return (uint32_t)strlen(p);
}
inline uint32_t utf8_charbytes (const char *s, uint32_t i) {
unsigned char c = s[i];
if ((c > 0) && (c <= 127)) return 1;
if ((c >= 194) && (c <= 223)) return 2;
if ((c >= 224) && (c <= 239)) return 3;
if ((c >= 240) && (c <= 244)) return 4;
return 0;
}
uint32_t utf8_len (const char *s, uint32_t nbytes) {
if (nbytes == 0) nbytes = (uint32_t)strlen(s);
uint32_t pos = 1;
uint32_t len = 0;
while (pos <= nbytes) {
++len;
uint32_t n = utf8_charbytes(s, pos);
if (n == 0) return 0;
pos += n;
}
return len;
}
void utf8_reverse (char *p) {
char *q = p;
string_reverse(p);
while(q && *q) ++q;
while(p < --q)
switch( (*q & 0xF0) >> 4 ) {
case 0xF:
SWP(*(q-0), *(q-3));
SWP(*(q-1), *(q-2));
q -= 3;
break;
case 0xE:
SWP(*(q-0), *(q-2));
q -= 2;
break;
case 0xC:
case 0xD:
SWP(*(q-0), *(q-1));
q--;
break;
}
}
uint32_t power_of2_ceil (uint32_t n) {
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
int64_t number_from_hex (const char *s, uint32_t len) {
#pragma unused(len)
return (int64_t) strtoll(s, NULL, 16);
}
int64_t number_from_oct (const char *s, uint32_t len) {
#pragma unused(len)
return (int64_t) strtoll(s, NULL, 8);
}
int64_t number_from_bin (const char *s, uint32_t len) {
int64_t value = 0;
for (uint32_t i=0; i<len; ++i) {
int c = s[i];
value = (value << 1) + (c - '0');
}
return value;
}