filesystem.monkey2 13 KB

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