filesystem.monkey2 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. Namespace std.filesystem
  2. Using libc
  3. #Import "native/filesystem.h"
  4. #Import "native/filesystem.cpp"
  5. Extern
  6. #rem monkeydoc Gets application directory.
  7. @return The directory containing the application executable.
  8. #end
  9. Function AppDir:String()="bbFileSystem::appDir"
  10. #rem monkeydoc Gets the application file path.
  11. @return The path of the application executable.
  12. #end
  13. Function AppPath:String()="bbFileSystem::appPath"
  14. #rem monkeydoc Gets application command line arguments.
  15. The first argument is always the application name.
  16. @return The application command line arguments.
  17. #end
  18. Function AppArgs:String[]()="bbFileSystem::appArgs"
  19. #rem monkeydoc Copies a file.
  20. Copies a file from `srcPath` to `dstPath`, overwriting `dstpath` if it alreay exits.
  21. Returns true if successful.
  22. @return True if the file was successfully copied.
  23. #end
  24. Function CopyFile:Bool( srcPath:String,dstPath:String )="bbFileSystem::copyFile"
  25. Public
  26. #rem monkeydoc FileType enumeration.
  27. | FileType | Description
  28. |:--------------|:-----------
  29. | `None` | File does not exist.
  30. | `File` | File is a normal file.
  31. | `Directory` | File is a directory.
  32. | `Unknown` | File is of unknown type.
  33. #end
  34. Enum FileType
  35. None=0
  36. File=1
  37. Directory=2
  38. Unknown=3
  39. End
  40. 'For backward compatibility - don't use!
  41. '
  42. #rem monkeydoc @hidden
  43. #end
  44. Const FILETYPE_NONE:=FileType.None
  45. #rem monkeydoc @hidden
  46. #end
  47. Const FILETYPE_FILE:=FileType.File
  48. #rem monkeydoc @hidden
  49. #end
  50. Const FILETYPE_DIR:=FileType.Directory
  51. #rem monkeydoc @hidden
  52. #end
  53. Const FILETYPE_UNKNOWN:=FileType.Unknown
  54. #rem monkeydoc Gets the filesystem directory of the assets directory.
  55. Note that assets are only stored in the filesystem on the desktop and emscripten targets. Other targets will return an empty string.
  56. @return The directory app assets are stored in.
  57. #end
  58. Function AssetsDir:String()
  59. #If __TARGET__="macos"
  60. Return AppDir()+"../Resources/"
  61. #Else If __DESKTOP_TARGET__ Or __TARGET__="emscripten"
  62. Return AppDir()+"assets/"
  63. #Else
  64. Return ""
  65. #Endif
  66. End
  67. #rem monkeydoc Gets the filesystem directory of the desktop directory.
  68. Note that only the desktop targets have a desktop directory. Other targets will return an empty string.
  69. @return The desktop directory.
  70. #end
  71. Function DesktopDir:String()
  72. #If __TARGET__="windows"
  73. Return (String.FromCString( getenv( "HOMEDRIVE" ) )+String.FromCString( getenv( "HOMEPATH" ) )).Replace( "\","/" )+"/Desktop/"
  74. #Else If __DESKTOP_TARGET__
  75. Return String.FromCString( getenv( "HOME" ) )+"/Desktop/"
  76. #Endif
  77. Return ""
  78. End
  79. #rem monkeydoc Extracts the root directory from a file system path.
  80. A root directory is a directory path that:
  81. * Starts with '//' or '/', or...
  82. * Starts with 'blah:/', 'blah://' or 'blah::'.
  83. @param path The filesystem path.
  84. @return The root directory of `path`, or an empty string if `path` is not an absolute path.
  85. #end
  86. Function ExtractRootDir:String( path:String )
  87. If path.StartsWith( "//" ) Return "//"
  88. Local i:=path.Find( "/" )
  89. If i=0 Return "/"
  90. If i=-1 i=path.Length
  91. Local j:=path.Find( "://" )
  92. If j>0 And j<i Return path.Slice( 0,j+3 )
  93. j=path.Find( ":/" )
  94. If j>0 And j<i Return path.Slice( 0,j+2 )
  95. j=path.Find( "::" )
  96. If j>0 And j<i Return path.Slice( 0,j+2 )
  97. Return ""
  98. End
  99. #rem monkeydoc Checks if a path is a root directory.
  100. @param path The filesystem path to check.
  101. @return True if `path` is a root directory path.
  102. #end
  103. Function IsRootDir:Bool( path:String )
  104. If path="//" Return True
  105. If path="/" Return True
  106. Local i:=path.Find( "/" )
  107. If i=-1 i=path.Length
  108. Local j:=path.Find( "://" )
  109. If j>0 And j<i Return j+3=path.Length
  110. j=path.Find( ":/" )
  111. If j>0 And j<i Return j+2=path.Length
  112. j=path.Find( "::" )
  113. If j>0 And j<i Return j+2=path.Length
  114. Return False
  115. End
  116. #rem monkeydoc Strips any trailing slashes from a filesystem path.
  117. This function will not strip slashes from a root directory path.
  118. @param path The filesystem path.
  119. @return The path stripped of trailing slashes.
  120. #end
  121. Function StripSlashes:String( path:String )
  122. If Not path.EndsWith( "/" ) Return path
  123. Local root:=ExtractRootDir( path )
  124. Repeat
  125. If path=root Return path
  126. path=path.Slice( 0,-1 )
  127. Until Not path.EndsWith( "/" )
  128. Return path
  129. End
  130. #rem monkeydoc Extracts the directory component from a filesystem path.
  131. If `path` is a root directory it is returned without modification.
  132. If `path` does not contain a directory component, an empty string is returned.
  133. @param path The filesystem path.
  134. @return The directory component of `path`.
  135. #end
  136. Function ExtractDir:String( path:String )
  137. path=StripSlashes( path )
  138. If IsRootDir( path ) Return path
  139. Local i:=path.FindLast( "/" )
  140. If i>=0 Return path.Slice( 0,i+1 )
  141. i=path.Find( "::" )
  142. If i>=0 Return path.Slice( 0,i+2 )
  143. Return ""
  144. End
  145. #rem monkeydoc Strips the directory component from a filesystem path.
  146. If `path` is a root directory an empty string is returned.
  147. If `path` does not contain a directory component, `path` is returned without modification.
  148. @param path The filesystem path.
  149. @return The path with the directory component stripped.
  150. #end
  151. Function StripDir:String( path:String )
  152. path=StripSlashes( path )
  153. If IsRootDir( path ) Return ""
  154. Local i:=path.FindLast( "/" )
  155. If i>=0 Return path.Slice( i+1 )
  156. i=path.Find( "::" )
  157. If i>=0 Return path.Slice( i+2 )
  158. Return path
  159. End
  160. #rem monkeydoc Extracts the extension component from a filesystem path.
  161. @param path The filesystem path.
  162. @return The extension component of `path` including the '.' if any.
  163. #end
  164. Function ExtractExt:String( path:String )
  165. Local i:=path.FindLast( "." )
  166. If i=-1 Return ""
  167. Local j:=path.Find( "/",i+1 )
  168. If j=-1 Return path.Slice( i )
  169. Return ""
  170. End
  171. #rem monkeydoc Strips the extension component from a filesystem path.
  172. @param path The filesystem path.
  173. @return The path with the extension stripped.
  174. #end
  175. Function StripExt:String( path:String )
  176. Local i:=path.FindLast( "." )
  177. If i=-1 Return path
  178. Local j:=path.Find( "/",i+1 )
  179. If j=-1 Return path.Slice( 0,i )
  180. Return path
  181. End
  182. #rem monkeydoc Converts a path to a real path.
  183. If `path` is a relative path, it is first converted into an absolute path by prefixing the current directory.
  184. Then, any internal './' or '../' references in the path are collapsed.
  185. @param path The filesystem path.
  186. @return An absolute path with any './', '../' references collapsed.
  187. #end
  188. Function RealPath:String( path:String )
  189. Local rpath:=ExtractRootDir( path )
  190. If rpath
  191. path=path.Slice( rpath.Length )
  192. Else
  193. rpath=CurrentDir()
  194. Endif
  195. While path
  196. Local i:=path.Find( "/" )
  197. If i=-1 Return rpath+path
  198. Local t:=path.Slice( 0,i )
  199. path=path.Slice( i+1 )
  200. Select t
  201. Case ""
  202. Case "."
  203. Case ".."
  204. If Not rpath rpath=CurrentDir()
  205. rpath=ExtractDir( rpath )
  206. Default
  207. rpath+=t+"/"
  208. End
  209. Wend
  210. Return rpath
  211. End
  212. #rem monkeydoc Gets the type of the file at a filesystem path.
  213. @param path The filesystem path.
  214. @return The file type of the file at `path`, one of: FileType.None, FileType.File or FileType.Directory.
  215. #end
  216. Function GetFileType:FileType( path:String )
  217. Local st:stat_t
  218. If stat( StripSlashes( path ),Varptr st )<0 Return FileType.None
  219. Select st.st_mode & S_IFMT
  220. Case S_IFREG Return FileType.File
  221. Case S_IFDIR Return FileType.Directory
  222. End
  223. Return FileType.Unknown
  224. End
  225. #rem monkeydoc Gets the time a file was most recently modified.
  226. @param path The filesystem path.
  227. @return The time the file at `path` was most recently modified.
  228. #end
  229. Function GetFileTime:Long( path:String )
  230. Local st:stat_t
  231. If stat( StripSlashes( path ),Varptr st )<0 Return 0
  232. Return libc.tolong( st.st_mtime )
  233. End
  234. #rem monkeydoc Gets the size of the file at a filesystem path.
  235. @param path The filesystem path.
  236. @return The size file at `path` in bytes.
  237. #end
  238. Function GetFileSize:Long( path:String )
  239. path=StripSlashes( path )
  240. Local st:stat_t
  241. If stat( path,Varptr st )<0 Return 0
  242. return st.st_size
  243. End
  244. #rem monkeydoc Gets the process current directory.
  245. @return The current directory for the running process.
  246. #end
  247. Function CurrentDir:String()
  248. Local sz:=4096
  249. Local buf:=Cast<char_t Ptr>( malloc( sz ) )
  250. getcwd( buf,sz )
  251. Local path:=String.FromCString( buf )
  252. free( buf )
  253. path=path.Replace( "\","/" )
  254. If path.EndsWith( "/" ) Return path
  255. Return path+"/"
  256. End
  257. #rem monkeydoc Changes the process current directory.
  258. @param path The filesystem path of the directory to make current.
  259. #end
  260. Function ChangeDir( path:String )
  261. chdir( StripSlashes( path ) )
  262. End
  263. #rem monkeydoc Loads a directory.
  264. Loads the contents of directory into an array.
  265. Does not return any '.' or '..' entries in a directory.
  266. @param path The filesystem path of the directory to load.
  267. @return An array containing all filenames in the `path`, excluding '.' and '..' entries.
  268. #end
  269. Function LoadDir:String[]( path:String )
  270. path=StripSlashes( path )
  271. Local dir:=opendir( path )
  272. If Not dir Return Null
  273. Local files:=New StringStack
  274. Repeat
  275. Local ent:=readdir( dir )
  276. If Not ent Exit
  277. Local file:=String.FromCString( ent[0].d_name )
  278. If file="." Or file=".." Continue
  279. files.Push( file )
  280. Forever
  281. closedir( dir )
  282. Return files.ToArray()
  283. End
  284. #rem monkeydoc Creates a file at a filesystem path.
  285. Any existing file at the path will be overwritten.
  286. Returns true if successful.
  287. @param path The filesystem path of the file file to create.
  288. @param createDir If true, also creates the file directory if necessary.
  289. @return True if a file at the given path was created.
  290. #end
  291. Function CreateFile:Bool( path:String,createDir:Bool=True )
  292. If createDir And Not CreateDir( ExtractDir( path ),True ) Return False
  293. Local f:=fopen( path,"wb" )
  294. If Not f Return False
  295. fclose( f )
  296. Return True
  297. End
  298. #rem monkeydoc Creates a directory at a filesystem path.
  299. @param path The filesystem path of the directory to create.
  300. @param recursive If true, any required parent directories are also created.
  301. @param clean If true, any existing directory at `dir` is first deleted.
  302. @return True if a directory at `path` was successfully created or already existed.
  303. #end
  304. Function CreateDir:Bool( dir:String,recursive:Bool=True,clean:Bool=False )
  305. If recursive
  306. Local parent:=ExtractDir( dir )
  307. If parent And Not IsRootDir( parent )
  308. Select GetFileType( parent )
  309. Case FileType.None
  310. If Not CreateDir( parent,True,False ) Return False
  311. Case FileType.File
  312. Return False
  313. End
  314. Endif
  315. Endif
  316. If clean And Not DeleteDir( dir,True ) Return False
  317. mkdir( StripSlashes( dir ),$1ff )
  318. Return GetFileType( dir )=FileType.Directory
  319. End
  320. #rem monkeydoc Deletes a file at a filesystem path.
  321. Returns true if successful.
  322. @param path The filesystem path.
  323. @return True if the file was successfully deleted.
  324. #end
  325. Function DeleteFile:Bool( path:String )
  326. remove( path )
  327. Return GetFileType( path )=FileType.None
  328. End
  329. #rem monkeydoc Deletes a directory at a filesystem path.
  330. If `recursive` is true, all subdirectories are also deleted.
  331. Returns true if successful.
  332. @param path The filesystem path.
  333. @param recursive True to delete subdirectories too.
  334. @return True if the directory was successfully deleted or never existed.
  335. #end
  336. Function DeleteDir:Bool( dir:String,recursive:Bool=False )
  337. If GetFileType( dir )=FileType.Directory
  338. If recursive
  339. For Local f:=Eachin LoadDir( dir )
  340. Local p:=dir+"/"+f
  341. Select GetFileType( p )
  342. Case FileType.File
  343. If Not DeleteFile( p ) Return False
  344. Case FileType.Directory
  345. If Not DeleteDir( p,True ) Return false
  346. End
  347. Next
  348. Endif
  349. rmdir( StripSlashes( dir ) )
  350. Endif
  351. Return GetFileType( dir )=FileType.None
  352. End
  353. #rem monkeydoc Copies a directory.
  354. Copies a directory from `srcDir` to `dstDir`.
  355. If `recursive` is true, all subdirectories are also copied.
  356. Returns true if successful.
  357. @param srcDir Source directory.
  358. @param dstDir Destination directory.
  359. @param recursive Recursive flag.
  360. @return True if successful.
  361. #end
  362. Function CopyDir:Bool( srcDir:String,dstDir:String,recursive:Bool=True )
  363. If GetFileType( srcDir )<>FileType.Directory Return False
  364. If GetFileType( dstDir )<>FileType.Directory And Not CreateDir( dstDir,True ) Return False
  365. For Local f:=Eachin LoadDir( srcDir )
  366. Local src:=srcDir+"/"+f
  367. Local dst:=dstDir+"/"+f
  368. Select GetFileType( src )
  369. Case FileType.File
  370. If Not CopyFile( src,dst ) Return False
  371. Case FileType.Directory
  372. If recursive And Not CopyDir( src,dst ) Return False
  373. End
  374. Next
  375. Return True
  376. End