filesystem.monkey2 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. Namespace std.filesystem
  2. Using libc
  3. #Import "native/filesystem.h"
  4. #Import "native/filesystem.cpp"
  5. #If __TARGET__="android"
  6. #Import "native/Monkey2FileSystem.java"
  7. #Elseif __TARGET__="ios"
  8. #Import "native/filesystem.mm"
  9. #endif
  10. Extern
  11. #rem monkeydoc Gets application directory.
  12. @return The directory containing the application executable.
  13. #end
  14. Function AppDir:String()="bbFileSystem::appDir"
  15. #rem monkeydoc Gets the application file path.
  16. @return The path of the application executable.
  17. #end
  18. Function AppPath:String()="bbFileSystem::appPath"
  19. #rem monkeydoc Gets application command line arguments.
  20. The first argument is always the application name.
  21. @return The application command line arguments.
  22. #end
  23. Function AppArgs:String[]()="bbFileSystem::appArgs"
  24. #rem monkeydoc Copies a file.
  25. Copies a file from `srcPath` to `dstPath`, overwriting `dstpath` if it alreay exits.
  26. Returns true if successful.
  27. @return True if the file was successfully copied.
  28. #end
  29. Function CopyFile:Bool( srcPath:String,dstPath:String )="bbFileSystem::copyFile"
  30. Private
  31. Function FixPath:String( path:String )
  32. Local root:=ExtractRootDir( path )
  33. If Not root.EndsWith( "::" ) Return path
  34. path=path.Slice( root.Length )
  35. Select root
  36. Case "asset::" return AssetsDir()+path
  37. Case "desktop::" Return DesktopDir()+path
  38. Case "home::" Return HomeDir()+path
  39. #If __MOBILE_TARGET__
  40. Case "internal::" Return InternalDir()+path
  41. Case "external::" Return ExternalDir()+path
  42. #endif
  43. End
  44. Return ""
  45. End
  46. Function FixFilePath:String( path:String )
  47. Return FixPath( StripSlashes( path ) )
  48. End
  49. #If __TARGET__="android"
  50. Function GetSpecialDir:String( name:String )
  51. Global _class:jclass
  52. Global _getSpecilarDir:jmethodID
  53. If Not _getSpecialDir
  54. Local env:=sdl2.Android_JNI_GetEnv()
  55. _class=env.FindClass( "com/monkey2/lib/Monkey2FileSystem" )
  56. _getSpecialDir=env.GetStaticMethodID( cls,"getSpecialDir","(Ljava/lang/String;)Ljava/lang/String;" )
  57. Endif
  58. Local dir:=env.CallStaticStringMethod( _class,_getSpecialDir,New Variant[]( name ) )
  59. Return dir
  60. End
  61. #Elseif __TARGET__="ios"
  62. Extern Private
  63. Function GetSpecialDir:String()="bbFileSystem::getSpecialDir"
  64. Private
  65. #else
  66. Function GetSpecialDir:String( name:String )
  67. Return ""
  68. End
  69. #Endif
  70. Public
  71. #rem monkeydoc FileType enumeration.
  72. | FileType | Description
  73. |:--------------|:-----------
  74. | `None` | File does not exist.
  75. | `File` | File is a normal file.
  76. | `Directory` | File is a directory.
  77. | `Unknown` | File is of unknown type.
  78. #end
  79. Enum FileType
  80. None=0
  81. File=1
  82. Directory=2
  83. Unknown=3
  84. End
  85. 'For backward compatibility - don't use!
  86. '
  87. #rem monkeydoc @hidden
  88. #end
  89. Const FILETYPE_NONE:=FileType.None
  90. #rem monkeydoc @hidden
  91. #end
  92. Const FILETYPE_FILE:=FileType.File
  93. #rem monkeydoc @hidden
  94. #end
  95. Const FILETYPE_DIR:=FileType.Directory
  96. #rem monkeydoc @hidden
  97. #end
  98. Const FILETYPE_UNKNOWN:=FileType.Unknown
  99. #rem monkeydoc Gets an environment variable.
  100. Returns the value of the given environment variable, or `defaultValue` if none was found.
  101. #end
  102. Function GetEnv:String( name:String,defaultValue:String="" )
  103. Local p:=getenv( name )
  104. If p Return String.FromCString( p )
  105. Return defaultValue
  106. End
  107. #rem monkeydoc Sets an environment variable.
  108. Sets the value of a given environment variable.
  109. #end
  110. Function SetEnv( name:String,value:String )
  111. setenv( name,value,1 )
  112. End
  113. #rem monkeydoc Gets the filesystem directory of the app's assets directory.
  114. Note that only the desktop and web targets have an assets directory. Other targets will return an empty string.
  115. @return The directory app assets are stored in.
  116. #end
  117. Function AssetsDir:String()
  118. #If __TARGET__="macos"
  119. Return AppDir()+"../Resources/"
  120. 'Return ExtractDir( AppDir() )+"/Resources/" 'enable me!
  121. #Else If __DESKTOP_TARGET__ Or __WEB_TARGET__
  122. Return AppDir()+"assets/"
  123. #Else
  124. Return ""
  125. #Endif
  126. End
  127. #rem monkeydoc Gets the filesystem directory of the user's desktop directory.
  128. Note that only the desktop targets have a desktop directory. Other targets will return an empty string.
  129. @return The desktop directory.
  130. #end
  131. Function DesktopDir:String()
  132. #If __TARGET__="windows"
  133. Return GetEnv( "USERPROFILE" ).Replace( "\","/" )+"/Desktop/"
  134. #Else If __DESKTOP_TARGET__
  135. Return GetEnv( "HOME" )+"/Desktop/"
  136. #Else
  137. Return ""
  138. #Endif
  139. End
  140. #rem monkeydoc Gets the filesystem directory of the user's home directory.
  141. Note that only the desktop targets have a home directory. Other targets will return an empty string.
  142. @return The home directory.
  143. #end
  144. Function HomeDir:String()
  145. #If __TARGET__="windows"
  146. Return GetEnv( "USERPROFILE" ).Replace( "\","/" )+"/"
  147. #Else if __DESKTOP_TARGET__
  148. Return GetEnv( "HOME" )+"/"
  149. #Else
  150. Return ""
  151. #Endif
  152. End
  153. #rem monkeydoc Gets the filesystem directory of the app's internal storage directory.
  154. Returns the absolute path to the directory on the filesystem where files created with openFileOutput(String, int) are stored.
  155. This directory will be removed when your app is uninstalled.
  156. This function is only available on mobile targets.
  157. @return The app's internal directory.
  158. #End
  159. Function InternalDir:String()
  160. Return GetSpecialDir( "internal" )
  161. End
  162. #rem monkeydoc Gets the filesystem directory of the app's external storage directory.
  163. Returns the absolute path to the directory on the primary shared/external storage device where the application can place persistent files it owns. These files are internal to the applications, and not typically visible to the user as media.
  164. This directory will be removed when your app is uninstalled.
  165. This function is only available on mobile targets.
  166. @return The app's external storage directory.
  167. #End
  168. Function ExternalDir:String()
  169. Return GetSpecialDir( "external" )
  170. End
  171. #rem monkeydoc Extracts the root directory from a file system path.
  172. A root directory is a directory path that:
  173. * Starts with '//' or '/', or...
  174. * Starts with 'blah:/', 'blah://' or 'blah::'.
  175. @param path The filesystem path.
  176. @return The root directory of `path`, or an empty string if `path` is not an absolute path.
  177. #end
  178. Function ExtractRootDir:String( path:String )
  179. If path.StartsWith( "//" ) Return "//"
  180. Local i:=path.Find( "/" )
  181. If i=0 Return "/"
  182. If i=-1 i=path.Length
  183. Local j:=path.Find( "://" )
  184. If j>0 And j<i Return path.Slice( 0,j+3 )
  185. j=path.Find( ":/" )
  186. If j>0 And j<i Return path.Slice( 0,j+2 )
  187. j=path.Find( "::" )
  188. If j>0 And j<i Return path.Slice( 0,j+2 )
  189. Return ""
  190. End
  191. #rem monkeydoc Checks if a path is a root directory.
  192. @param path The filesystem path to check.
  193. @return True if `path` is a root directory path.
  194. #end
  195. Function IsRootDir:Bool( path:String )
  196. If path="//" Return True
  197. If path="/" Return True
  198. Local i:=path.Find( "/" )
  199. If i=-1 i=path.Length
  200. Local j:=path.Find( "://" )
  201. If j>0 And j<i Return j+3=path.Length
  202. j=path.Find( ":/" )
  203. If j>0 And j<i Return j+2=path.Length
  204. j=path.Find( "::" )
  205. If j>0 And j<i Return j+2=path.Length
  206. Return False
  207. End
  208. #rem monkeydoc Gets the process current directory.
  209. @return The current directory for the running process.
  210. #end
  211. Function CurrentDir:String()
  212. Local buf:=New char_t[PATH_MAX]
  213. getcwd( buf.Data,PATH_MAX )
  214. Local path:=String.FromCString( buf.Data )
  215. #If __TARGET__="windows"
  216. path=path.Replace( "\","/" )
  217. #Endif
  218. If path.EndsWith( "/" ) Return path
  219. Return path+"/"
  220. End
  221. #rem monkeydoc Converts a path to a real path.
  222. If `path` is a relative path, it is first converted into an absolute path by prefixing the current directory.
  223. Then, any internal './' or '../' references in the path are collapsed.
  224. @param path The filesystem path.
  225. @return An absolute path with any './', '../' references collapsed.
  226. #end
  227. Function RealPath:String( path:String )
  228. path=FixPath( path )
  229. Local rpath:=ExtractRootDir( path )
  230. If rpath
  231. path=path.Slice( rpath.Length )
  232. Else
  233. rpath=CurrentDir()
  234. Endif
  235. While path
  236. Local i:=path.Find( "/" )
  237. If i=-1 Return rpath+path
  238. Local t:=path.Slice( 0,i )
  239. path=path.Slice( i+1 )
  240. Select t
  241. Case ""
  242. Case "."
  243. Case ".."
  244. If Not rpath rpath=CurrentDir()
  245. rpath=ExtractDir( rpath )
  246. Default
  247. rpath+=t+"/"
  248. End
  249. Wend
  250. Return rpath
  251. #rem Not working on macos!
  252. path=FixPath( path )
  253. Local buf:=New char_t[PATH_MAX]
  254. If Not libc.realpath( path,buf.Data ) Return ""
  255. Local rpath:=String.FromCString( buf.Data )
  256. #If __TARGET__="windows"
  257. rpath=rpath.Replace( "\","/" )
  258. #Endif
  259. Return rpath
  260. #end
  261. End
  262. #rem monkeydoc Strips any trailing slashes from a filesystem path.
  263. This function will not strip slashes from a root directory path.
  264. @param path The filesystem path.
  265. @return The path stripped of trailing slashes.
  266. #end
  267. Function StripSlashes:String( path:String )
  268. If Not path.EndsWith( "/" ) Return path
  269. Local root:=ExtractRootDir( path )
  270. Repeat
  271. If path=root Return path
  272. path=path.Slice( 0,-1 )
  273. Until Not path.EndsWith( "/" )
  274. Return path
  275. End
  276. #rem monkeydoc Extracts the directory component from a filesystem path.
  277. If `path` is a root directory it is returned without modification.
  278. If `path` does not contain a directory component, an empty string is returned.
  279. @param path The filesystem path.
  280. @return The directory component of `path`.
  281. #end
  282. Function ExtractDir:String( path:String )
  283. path=StripSlashes( path )
  284. If IsRootDir( path ) Return path
  285. Local i:=path.FindLast( "/" )
  286. If i>=0 Return path.Slice( 0,i+1 )
  287. i=path.Find( "::" )
  288. If i>=0 Return path.Slice( 0,i+2 )
  289. Return ""
  290. End
  291. #rem monkeydoc Strips the directory component from a filesystem path.
  292. If `path` is a root directory an empty string is returned.
  293. If `path` does not contain a directory component, `path` is returned without modification.
  294. @param path The filesystem path.
  295. @return The path with the directory component stripped.
  296. #end
  297. Function StripDir:String( path:String )
  298. path=StripSlashes( path )
  299. If IsRootDir( path ) Return ""
  300. Local i:=path.FindLast( "/" )
  301. If i>=0 Return path.Slice( i+1 )
  302. i=path.Find( "::" )
  303. If i>=0 Return path.Slice( i+2 )
  304. Return path
  305. End
  306. #rem monkeydoc Extracts the extension component from a filesystem path.
  307. @param path The filesystem path.
  308. @return The extension component of `path` including the '.' if any.
  309. #end
  310. Function ExtractExt:String( path:String )
  311. Local i:=path.FindLast( "." )
  312. If i=-1 Return ""
  313. Local j:=path.Find( "/",i+1 )
  314. If j=-1 Return path.Slice( i )
  315. Return ""
  316. End
  317. #rem monkeydoc Strips the extension component from a filesystem path.
  318. @param path The filesystem path.
  319. @return The path with the extension stripped.
  320. #end
  321. Function StripExt:String( path:String )
  322. Local i:=path.FindLast( "." )
  323. If i=-1 Return path
  324. Local j:=path.Find( "/",i+1 )
  325. If j=-1 Return path.Slice( 0,i )
  326. Return path
  327. End
  328. #rem monkeydoc Gets the type of the file at a filesystem path.
  329. @param path The filesystem path.
  330. @return The file type of the file at `path`, one of: FileType.None, FileType.File or FileType.Directory.
  331. #end
  332. Function GetFileType:FileType( path:String )
  333. path=FixFilePath( path )
  334. Local st:stat_t
  335. If stat( path,Varptr st )<0 Return FileType.None
  336. Select st.st_mode & S_IFMT
  337. Case S_IFREG Return FileType.File
  338. Case S_IFDIR Return FileType.Directory
  339. End
  340. Return FileType.Unknown
  341. End
  342. #rem monkeydoc Gets the time a file was most recently modified.
  343. @param path The filesystem path.
  344. @return The time the file at `path` was most recently modified.
  345. #end
  346. Function GetFileTime:Long( path:String )
  347. path=FixFilePath( path )
  348. Local st:stat_t
  349. If stat( path,Varptr st )<0 Return 0
  350. Return libc.tolong( st.st_mtime )
  351. End
  352. #rem monkeydoc Gets the size of the file at a filesystem path.
  353. @param path The filesystem path.
  354. @return The size file at `path` in bytes.
  355. #end
  356. Function GetFileSize:Long( path:String )
  357. path=FixFilePath( path )
  358. Local st:stat_t
  359. If stat( path,Varptr st )<0 Return 0
  360. return st.st_size
  361. End
  362. #rem monkeydoc Changes the process current directory.
  363. @param path The filesystem path of the directory to make current.
  364. #end
  365. Function ChangeDir( path:String )
  366. path=FixFilePath( path )
  367. chdir( path )
  368. End
  369. #rem monkeydoc Loads a directory.
  370. Loads the contents of directory into an array.
  371. Does not return any '.' or '..' entries in a directory.
  372. @param path The filesystem path of the directory to load.
  373. @return An array containing all filenames in the `path`, excluding '.' and '..' entries.
  374. #end
  375. Function LoadDir:String[]( path:String )
  376. path=FixFilePath( path )
  377. Local dir:=opendir( path )
  378. If Not dir Return Null
  379. Local files:=New StringStack
  380. Repeat
  381. Local ent:=readdir( dir )
  382. If Not ent Exit
  383. Local file:=String.FromCString( ent[0].d_name )
  384. If file="." Or file=".." Continue
  385. files.Push( file )
  386. Forever
  387. closedir( dir )
  388. Return files.ToArray()
  389. End
  390. #rem monkeydoc Creates a file at a filesystem path.
  391. Any existing file at the path will be overwritten.
  392. Returns true if successful.
  393. @param path The filesystem path of the file file to create.
  394. @param createDir If true, also creates the file directory if necessary.
  395. @return True if a file at the given path was created.
  396. #end
  397. Function CreateFile:Bool( path:String,createDir:Bool=True )
  398. path=FixFilePath( path )
  399. If createDir And Not CreateDir( ExtractDir( path ),True ) Return False
  400. Local f:=fopen( path,"wb" )
  401. If Not f Return False
  402. fclose( f )
  403. Return True
  404. End
  405. #rem monkeydoc Creates a directory at a filesystem path.
  406. @param path The filesystem path of the directory to create.
  407. @param recursive If true, any required parent directories are also created.
  408. @param clean If true, any existing directory at `dir` is first deleted.
  409. @return True if a directory at `path` was successfully created or already existed.
  410. #end
  411. Function CreateDir:Bool( dir:String,recursive:Bool=True,clean:Bool=False )
  412. dir=FixFilePath( dir )
  413. If recursive
  414. Local parent:=ExtractDir( dir )
  415. If parent And Not IsRootDir( parent )
  416. Select GetFileType( parent )
  417. Case FileType.None
  418. If Not CreateDir( parent,True,False ) Return False
  419. Case FileType.File
  420. Return False
  421. End
  422. Endif
  423. Endif
  424. If clean And Not DeleteDir( dir,True ) Return False
  425. mkdir( dir,$1ff )
  426. Return GetFileType( dir )=FileType.Directory
  427. End
  428. #rem monkeydoc Deletes a file at a filesystem path.
  429. Returns true if successful.
  430. @param path The filesystem path.
  431. @return True if the file was successfully deleted.
  432. #end
  433. Function DeleteFile:Bool( path:String )
  434. path=FixFilePath( path )
  435. remove( path )
  436. Return GetFileType( path )=FileType.None
  437. End
  438. #rem monkeydoc Deletes a directory at a filesystem path.
  439. If `recursive` is true, all subdirectories are also deleted.
  440. Returns true if successful.
  441. @param path The filesystem path.
  442. @param recursive True to delete subdirectories too.
  443. @return True if the directory was successfully deleted or never existed.
  444. #end
  445. Function DeleteDir:Bool( dir:String,recursive:Bool=False )
  446. dir=FixFilePath( dir )
  447. If GetFileType( dir )=FileType.Directory
  448. If recursive
  449. For Local f:=Eachin LoadDir( dir )
  450. Local p:=dir+"/"+f
  451. Select GetFileType( p )
  452. Case FileType.File
  453. If Not DeleteFile( p ) Return False
  454. Case FileType.Directory
  455. If Not DeleteDir( p,True ) Return false
  456. End
  457. Next
  458. Endif
  459. rmdir( dir )
  460. Endif
  461. Return GetFileType( dir )=FileType.None
  462. End
  463. #rem monkeydoc Copies a directory.
  464. Copies a directory from `srcDir` to `dstDir`.
  465. If `recursive` is true, all subdirectories are also copied.
  466. Returns true if successful.
  467. @param srcDir Source directory.
  468. @param dstDir Destination directory.
  469. @param recursive Recursive flag.
  470. @return True if successful.
  471. #end
  472. Function CopyDir:Bool( srcDir:String,dstDir:String,recursive:Bool=True )
  473. srcDir=FixFilePath( srcDir )
  474. dstDir=FixFilePath( dstDir )
  475. If GetFileType( srcDir )<>FileType.Directory Return False
  476. If GetFileType( dstDir )<>FileType.Directory And Not CreateDir( dstDir,True ) Return False
  477. For Local f:=Eachin LoadDir( srcDir )
  478. Local src:=srcDir+"/"+f
  479. Local dst:=dstDir+"/"+f
  480. Select GetFileType( src )
  481. Case FileType.File
  482. If Not CopyFile( src,dst ) Return False
  483. Case FileType.Directory
  484. If recursive And Not CopyDir( src,dst ) Return False
  485. End
  486. Next
  487. Return True
  488. End