macCocoaPlatform.mm 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #import <Cocoa/Cocoa.h>
  23. #import <Carbon/Carbon.h>
  24. #include <unistd.h>
  25. #include "platform/platform.h"
  26. #include "console/console.h"
  27. #include "core/stringTable.h"
  28. #include "platform/platformInput.h"
  29. #include "platform/threads/thread.h"
  30. #pragma mark ---- Various Directories ----
  31. //-----------------------------------------------------------------------------
  32. const char* Platform::getUserDataDirectory()
  33. {
  34. // application support directory is most in line with the current usages of this function.
  35. // this may change with later usage
  36. // perhaps the user data directory should be pref-controlled?
  37. NSString *nsDataDir = [@"~/Library/Application Support/" stringByStandardizingPath];
  38. return StringTable->insert([nsDataDir UTF8String]);
  39. }
  40. //-----------------------------------------------------------------------------
  41. const char* Platform::getUserHomeDirectory()
  42. {
  43. return StringTable->insert([[@"~/" stringByStandardizingPath] UTF8String]);
  44. }
  45. //-----------------------------------------------------------------------------
  46. StringTableEntry osGetTemporaryDirectory()
  47. {
  48. NSString *tdir = NSTemporaryDirectory();
  49. const char *path = [tdir UTF8String];
  50. return StringTable->insert(path);
  51. }
  52. #pragma mark ---- Administrator ----
  53. //-----------------------------------------------------------------------------
  54. bool Platform::getUserIsAdministrator()
  55. {
  56. // if we can write to /Library, we're probably an admin
  57. // HACK: this is not really very good, because people can chmod Library.
  58. return (access("/Library", W_OK) == 0);
  59. }
  60. #pragma mark ---- Cosmetic ----
  61. //-----------------------------------------------------------------------------
  62. bool Platform::displaySplashWindow()
  63. {
  64. return false;
  65. }
  66. bool Platform::closeSplashWindow()
  67. {
  68. return false;
  69. }
  70. #pragma mark ---- File IO ----
  71. //-----------------------------------------------------------------------------
  72. bool dPathCopy(const char* source, const char* dest, bool nooverwrite)
  73. {
  74. NSFileManager *manager = [NSFileManager defaultManager];
  75. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  76. NSString *nsource = [[NSString stringWithUTF8String:source] stringByStandardizingPath];
  77. NSString *ndest = [[NSString stringWithUTF8String:dest] stringByStandardizingPath];
  78. NSString *ndestFolder = [ndest stringByDeletingLastPathComponent];
  79. if(! [manager fileExistsAtPath:nsource])
  80. {
  81. Con::errorf("dPathCopy: no file exists at %s",source);
  82. return false;
  83. }
  84. if( [manager fileExistsAtPath:ndest] )
  85. {
  86. if(nooverwrite)
  87. {
  88. Con::errorf("dPathCopy: file already exists at %s",dest);
  89. return false;
  90. }
  91. Con::warnf("Deleting files at path: %s", dest);
  92. bool deleted = [manager removeFileAtPath:ndest handler:nil];
  93. if(!deleted)
  94. {
  95. Con::errorf("Copy failed! Could not delete files at path: %s", dest);
  96. return false;
  97. }
  98. }
  99. if([manager fileExistsAtPath:ndestFolder] == NO)
  100. {
  101. ndestFolder = [ndestFolder stringByAppendingString:@"/"]; // createpath requires a trailing slash
  102. Platform::createPath([ndestFolder UTF8String]);
  103. }
  104. bool ret = [manager copyPath:nsource toPath:ndest handler:nil];
  105. [pool release];
  106. return ret;
  107. }
  108. //-----------------------------------------------------------------------------
  109. bool dFileRename(const char *source, const char *dest)
  110. {
  111. if(source == NULL || dest == NULL)
  112. return false;
  113. NSFileManager *manager = [NSFileManager defaultManager];
  114. NSString *nsource = [manager stringWithFileSystemRepresentation:source length:dStrlen(source)];
  115. NSString *ndest = [manager stringWithFileSystemRepresentation:dest length:dStrlen(dest)];
  116. if(! [manager fileExistsAtPath:nsource])
  117. {
  118. Con::errorf("dFileRename: no file exists at %s",source);
  119. return false;
  120. }
  121. if( [manager fileExistsAtPath:ndest] )
  122. {
  123. Con::warnf("dFileRename: Deleting files at path: %s", dest);
  124. }
  125. bool ret = [manager movePath:nsource toPath:ndest handler:nil];
  126. return ret;
  127. }
  128. #pragma mark -
  129. #pragma mark ---- ShellExecute ----
  130. class ExecuteThread : public Thread
  131. {
  132. const char* zargs;
  133. const char* directory;
  134. const char* executable;
  135. public:
  136. ExecuteThread(const char *_executable, const char *_args /* = NULL */, const char *_directory /* = NULL */) : Thread(0, NULL, false, true)
  137. {
  138. zargs = dStrdup(_args);
  139. directory = dStrdup(_directory);
  140. executable = dStrdup(_executable);
  141. start();
  142. }
  143. virtual void run(void* arg);
  144. };
  145. static char* _unDoubleQuote(char* arg)
  146. {
  147. U32 len = dStrlen(arg);
  148. if(!len)
  149. return arg;
  150. if(arg[0] == '"' && arg[len-1] == '"')
  151. {
  152. arg[len - 1] = '\0';
  153. return arg + 1;
  154. }
  155. return arg;
  156. }
  157. void ExecuteThread::run(void* arg)
  158. {
  159. // 2k should be enough. if it's not, bail.
  160. // char buf[2048];
  161. // U32 len = dSprintf(buf, sizeof(buf), "%s %s -workingDir %s", executable, args, directory);
  162. // if( len >= sizeof(buf))
  163. // {
  164. // Con::errorf("shellExecute(): the command was too long, and won't be run.");
  165. // return;
  166. // }
  167. // // calls sh with the string and blocks until the command returns.
  168. // system(buf);
  169. // FIXME: there is absolutely no error checking in here.
  170. printf("creating nstask\n");
  171. NSTask *aTask = [[NSTask alloc] init];
  172. NSMutableArray *array = [NSMutableArray array];
  173. // scan the args list, breaking it up, space delimited, backslash escaped.
  174. U32 len = dStrlen(zargs);
  175. char args[len+1];
  176. dStrncpy(args, zargs, len+1);
  177. char *lastarg = args;
  178. bool escaping = false;
  179. for(int i = 0; i< len; i++)
  180. {
  181. char c = args[i];
  182. // a backslash escapes the next character
  183. if(escaping)
  184. continue;
  185. if(c == '\\')
  186. escaping = true;
  187. if(c == ' ')
  188. {
  189. args[i] = '\0';
  190. if(*lastarg)
  191. [array addObject:[NSString stringWithUTF8String: _unDoubleQuote(lastarg)]];
  192. lastarg = args + i + 1;
  193. }
  194. }
  195. if(*lastarg)
  196. [array addObject:[NSString stringWithUTF8String: _unDoubleQuote(lastarg)]];
  197. [aTask setArguments: array];
  198. [aTask setCurrentDirectoryPath:[NSString stringWithUTF8String: this->directory]];
  199. [aTask setLaunchPath:[NSString stringWithUTF8String:executable]];
  200. [aTask launch];
  201. [aTask waitUntilExit];
  202. U32 ret = [aTask terminationStatus];
  203. Con::executef("onExecuteDone", Con::getIntArg(ret));
  204. printf("done nstask\n");
  205. }
  206. ConsoleFunction(shellExecute, bool, 2, 4, "(executable, [args], [directory])")
  207. {
  208. ExecuteThread *et = new ExecuteThread(argv[1], argc > 2 ? argv[2] : NULL, argc > 3 ? argv[3] : NULL);
  209. TORQUE_UNUSED(et);
  210. return true; // Bug: BPNC error: need feedback on whether the command was sucessful
  211. }