1 /* 2 * Schism Tracker - a cross-platform Impulse Tracker clone 3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com> 4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org> 5 * copyright (c) 2009 Storlek & Mrs. Brisby 6 * copyright (c) 2010-2012 Storlek 7 * URL: http://schismtracker.org/ 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24 /* This is just a collection of some useful functions. None of these use any 25 extraneous libraries (i.e. GLib). */ 26 27 28 #define NEED_DIRENT 29 #define NEED_TIME 30 #include "headers.h" 31 32 #include "util.h" 33 #include "osdefs.h" /* need this for win32_filecreated_callback */ 34 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 38 #include <errno.h> 39 40 #include <stdarg.h> 41 42 #include <math.h> 43 44 #if defined(__amigaos4__) 45 # define FALLBACK_DIR "." /* not used... */ 46 #elif defined(WIN32) 47 # define FALLBACK_DIR "C:\\" 48 #elif defined(GEKKO) 49 # define FALLBACK_DIR "isfs:/" // always exists, seldom useful 50 #else /* POSIX? */ 51 # define FALLBACK_DIR "/" 52 #endif 53 54 #ifdef WIN32 55 #include <windows.h> 56 #include <process.h> 57 #include <shlobj.h> 58 #else 59 #include <sys/types.h> 60 #include <sys/wait.h> 61 #endif 62 63 void ms_sleep(unsigned int ms) 64 { 65 #ifdef WIN32 66 SleepEx(ms,FALSE); 67 #else 68 usleep(ms*1000); 69 #endif 70 } 71 72 char *str_dup(const char *s) 73 { 74 char *q; 75 q = strdup(s); 76 if (!q) { 77 /* throw out of memory exception */ 78 perror("strdup"); 79 exit(255); 80 } 81 return q; 82 } 83 84 char *strn_dup(const char *s, size_t n) 85 { 86 char *q; 87 q = malloc(n + 1); 88 if (!q) { 89 /* throw out of memory exception */ 90 perror("strndup"); 91 exit(255); 92 } 93 memcpy(q, s, n); 94 q[n] = '\0'; 95 return q; 96 } 97 98 void *mem_alloc(size_t amount) 99 { 100 void *q; 101 q = malloc(amount); 102 if (!q) { 103 /* throw out of memory exception */ 104 perror("malloc"); 105 exit(255); 106 } 107 return q; 108 } 109 110 void *mem_calloc(size_t nmemb, size_t size) 111 { 112 void *q; 113 q = calloc(nmemb, size); 114 if (!q) { 115 /* throw out of memory exception */ 116 perror("calloc"); 117 exit(255); 118 } 119 return q; 120 } 121 122 void *mem_realloc(void *orig, size_t amount) 123 { 124 void *q; 125 if (!orig) return mem_alloc(amount); 126 q = realloc(orig, amount); 127 if (!q) { 128 /* throw out of memory exception */ 129 perror("malloc"); 130 exit(255); 131 } 132 return q; 133 } 134 135 136 /* --------------------------------------------------------------------- */ 137 /* CONVERSION FUNCTIONS */ 138 139 /* linear -> deciBell */ 140 /* amplitude normalized to 1.0f. */ 141 float dB(float amplitude) 142 { 143 return 20.0f * log10f(amplitude); 144 } 145 146 /* deciBell -> linear */ 147 float dB2_amp(float db) 148 { 149 return powf(10.0f, db / 20.0f); 150 } 151 152 /* linear -> deciBell */ 153 /* power normalized to 1.0f. */ 154 float pdB(float power) 155 { 156 return 10.0f * log10f(power); 157 } 158 159 /* deciBell -> linear */ 160 float dB2_power(float db) 161 { 162 return powf(10.0f, db / 10.0f); 163 } 164 /* linear -> deciBell */ 165 /* amplitude normalized to 1.0f. */ 166 /* Output scaled (and clipped) to 128 lines with noisefloor range. */ 167 /* ([0..128] = [-noisefloor..0dB]) */ 168 /* correction_dBs corrects the dB after converted, but before scaling.*/ 169 short dB_s(int noisefloor, float amplitude, float correction_dBs) 170 { 171 float db = dB(amplitude) + correction_dBs; 172 return CLAMP((int)(128.f*(db+noisefloor))/noisefloor, 0, 127); 173 } 174 175 /* deciBell -> linear */ 176 /* Input scaled to 128 lines with noisefloor range. */ 177 /* ([0..128] = [-noisefloor..0dB]) */ 178 /* amplitude normalized to 1.0f. */ 179 /* correction_dBs corrects the dB after converted, but before scaling.*/ 180 short dB2_amp_s(int noisefloor, int db, float correction_dBs) 181 { 182 return dB2_amp((db*noisefloor/128.f)-noisefloor-correction_dBs); 183 } 184 /* linear -> deciBell */ 185 /* power normalized to 1.0f. */ 186 /* Output scaled (and clipped) to 128 lines with noisefloor range. */ 187 /* ([0..128] = [-noisefloor..0dB]) */ 188 /* correction_dBs corrects the dB after converted, but before scaling.*/ 189 short pdB_s(int noisefloor, float power, float correction_dBs) 190 { 191 float db = pdB(power)+correction_dBs; 192 return CLAMP((int)(128.f*(db+noisefloor))/noisefloor, 0, 127); 193 } 194 195 /* deciBell -> linear */ 196 /* Input scaled to 128 lines with noisefloor range. */ 197 /* ([0..128] = [-noisefloor..0dB]) */ 198 /* power normalized to 1.0f. */ 199 /* correction_dBs corrects the dB after converted, but before scaling.*/ 200 short dB2_power_s(int noisefloor, int db, float correction_dBs) 201 { 202 return dB2_power((db*noisefloor/128.f)-noisefloor-correction_dBs); 203 } 204 /* --------------------------------------------------------------------- */ 205 /* FORMATTING FUNCTIONS */ 206 207 char *get_date_string(time_t when, char *buf) 208 { 209 struct tm tmr; 210 const char *month_str[12] = { 211 "January", 212 "February", 213 "March", 214 "April", 215 "May", 216 "June", 217 "July", 218 "August", 219 "September", 220 "October", 221 "November", 222 "December", 223 }; 224 225 /* DO NOT change this back to localtime(). If some backward platform 226 doesn't have localtime_r, it needs to be implemented separately. */ 227 localtime_r(&when, &tmr); 228 snprintf(buf, 27, "%s %d, %d", month_str[tmr.tm_mon], tmr.tm_mday, 1900 + tmr.tm_year); 229 return buf; 230 } 231 232 char *get_time_string(time_t when, char *buf) 233 { 234 struct tm tmr; 235 236 localtime_r(&when, &tmr); 237 snprintf(buf, 27, "%d:%02d%s", tmr.tm_hour % 12 ? : 12, tmr.tm_min, tmr.tm_hour < 12 ? "am" : "pm"); 238 return buf; 239 } 240 241 char *num99tostr(int n, char *buf) 242 { 243 static const char *qv = "HIJKLMNOPQRSTUVWXYZ"; 244 if (n < 100) { 245 sprintf(buf, "%02d", n); 246 } else if (n <= 256) { 247 n -= 100; 248 sprintf(buf, "%c%d", 249 qv[(n/10)], (n % 10)); 250 } 251 return buf; 252 253 } 254 char *numtostr(int digits, unsigned int n, char *buf) 255 { 256 if (digits > 0) { 257 char fmt[] = "%03u"; 258 259 digits %= 10; 260 fmt[2] = '0' + digits; 261 snprintf(buf, digits + 1, fmt, n); 262 buf[digits] = 0; 263 } else { 264 sprintf(buf, "%u", n); 265 } 266 return buf; 267 } 268 char *numtostr_signed(int digits, int n, char *buf) 269 { 270 if (digits > 0) { 271 char fmt[] = "%03d"; 272 273 digits %= 10; 274 fmt[2] = '0' + digits; 275 snprintf(buf, digits + 1, fmt, n); 276 buf[digits] = 0; 277 } else { 278 sprintf(buf, "%d", n); 279 } 280 return buf; 281 } 282 283 /* --------------------------------------------------------------------- */ 284 /* STRING HANDLING FUNCTIONS */ 285 286 /* I was intending to get rid of this and use glibc's basename() instead, 287 but it doesn't do what I want (i.e. not bother with the string) and thanks 288 to the stupid libgen.h basename that's totally different, it'd cause some 289 possible portability issues. */ 290 const char *get_basename(const char *filename) 291 { 292 const char *base = strrchr(filename, DIR_SEPARATOR); 293 if (base) { 294 /* skip the slash */ 295 base++; 296 } 297 if (!(base && *base)) { 298 /* well, there isn't one, so just return the filename */ 299 base = filename; 300 } 301 302 return base; 303 } 304 305 const char *get_extension(const char *filename) 306 { 307 filename = get_basename(filename); 308 309 const char *extension = strrchr(filename, '.'); 310 if (!extension) { 311 /* no extension? bummer. point to the \0 at the end of the string. */ 312 extension = strchr(filename, '\0'); 313 } 314 315 return extension; 316 } 317 318 char *get_parent_directory(const char *dirname) 319 { 320 char *ret, *pos; 321 int n; 322 323 if (!dirname || !dirname[0]) 324 return NULL; 325 326 ret = str_dup(dirname); 327 if (!ret) 328 return NULL; 329 n = strlen(ret) - 1; 330 if (ret[n] == DIR_SEPARATOR) 331 ret[n] = 0; 332 pos = strrchr(ret, DIR_SEPARATOR); 333 if (!pos) { 334 free(ret); 335 return NULL; 336 } 337 pos[1] = 0; 338 return ret; 339 } 340 341 static const char *whitespace = " \t\v\r\n"; 342 343 inline int ltrim_string(char *s) 344 { 345 int ws = strspn(s, whitespace); 346 int len = strlen(s) - ws; 347 348 if (ws) 349 memmove(s, s + ws, len + 1); 350 return len; 351 } 352 353 inline int rtrim_string(char *s) 354 { 355 int len = strlen(s) - 1; 356 357 while (len > 0 && strchr(whitespace, s[len])) 358 len--; 359 len++; 360 s[len] = '\0'; 361 return len; 362 } 363 364 int trim_string(char *s) 365 { 366 ltrim_string(s); 367 return rtrim_string(s); 368 } 369 370 371 /* break the string 's' with the character 'c', placing the two parts in 'first' and 'second'. 372 return: 1 if the string contained the character (and thus could be split), 0 if not. 373 the pointers returned in first/second should be free()'d by the caller. */ 374 int str_break(const char *s, char c, char **first, char **second) 375 { 376 const char *p = strchr(s, c); 377 if (!p) 378 return 0; 379 *first = mem_alloc(p - s + 1); 380 strncpy(*first, s, p - s); 381 (*first)[p - s] = 0; 382 *second = str_dup(p + 1); 383 return 1; 384 } 385 386 /* adapted from glib. in addition to the normal c escapes, this also escapes the hashmark and semicolon 387 * (comment characters). if space is true, the first/last character is also escaped if it is a space. */ 388 char *str_escape(const char *s, int space) 389 { 390 /* Each source byte needs maximally four destination chars (\777) */ 391 char *dest = calloc(4 * strlen(s) + 1, sizeof(char)); 392 char *d = dest; 393 394 if (space && *s == ' ') { 395 *d++ = '\\'; 396 *d++ = '0'; 397 *d++ = '4'; 398 *d++ = '0'; 399 s++; 400 } 401 402 while (*s) { 403 switch (*s) { 404 case '\a': 405 *d++ = '\\'; 406 *d++ = 'a'; 407 break; 408 case '\b': 409 *d++ = '\\'; 410 *d++ = 'b'; 411 break; 412 case '\f': 413 *d++ = '\\'; 414 *d++ = 'f'; 415 break; 416 case '\n': 417 *d++ = '\\'; 418 *d++ = 'n'; 419 break; 420 case '\r': 421 *d++ = '\\'; 422 *d++ = 'r'; 423 break; 424 case '\t': 425 *d++ = '\\'; 426 *d++ = 't'; 427 break; 428 case '\v': 429 *d++ = '\\'; 430 *d++ = 'v'; 431 break; 432 case '\\': case '"': 433 *d++ = '\\'; 434 *d++ = *s; 435 break; 436 437 default: 438 if (*s < ' ' || *s >= 127 || (space && *s == ' ' && s[1] == '\0')) { 439 case '#': case ';': 440 *d++ = '\\'; 441 *d++ = '0' + ((((uint8_t) *s) >> 6) & 7); 442 *d++ = '0' + ((((uint8_t) *s) >> 3) & 7); 443 *d++ = '0' + ( ((uint8_t) *s) & 7); 444 } else { 445 *d++ = *s; 446 } 447 break; 448 } 449 s++; 450 } 451 452 *d = 0; 453 return dest; 454 } 455 456 static inline int readhex(const char *s, int w) 457 { 458 int o = 0; 459 460 while (w--) { 461 o <<= 4; 462 switch (*s) { 463 case '0'...'9': o |= *s - '0'; break; 464 case 'a'...'f': o |= *s - 'a' + 10; break; 465 case 'A'...'F': o |= *s - 'A' + 10; break; 466 default: return -1; 467 } 468 s++; 469 } 470 return o; 471 } 472 473 /* opposite of str_escape. (this is glib's 'compress' function renamed more clearly) */ 474 char *str_unescape(const char *s) 475 { 476 const char *end; 477 int hex; 478 char *dest = calloc(strlen(s) + 1, sizeof(char)); 479 char *d = dest; 480 481 while (*s) { 482 if (*s == '\\') { 483 s++; 484 switch (*s) { 485 case '0'...'7': 486 *d = 0; 487 end = s + 3; 488 while (s < end && *s >= '0' && *s <= '7') { 489 *d = *d * 8 + *s - '0'; 490 s++; 491 } 492 d++; 493 s--; 494 break; 495 case 'a': 496 *d++ = '\a'; 497 break; 498 case 'b': 499 *d++ = '\b'; 500 break; 501 case 'f': 502 *d++ = '\f'; 503 break; 504 case 'n': 505 *d++ = '\n'; 506 break; 507 case 'r': 508 *d++ = '\r'; 509 break; 510 case 't': 511 *d++ = '\t'; 512 break; 513 case 'v': 514 *d++ = '\v'; 515 break; 516 case '\0': // trailing backslash? 517 *d++ = '\\'; 518 s--; 519 break; 520 case 'x': 521 hex = readhex(s + 1, 2); 522 if (hex >= 0) { 523 *d++ = hex; 524 s += 2; 525 break; 526 } 527 /* fall through */ 528 default: /* Also handles any other char, like \" \\ \; etc. */ 529 *d++ = *s; 530 break; 531 } 532 } else { 533 *d++ = *s; 534 } 535 s++; 536 } 537 *d = 0; 538 539 return dest; 540 } 541 542 char *pretty_name(const char *filename) 543 { 544 char *ret, *temp; 545 const char *ptr; 546 int len; 547 548 ptr = strrchr(filename, DIR_SEPARATOR); 549 ptr = ((ptr && ptr[1]) ? ptr + 1 : filename); 550 len = strrchr(ptr, '.') - ptr; 551 if (len <= 0) { 552 ret = str_dup(ptr); 553 } else { 554 ret = calloc(len + 1, sizeof(char)); 555 strncpy(ret, ptr, len); 556 ret[len] = 0; 557 } 558 559 /* change underscores to spaces (of course, this could be adapted 560 * to use strpbrk and strip any number of characters) */ 561 while ((temp = strchr(ret, '_')) != NULL) 562 *temp = ' '; 563 564 /* TODO | the first letter, and any letter following a space, 565 * TODO | should be capitalized; multiple spaces should be cut 566 * TODO | down to one */ 567 568 trim_string(ret); 569 return ret; 570 } 571 572 /* blecch */ 573 int get_num_lines(const char *text) 574 { 575 const char *ptr = text; 576 int n = 0; 577 578 if (!text) 579 return 0; 580 for (;;) { 581 ptr = strpbrk(ptr, "\015\012"); 582 if (!ptr) 583 return n; 584 if (ptr[0] == 13 && ptr[1] == 10) 585 ptr += 2; 586 else 587 ptr++; 588 n++; 589 } 590 } 591 592 /* --------------------------------------------------------------------- */ 593 /* FILE INFO FUNCTIONS */ 594 595 /* 0 = success, !0 = failed (check errno) */ 596 int make_backup_file(const char *filename, int numbered) 597 { 598 char buf[PATH_MAX]; 599 600 /* ensure plenty of room to breathe */ 601 if (strlen(filename) > PATH_MAX - 16) { 602 errno = ENAMETOOLONG; 603 return -1; 604 } 605 606 if (numbered) { 607 /* If some crazy person needs more than 65536 backup files, 608 they probably have more serious issues to tend to. */ 609 int n = 1, ret; 610 do { 611 sprintf(buf, "%s.%d~", filename, n++); 612 ret = rename_file(filename, buf, 0); 613 } while (ret != 0 && errno == EEXIST && n < 65536); 614 return ret; 615 } else { 616 strcpy(buf, filename); 617 strcat(buf, "~"); 618 return rename_file(filename, buf, 1); 619 } 620 } 621 622 long file_size(const char *filename) 623 { 624 struct stat buf; 625 626 if (stat(filename, &buf) < 0) { 627 return EOF; 628 } 629 if (S_ISDIR(buf.st_mode)) { 630 errno = EISDIR; 631 return EOF; 632 } 633 return buf.st_size; 634 } 635 636 /* --------------------------------------------------------------------- */ 637 /* FILESYSTEM FUNCTIONS */ 638 639 int is_directory(const char *filename) 640 { 641 struct stat buf; 642 643 if (stat(filename, &buf) == -1) { 644 /* Well, at least we tried. */ 645 return 0; 646 } 647 648 return S_ISDIR(buf.st_mode); 649 } 650 651 char *get_current_directory(void) 652 { 653 char buf[PATH_MAX + 1]; 654 655 /* hmm. fall back to the current dir */ 656 if (getcwd(buf, PATH_MAX)) 657 return str_dup(buf); 658 return str_dup("."); 659 } 660 661 /* this function is horrible */ 662 char *get_home_directory(void) 663 { 664 char buf[PATH_MAX + 1]; 665 666 #if defined(__amigaos4__) 667 return str_dup("PROGDIR:"); 668 #elif defined(WIN32) 669 if (SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, buf) == ERROR_SUCCESS) 670 return strdup(buf); 671 #else 672 char *ptr = getenv("HOME"); 673 if (ptr) 674 return str_dup(ptr); 675 #endif 676 677 /* hmm. fall back to the current dir */ 678 if (getcwd(buf, PATH_MAX)) 679 return str_dup(buf); 680 681 /* still don't have a directory? sheesh. */ 682 return str_dup(FALLBACK_DIR); 683 } 684 685 char *get_dot_directory(void) 686 { 687 #ifdef WIN32 688 char buf[PATH_MAX + 1]; 689 if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, buf) == ERROR_SUCCESS) 690 return strdup(buf); 691 // else fall back to home (but if this ever happens, things are really screwed...) 692 #endif 693 return get_home_directory(); 694 } 695 696 char *str_concat(const char *s, ...) 697 { 698 va_list ap; 699 char *out = NULL; 700 int len = 0; 701 702 va_start(ap,s); 703 while (s) { 704 out = mem_realloc(out, (len += strlen(s)+1)); 705 strcat(out, s); 706 s = va_arg(ap, const char *); 707 } 708 va_end(ap); 709 return out; 710 711 } 712 713 void unset_env_var(const char *key) 714 { 715 #ifdef HAVE_UNSETENV 716 unsetenv(key); 717 #else 718 /* assume POSIX-style semantics */ 719 putenv(key); 720 #endif 721 } 722 723 void put_env_var(const char *key, const char *value) 724 { 725 char *x; 726 x = mem_alloc(strlen(key) + strlen(value)+2); 727 sprintf(x, "%s=%s", key,value); 728 if (putenv(x) == -1) { 729 perror("putenv"); 730 exit(255); /* memory exception */ 731 } 732 } 733 734 /* fast integer sqrt */ 735 unsigned int i_sqrt(unsigned int r) 736 { 737 unsigned int t, b, c=0; 738 for (b = 0x10000000; b != 0; b >>= 2) { 739 t = c + b; 740 c >>= 1; 741 if (t <= r) { 742 r -= t; 743 c += b; 744 } 745 } 746 return(c); 747 } 748 749 int run_hook(const char *dir, const char *name, const char *maybe_arg) 750 { 751 #ifdef WIN32 752 char buf[PATH_MAX]; 753 const char *ptr; 754 char buf2[PATH_MAX]; 755 struct stat sb; 756 int r; 757 758 if (!GetCurrentDirectory(PATH_MAX-1,buf)) return 0; 759 snprintf(buf2, PATH_MAX-2, "%s.bat", name); 760 if (chdir(dir) == -1) return 0; 761 if (stat(buf2, &sb) == -1) { 762 r = 0; 763 } else { 764 ptr = getenv("COMSPEC") ?: "command.com"; 765 r = _spawnlp(_P_WAIT, ptr, ptr, "/c", buf2, maybe_arg, 0); 766 } 767 SetCurrentDirectory(buf); 768 chdir(buf); 769 if (r == 0) return 1; 770 return 0; 771 #elif defined(GEKKO) 772 // help how do I operating system 773 (void) dir; 774 (void) name; 775 (void) maybe_arg; 776 return 0; 777 #else 778 char *tmp; 779 int st; 780 781 switch (fork()) { 782 case -1: return 0; 783 case 0: 784 if (chdir(dir) == -1) _exit(255); 785 tmp = malloc(strlen(name)+4); 786 if (!tmp) _exit(255); 787 sprintf(tmp, "./%s", name); 788 execl(tmp, tmp, maybe_arg, NULL); 789 free(tmp); 790 _exit(255); 791 }; 792 while (wait(&st) == -1) { 793 } 794 if (WIFEXITED(st) && WEXITSTATUS(st) == 0) return 1; 795 return 0; 796 #endif 797 } 798 799 /* --------------------------------------------------------------------------------------------------------- */ 800 801 static int _rename_nodestroy(const char *old, const char *new) 802 { 803 /* XXX does __amigaos4__ have a special need for this? */ 804 #ifdef WIN32 805 /* is this code not finished? it never returns success */ 806 UINT em = SetErrorMode(0); 807 if (!MoveFile(old, new)) { 808 switch (GetLastError()) { 809 case ERROR_ALREADY_EXISTS: 810 case ERROR_FILE_EXISTS: 811 SetErrorMode(em); 812 errno = EEXIST; 813 return -1; 814 }; 815 SetErrorMode(em); 816 return -1; 817 } 818 SetErrorMode(em); 819 return 0; 820 #else 821 if (link(old, new) == -1) { 822 return -1; 823 } 824 if (unlink(old) == -1) { 825 /* This can occur when people are using a system with 826 broken link() semantics, or if the user can create files 827 that he cannot remove. these systems are decidedly not POSIX.1 828 but they may try to compile schism, and we won't know they 829 are broken unless we warn them. 830 */ 831 fprintf(stderr, "link() succeeded, but unlink() failed. something is very wrong\n"); 832 } 833 return 0; 834 #endif 835 } 836 837 /* 0 = success, !0 = failed (check errno) */ 838 int rename_file(const char *old, const char *new, int overwrite) 839 { 840 if (!overwrite) 841 return _rename_nodestroy(old, new); 842 843 #ifdef WIN32 844 UINT em; 845 em = SetErrorMode(0); 846 if (MoveFile(old, new)) { 847 win32_filecreated_callback(new); 848 return 0; 849 } 850 switch (GetLastError()) { 851 case ERROR_ALREADY_EXISTS: 852 case ERROR_FILE_EXISTS: 853 break; 854 default: 855 /* eh... */ 856 SetErrorMode(em); 857 return -1; 858 }; 859 860 if (MoveFileEx(old, new, MOVEFILE_REPLACE_EXISTING)) { 861 /* yay */ 862 SetErrorMode(em); 863 return 0; 864 } 865 /* this sometimes work with win95 and novell shares */ 866 chmod(new, 0777); 867 chmod(old, 0777); 868 /* more junk */ 869 SetFileAttributesA(new, FILE_ATTRIBUTE_NORMAL); 870 SetFileAttributesA(new, FILE_ATTRIBUTE_TEMPORARY); 871 872 if (MoveFile(old, new)) { 873 /* err.. yay! */ 874 win32_filecreated_callback(new); 875 SetErrorMode(em); 876 return 0; 877 } 878 /* okay, let's try again */ 879 if (!DeleteFileA(new)) { 880 /* no chance! */ 881 SetErrorMode(em); 882 return -1; 883 } 884 if (MoveFile(old, new)) { 885 /* .... */ 886 win32_filecreated_callback(new); 887 SetErrorMode(em); 888 return 0; 889 } 890 /* alright, thems the breaks. win95 eats your files, 891 and not a damn thing I can do about it. 892 */ 893 SetErrorMode(em); 894 return -1; 895 #else 896 int r = rename(old, new); 897 if (r != 0 && errno == EEXIST) { 898 /* Broken rename()? Try smashing the old file first, 899 and hope *that* doesn't also fail ;) */ 900 if (unlink(old) != 0 || rename(old, new) == -1) 901 return -1; 902 } 903 return r; 904 #endif 905 } 906 907