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