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