⛏️ index : haiku.git

/*
 * Copyright 2003-2007, Axel DΓΆrfler, axeld@pinc-software.de.
 * Copyright 2005-2007, FranΓ§ois Revol, revol@free.fr.
 * Copyright 2009, Jonas SundstrΓΆm, jonas@kirilla.com.
 * Copyright 2014 Haiku, Inc. All rights reserved.
 *
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Axel DΓΆrfler, axeld@pinc-software.de
 *		FranΓ§ois Revol, revol@free.fr
 *		John Scipione, jscipione@gmail.com
 *		Jonas SundstrΓΆm, jonas@kirilla.com
 */

/*! Launches an application/document from the shell */


#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#include <Entry.h>
#include <List.h>
#include <Mime.h>
#include <Roster.h>
#include <String.h>
#include <Url.h>

#include <tracker_private.h>


status_t
open_file(const char* openWith, BEntry& entry, int32 line = -1, int32 col = -1)
{
	entry_ref ref;
	status_t result = entry.GetRef(&ref);
	if (result != B_OK)
		return result;

	BMessenger target(openWith != NULL ? openWith : kTrackerSignature);
	if (!target.IsValid())
		return be_roster->Launch(&ref);

	BMessage message(B_REFS_RECEIVED);
	message.AddRef("refs", &ref);
	if (line > -1)
		message.AddInt32("be:line", line);

	if (col > -1)
		message.AddInt32("be:column", col);

	// tell the app to open the file
	return target.SendMessage(&message);
}


int
main(int argc, char** argv)
{
	int exitCode = EXIT_SUCCESS;
	const char* openWith = NULL;

	char* progName = argv[0];
	if (strrchr(progName, '/'))
		progName = strrchr(progName, '/') + 1;

	if (argc < 2) {
		fprintf(stderr,"usage: %s <file[:line[:column]] or url or application "
			"signature> ...\n", progName);
	}

	while (*++argv) {
		status_t result = B_OK;
		argc--;

		BEntry entry(*argv);
		if ((result = entry.InitCheck()) == B_OK && entry.Exists()) {
			result = open_file(openWith, entry);
		} else if (!strncasecmp("application/", *argv, 12)) {
			// maybe it's an application-mimetype?

			// subsequent files are open with that app
			openWith = *argv;

			// in the case the app is already started, 
			// don't start it twice if we have other args
			BList teams;
			if (argc > 1)
				be_roster->GetAppList(*argv, &teams);

			if (teams.IsEmpty())
				result = be_roster->Launch(*argv);
			else
				result = B_OK;
		} else if (strchr(*argv, ':')) {
			// try to open it as an URI
			BUrl url(*argv, true);
			result = url.OpenWithPreferredApplication();
			if (result == B_OK || result == B_ALREADY_RUNNING)
				continue;

			// maybe it's "file:line" or "file:line:col"
			int line = 0, col = 0, i;
			result = B_ENTRY_NOT_FOUND;
			// remove gcc error's last :
			BString arg(*argv);
			if (arg[arg.Length() - 1] == ':')
				arg.Truncate(arg.Length() - 1);

			i = arg.FindLast(':');
			if (i > 0) {
				line = atoi(arg.String() + i + 1);
				arg.Truncate(i);

				result = entry.SetTo(arg.String());
				if (result == B_OK && entry.Exists()) {
					result = open_file(openWith, entry, line);
					if (result == B_OK)
						continue;
				}

				// get the column
				col = line;
				i = arg.FindLast(':');
				line = atoi(arg.String() + i + 1);
				arg.Truncate(i);

				result = entry.SetTo(arg.String());
				if (result == B_OK && entry.Exists())
					result = open_file(openWith, entry, line, col);
			}
		} else
			result = B_ENTRY_NOT_FOUND;

		if (result != B_OK && result != B_ALREADY_RUNNING) {
			fprintf(stderr, "%s: \"%s\": %s\n", progName, *argv,
				strerror(result));
			// make sure the shell knows this
			exitCode = EXIT_FAILURE;
		}
	}

	return exitCode;
}