600 |
604 |
601 SetUnhandledExceptionFilter(ExceptionHandler); |
605 SetUnhandledExceptionFilter(ExceptionHandler); |
602 } |
606 } |
603 #endif /* _MSC_VER */ |
607 #endif /* _MSC_VER */ |
604 |
608 |
|
609 /* Code below for windows version of opendir/readdir/closedir copied and |
|
610 * modified from Jan Wassenberg's GPL implementation posted over at |
|
611 * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1� */ |
|
612 |
|
613 /* suballocator - satisfies most requests with a reusable static instance. |
|
614 * this avoids hundreds of alloc/free which would fragment the heap. |
|
615 * To guarantee thread-safety, we fall back to malloc if the instance is |
|
616 * already in use (it's important to avoid suprises since this is such a |
|
617 * low-level routine). */ |
|
618 static DIR _global_dir; |
|
619 static bool _global_dir_is_in_use = false; |
|
620 |
|
621 static inline DIR *dir_calloc(void) |
|
622 { |
|
623 DIR *d; |
|
624 |
|
625 if (_global_dir_is_in_use) { |
|
626 d = calloc(1, sizeof(DIR)); |
|
627 } else { |
|
628 _global_dir_is_in_use = true; |
|
629 d = &_global_dir; |
|
630 memset(d, 0, sizeof(DIR)); |
|
631 } |
|
632 return d; |
|
633 } |
|
634 |
|
635 static inline void dir_free(DIR *d) |
|
636 { |
|
637 if (d == &_global_dir) { |
|
638 _global_dir_is_in_use = false; |
|
639 } else { |
|
640 free(d); |
|
641 } |
|
642 } |
|
643 |
|
644 DIR *opendir(const char *path) |
|
645 { |
|
646 char search_path[MAX_PATH]; |
|
647 DIR *d; |
|
648 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box |
|
649 DWORD fa = GetFileAttributes(path); |
|
650 |
|
651 /* not a directory or path not found */ |
|
652 if (fa == INVALID_FILE_ATTRIBUTES || (fa & FILE_ATTRIBUTE_DIRECTORY) == 0) { |
|
653 errno = ENOENT; |
|
654 return NULL; |
|
655 } |
|
656 |
|
657 d = dir_calloc(); |
|
658 if (d == NULL) { |
|
659 errno = ENOMEM; |
|
660 return NULL; |
|
661 } |
|
662 |
|
663 /* build search path for FindFirstFile */ |
|
664 snprintf(search_path, lengthof(search_path), "%s" PATHSEP "*", path); |
|
665 d->hFind = FindFirstFile(search_path, &d->fd); |
|
666 SetErrorMode(sem); // restore previous setting |
|
667 |
|
668 if (d->hFind == INVALID_HANDLE_VALUE) { |
|
669 /* not an error - the directory is just empty */ |
|
670 if (GetLastError() == ERROR_NO_MORE_FILES) return NULL; |
|
671 dir_free(d); |
|
672 } |
|
673 |
|
674 d->ent.dir = d; |
|
675 d->at_first_entry = true; |
|
676 return d; |
|
677 } |
|
678 |
|
679 struct dirent *readdir(DIR *d) |
|
680 { |
|
681 DWORD prev_err = GetLastError(); // avoid polluting last error |
|
682 |
|
683 if (d->at_first_entry) { |
|
684 /* the directory was empty when opened */ |
|
685 if (d->hFind == INVALID_HANDLE_VALUE) return NULL; |
|
686 d->at_first_entry = false; |
|
687 goto already_have_file; |
|
688 } |
|
689 |
|
690 /* Go until the end of directory or until a valid entry was found */ |
|
691 if (!FindNextFile(d->hFind, &d->fd)) { // determine cause and bail |
|
692 if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err); |
|
693 return NULL; |
|
694 } |
|
695 |
|
696 already_have_file: |
|
697 /* This entry has passed all checks; return information about it. |
|
698 * (note: d_name is a pointer; see struct dirent definition) */ |
|
699 d->ent.d_name = d->fd.cFileName; |
|
700 return &d->ent; |
|
701 } |
|
702 |
|
703 int closedir(DIR *d) |
|
704 { |
|
705 FindClose(d->hFind); |
|
706 dir_free(d); |
|
707 return 0; |
|
708 } |
|
709 |
605 static char *_fios_path; |
710 static char *_fios_path; |
606 static char *_fios_save_path; |
711 static char *_fios_save_path; |
607 static char *_fios_scn_path; |
712 static char *_fios_scn_path; |
608 static FiosItem *_fios_items; |
713 static FiosItem *_fios_items; |
609 static int _fios_count, _fios_alloc; |
714 static int _fios_count, _fios_alloc; |