| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1 | //===-- Host.mm -------------------------------------------------*- C++ -*-===// | 
 | 2 | // | 
 | 3 | //                     The LLVM Compiler Infrastructure | 
 | 4 | // | 
 | 5 | // This file is distributed under the University of Illinois Open Source | 
 | 6 | // License. See LICENSE.TXT for details. | 
 | 7 | // | 
 | 8 | //===----------------------------------------------------------------------===// | 
 | 9 |  | 
| Greg Clayton | 8f3b21d | 2010-09-07 20:11:56 +0000 | [diff] [blame] | 10 | #include "lldb/Host/Host.h" | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 11 |  | 
 | 12 | #include <sys/types.h> | 
 | 13 | #include <sys/stat.h> | 
 | 14 |  | 
 | 15 | #include "lldb/Core/ArchSpec.h" | 
| Greg Clayton | 8f3b21d | 2010-09-07 20:11:56 +0000 | [diff] [blame] | 16 | #include "lldb/Core/FileSpec.h" | 
 | 17 | #include "lldb/Core/Log.h" | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 18 | #include "lldb/Core/StreamFile.h" | 
 | 19 | #include "lldb/Core/StreamString.h" | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 20 |  | 
| Greg Clayton | 54e7afa | 2010-07-09 20:39:50 +0000 | [diff] [blame] | 21 | #include "cfcpp/CFCBundle.h" | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 22 | #include "cfcpp/CFCMutableArray.h" | 
| Greg Clayton | 4b40711 | 2010-09-30 21:49:03 +0000 | [diff] [blame] | 23 | #include "cfcpp/CFCMutableDictionary.h" | 
| Greg Clayton | 54e7afa | 2010-07-09 20:39:50 +0000 | [diff] [blame] | 24 | #include "cfcpp/CFCReleaser.h" | 
 | 25 | #include "cfcpp/CFCString.h" | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 26 |  | 
| Greg Clayton | 8f3b21d | 2010-09-07 20:11:56 +0000 | [diff] [blame] | 27 | #include <objc/objc-auto.h> | 
 | 28 |  | 
| Greg Clayton | 4b40711 | 2010-09-30 21:49:03 +0000 | [diff] [blame] | 29 | #include <ApplicationServices/ApplicationServices.h> | 
| Greg Clayton | 8f3b21d | 2010-09-07 20:11:56 +0000 | [diff] [blame] | 30 | #include <Carbon/Carbon.h> | 
 | 31 | #include <Foundation/Foundation.h> | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 32 |  | 
 | 33 | using namespace lldb; | 
 | 34 | using namespace lldb_private; | 
 | 35 |  | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 36 | class MacOSXDarwinThread | 
 | 37 | { | 
 | 38 | public: | 
 | 39 |     MacOSXDarwinThread(const char *thread_name) : | 
 | 40 |         m_pool (nil) | 
 | 41 |     { | 
 | 42 |         // Register our thread with the collector if garbage collection is enabled. | 
 | 43 |         if (objc_collectingEnabled()) | 
 | 44 |         { | 
 | 45 | #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 | 
 | 46 |             // On Leopard and earlier there is no way objc_registerThreadWithCollector | 
 | 47 |             // function, so we do it manually. | 
 | 48 |             auto_zone_register_thread(auto_zone()); | 
 | 49 | #else | 
 | 50 |             // On SnowLoepard and later we just call the thread registration function. | 
 | 51 |             objc_registerThreadWithCollector(); | 
 | 52 | #endif | 
 | 53 |         } | 
 | 54 |         else | 
 | 55 |         { | 
 | 56 |             m_pool = [[NSAutoreleasePool alloc] init]; | 
 | 57 |         } | 
 | 58 |  | 
 | 59 |  | 
 | 60 |         Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name); | 
 | 61 |     } | 
 | 62 |  | 
 | 63 |     ~MacOSXDarwinThread() | 
 | 64 |     { | 
 | 65 |         if (m_pool) | 
 | 66 |             [m_pool release]; | 
 | 67 |     } | 
 | 68 |  | 
 | 69 |     static void PThreadDestructor (void *v) | 
 | 70 |     { | 
 | 71 |         delete (MacOSXDarwinThread*)v; | 
 | 72 |     } | 
 | 73 |  | 
 | 74 | protected: | 
 | 75 |     NSAutoreleasePool * m_pool; | 
 | 76 | private: | 
 | 77 |     DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread); | 
 | 78 | }; | 
 | 79 |  | 
 | 80 | static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT; | 
 | 81 | static pthread_key_t g_thread_create_key = 0; | 
 | 82 |  | 
 | 83 | static void | 
 | 84 | InitThreadCreated() | 
 | 85 | { | 
 | 86 |     ::pthread_key_create (&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor); | 
 | 87 | } | 
 | 88 |  | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 89 | void | 
 | 90 | Host::ThreadCreated (const char *thread_name) | 
 | 91 | { | 
 | 92 |     ::pthread_once (&g_thread_create_once, InitThreadCreated); | 
 | 93 |     if (g_thread_create_key) | 
 | 94 |     { | 
 | 95 |         ::pthread_setspecific (g_thread_create_key, new MacOSXDarwinThread(thread_name)); | 
 | 96 |     } | 
 | 97 | } | 
 | 98 |  | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 99 |  | 
 | 100 | bool | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 101 | Host::ResolveExecutableInBundle (FileSpec &file) | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 102 | { | 
| Greg Clayton | 8f3b21d | 2010-09-07 20:11:56 +0000 | [diff] [blame] | 103 | #if defined (__APPLE__) | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 104 |     if (file.GetFileType () == FileSpec::eFileTypeDirectory) | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 105 |     { | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 106 |         char path[PATH_MAX]; | 
 | 107 |         if (file.GetPath(path, sizeof(path))) | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 108 |         { | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 109 |             CFCBundle bundle (path); | 
 | 110 |             CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ()); | 
 | 111 |             if (url.get()) | 
 | 112 |             { | 
 | 113 |                 if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path))) | 
 | 114 |                 { | 
 | 115 |                     file.SetFile(path); | 
 | 116 |                     return true; | 
 | 117 |                 } | 
 | 118 |             } | 
| Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 119 |         } | 
 | 120 |     } | 
| Greg Clayton | 8f3b21d | 2010-09-07 20:11:56 +0000 | [diff] [blame] | 121 | #endif | 
 | 122 |   return false; | 
| Jim Ingham | 7508e73 | 2010-08-09 23:31:02 +0000 | [diff] [blame] | 123 | } | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 124 |  | 
| Greg Clayton | 4b40711 | 2010-09-30 21:49:03 +0000 | [diff] [blame] | 125 | lldb::pid_t | 
 | 126 | Host::LaunchApplication (const FileSpec &app_file_spec) | 
 | 127 | { | 
 | 128 |     char app_path[PATH_MAX]; | 
 | 129 |     app_file_spec.GetPath(app_path, sizeof(app_path)); | 
 | 130 |  | 
 | 131 |     LSApplicationParameters app_params; | 
 | 132 |     ::bzero (&app_params, sizeof (app_params)); | 
 | 133 |     app_params.flags = kLSLaunchDefaults |  | 
 | 134 |                        kLSLaunchDontAddToRecents |  | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 135 |                        kLSLaunchNewInstance; | 
 | 136 |      | 
| Greg Clayton | 4b40711 | 2010-09-30 21:49:03 +0000 | [diff] [blame] | 137 |      | 
 | 138 |     FSRef app_fsref; | 
 | 139 |     CFCString app_cfstr (app_path, kCFStringEncodingUTF8); | 
 | 140 |      | 
 | 141 |     OSStatus error = ::FSPathMakeRef ((const UInt8 *)app_path, &app_fsref, false); | 
 | 142 |      | 
 | 143 |     // If we found the app, then store away the name so we don't have to re-look it up. | 
 | 144 |     if (error != noErr) | 
 | 145 |         return LLDB_INVALID_PROCESS_ID; | 
 | 146 |      | 
 | 147 |     app_params.application = &app_fsref; | 
 | 148 |  | 
 | 149 |     ProcessSerialNumber psn; | 
 | 150 |  | 
 | 151 |     error = ::LSOpenApplication (&app_params, &psn); | 
 | 152 |  | 
 | 153 |     if (error != noErr) | 
 | 154 |         return LLDB_INVALID_PROCESS_ID; | 
 | 155 |  | 
 | 156 |     ::pid_t pid = LLDB_INVALID_PROCESS_ID; | 
 | 157 |     error = ::GetProcessPID(&psn, &pid); | 
 | 158 |     return pid; | 
 | 159 | } | 
 | 160 |  | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 161 | lldb::pid_t | 
 | 162 | Host::LaunchInNewTerminal  | 
 | 163 | ( | 
 | 164 |     const char **argv,  | 
 | 165 |     const char **envp, | 
 | 166 |     const ArchSpec *arch_spec, | 
 | 167 |     bool stop_at_entry, | 
 | 168 |     bool disable_aslr | 
 | 169 | ) | 
 | 170 | { | 
 | 171 |     if (!argv || !argv[0]) | 
 | 172 |         return LLDB_INVALID_PROCESS_ID; | 
 | 173 |  | 
 | 174 |     OSStatus error = 0; | 
 | 175 |      | 
 | 176 |     FileSpec program (argv[0]); | 
 | 177 |      | 
 | 178 |      | 
 | 179 |     char temp_file_path[PATH_MAX]; | 
 | 180 |     const char *tmpdir = ::getenv ("TMPDIR"); | 
 | 181 |     if (tmpdir == NULL) | 
 | 182 |         tmpdir = "/tmp/"; | 
 | 183 |     ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString()); | 
 | 184 |      | 
 | 185 |     if (::mktemp (temp_file_path) == NULL) | 
 | 186 |         return LLDB_INVALID_PROCESS_ID; | 
 | 187 |  | 
 | 188 |     ::strncat (temp_file_path, ".command", sizeof (temp_file_path)); | 
 | 189 |  | 
 | 190 |     StreamFile command_file (temp_file_path, "w"); | 
 | 191 |      | 
 | 192 |     FileSpec darwin_debug_file_spec; | 
 | 193 |     if (!Host::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec)) | 
 | 194 |         return LLDB_INVALID_PROCESS_ID; | 
 | 195 |     darwin_debug_file_spec.GetFilename().SetCString("darwin-debug"); | 
 | 196 |          | 
 | 197 |     if (!darwin_debug_file_spec.Exists()) | 
 | 198 |         return LLDB_INVALID_PROCESS_ID; | 
 | 199 |      | 
 | 200 |     char launcher_path[PATH_MAX]; | 
 | 201 |     darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path)); | 
 | 202 |     command_file.Printf("\"%s\" ", launcher_path); | 
 | 203 |      | 
 | 204 |     if (arch_spec && arch_spec->IsValid()) | 
 | 205 |     { | 
 | 206 |         command_file.Printf("--arch=%s ", arch_spec->AsCString()); | 
 | 207 |     } | 
 | 208 |  | 
 | 209 |     if (disable_aslr) | 
 | 210 |     { | 
 | 211 |         command_file.PutCString("--disable-aslr "); | 
 | 212 |     } | 
 | 213 |          | 
 | 214 |     command_file.PutCString("-- "); | 
 | 215 |  | 
 | 216 |     if (argv) | 
 | 217 |     { | 
 | 218 |         for (size_t i=0; argv[i] != NULL; ++i) | 
 | 219 |         { | 
 | 220 |             command_file.Printf("\"%s\" ", argv[i]); | 
 | 221 |         } | 
 | 222 |     } | 
