⛏️ index : haiku.git

/*
 * Copyright 2005, Haiku Inc.
 * Distributed under the terms of the MIT license.
 *
 * Authors:
 *		Jonas Sundström, jonas@kirilla.com
 *		Axel Dörfler, axeld@pinc-software.de.
 */


#include <Application.h>
#include <Clipboard.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include <String.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>


extern const char *__progname;
static const char *kProgramName = __progname;

static int sExitValue = EXIT_SUCCESS;


class ClipboardApp : public BApplication {
	public:
		ClipboardApp(void);
		virtual ~ClipboardApp(void);

		virtual void ReadyToRun(void);
		virtual void ArgvReceived(int32 argc, char **argv);

	private:
		void Usage(void);
		status_t Load(const char *path);
		status_t Save(const char *path);
		status_t Copy(const char *string);
		status_t Clear(void);
		status_t Print(bool debug);

		bool fGotArguments;
};


ClipboardApp::ClipboardApp(void)
	: BApplication("application/x-vnd.haiku-clipboard"),
	fGotArguments(false)
{
}


ClipboardApp::~ClipboardApp(void)
{
}


void
ClipboardApp::ArgvReceived(int32 argc, char **argv)
{
	status_t status = B_OK;

	static struct option const kLongOptions[] = {
		{"load", required_argument, 0, 'l'},
		{"save", required_argument, 0, 's'},
		{"copy", required_argument, 0, 'c'},
		{"clear", no_argument, 0, 'r'},
		{"stdin", no_argument, 0, 'i'},
		{"print", no_argument, 0, 'p'},
		{"debug", no_argument, 0, 'd'},
		{"help", no_argument, 0, 'h'},
		{NULL}
	};

	int c;
	while ((c = getopt_long(argc, argv, "l:s:o:c:ripdh", kLongOptions, NULL))
		!= -1) {
		switch (c) {
			case 'l':
				status = Load(optarg);
				break;
			case 's':
			case 'o':
				status = Save(optarg);
				break;
			case 'c':
				status = Copy(optarg);
				break;
			case 'r':
				status = Clear();
				break;
			case 'i':
				status = Copy(NULL);
				break;
			case 'p':
				status = Print(false);
				break;
			case 'd':
				status = Print(true);
				break;
			case 0:
				break;
			case 'h':
				// help text is printed in ReadyToRun()
				return;
			default:
				status = B_ERROR;
				break;
		}
	}

	if (status == B_OK)
		fGotArguments =	true;
	else
		sExitValue = EXIT_FAILURE;
}


void
ClipboardApp::ReadyToRun(void)
{
	if (fGotArguments == false)
		Usage();

	PostMessage(B_QUIT_REQUESTED);
}


void
ClipboardApp::Usage(void)
{
	printf("usage: %s [-olcirpd]\n"
		"  -s, --save=file\tSave clipboard to file (flattened BMessage)\n"
		"  -o\t\t\tthe same\n" // ToDo: (\"-\" for standard output/input)\n"
		"  -l, --load=file\tLoad clipboard from file (flattened BMessage)\n"
		"  -c, --copy=string\tPut the given string on the clipboard\n"
		"  -i, --stdin\t\tLoad clipboard with string from standard input\n\n"

		"  -r, --clear\t\tRemove all contents from clipboard\n\n"

		"  -p, --print\t\tPrint clipboard to standard output\n"
		"  -d, --debug\t\tPrint clipboard message to stdout\n\n"

		"  -h, --help\t\tDisplay this help and exit\n",
		kProgramName);
}


status_t
ClipboardApp::Load(const char *path)
{
	status_t status = B_OK;
	BFile file;

	status = file.SetTo(path, B_READ_ONLY);
	if (status != B_OK) {
		fprintf(stderr, "%s: Could not open file: %s\n", kProgramName,
			strerror(status));
		return status;
	}

	// get BMessage from file
	BMessage clipFromFile;
	status = clipFromFile.Unflatten(&file);
	if (status != B_OK) {
		fprintf(stderr, "%s: Could not read clip: %s\n", kProgramName,
			strerror(status));
		return status;
	}

	// load clip into clipboard
	if (!be_clipboard->Lock()) {
		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
		return B_ERROR;
	}

	be_clipboard->Clear();

	BMessage *clip = be_clipboard->Data();
	*clip = clipFromFile;

	status = be_clipboard->Commit();
	if (status != B_OK) {
		fprintf(stderr, "%s: could not commit data to clipboard.\n",
			kProgramName);
		be_clipboard->Unlock();
		return status;
	}

	be_clipboard->Unlock();
	return B_OK;
}


status_t
ClipboardApp::Save(const char *path)
{
	status_t status = B_OK;
	BFile file;

	status = file.SetTo(path, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
	if (status != B_OK) {
		fprintf(stderr, "%s: Could not create file: %s\n", kProgramName,
			strerror(status));
		return status;
	}

	// get clip
	if (!be_clipboard->Lock()) {
		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
		return B_ERROR;
	}

	BMessage *clip = be_clipboard->Data();

	be_clipboard->Unlock();

	// flatten clip to file
	status = clip->Flatten(&file);
	if (status != B_OK) {
		fprintf(stderr, "%s: Could not write data: %s\n", kProgramName,
			strerror(status));
		return status;
	}

	return B_OK;
}


status_t
ClipboardApp::Copy(const char *string)
{
	status_t status = B_OK;
	BString inputString;

	if (string == NULL) {
		// read from standard input
		int c;
		while ((c = fgetc(stdin)) != EOF) {
			inputString += (char)c;
		}

		string = inputString.String();
	}

	// get clipboard BMessage

	if (be_clipboard->Lock()) {
		be_clipboard->Clear();

		BMessage *clip = be_clipboard->Data();

		// add data to clipboard
		clip->AddData("text/plain", B_MIME_TYPE, string, strlen(string));

		status = be_clipboard->Commit();
		if (status != B_OK) {
			fprintf(stderr, "%s: could not commit data to clipboard.\n",
				kProgramName);
			be_clipboard->Unlock();
			return status;
		}

		be_clipboard->Unlock();
	} else {
		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
		return B_ERROR;
	}

	return B_OK;
}


status_t
ClipboardApp::Clear(void)
{
	status_t status = B_OK;

	if (!be_clipboard->Lock()) {
		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
		return B_ERROR;
	}

	be_clipboard->Clear();

	status = be_clipboard->Commit();
	if (status != B_OK) {
		fprintf(stderr, "%s: could not clear clipboard.\n", kProgramName);
		be_clipboard->Unlock();
		return status;
	}

	be_clipboard->Unlock();
	return B_OK;
}


status_t
ClipboardApp::Print(bool debug)
{
	// get clip & print contents
	// (or the entire clip, in case of --debug)

	if (!be_clipboard->Lock()) {
		fprintf(stderr, "%s: could not lock clipboard.\n", kProgramName);
		return B_ERROR;
	}

	BMessage *clip = be_clipboard->Data();

	if (debug)
		clip->PrintToStream();
	else {
		const char * textBuffer;
		ssize_t textLength;
		clip->FindData("text/plain", B_MIME_TYPE, (const void **)&textBuffer,
			&textLength);

		if (textBuffer != NULL && textLength > 0) {
			BString textString(textBuffer, textLength);
			printf("%s\n", textString.String());
		}
	}

	be_clipboard->Unlock();
	return B_OK;
}


//	#pragma mark -


int
main()
{
	ClipboardApp clip_app;
	clip_app.Run();

	return sExitValue;
}