annotate util.c @ 1021:4a92889e2889 v0.4.0

Fix OS X build
author Michael Pavone <pavone@retrodev.com>
date Wed, 04 May 2016 00:50:20 -0700
parents 51885857c019
children 86ed81bb574f
rev   line source
pavone@495 1 #include <string.h>
pavone@495 2 #include <stdlib.h>
pavone@495 3 #include <stdio.h>
pavone@495 4 #include <ctype.h>
pavone@768 5 #include <stdint.h>
pavone@805 6 #include <stdarg.h>
pavone@495 7
pavone@496 8 #include <sys/types.h>
pavone@496 9 #include <sys/stat.h>
pavone@496 10 #include <unistd.h>
pavone@955 11 #include <errno.h>
pavone@496 12
pavone@879 13 #ifdef __ANDROID__
pavone@879 14 #include <android/log.h>
pavone@879 15 #define info_puts(msg) __android_log_write(ANDROID_LOG_INFO, "BlastEm", msg)
pavone@879 16 #define warning_puts(msg) __android_log_write(ANDROID_LOG_WARN, "BlastEm", msg)
pavone@879 17 #define fatal_puts(msg) __android_log_write(ANDROID_LOG_FATAL, "BlastEm", msg)
pavone@879 18
pavone@879 19 #define info_printf(msg, args) __android_log_vprint(ANDROID_LOG_INFO, "BlastEm", msg, args)
pavone@879 20 #define warning_printf(msg, args) __android_log_vprint(ANDROID_LOG_WARN, "BlastEm", msg, args)
pavone@879 21 #define fatal_printf(msg, args) __android_log_vprint(ANDROID_LOG_FATAL, "BlastEm", msg, args)
pavone@879 22 #else
pavone@884 23 #define info_puts(msg) fputs(msg, stdout);
pavone@884 24 #define warning_puts(msg) fputs(msg, stderr);
pavone@884 25 #define fatal_puts(msg) fputs(msg, stderr);
pavone@879 26
pavone@883 27 #define info_printf(msg, args) vprintf(msg, args)
pavone@883 28 #define warning_printf(msg, args) vfprintf(stderr, msg, args)
pavone@883 29 #define fatal_printf(msg, args) vfprintf(stderr, msg, args)
pavone@879 30 #endif
pavone@879 31
pavone@792 32 #include "blastem.h" //for headless global
pavone@792 33 #include "render.h" //for render_errorbox
pavone@866 34 #include "util.h"
pavone@792 35
pavone@876 36 char * alloc_concat(char const * first, char const * second)
pavone@495 37 {
pavone@495 38 int flen = strlen(first);
pavone@495 39 int slen = strlen(second);
pavone@495 40 char * ret = malloc(flen + slen + 1);
pavone@495 41 memcpy(ret, first, flen);
pavone@495 42 memcpy(ret+flen, second, slen+1);
pavone@495 43 return ret;
pavone@495 44 }
pavone@495 45
pavone@876 46 char * alloc_concat_m(int num_parts, char const ** parts)
pavone@495 47 {
pavone@495 48 int total = 0;
pavone@495 49 for (int i = 0; i < num_parts; i++) {
pavone@495 50 total += strlen(parts[i]);
pavone@495 51 }
pavone@495 52 char * ret = malloc(total + 1);
pavone@495 53 *ret = 0;
pavone@495 54 for (int i = 0; i < num_parts; i++) {
pavone@495 55 strcat(ret, parts[i]);
pavone@495 56 }
pavone@495 57 return ret;
pavone@495 58 }
pavone@495 59
pavone@495 60 long file_size(FILE * f)
pavone@495 61 {
pavone@495 62 fseek(f, 0, SEEK_END);
pavone@495 63 long fsize = ftell(f);
pavone@495 64 fseek(f, 0, SEEK_SET);
pavone@495 65 return fsize;
pavone@495 66 }
pavone@495 67
pavone@495 68 char * strip_ws(char * text)
pavone@495 69 {
pavone@495 70 while (*text && (!isprint(*text) || isblank(*text)))
pavone@495 71 {
pavone@495 72 text++;
pavone@495 73 }
pavone@495 74 char * ret = text;
pavone@495 75 text = ret + strlen(ret) - 1;
pavone@495 76 while (text > ret && (!isprint(*text) || isblank(*text)))
pavone@495 77 {
pavone@495 78 *text = 0;
pavone@495 79 text--;
pavone@495 80 }
pavone@495 81 return ret;
pavone@495 82 }
pavone@495 83
pavone@495 84 char * split_keyval(char * text)
pavone@495 85 {
pavone@495 86 while (*text && !isblank(*text))
pavone@495 87 {
pavone@495 88 text++;
pavone@495 89 }
pavone@495 90 if (!*text) {
pavone@495 91 return text;
pavone@495 92 }
pavone@495 93 *text = 0;
pavone@495 94 return text+1;
pavone@495 95 }
pavone@496 96
pavone@1008 97 char is_path_sep(char c)
pavone@1008 98 {
pavone@1008 99 #ifdef _WIN32
pavone@1008 100 if (c == '\\') {
pavone@1008 101 return 1;
pavone@1008 102 }
pavone@1008 103 #endif
pavone@1008 104 return c == '/';
pavone@1008 105 }
pavone@1008 106
pavone@1008 107 char is_absolute_path(char *path)
pavone@1008 108 {
pavone@1008 109 #ifdef _WIN32
pavone@1008 110 if (path[1] == ':' && is_path_sep(path[2]) && isalpha(path[0])) {
pavone@1008 111 return 1;
pavone@1008 112 }
pavone@1008 113 #endif
pavone@1008 114 return is_path_sep(path[0]);
pavone@1008 115 }
pavone@1008 116
pavone@955 117 char * basename_no_extension(char *path)
pavone@955 118 {
pavone@955 119 char *lastdot = NULL;
pavone@955 120 char *lastslash = NULL;
pavone@955 121 char *cur;
pavone@955 122 for (cur = path; *cur; cur++)
pavone@955 123 {
pavone@955 124 if (*cur == '.') {
pavone@955 125 lastdot = cur;
pavone@1008 126 } else if (is_path_sep(*cur)) {
pavone@955 127 lastslash = cur + 1;
pavone@955 128 }
pavone@955 129 }
pavone@955 130 if (!lastdot) {
pavone@955 131 lastdot = cur;
pavone@955 132 }
pavone@955 133 if (!lastslash) {
pavone@955 134 lastslash = path;
pavone@955 135 }
pavone@955 136 char *barename = malloc(lastdot-lastslash+1);
pavone@955 137 memcpy(barename, lastslash, lastdot-lastslash);
pavone@955 138 barename[lastdot-lastslash] = 0;
pavone@955 139
pavone@955 140 return barename;
pavone@955 141 }
pavone@955 142
pavone@768 143 uint32_t nearest_pow2(uint32_t val)
pavone@768 144 {
pavone@768 145 uint32_t ret = 1;
pavone@768 146 while (ret < val)
pavone@768 147 {
pavone@768 148 ret = ret << 1;
pavone@768 149 }
pavone@768 150 return ret;
pavone@768 151 }
pavone@768 152
pavone@496 153 static char * exe_str;
pavone@496 154
pavone@496 155 void set_exe_str(char * str)
pavone@496 156 {
pavone@496 157 exe_str = str;
pavone@496 158 }
pavone@496 159
pavone@792 160 void fatal_error(char *format, ...)
pavone@792 161 {
pavone@792 162 va_list args;
pavone@792 163 va_start(args, format);
pavone@792 164 if (!headless) {
pavone@792 165 //take a guess at the final size
pavone@792 166 size_t size = strlen(format) * 2;
pavone@792 167 char *buf = malloc(size);
pavone@792 168 size_t actual = vsnprintf(buf, size, format, args);
pavone@792 169 if (actual >= size) {
pavone@792 170 actual++;
pavone@792 171 free(buf);
pavone@792 172 buf = malloc(actual);
pavone@792 173 va_end(args);
pavone@792 174 va_start(args, format);
pavone@792 175 vsnprintf(buf, actual, format, args);
pavone@792 176 }
pavone@879 177 fatal_puts(buf);
pavone@792 178 render_errorbox("Fatal Error", buf);
pavone@792 179 free(buf);
pavone@792 180 } else {
pavone@879 181 fatal_printf(format, args);
pavone@792 182 }
pavone@792 183 va_end(args);
pavone@792 184 exit(1);
pavone@792 185 }
pavone@792 186
pavone@794 187 void warning(char *format, ...)
pavone@794 188 {
pavone@794 189 va_list args;
pavone@794 190 va_start(args, format);
pavone@794 191 #ifndef _WIN32
pavone@794 192 if (headless || (isatty(STDERR_FILENO) && isatty(STDIN_FILENO))) {
pavone@879 193 warning_printf(format, args);
pavone@794 194 } else {
pavone@794 195 #endif
pavone@794 196 size_t size = strlen(format) * 2;
pavone@794 197 char *buf = malloc(size);
pavone@794 198 size_t actual = vsnprintf(buf, size, format, args);
pavone@794 199 if (actual >= size) {
pavone@794 200 actual++;
pavone@794 201 free(buf);
pavone@794 202 buf = malloc(actual);
pavone@794 203 va_end(args);
pavone@794 204 va_start(args, format);
pavone@794 205 vsnprintf(buf, actual, format, args);
pavone@794 206 }
pavone@879 207 warning_puts(buf);
pavone@794 208 render_infobox("BlastEm Info", buf);
pavone@794 209 free(buf);
pavone@794 210 #ifndef _WIN32
pavone@794 211 }
pavone@794 212 #endif
pavone@794 213 va_end(args);
pavone@794 214 }
pavone@794 215
pavone@792 216 void info_message(char *format, ...)
pavone@792 217 {
pavone@792 218 va_list args;
pavone@792 219 va_start(args, format);
pavone@792 220 #ifndef _WIN32
pavone@792 221 if (headless || (isatty(STDOUT_FILENO) && isatty(STDIN_FILENO))) {
pavone@879 222 info_printf(format, args);
pavone@792 223 } else {
pavone@792 224 #endif
pavone@792 225 size_t size = strlen(format) * 2;
pavone@792 226 char *buf = malloc(size);
pavone@792 227 size_t actual = vsnprintf(buf, size, format, args);
pavone@792 228 if (actual >= size) {
pavone@792 229 actual++;
pavone@792 230 free(buf);
pavone@792 231 buf = malloc(actual);
pavone@792 232 va_end(args);
pavone@792 233 va_start(args, format);
pavone@792 234 vsnprintf(buf, actual, format, args);
pavone@792 235 }
pavone@879 236 info_puts(buf);
pavone@792 237 render_infobox("BlastEm Info", buf);
pavone@792 238 free(buf);
pavone@792 239 #ifndef _WIN32
pavone@792 240 }
pavone@792 241 #endif
pavone@792 242 va_end(args);
pavone@792 243 }
pavone@792 244
pavone@742 245 #ifdef _WIN32
heuripedes@795 246 #include <windows.h>
heuripedes@795 247 #include <shlobj.h>
pavone@742 248
pavone@742 249 char * get_home_dir()
pavone@742 250 {
pavone@742 251 static char path[MAX_PATH];
pavone@742 252 SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, path);
pavone@742 253 return path;
pavone@742 254 }
pavone@742 255
pavone@742 256 char * get_exe_dir()
pavone@742 257 {
pavone@742 258 static char path[MAX_PATH];
pavone@742 259 HMODULE module = GetModuleHandleA(NULL);
pavone@742 260 GetModuleFileNameA(module, path, MAX_PATH);
pavone@742 261
pavone@742 262 int pathsize = strlen(path);
pavone@742 263 for(char * cur = path + pathsize - 1; cur != path; cur--)
pavone@742 264 {
pavone@742 265 if (*cur == '\\') {
pavone@742 266 *cur = 0;
pavone@742 267 break;
pavone@742 268 }
pavone@742 269 }
pavone@742 270 return path;
pavone@742 271 }
pavone@742 272
pavone@972 273 dir_entry *get_dir_list(char *path, size_t *numret)
pavone@972 274 {
pavone@972 275 HANDLE dir;
pavone@972 276 WIN32_FIND_DATA file;
pavone@972 277 char *pattern = alloc_concat(path, "/*.*");
pavone@972 278 dir = FindFirstFile(pattern, &file);
pavone@972 279 free(pattern);
pavone@972 280 if (dir == INVALID_HANDLE_VALUE) {
pavone@972 281 if (numret) {
pavone@972 282 *numret = 0;
pavone@972 283 }
pavone@972 284 return NULL;
pavone@972 285 }
pavone@972 286
pavone@972 287 size_t storage = 64;
pavone@972 288 dir_entry *ret = malloc(sizeof(dir_entry) * storage);
pavone@972 289 size_t pos = 0;
pavone@972 290
pavone@972 291 do {
pavone@972 292 if (pos == storage) {
pavone@972 293 storage = storage * 2;
pavone@972 294 ret = realloc(ret, sizeof(dir_entry) * storage);
pavone@972 295 }
pavone@972 296 ret[pos].name = strdup(file.cFileName);
pavone@972 297 ret[pos++].is_dir = (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
pavone@972 298 } while (FindNextFile(dir, &file));
pavone@972 299
pavone@972 300 FindClose(dir);
pavone@972 301 if (numret) {
pavone@972 302 *numret = pos;
pavone@972 303 }
pavone@972 304 return ret;
pavone@972 305 }
pavone@972 306
pavone@972 307 time_t get_modification_time(char *path)
pavone@972 308 {
pavone@974 309 HANDLE results;
pavone@974 310 WIN32_FIND_DATA file;
pavone@974 311 results = FindFirstFile(path, &file);
pavone@974 312 if (results == INVALID_HANDLE_VALUE) {
pavone@972 313 return 0;
pavone@972 314 }
pavone@974 315 FindClose(results);
pavone@974 316 uint64_t wintime = ((uint64_t)file.ftLastWriteTime.dwHighDateTime) << 32 | file.ftLastWriteTime.dwLowDateTime;
pavone@974 317 //convert to seconds
pavone@974 318 wintime /= 10000000;
pavone@974 319 //adjust for difference between Windows and Unix Epoch
pavone@974 320 wintime -= 11644473600LL;
pavone@974 321 return (time_t)wintime;
pavone@972 322 }
pavone@972 323
pavone@972 324 int ensure_dir_exists(char *path)
pavone@972 325 {
pavone@972 326 if (CreateDirectory(path, NULL)) {
pavone@972 327 return 1;
pavone@972 328 }
pavone@972 329 if (GetLastError() == ERROR_ALREADY_EXISTS) {
pavone@972 330 return 1;
pavone@972 331 }
pavone@972 332 if (GetLastError() != ERROR_PATH_NOT_FOUND) {
pavone@972 333 warning("CreateDirectory failed with unexpected error code %X\n", GetLastError());
pavone@972 334 return 0;
pavone@972 335 }
pavone@972 336 char *parent = strdup(path);
pavone@1008 337 //Windows technically supports both native and Unix-style path separators
pavone@1008 338 //so search for both
pavone@1008 339 char *sep = strrchr(parent, '\\');
pavone@1008 340 char *osep = strrchr(parent, '/');
pavone@1008 341 if (osep && (!sep || osep < sep)) {
pavone@1008 342 sep = osep;
pavone@1008 343 }
pavone@972 344 if (!sep || sep == parent) {
pavone@972 345 //relative path, but for some reason we failed
pavone@972 346 return 0;
pavone@972 347 }
pavone@972 348 *sep = 0;
pavone@972 349 if (!ensure_dir_exists(parent)) {
pavone@972 350 free(parent);
pavone@972 351 return 0;
pavone@972 352 }
pavone@972 353 free(parent);
pavone@972 354 return CreateDirectory(path, NULL);
pavone@972 355 }
pavone@972 356
pavone@742 357 #else
pavone@742 358
pavone@742 359 char * get_home_dir()
pavone@742 360 {
pavone@742 361 return getenv("HOME");
pavone@742 362 }
pavone@742 363
pavone@496 364 char * readlink_alloc(char * path)
pavone@496 365 {
pavone@496 366 char * linktext = NULL;
pavone@496 367 ssize_t linksize = 512;
pavone@496 368 ssize_t cursize = 0;
pavone@496 369 do {
pavone@496 370 if (linksize > cursize) {
pavone@496 371 cursize = linksize;
pavone@496 372 if (linktext) {
pavone@496 373 free(linktext);
pavone@496 374 }
pavone@496 375 }
pavone@496 376 linktext = malloc(cursize);
pavone@496 377 linksize = readlink(path, linktext, cursize-1);
pavone@496 378 if (linksize == -1) {
pavone@496 379 perror("readlink");
pavone@496 380 free(linktext);
pavone@559 381 return NULL;
pavone@496 382 }
pavone@549 383 } while ((linksize+1) > cursize);
pavone@549 384 linktext[linksize] = 0;
pavone@496 385 return linktext;
pavone@496 386 }
pavone@496 387
pavone@496 388 char * get_exe_dir()
pavone@496 389 {
pavone@496 390 static char * exe_dir;
pavone@496 391 if (!exe_dir) {
pavone@762 392 char * cur;
pavone@763 393 #ifdef HAS_PROC
pavone@496 394 char * linktext = readlink_alloc("/proc/self/exe");
pavone@496 395 if (!linktext) {
pavone@496 396 goto fallback;
pavone@496 397 }
pavone@496 398 int linksize = strlen(linktext);
pavone@496 399 for(cur = linktext + linksize - 1; cur != linktext; cur--)
pavone@496 400 {
pavone@1008 401 if (is_path_sep(*cur)) {
pavone@496 402 *cur = 0;
pavone@496 403 break;
pavone@496 404 }
pavone@496 405 }
pavone@496 406 if (cur == linktext) {
pavone@496 407 free(linktext);
pavone@496 408 fallback:
pavone@762 409 #endif
pavone@496 410 if (!exe_str) {
pavone@496 411 fputs("/proc/self/exe is not available and set_exe_str was not called!", stderr);
pavone@496 412 }
pavone@496 413 int pathsize = strlen(exe_str);
pavone@496 414 for(cur = exe_str + pathsize - 1; cur != exe_str; cur--)
pavone@496 415 {
pavone@1008 416 if (is_path_sep(*cur)) {
pavone@496 417 exe_dir = malloc(cur-exe_str+1);
pavone@496 418 memcpy(exe_dir, exe_str, cur-exe_str);
pavone@496 419 exe_dir[cur-exe_str] = 0;
pavone@496 420 break;
pavone@496 421 }
pavone@496 422 }
pavone@763 423 #ifdef HAS_PROC
pavone@496 424 } else {
pavone@496 425 exe_dir = linktext;
pavone@496 426 }
pavone@762 427 #endif
pavone@496 428 }
pavone@496 429 return exe_dir;
pavone@496 430 }
pavone@866 431 #include <dirent.h>
pavone@866 432
pavone@866 433 dir_entry *get_dir_list(char *path, size_t *numret)
pavone@866 434 {
pavone@866 435 DIR *d = opendir(path);
pavone@866 436 if (!d) {
pavone@866 437 if (numret) {
pavone@866 438 *numret = 0;
pavone@866 439 }
pavone@866 440 return NULL;
pavone@866 441 }
pavone@866 442 size_t storage = 64;
pavone@866 443 dir_entry *ret = malloc(sizeof(dir_entry) * storage);
pavone@866 444 size_t pos = 0;
pavone@866 445 struct dirent* entry;
pavone@866 446 while (entry = readdir(d))
pavone@866 447 {
pavone@866 448 if (entry->d_type != DT_REG && entry->d_type != DT_LNK && entry->d_type != DT_DIR) {
pavone@866 449 continue;
pavone@866 450 }
pavone@866 451 if (pos == storage) {
pavone@866 452 storage = storage * 2;
pavone@866 453 ret = realloc(ret, sizeof(dir_entry) * storage);
pavone@866 454 }
pavone@866 455 ret[pos].name = strdup(entry->d_name);
pavone@866 456 ret[pos++].is_dir = entry->d_type == DT_DIR;
pavone@866 457 }
pavone@866 458 if (numret) {
pavone@866 459 *numret = pos;
pavone@866 460 }
pavone@866 461 return ret;
pavone@866 462 }
pavone@866 463
pavone@957 464 time_t get_modification_time(char *path)
pavone@957 465 {
pavone@957 466 struct stat st;
pavone@957 467 if (stat(path, &st)) {
pavone@957 468 return 0;
pavone@957 469 }
pavone@1021 470 #ifdef __APPLE__
pavone@1021 471 return st.st_mtimespec.tv_sec;
pavone@1021 472 #else
pavone@957 473 return st.st_mtim.tv_sec;
pavone@1021 474 #endif
pavone@957 475 }
pavone@957 476
pavone@955 477 int ensure_dir_exists(char *path)
pavone@955 478 {
pavone@955 479 struct stat st;
pavone@955 480 if (stat(path, &st)) {
pavone@955 481 if (errno == ENOENT) {
pavone@955 482 char *parent = strdup(path);
pavone@955 483 char *sep = strrchr(parent, '/');
pavone@955 484 if (sep && sep != parent) {
pavone@955 485 *sep = 0;
pavone@955 486 if (!ensure_dir_exists(parent)) {
pavone@955 487 free(parent);
pavone@955 488 return 0;
pavone@955 489 }
pavone@955 490 free(parent);
pavone@955 491 }
pavone@955 492 return mkdir(path, 0777) == 0;
pavone@955 493 } else {
pavone@955 494 char buf[80];
pavone@955 495 strerror_r(errno, buf, sizeof(buf));
pavone@955 496 warning("stat failed with error: %s", buf);
pavone@955 497 return 0;
pavone@955 498 }
pavone@955 499 }
pavone@955 500 return S_ISDIR(st.st_mode);
pavone@955 501 }
pavone@955 502
pavone@741 503 #endif
pavone@875 504
pavone@972 505 void free_dir_list(dir_entry *list, size_t numentries)
pavone@972 506 {
pavone@972 507 for (size_t i = 0; i < numentries; i++)
pavone@972 508 {
pavone@972 509 free(list[i].name);
pavone@972 510 }
pavone@972 511 free(list);
pavone@972 512 }
pavone@972 513
pavone@875 514 #ifdef __ANDROID__
pavone@875 515
pavone@875 516 #include <SDL.h>
pavone@875 517 char *read_bundled_file(char *name, long *sizeret)
pavone@875 518 {
pavone@876 519 SDL_RWops *rw = SDL_RWFromFile(name, "rb");
pavone@875 520 if (!rw) {
pavone@875 521 if (sizeret) {
pavone@875 522 *sizeret = -1;
pavone@875 523 }
pavone@875 524 return NULL;
pavone@875 525 }
pavone@875 526
pavone@875 527 long fsize = rw->size(rw);
pavone@875 528 if (sizeret) {
pavone@875 529 *sizeret = fsize;
pavone@875 530 }
pavone@875 531 char *ret;
pavone@875 532 if (fsize) {
pavone@875 533 ret = malloc(fsize);
pavone@875 534 if (SDL_RWread(rw, ret, 1, fsize) != fsize) {
pavone@875 535 free(ret);
pavone@875 536 ret = NULL;
pavone@875 537 }
pavone@875 538 } else {
pavone@875 539 ret = NULL;
pavone@875 540 }
pavone@875 541 SDL_RWclose(rw);
pavone@875 542 return ret;
pavone@875 543 }
pavone@875 544
pavone@876 545 char const *get_config_dir()
pavone@875 546 {
pavone@875 547 return SDL_AndroidGetInternalStoragePath();
pavone@875 548 }
pavone@875 549
pavone@955 550 char const *get_save_dir()
pavone@955 551 {
pavone@955 552 return SDL_AndroidGetInternalStoragePath();
pavone@955 553 }
pavone@955 554
pavone@875 555 #else
pavone@875 556
pavone@875 557 char *read_bundled_file(char *name, long *sizeret)
pavone@875 558 {
pavone@875 559 char *exe_dir = get_exe_dir();
pavone@875 560 if (!exe_dir) {
pavone@875 561 if (sizeret) {
pavone@875 562 *sizeret = -1;
pavone@875 563 }
pavone@875 564 return NULL;
pavone@875 565 }
pavone@1008 566 char const *pieces[] = {exe_dir, PATH_SEP, name};
pavone@875 567 char *path = alloc_concat_m(3, pieces);
pavone@875 568 FILE *f = fopen(path, "rb");
pavone@875 569 free(path);
pavone@875 570 if (!f) {
pavone@875 571 if (sizeret) {
pavone@875 572 *sizeret = -1;
pavone@875 573 }
pavone@875 574 return NULL;
pavone@875 575 }
pavone@875 576
pavone@875 577 long fsize = file_size(f);
pavone@875 578 if (sizeret) {
pavone@875 579 *sizeret = fsize;
pavone@875 580 }
pavone@875 581 char *ret;
pavone@875 582 if (fsize) {
pavone@875 583 //reserve an extra byte in case caller wants
pavone@875 584 //to null terminate the data
pavone@875 585 ret = malloc(fsize+1);
pavone@875 586 if (fread(ret, 1, fsize, f) != fsize) {
pavone@875 587 free(ret);
pavone@875 588 ret = NULL;
pavone@875 589 }
pavone@875 590 } else {
pavone@875 591 ret = NULL;
pavone@875 592 }
pavone@875 593 return ret;
pavone@875 594 }
pavone@875 595
pavone@876 596 char const *get_config_dir()
pavone@875 597 {
pavone@875 598 static char* confdir;
pavone@875 599 if (!confdir) {
pavone@875 600 char *homedir = get_home_dir();
pavone@875 601 if (homedir) {
pavone@875 602 confdir = alloc_concat(homedir, "/.config/blastem");
pavone@875 603 }
pavone@875 604 }
pavone@875 605 return confdir;
pavone@875 606 }
pavone@875 607
pavone@955 608 char const *get_save_dir()
pavone@955 609 {
pavone@955 610 static char* savedir;
pavone@955 611 if (!savedir) {
pavone@955 612 char *homedir = get_home_dir();
pavone@955 613 if (homedir) {
pavone@955 614 savedir = alloc_concat(homedir, "/.local/share/blastem");
pavone@955 615 }
pavone@955 616 }
pavone@955 617 return savedir;
pavone@955 618 }
pavone@955 619
pavone@875 620 #endif