| Greg Clayton | c1d3775 | 2010-10-18 01:45:30 +0000 | [diff] [blame^] | 223 |     command_file.PutCString("\necho Process exited with status $?\n"); | 
| Greg Clayton | 24b48ff | 2010-10-17 22:03:32 +0000 | [diff] [blame] | 224 |     command_file.Close(); | 
 | 225 |     if (::chmod (temp_file_path, S_IRWXU | S_IRWXG) != 0) | 
 | 226 |         return LLDB_INVALID_PROCESS_ID; | 
 | 227 |              | 
 | 228 |     CFCMutableDictionary cf_env_dict; | 
 | 229 |      | 
 | 230 |     const bool can_create = true; | 
 | 231 |     if (envp) | 
 | 232 |     { | 
 | 233 |         for (size_t i=0; envp[i] != NULL; ++i) | 
 | 234 |         { | 
 | 235 |             const char *env_entry = envp[i];             | 
 | 236 |             const char *equal_pos = strchr(env_entry, '='); | 
 | 237 |             if (equal_pos) | 
 | 238 |             { | 
 | 239 |                 std::string env_key (env_entry, equal_pos); | 
 | 240 |                 std::string env_val (equal_pos + 1); | 
 | 241 |                 CFCString cf_env_key (env_key.c_str(), kCFStringEncodingUTF8); | 
 | 242 |                 CFCString cf_env_val (env_val.c_str(), kCFStringEncodingUTF8); | 
 | 243 |                 cf_env_dict.AddValue (cf_env_key.get(), cf_env_val.get(), can_create); | 
 | 244 |             } | 
 | 245 |         } | 
 | 246 |     } | 
 | 247 |      | 
 | 248 |     LSApplicationParameters app_params; | 
 | 249 |     ::bzero (&app_params, sizeof (app_params)); | 
 | 250 |     app_params.flags = kLSLaunchDontAddToRecents | kLSLaunchAsync; | 
 | 251 |     app_params.argv = NULL; | 
 | 252 |     app_params.environment = (CFDictionaryRef)cf_env_dict.get(); | 
 | 253 |  | 
 | 254 |     CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL,  | 
 | 255 |                                                                                        (const UInt8 *)temp_file_path,  | 
 | 256 |                                                                                        strlen (temp_file_path),  | 
 | 257 |                                                                                        false)); | 
 | 258 |      | 
 | 259 |     CFCMutableArray urls; | 
 | 260 |      | 
 | 261 |     // Terminal.app will open the ".command" file we have created | 
 | 262 |     // and run our process inside it which will wait at the entry point | 
 | 263 |     // for us to attach. | 
 | 264 |     urls.AppendValue(command_file_url.get()); | 
 | 265 |  | 
 | 266 |     ProcessSerialNumber psn; | 
 | 267 |     error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1); | 
 | 268 |  | 
 | 269 |     if (error != noErr) | 
 | 270 |         return LLDB_INVALID_PROCESS_ID; | 
 | 271 |  | 
 | 272 |     ::pid_t pid = LLDB_INVALID_PROCESS_ID; | 
 | 273 |     error = ::GetProcessPID(&psn, &pid); | 
 | 274 |     return pid; | 
 | 275 | } | 
 | 276 |  | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 277 | bool | 
