filesystem.monkey2 14 KB

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