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