| Greg Clayton | 4b40711 | 2010-09-30 21:49:03 +0000 | [diff] [blame] | 278 | Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no) | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 279 | { | 
 | 280 |     // We attach this to an 'odoc' event to specify a particular selection | 
 | 281 |     typedef struct { | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 282 |         int16_t   reserved0;  // must be zero | 
 | 283 |         int16_t   fLineNumber; | 
 | 284 |         int32_t   fSelStart; | 
 | 285 |         int32_t   fSelEnd; | 
 | 286 |         uint32_t  reserved1;  // must be zero | 
 | 287 |         uint32_t  reserved2;  // must be zero | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 288 |     } BabelAESelInfo; | 
 | 289 |      | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 290 |     Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 291 |     char file_path[PATH_MAX]; | 
 | 292 |     file_spec.GetPath(file_path, PATH_MAX); | 
 | 293 |     CFCString file_cfstr (file_path, kCFStringEncodingUTF8); | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 294 |     CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,  | 
 | 295 |                                                                      file_cfstr.get(),  | 
 | 296 |                                                                      kCFURLPOSIXPathStyle,  | 
 | 297 |                                                                      false)); | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 298 |                                                                       | 
 | 299 |     if (log) | 
 | 300 |         log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no); | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 301 |      | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 302 |     OSStatus error;	 | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 303 |     BabelAESelInfo file_and_line_info =  | 
 | 304 |     { | 
 | 305 |         0,              // reserved0 | 
 | 306 |         line_no - 1,    // fLineNumber (zero based line number) | 
 | 307 |         1,              // fSelStart | 
 | 308 |         1024,           // fSelEnd | 
 | 309 |         0,              // reserved1 | 
 | 310 |         0               // reserved2 | 
 | 311 |     }; | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 312 |  | 
 | 313 |     AEKeyDesc file_and_line_desc; | 
 | 314 |      | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 315 |     error = ::AECreateDesc (typeUTF8Text,  | 
 | 316 |                             &file_and_line_info,  | 
 | 317 |                             sizeof (file_and_line_info),  | 
 | 318 |                             &(file_and_line_desc.descContent)); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 319 |      | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 320 |     if (error != noErr) | 
 | 321 |     { | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 322 |         if (log) | 
 | 323 |             log->Printf("Error creating AEDesc: %d.\n", error); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 324 |         return false; | 
 | 325 |     } | 
 | 326 |      | 
 | 327 |     file_and_line_desc.descKey = keyAEPosition; | 
 | 328 |      | 
