4
4
5
5
#include " libqb-common.h"
6
6
7
+ #include " error_handle.h"
7
8
#include " filepath.h"
8
9
#include " filesystem.h"
9
10
10
11
#include " ../../libqb.h"
11
12
12
13
#include < algorithm>
13
14
#include < dirent.h>
15
+ #include < memory>
14
16
#include < sys/stat.h>
15
17
#include < unistd.h>
16
18
#ifdef QB64_WINDOWS
@@ -423,7 +425,7 @@ qbs *func__dir(qbs *qbsContext) {
423
425
// / @param path The directory path
424
426
// / @return True if the directory exists
425
427
int32_t func__direxists (qbs *path) {
426
- if (new_error )
428
+ if (is_error_pending () )
427
429
return QB_FALSE;
428
430
429
431
std::string pathName (reinterpret_cast <char *>(path->chr ), path->len );
@@ -450,7 +452,7 @@ bool FS_FileExists(const char *path) {
450
452
// / @param path The file path to check for
451
453
// / @return True if the file exists
452
454
int32_t func__fileexists (qbs *path) {
453
- if (new_error )
455
+ if (is_error_pending () )
454
456
return QB_FALSE;
455
457
456
458
std::string pathName (reinterpret_cast <char *>(path->chr ), path->len );
@@ -471,7 +473,7 @@ qbs *func__startdir() {
471
473
// / @brief Changes the current directory
472
474
// / @param str The directory path to change to
473
475
void sub_chdir (qbs *str) {
474
- if (new_error )
476
+ if (is_error_pending () )
475
477
return ;
476
478
477
479
std::string pathName (reinterpret_cast <char *>(str->chr ), str->len );
@@ -540,21 +542,34 @@ static inline bool FS_IsPatternMatching(const char *fileSpec, const char *fileNa
540
542
// / @return True if * or ? are found
541
543
static inline bool FS_HasPattern (const char *fileSpec) { return fileSpec != nullptr && (strchr (fileSpec, ' *' ) || strchr (fileSpec, ' ?' )); }
542
544
545
+ struct DirectoryContext {
546
+ DIR *directory;
547
+ char pattern[FS_PATHNAME_LENGTH_MAX];
548
+ char entry[FS_PATHNAME_LENGTH_MAX];
549
+
550
+ DirectoryContext () : directory(nullptr ) {
551
+ pattern[0 ] = ' \0 ' ;
552
+ entry[0 ] = ' \0 ' ;
553
+ }
554
+
555
+ ~DirectoryContext () {
556
+ if (directory)
557
+ closedir (directory);
558
+ }
559
+ };
560
+
543
561
// / @brief An MS BASIC PDS DIR$ style function
562
+ // / @param ctx The directory context
544
563
// / @param fileSpec This can be a path with wildcard for the final level (i.e. C:/Windows/*.* or /usr/lib/* etc.)
545
564
// / @return Returns a file or directory name matching fileSpec or an empty string when there is nothing left
546
- static const char *FS_GetDirectoryEntryName (const char *fileSpec) {
547
- static DIR *pDir = nullptr ;
548
- static char pattern[FS_PATHNAME_LENGTH_MAX];
549
- static char entry[FS_PATHNAME_LENGTH_MAX];
550
-
551
- entry[0 ] = ' \0 ' ; // set to an empty string
565
+ static const char *FS_GetDirectoryEntryName (DirectoryContext *ctx, const char *fileSpec) {
566
+ ctx->entry [0 ] = ' \0 ' ; // set to an empty string
552
567
553
568
if (!FS_IsStringEmpty (fileSpec)) {
554
569
// We got a filespec. Check if we have one already going and if so, close it
555
- if (pDir ) {
556
- closedir (pDir );
557
- pDir = nullptr ;
570
+ if (ctx-> directory ) {
571
+ closedir (ctx-> directory );
572
+ ctx-> directory = nullptr ;
558
573
}
559
574
560
575
char dirName[FS_PATHNAME_LENGTH_MAX]; // we only need this for opendir()
@@ -569,62 +584,63 @@ static const char *FS_GetDirectoryEntryName(const char *fileSpec) {
569
584
570
585
if (p) {
571
586
// Split the path and the filespec
572
- strncpy (pattern, p + 1 , FS_PATHNAME_LENGTH_MAX);
573
- pattern[FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
587
+ strncpy (ctx-> pattern , p + 1 , FS_PATHNAME_LENGTH_MAX);
588
+ ctx-> pattern [FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
574
589
auto len = std::min<size_t >((p - fileSpec) + 1 , FS_PATHNAME_LENGTH_MAX - 1 );
575
590
memcpy (dirName, fileSpec, len);
576
591
dirName[len] = ' \0 ' ;
577
592
} else {
578
593
// No path. Use the current path
579
- strncpy (pattern, fileSpec, FS_PATHNAME_LENGTH_MAX);
580
- pattern[FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
594
+ strncpy (ctx-> pattern , fileSpec, FS_PATHNAME_LENGTH_MAX);
595
+ ctx-> pattern [FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
581
596
strcpy (dirName, " ./" );
582
597
}
583
598
} else {
584
599
// No pattern. Check if this is a file and simply return the name if it exists
585
600
if (FS_FileExists (fileSpec)) {
586
- strncpy (entry, filepath_get_filename (fileSpec), FS_PATHNAME_LENGTH_MAX);
587
- entry[FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
601
+ strncpy (ctx-> entry , filepath_get_filename (fileSpec), FS_PATHNAME_LENGTH_MAX);
602
+ ctx-> entry [FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
588
603
589
- return entry;
604
+ return ctx-> entry ;
590
605
}
591
606
592
607
// Else, We'll just assume it's a directory
593
608
strncpy (dirName, fileSpec, FS_PATHNAME_LENGTH_MAX);
594
609
dirName[FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
595
- strcpy (pattern, " *" );
610
+ strcpy (ctx-> pattern , " *" );
596
611
}
597
612
598
- pDir = opendir (dirName);
613
+ ctx-> directory = opendir (dirName);
599
614
}
600
615
601
- if (pDir ) {
616
+ if (ctx-> directory ) {
602
617
for (;;) {
603
- auto pDirent = readdir (pDir );
618
+ auto pDirent = readdir (ctx-> directory );
604
619
if (!pDirent) {
605
- closedir (pDir );
606
- pDir = nullptr ;
620
+ closedir (ctx-> directory );
621
+ ctx-> directory = nullptr ;
607
622
608
623
break ;
609
624
}
610
625
611
- if (FS_IsPatternMatching (pattern, pDirent->d_name )) {
612
- strncpy (entry, pDirent->d_name , FS_PATHNAME_LENGTH_MAX);
613
- entry[FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
626
+ if (FS_IsPatternMatching (ctx-> pattern , pDirent->d_name )) {
627
+ strncpy (ctx-> entry , pDirent->d_name , FS_PATHNAME_LENGTH_MAX);
628
+ ctx-> entry [FS_PATHNAME_LENGTH_MAX - 1 ] = ' \0 ' ;
614
629
615
630
break ;
616
631
}
617
632
}
618
633
}
619
634
620
- return entry;
635
+ return ctx-> entry ;
621
636
}
622
637
623
638
// / @brief This mimics MS BASIC PDS 7.1 & VBDOS 1.0 DIR$() function
624
639
// / @param qbsFileSpec This can be a path with wildcard for the final level (i.e. C:/Windows/*.* or /usr/lib/* etc.)
625
640
// / @param passed Flags for optional parameters
626
641
// / @return Returns a qbs with the directory entry name or an empty string if there are no more entries
627
642
qbs *func__files (qbs *qbsFileSpec, int32_t passed) {
643
+ static DirectoryContext directoryContext;
628
644
static std::string directory;
629
645
std::string pathName;
630
646
const char *entry;
@@ -645,7 +661,7 @@ qbs *func__files(qbs *qbsFileSpec, int32_t passed) {
645
661
directory = " ./" ;
646
662
}
647
663
648
- entry = FS_GetDirectoryEntryName (fileSpec.c_str ());
664
+ entry = FS_GetDirectoryEntryName (&directoryContext, fileSpec.c_str ());
649
665
} else {
650
666
// Check if we've been called the first time without a filespec
651
667
if (directory.empty ()) {
@@ -655,7 +671,7 @@ qbs *func__files(qbs *qbsFileSpec, int32_t passed) {
655
671
return qbsFinal;
656
672
}
657
673
658
- entry = FS_GetDirectoryEntryName (nullptr ); // get the next entry
674
+ entry = FS_GetDirectoryEntryName (&directoryContext, nullptr ); // get the next entry
659
675
}
660
676
661
677
filepath_join (pathName, directory, entry);
@@ -781,7 +797,7 @@ static std::string FS_GetShortName(const char *path) {
781
797
void sub_files (qbs *str, int32_t passed) {
782
798
static qbs *strz = nullptr ;
783
799
784
- if (new_error )
800
+ if (is_error_pending () )
785
801
return ;
786
802
787
803
if (!strz)
@@ -819,7 +835,8 @@ void sub_files(qbs *str, int32_t passed) {
819
835
qbs_set (strz, qbs_new_txt_len (shortName.c_str (), shortName.size ()));
820
836
qbs_print (strz, 1 );
821
837
822
- auto entry = FS_GetDirectoryEntryName (fileSpec.c_str ()); // get the first entry
838
+ auto directoryContext = std::make_unique<DirectoryContext>();
839
+ auto entry = FS_GetDirectoryEntryName (directoryContext.get (), fileSpec.c_str ()); // get the first entry
823
840
filepath_join (pathName, directory, entry);
824
841
825
842
if (FS_IsStringEmpty (entry)) {
@@ -854,7 +871,7 @@ void sub_files(qbs *str, int32_t passed) {
854
871
makefit (strz);
855
872
qbs_print (strz, 0 );
856
873
857
- entry = FS_GetDirectoryEntryName (nullptr ); // get the next entry
874
+ entry = FS_GetDirectoryEntryName (directoryContext. get (), nullptr ); // get the next entry
858
875
filepath_join (pathName, directory, entry);
859
876
} while (!FS_IsStringEmpty (entry));
860
877
@@ -872,13 +889,15 @@ void sub_files(qbs *str, int32_t passed) {
872
889
// / @brief Deletes files from disk
873
890
// / @param str The file(s) to delete (may contain wildcard at the final level)
874
891
void sub_kill (qbs *str) {
875
- if (new_error)
892
+
893
+ if (is_error_pending ())
876
894
return ;
877
895
878
896
std::string directory, pathName, fileSpec (reinterpret_cast <char *>(str->chr ), str->len );
879
-
880
897
filepath_split (filepath_fix_directory (fileSpec), directory, pathName); // split the file path
881
- auto entry = FS_GetDirectoryEntryName (fileSpec.c_str ()); // get the first entry
898
+
899
+ auto directoryContext = std::make_unique<DirectoryContext>();
900
+ auto entry = FS_GetDirectoryEntryName (directoryContext.get (), fileSpec.c_str ()); // get the first entry
882
901
883
902
// Keep looking through the entries until we file a file
884
903
while (!FS_IsStringEmpty (entry)) {
@@ -887,7 +906,7 @@ void sub_kill(qbs *str) {
887
906
if (FS_FileExists (pathName.c_str ()))
888
907
break ;
889
908
890
- entry = FS_GetDirectoryEntryName (nullptr ); // get the next entry
909
+ entry = FS_GetDirectoryEntryName (directoryContext. get (), nullptr ); // get the next entry
891
910
}
892
911
893
912
// Check if we have exhausted the entries without ever finding a file
@@ -917,15 +936,15 @@ void sub_kill(qbs *str) {
917
936
}
918
937
}
919
938
920
- entry = FS_GetDirectoryEntryName (nullptr ); // get the next entry
939
+ entry = FS_GetDirectoryEntryName (directoryContext. get (), nullptr ); // get the next entry
921
940
filepath_join (pathName, directory, entry);
922
941
} while (!FS_IsStringEmpty (entry));
923
942
}
924
943
925
944
// / @brief Creates a new directory
926
945
// / @param str The directory path name to create
927
946
void sub_mkdir (qbs *str) {
928
- if (new_error )
947
+ if (is_error_pending () )
929
948
return ;
930
949
931
950
std::string pathName (reinterpret_cast <char *>(str->chr ), str->len );
@@ -949,7 +968,7 @@ void sub_mkdir(qbs *str) {
949
968
// / @param oldname The old file / directory name
950
969
// / @param newname The new file / directory name
951
970
void sub_name (qbs *oldname, qbs *newname) {
952
- if (new_error )
971
+ if (is_error_pending () )
953
972
return ;
954
973
955
974
std::string pathNameOld (reinterpret_cast <char *>(oldname->chr ), oldname->len ), pathNameNew (reinterpret_cast <char *>(newname->chr ), newname->len );
@@ -979,7 +998,7 @@ void sub_name(qbs *oldname, qbs *newname) {
979
998
// / @brief Deletes an empty directory
980
999
// / @param str The path name of the directory to delete
981
1000
void sub_rmdir (qbs *str) {
982
- if (new_error )
1001
+ if (is_error_pending () )
983
1002
return ;
984
1003
985
1004
std::string pathName (reinterpret_cast <char *>(str->chr ), str->len );
0 commit comments