xref: /haiku/src/bin/open.cpp (revision 93a78ecaa45114d68952d08c4778f073515102f2)
1 /*
2  * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Copyright 2005-2007, François Revol, revol@free.fr.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 /*! Launches an application/document from the shell */
8 
9 
10 #include <Entry.h>
11 #include <List.h>
12 #include <Roster.h>
13 #include <String.h>
14 
15 #include <errno.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 
20 
21 const char *kTrackerSignature = "application/x-vnd.Be-TRAK";
22 
23 
24 status_t
25 open_file(const char* openWith, BEntry &entry, int32 line = -1, int32 col = -1)
26 {
27 	entry_ref ref;
28 	status_t status = entry.GetRef(&ref);
29 	if (status < B_OK)
30 		return status;
31 
32 	BMessenger target(openWith ? openWith : kTrackerSignature);
33 	if (!target.IsValid())
34 		return be_roster->Launch(&ref);
35 
36 	BMessage message(B_REFS_RECEIVED);
37 	message.AddRef("refs", &ref);
38 	if (line > -1)
39 		message.AddInt32("be:line", line);
40 	if (col > -1)
41 		message.AddInt32("be:column", col);
42 
43 	// tell the app to open the file
44 	return target.SendMessage(&message);
45 }
46 
47 
48 int
49 main(int argc, char **argv)
50 {
51 	int exitcode = EXIT_SUCCESS;
52 	const char *openWith = NULL;
53 
54 	char *progName = argv[0];
55 	if (strrchr(progName, '/'))
56 		progName = strrchr(progName, '/') + 1;
57 
58 	if (argc < 2)
59 		fprintf(stderr,"usage: %s <file[:line[:column]] or url or application signature> ...\n", progName);
60 
61 	while (*++argv) {
62 		status_t status = B_OK;
63 		argc--;
64 
65 		BEntry entry(*argv);
66 		if ((status = entry.InitCheck()) == B_OK && entry.Exists()) {
67 			status = open_file(openWith, entry);
68 		} else if (!strncasecmp("application/", *argv, 12)) {
69 			// maybe it's an application-mimetype?
70 
71 			// subsequent files are open with that app
72 			openWith = *argv;
73 
74 			// in the case the app is already started,
75 			// don't start it twice if we have other args
76 			BList teams;
77 			if (argc > 1)
78 				be_roster->GetAppList(*argv, &teams);
79 
80 			if (teams.IsEmpty())
81 				status = be_roster->Launch(*argv);
82 			else
83 				status = B_OK;
84 		} else if (strchr(*argv, ':')) {
85 			// try to open it as an URI
86 			BString mimeType = "application/x-vnd.Be.URL.";
87 			BString arg(*argv);
88 			if (arg.FindFirst("://") >= 0)
89 				mimeType.Append(arg, arg.FindFirst("://"));
90 			else
91 				mimeType.Append(arg, arg.FindFirst(":"));
92 
93 			char *args[2] = { *argv, NULL };
94 			status = be_roster->Launch(openWith ? openWith : mimeType.String(), 1, args);
95 			if (status == B_OK)
96 				continue;
97 
98 			// maybe it's "file:line" or "file:line:col"
99 			int line = 0, col = 0, i;
100 			status = B_ENTRY_NOT_FOUND;
101 			// remove gcc error's last :
102 			if (arg[arg.Length() - 1] == ':')
103 				arg.Truncate(arg.Length() - 1);
104 
105 			i = arg.FindLast(':');
106 			if (i > 0) {
107 				line = atoi(arg.String() + i + 1);
108 				arg.Truncate(i);
109 
110 				status = entry.SetTo(arg.String());
111 				if (status == B_OK && entry.Exists())
112 					status = open_file(openWith, entry, line - 1, col - 1);
113 				if (status == B_OK)
114 					continue;
115 
116 				// get the column
117 				col = line;
118 				i = arg.FindLast(':');
119 				line = atoi(arg.String() + i + 1);
120 				arg.Truncate(i);
121 
122 				status = entry.SetTo(arg.String());
123 				if (status == B_OK && entry.Exists())
124 					status = open_file(openWith, entry, line - 1, col - 1);
125 			}
126 		} else
127 			status = B_ENTRY_NOT_FOUND;
128 
129 		if (status != B_OK && status != B_ALREADY_RUNNING) {
130 			fprintf(stderr, "%s: \"%s\": %s\n", progName, *argv, strerror(status));
131 			// make sure the shell knows this
132 			exitcode = EXIT_FAILURE;
133 		}
134 	}
135 
136 	return exitcode;
137 }
138