| Greg Clayton | cb0989a | 2010-08-31 18:56:24 +0000 | [diff] [blame] | 329 |     static std::string g_app_name; | 
| Greg Clayton | 452bf61 | 2010-08-31 18:35:14 +0000 | [diff] [blame] | 330 |     static FSRef g_app_fsref; | 
 | 331 |  | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 332 |     LSApplicationParameters app_params; | 
| Greg Clayton | 452bf61 | 2010-08-31 18:35:14 +0000 | [diff] [blame] | 333 |     ::bzero (&app_params, sizeof (app_params)); | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 334 |     app_params.flags = kLSLaunchDefaults |  | 
 | 335 |                        kLSLaunchDontAddToRecents |  | 
 | 336 |                        kLSLaunchDontSwitch; | 
| Greg Clayton | 452bf61 | 2010-08-31 18:35:14 +0000 | [diff] [blame] | 337 |      | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 338 |     char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR"); | 
 | 339 |      | 
| Greg Clayton | 452bf61 | 2010-08-31 18:35:14 +0000 | [diff] [blame] | 340 |     if (external_editor) | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 341 |     { | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 342 |         if (log) | 
 | 343 |             log->Printf("Looking for external editor \"%s\".\n", external_editor); | 
 | 344 |  | 
| Greg Clayton | cb0989a | 2010-08-31 18:56:24 +0000 | [diff] [blame] | 345 |         if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0) | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 346 |         { | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 347 |             CFCString editor_name (external_editor, kCFStringEncodingUTF8); | 
| Greg Clayton | 452bf61 | 2010-08-31 18:35:14 +0000 | [diff] [blame] | 348 |             error = ::LSFindApplicationForInfo (kLSUnknownCreator,  | 
 | 349 |                                                 NULL,  | 
 | 350 |                                                 editor_name.get(),  | 
 | 351 |                                                 &g_app_fsref,  | 
 | 352 |                                                 NULL); | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 353 |              | 
 | 354 |             // If we found the app, then store away the name so we don't have to re-look it up. | 
| Greg Clayton | 452bf61 | 2010-08-31 18:35:14 +0000 | [diff] [blame] | 355 |             if (error != noErr) | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 356 |             { | 
 | 357 |                 if (log) | 
 | 358 |                     log->Printf("Could not find External Editor application, error: %d.\n", error); | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 359 |                 return false; | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 360 |             } | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 361 |                  | 
 | 362 |         } | 
