blob: b9f6235c5f5e3257ed9e14f580d789441969b958 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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 Clayton8f3b21d2010-09-07 20:11:56 +000010#include "lldb/Host/Host.h"
Greg Clayton24b48ff2010-10-17 22:03:32 +000011
12#include <sys/types.h>
13#include <sys/stat.h>
14
15#include "lldb/Core/ArchSpec.h"
Greg Clayton36f63a92010-10-19 03:25:40 +000016#include "lldb/Core/Communication.h"
17#include "lldb/Core/ConnectionFileDescriptor.h"
Greg Clayton8f3b21d2010-09-07 20:11:56 +000018#include "lldb/Core/FileSpec.h"
19#include "lldb/Core/Log.h"
Greg Clayton24b48ff2010-10-17 22:03:32 +000020#include "lldb/Core/StreamFile.h"
21#include "lldb/Core/StreamString.h"
Chris Lattner24943d22010-06-08 16:52:24 +000022
Greg Clayton54e7afa2010-07-09 20:39:50 +000023#include "cfcpp/CFCBundle.h"
Greg Clayton24b48ff2010-10-17 22:03:32 +000024#include "cfcpp/CFCMutableArray.h"
Greg Clayton4b407112010-09-30 21:49:03 +000025#include "cfcpp/CFCMutableDictionary.h"
Greg Clayton54e7afa2010-07-09 20:39:50 +000026#include "cfcpp/CFCReleaser.h"
27#include "cfcpp/CFCString.h"
Chris Lattner24943d22010-06-08 16:52:24 +000028
Greg Clayton8f3b21d2010-09-07 20:11:56 +000029#include <objc/objc-auto.h>
30
Greg Clayton4b407112010-09-30 21:49:03 +000031#include <ApplicationServices/ApplicationServices.h>
Greg Clayton8f3b21d2010-09-07 20:11:56 +000032#include <Carbon/Carbon.h>
33#include <Foundation/Foundation.h>
Chris Lattner24943d22010-06-08 16:52:24 +000034
35using namespace lldb;
36using namespace lldb_private;
37
Chris Lattner24943d22010-06-08 16:52:24 +000038class MacOSXDarwinThread
39{
40public:
41 MacOSXDarwinThread(const char *thread_name) :
42 m_pool (nil)
43 {
44 // Register our thread with the collector if garbage collection is enabled.
45 if (objc_collectingEnabled())
46 {
47#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
48 // On Leopard and earlier there is no way objc_registerThreadWithCollector
49 // function, so we do it manually.
50 auto_zone_register_thread(auto_zone());
51#else
52 // On SnowLoepard and later we just call the thread registration function.
53 objc_registerThreadWithCollector();
54#endif
55 }
56 else
57 {
58 m_pool = [[NSAutoreleasePool alloc] init];
59 }
60
61
62 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
63 }
64
65 ~MacOSXDarwinThread()
66 {
67 if (m_pool)
68 [m_pool release];
69 }
70
71 static void PThreadDestructor (void *v)
72 {
73 delete (MacOSXDarwinThread*)v;
74 }
75
76protected:
77 NSAutoreleasePool * m_pool;
78private:
79 DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread);
80};
81
82static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
83static pthread_key_t g_thread_create_key = 0;
84
85static void
86InitThreadCreated()
87{
88 ::pthread_key_create (&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor);
89}
90
Chris Lattner24943d22010-06-08 16:52:24 +000091void
92Host::ThreadCreated (const char *thread_name)
93{
94 ::pthread_once (&g_thread_create_once, InitThreadCreated);
95 if (g_thread_create_key)
96 {
97 ::pthread_setspecific (g_thread_create_key, new MacOSXDarwinThread(thread_name));
98 }
99}
100
Chris Lattner24943d22010-06-08 16:52:24 +0000101
102bool
Greg Clayton24b48ff2010-10-17 22:03:32 +0000103Host::ResolveExecutableInBundle (FileSpec &file)
Chris Lattner24943d22010-06-08 16:52:24 +0000104{
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000105#if defined (__APPLE__)
Greg Clayton24b48ff2010-10-17 22:03:32 +0000106 if (file.GetFileType () == FileSpec::eFileTypeDirectory)
Chris Lattner24943d22010-06-08 16:52:24 +0000107 {
Greg Clayton24b48ff2010-10-17 22:03:32 +0000108 char path[PATH_MAX];
109 if (file.GetPath(path, sizeof(path)))
Chris Lattner24943d22010-06-08 16:52:24 +0000110 {
Greg Clayton24b48ff2010-10-17 22:03:32 +0000111 CFCBundle bundle (path);
112 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
113 if (url.get())
114 {
115 if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
116 {
117 file.SetFile(path);
118 return true;
119 }
120 }
Chris Lattner24943d22010-06-08 16:52:24 +0000121 }
122 }
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000123#endif
124 return false;
Jim Ingham7508e732010-08-09 23:31:02 +0000125}
Jim Ingham74989e82010-08-30 19:44:40 +0000126
Greg Clayton4b407112010-09-30 21:49:03 +0000127lldb::pid_t
128Host::LaunchApplication (const FileSpec &app_file_spec)
129{
130 char app_path[PATH_MAX];
131 app_file_spec.GetPath(app_path, sizeof(app_path));
132
133 LSApplicationParameters app_params;
134 ::bzero (&app_params, sizeof (app_params));
135 app_params.flags = kLSLaunchDefaults |
136 kLSLaunchDontAddToRecents |
Greg Clayton24b48ff2010-10-17 22:03:32 +0000137 kLSLaunchNewInstance;
138
Greg Clayton4b407112010-09-30 21:49:03 +0000139
140 FSRef app_fsref;
141 CFCString app_cfstr (app_path, kCFStringEncodingUTF8);
142
143 OSStatus error = ::FSPathMakeRef ((const UInt8 *)app_path, &app_fsref, false);
144
145 // If we found the app, then store away the name so we don't have to re-look it up.
146 if (error != noErr)
147 return LLDB_INVALID_PROCESS_ID;
148
149 app_params.application = &app_fsref;
150
151 ProcessSerialNumber psn;
152
153 error = ::LSOpenApplication (&app_params, &psn);
154
155 if (error != noErr)
156 return LLDB_INVALID_PROCESS_ID;
157
158 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
159 error = ::GetProcessPID(&psn, &pid);
160 return pid;
161}
Greg Claytonea3259d2010-10-19 17:03:58 +0000162#define LLDB_HOST_USE_APPLESCRIPT
163#if defined (LLDB_HOST_USE_APPLESCRIPT)
Greg Clayton4b407112010-09-30 21:49:03 +0000164
Greg Clayton24b48ff2010-10-17 22:03:32 +0000165lldb::pid_t
166Host::LaunchInNewTerminal
167(
168 const char **argv,
169 const char **envp,
170 const ArchSpec *arch_spec,
171 bool stop_at_entry,
172 bool disable_aslr
173)
174{
175 if (!argv || !argv[0])
176 return LLDB_INVALID_PROCESS_ID;
Greg Claytonea3259d2010-10-19 17:03:58 +0000177
178 std::string unix_socket_name;
179
180 char temp_file_path[PATH_MAX] = "/tmp/XXXXXX";
181 if (::mktemp (temp_file_path) == NULL)
182 return LLDB_INVALID_PROCESS_ID;
183
184 unix_socket_name.assign (temp_file_path);
185
186 StreamString command;
187
188 FileSpec darwin_debug_file_spec;
189 if (!Host::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
190 return LLDB_INVALID_PROCESS_ID;
191 darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
192
193 if (!darwin_debug_file_spec.Exists())
194 return LLDB_INVALID_PROCESS_ID;
195
196 char launcher_path[PATH_MAX];
197 darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
198 command.Printf ("tell application \"Terminal\"\n do script \"'%s'", launcher_path);
199
200 command.Printf(" --unix-socket=%s", unix_socket_name.c_str());
201
202 if (arch_spec && arch_spec->IsValid())
203 {
204 command.Printf(" --arch=%s", arch_spec->AsCString());
205 }
206
207 if (disable_aslr)
208 {
209 command.PutCString(" --disable-aslr");
210 }
211
212 command.PutCString(" --");
213
214 if (argv)
215 {
216 for (size_t i=0; argv[i] != NULL; ++i)
217 {
218 command.Printf(" '%s'", argv[i]);
219 }
220 }
221 command.PutCString (" ; exit\"\nend tell\n");
222 const char *script_source = command.GetString().c_str();
223 NSAppleScript* applescript = [[NSAppleScript alloc] initWithSource:[NSString stringWithCString:script_source encoding:NSUTF8StringEncoding]];
224
225 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
226
227 Error lldb_error;
228 // Sleep and wait a bit for debugserver to start to listen...
229 ConnectionFileDescriptor file_conn;
230 char connect_url[128];
231 ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name.c_str());
232
233 [applescript executeAndReturnError:nil];
234 if (file_conn.Connect(connect_url, &lldb_error) == eConnectionStatusSuccess)
235 {
236 char pid_str[256];
237 ::bzero (pid_str, sizeof(pid_str));
238 ConnectionStatus status;
239 const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), status, NULL);
240 if (pid_str_len > 0)
241 {
242 pid = atoi (pid_str);
243 // Sleep for a bit to allow the process to exec and stop at the entry point...
244 sleep(1);
245 }
246 }
247 [applescript release];
248 return pid;
249}
250
251#else
252lldb::pid_t
253Host::LaunchInNewTerminal
254(
255 const char **argv,
256 const char **envp,
257 const ArchSpec *arch_spec,
258 bool stop_at_entry,
259 bool disable_aslr
260)
261{
262 if (!argv || !argv[0])
263 return LLDB_INVALID_PROCESS_ID;
Greg Clayton24b48ff2010-10-17 22:03:32 +0000264
265 OSStatus error = 0;
266
267 FileSpec program (argv[0]);
268
269
Greg Clayton36f63a92010-10-19 03:25:40 +0000270 std::string unix_socket_name;
271
Greg Clayton24b48ff2010-10-17 22:03:32 +0000272 char temp_file_path[PATH_MAX];
273 const char *tmpdir = ::getenv ("TMPDIR");
274 if (tmpdir == NULL)
275 tmpdir = "/tmp/";
276 ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString());
277
278 if (::mktemp (temp_file_path) == NULL)
279 return LLDB_INVALID_PROCESS_ID;
280
Greg Clayton36f63a92010-10-19 03:25:40 +0000281 unix_socket_name.assign (temp_file_path);
282
Greg Clayton24b48ff2010-10-17 22:03:32 +0000283 ::strncat (temp_file_path, ".command", sizeof (temp_file_path));
284
285 StreamFile command_file (temp_file_path, "w");
286
287 FileSpec darwin_debug_file_spec;
288 if (!Host::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
289 return LLDB_INVALID_PROCESS_ID;
290 darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
291
292 if (!darwin_debug_file_spec.Exists())
293 return LLDB_INVALID_PROCESS_ID;
294
295 char launcher_path[PATH_MAX];
296 darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
297 command_file.Printf("\"%s\" ", launcher_path);
298
Greg Clayton36f63a92010-10-19 03:25:40 +0000299 command_file.Printf("--unix-socket=%s ", unix_socket_name.c_str());
300
Greg Clayton24b48ff2010-10-17 22:03:32 +0000301 if (arch_spec && arch_spec->IsValid())
302 {
303 command_file.Printf("--arch=%s ", arch_spec->AsCString());
304 }
305
306 if (disable_aslr)
307 {
308 command_file.PutCString("--disable-aslr ");
309 }
310
311 command_file.PutCString("-- ");
312
313 if (argv)
314 {
315 for (size_t i=0; argv[i] != NULL; ++i)
316 {
317 command_file.Printf("\"%s\" ", argv[i]);
318 }
319 }
Greg Claytonc1d37752010-10-18 01:45:30 +0000320 command_file.PutCString("\necho Process exited with status $?\n");
Greg Clayton24b48ff2010-10-17 22:03:32 +0000321 command_file.Close();
322 if (::chmod (temp_file_path, S_IRWXU | S_IRWXG) != 0)
323 return LLDB_INVALID_PROCESS_ID;
324
325 CFCMutableDictionary cf_env_dict;
326
327 const bool can_create = true;
328 if (envp)
329 {
330 for (size_t i=0; envp[i] != NULL; ++i)
331 {
332 const char *env_entry = envp[i];
333 const char *equal_pos = strchr(env_entry, '=');
334 if (equal_pos)
335 {
336 std::string env_key (env_entry, equal_pos);
337 std::string env_val (equal_pos + 1);
338 CFCString cf_env_key (env_key.c_str(), kCFStringEncodingUTF8);
339 CFCString cf_env_val (env_val.c_str(), kCFStringEncodingUTF8);
340 cf_env_dict.AddValue (cf_env_key.get(), cf_env_val.get(), can_create);
341 }
342 }
343 }
344
345 LSApplicationParameters app_params;
346 ::bzero (&app_params, sizeof (app_params));
347 app_params.flags = kLSLaunchDontAddToRecents | kLSLaunchAsync;
348 app_params.argv = NULL;
349 app_params.environment = (CFDictionaryRef)cf_env_dict.get();
350
351 CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL,
352 (const UInt8 *)temp_file_path,
Greg Clayton36f63a92010-10-19 03:25:40 +0000353 strlen(temp_file_path),
Greg Clayton24b48ff2010-10-17 22:03:32 +0000354 false));
355
356 CFCMutableArray urls;
357
358 // Terminal.app will open the ".command" file we have created
359 // and run our process inside it which will wait at the entry point
360 // for us to attach.
361 urls.AppendValue(command_file_url.get());
362
Greg Clayton36f63a92010-10-19 03:25:40 +0000363
364 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
365
366 Error lldb_error;
367 // Sleep and wait a bit for debugserver to start to listen...
368 ConnectionFileDescriptor file_conn;
369 char connect_url[128];
370 ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name.c_str());
371
Greg Clayton24b48ff2010-10-17 22:03:32 +0000372 ProcessSerialNumber psn;
373 error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1);
Greg Clayton36f63a92010-10-19 03:25:40 +0000374 if (error == noErr)
375 {
376 if (file_conn.Connect(connect_url, &lldb_error) == eConnectionStatusSuccess)
377 {
378 char pid_str[256];
379 ::bzero (pid_str, sizeof(pid_str));
380 ConnectionStatus status;
381 const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), status, NULL);
382 if (pid_str_len > 0)
383 {
384 pid = atoi (pid_str);
385 // Sleep for a bit to allow the process to exec and stop at the entry point...
386 sleep(1);
387 }
388 }
389 }
Greg Clayton24b48ff2010-10-17 22:03:32 +0000390 return pid;
391}
Greg Claytonea3259d2010-10-19 17:03:58 +0000392#endif
Greg Clayton24b48ff2010-10-17 22:03:32 +0000393
Jim Ingham74989e82010-08-30 19:44:40 +0000394bool
Greg Clayton4b407112010-09-30 21:49:03 +0000395Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
Jim Ingham74989e82010-08-30 19:44:40 +0000396{
397 // We attach this to an 'odoc' event to specify a particular selection
398 typedef struct {
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000399 int16_t reserved0; // must be zero
400 int16_t fLineNumber;
401 int32_t fSelStart;
402 int32_t fSelEnd;
403 uint32_t reserved1; // must be zero
404 uint32_t reserved2; // must be zero
Jim Ingham74989e82010-08-30 19:44:40 +0000405 } BabelAESelInfo;
406
Jim Inghamb0fff352010-08-31 18:05:13 +0000407 Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST);
Jim Ingham74989e82010-08-30 19:44:40 +0000408 char file_path[PATH_MAX];
409 file_spec.GetPath(file_path, PATH_MAX);
410 CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000411 CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,
412 file_cfstr.get(),
413 kCFURLPOSIXPathStyle,
414 false));
Jim Inghamb0fff352010-08-31 18:05:13 +0000415
416 if (log)
417 log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000418
Jim Ingham74989e82010-08-30 19:44:40 +0000419 OSStatus error;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000420 BabelAESelInfo file_and_line_info =
421 {
422 0, // reserved0
423 line_no - 1, // fLineNumber (zero based line number)
424 1, // fSelStart
425 1024, // fSelEnd
426 0, // reserved1
427 0 // reserved2
428 };
Jim Ingham74989e82010-08-30 19:44:40 +0000429
430 AEKeyDesc file_and_line_desc;
431
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000432 error = ::AECreateDesc (typeUTF8Text,
433 &file_and_line_info,
434 sizeof (file_and_line_info),
435 &(file_and_line_desc.descContent));
Jim Ingham74989e82010-08-30 19:44:40 +0000436
Jim Ingham74989e82010-08-30 19:44:40 +0000437 if (error != noErr)
438 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000439 if (log)
440 log->Printf("Error creating AEDesc: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000441 return false;
442 }
443
444 file_and_line_desc.descKey = keyAEPosition;
445
Greg Claytoncb0989a2010-08-31 18:56:24 +0000446 static std::string g_app_name;
Greg Clayton452bf612010-08-31 18:35:14 +0000447 static FSRef g_app_fsref;
448
Jim Ingham74989e82010-08-30 19:44:40 +0000449 LSApplicationParameters app_params;
Greg Clayton452bf612010-08-31 18:35:14 +0000450 ::bzero (&app_params, sizeof (app_params));
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000451 app_params.flags = kLSLaunchDefaults |
452 kLSLaunchDontAddToRecents |
453 kLSLaunchDontSwitch;
Greg Clayton452bf612010-08-31 18:35:14 +0000454
Jim Ingham363180d2010-08-30 23:48:25 +0000455 char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
456
Greg Clayton452bf612010-08-31 18:35:14 +0000457 if (external_editor)
Jim Ingham363180d2010-08-30 23:48:25 +0000458 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000459 if (log)
460 log->Printf("Looking for external editor \"%s\".\n", external_editor);
461
Greg Claytoncb0989a2010-08-31 18:56:24 +0000462 if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
Jim Ingham363180d2010-08-30 23:48:25 +0000463 {
Jim Ingham363180d2010-08-30 23:48:25 +0000464 CFCString editor_name (external_editor, kCFStringEncodingUTF8);
Greg Clayton452bf612010-08-31 18:35:14 +0000465 error = ::LSFindApplicationForInfo (kLSUnknownCreator,
466 NULL,
467 editor_name.get(),
468 &g_app_fsref,
469 NULL);
Jim Ingham363180d2010-08-30 23:48:25 +0000470
471 // If we found the app, then store away the name so we don't have to re-look it up.
Greg Clayton452bf612010-08-31 18:35:14 +0000472 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000473 {
474 if (log)
475 log->Printf("Could not find External Editor application, error: %d.\n", error);
Jim Ingham363180d2010-08-30 23:48:25 +0000476 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000477 }
Jim Ingham363180d2010-08-30 23:48:25 +0000478
479 }
Greg Clayton452bf612010-08-31 18:35:14 +0000480 app_params.application = &g_app_fsref;
Jim Ingham363180d2010-08-30 23:48:25 +0000481 }
482
Jim Ingham74989e82010-08-30 19:44:40 +0000483 ProcessSerialNumber psn;
484 CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000485 error = ::LSOpenURLsWithRole (file_array.get(),
Jim Ingham363180d2010-08-30 23:48:25 +0000486 kLSRolesAll,
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000487 &file_and_line_desc,
488 &app_params,
489 &psn,
490 1);
491
Jim Ingham74989e82010-08-30 19:44:40 +0000492 AEDisposeDesc (&(file_and_line_desc.descContent));
493
494 if (error != noErr)
495 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000496 if (log)
497 log->Printf("LSOpenURLsWithRole failed, error: %d.\n", error);
498
Jim Ingham74989e82010-08-30 19:44:40 +0000499 return false;
500 }
501
502 ProcessInfoRec which_process;
503 bzero(&which_process, sizeof(which_process));
504 unsigned char ap_name[PATH_MAX];
505 which_process.processName = ap_name;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000506 error = ::GetProcessInformation (&psn, &which_process);
Jim Ingham74989e82010-08-30 19:44:40 +0000507
Jim Inghamb0fff352010-08-31 18:05:13 +0000508 bool using_xcode;
509 if (error != noErr)
510 {
511 if (log)
512 log->Printf("GetProcessInformation failed, error: %d.\n", error);
513 using_xcode = false;
514 }
515 else
516 using_xcode = strncmp((char *) ap_name+1, "Xcode", (int) ap_name[0]) == 0;
Jim Ingham74989e82010-08-30 19:44:40 +0000517
518 // Xcode doesn't obey the line number in the Open Apple Event. So I have to send
519 // it an AppleScript to focus on the right line.
520
521 if (using_xcode)
522 {
523 static ComponentInstance osa_component = NULL;
524 static const char *as_template = "tell application \"Xcode\"\n"
525 "set doc to the first document whose path is \"%s\"\n"
526 "set the selection to paragraph %d of doc\n"
527 "--- set the selected paragraph range to {%d, %d} of doc\n"
528 "end tell\n";
529 const int chars_for_int = 32;
530 static int as_template_len = strlen (as_template);
531
532
533 char *as_str;
534 AEDesc as_desc;
535
536 if (osa_component == NULL)
537 {
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000538 osa_component = ::OpenDefaultComponent (kOSAComponentType,
539 kAppleScriptSubtype);
Jim Ingham74989e82010-08-30 19:44:40 +0000540 }
541
542 if (osa_component == NULL)
543 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000544 if (log)
545 log->Printf("Could not get default AppleScript component.\n");
Jim Ingham74989e82010-08-30 19:44:40 +0000546 return false;
547 }
548
549 uint32_t as_str_size = as_template_len + strlen (file_path) + 3 * chars_for_int + 1;
550 as_str = (char *) malloc (as_str_size);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000551 ::snprintf (as_str,
552 as_str_size - 1,
553 as_template,
554 file_path,
555 line_no,
556 line_no,
557 line_no);
Jim Ingham74989e82010-08-30 19:44:40 +0000558
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000559 error = ::AECreateDesc (typeChar,
560 as_str,
561 strlen (as_str),
562 &as_desc);
563
564 ::free (as_str);
Jim Ingham74989e82010-08-30 19:44:40 +0000565
566 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000567 {
568 if (log)
569 log->Printf("Failed to create AEDesc for Xcode AppleEvent: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000570 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000571 }
Jim Ingham74989e82010-08-30 19:44:40 +0000572
573 OSAID ret_OSAID;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000574 error = ::OSACompileExecute (osa_component,
575 &as_desc,
576 kOSANullScript,
577 kOSAModeNeverInteract,
578 &ret_OSAID);
579
580 ::OSADispose (osa_component, ret_OSAID);
Jim Ingham74989e82010-08-30 19:44:40 +0000581
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000582 ::AEDisposeDesc (&as_desc);
Jim Ingham74989e82010-08-30 19:44:40 +0000583
584 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000585 {
586 if (log)
587 log->Printf("Sending AppleEvent to Xcode failed, error: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000588 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000589 }
Jim Ingham74989e82010-08-30 19:44:40 +0000590 }
591
592 return true;
593}