| Greg Clayton | 452bf61 | 2010-08-31 18:35:14 +0000 | [diff] [blame] | 363 |         app_params.application = &g_app_fsref; | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 364 |     } | 
 | 365 |  | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 366 |     ProcessSerialNumber psn; | 
 | 367 |     CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL)); | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 368 |     error = ::LSOpenURLsWithRole (file_array.get(),  | 
| Jim Ingham | 363180d | 2010-08-30 23:48:25 +0000 | [diff] [blame] | 369 |                                   kLSRolesAll,  | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 370 |                                   &file_and_line_desc,  | 
 | 371 |                                   &app_params,  | 
 | 372 |                                   &psn,  | 
 | 373 |                                   1); | 
 | 374 |      | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 375 |     AEDisposeDesc (&(file_and_line_desc.descContent)); | 
 | 376 |  | 
 | 377 |     if (error != noErr) | 
 | 378 |     { | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 379 |         if (log) | 
 | 380 |             log->Printf("LSOpenURLsWithRole failed, error: %d.\n", error); | 
 | 381 |  | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 382 |         return false; | 
 | 383 |     } | 
 | 384 |      | 
 | 385 |     ProcessInfoRec which_process; | 
 | 386 |     bzero(&which_process, sizeof(which_process)); | 
 | 387 |     unsigned char ap_name[PATH_MAX]; | 
 | 388 |     which_process.processName = ap_name; | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 389 |     error = ::GetProcessInformation (&psn, &which_process); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 390 |      | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 391 |     bool using_xcode; | 
 | 392 |     if (error != noErr) | 
 | 393 |     { | 
 | 394 |         if (log) | 
 | 395 |             log->Printf("GetProcessInformation failed, error: %d.\n", error); | 
 | 396 |         using_xcode = false; | 
 | 397 |     } | 
 | 398 |     else | 
 | 399 |         using_xcode = strncmp((char *) ap_name+1, "Xcode", (int) ap_name[0]) == 0; | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 400 |      | 
 | 401 |     // Xcode doesn't obey the line number in the Open Apple Event.  So I have to send | 
 | 402 |     // it an AppleScript to focus on the right line. | 
 | 403 |      | 
 | 404 |     if (using_xcode) | 
 | 405 |     { | 
 | 406 |         static ComponentInstance osa_component = NULL; | 
 | 407 |         static const char *as_template = "tell application \"Xcode\"\n" | 
 | 408 |                                    "set doc to the first document whose path is \"%s\"\n" | 
 | 409 |                                    "set the selection to paragraph %d of doc\n" | 
 | 410 |                                    "--- set the selected paragraph range to {%d, %d} of doc\n" | 
 | 411 |                                    "end tell\n"; | 
 | 412 |         const int chars_for_int = 32; | 
 | 413 |         static int as_template_len = strlen (as_template); | 
 | 414 |  | 
 | 415 |        | 
 | 416 |         char *as_str; | 
 | 417 |         AEDesc as_desc; | 
 | 418 |        | 
 | 419 |         if (osa_component == NULL) | 
 | 420 |         { | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 421 |             osa_component = ::OpenDefaultComponent (kOSAComponentType, | 
 | 422 |                                                     kAppleScriptSubtype); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 423 |         } | 
 | 424 |          | 
 | 425 |         if (osa_component == NULL) | 
 | 426 |         { | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 427 |             if (log) | 
 | 428 |                 log->Printf("Could not get default AppleScript component.\n"); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 429 |             return false; | 
 | 430 |         } | 
 | 431 |  | 
 | 432 |         uint32_t as_str_size = as_template_len + strlen (file_path) + 3 * chars_for_int + 1;      | 
 | 433 |         as_str = (char *) malloc (as_str_size); | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 434 |         ::snprintf (as_str,  | 
 | 435 |                     as_str_size - 1,  | 
 | 436 |                     as_template,  | 
 | 437 |                     file_path,  | 
 | 438 |                     line_no,  | 
 | 439 |                     line_no,  | 
 | 440 |                     line_no); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 441 |  | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 442 |         error = ::AECreateDesc (typeChar,  | 
 | 443 |                                 as_str,  | 
 | 444 |                                 strlen (as_str), | 
 | 445 |                                 &as_desc); | 
 | 446 |          | 
 | 447 |         ::free (as_str); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 448 |  | 
 | 449 |         if (error != noErr) | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 450 |         { | 
 | 451 |             if (log) | 
 | 452 |                 log->Printf("Failed to create AEDesc for Xcode AppleEvent: %d.\n", error); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 453 |             return false; | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 454 |         } | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 455 |              | 
 | 456 |         OSAID ret_OSAID; | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 457 |         error = ::OSACompileExecute (osa_component,  | 
 | 458 |                                      &as_desc,  | 
 | 459 |                                      kOSANullScript,  | 
 | 460 |                                      kOSAModeNeverInteract,  | 
 | 461 |                                      &ret_OSAID); | 
 | 462 |          | 
 | 463 |         ::OSADispose (osa_component, ret_OSAID); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 464 |  | 
| Greg Clayton | f4fa8a9 | 2010-08-30 22:00:34 +0000 | [diff] [blame] | 465 |         ::AEDisposeDesc (&as_desc); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 466 |  | 
 | 467 |         if (error != noErr) | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 468 |         { | 
 | 469 |             if (log) | 
 | 470 |                 log->Printf("Sending AppleEvent to Xcode failed, error: %d.\n", error); | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 471 |             return false; | 
| Jim Ingham | b0fff35 | 2010-08-31 18:05:13 +0000 | [diff] [blame] | 472 |         } | 
| Jim Ingham | 74989e8 | 2010-08-30 19:44:40 +0000 | [diff] [blame] | 473 |     } | 
 | 474 |        | 
 | 475 |     return true; | 
 | 476 | } |