1// clipboard.cpp
2
3#include <stdio.h>
4#include <string.h>
5#include <sys/utsname.h>
6
7#include <Application.h>
8#include <Clipboard.h>
9#include <Message.h>
10
11// usage
12static const char *kUsage =
13"Usage: %s [ <options> ] clear\n"
14"       %s [ <options> ] dump\n"
15"       %s [ <options> ] set <value>\n"
16"\n"
17"Manipulates or dump the contents of the clipboard.\n"
18"\n"
19"Commands:\n"
20"  clear          - Clears the contents of the clipboard.\n"
21"  dump           - Prints the contents of the clipboard.\n"
22"  set            - Clears the clipboard and adds <value> as \"text/plain\".\n"
23"\n"
24"Options:\n"
25"  -h, --help     - Print this text.\n"
26"  -c <clipboard> - The name of the clipboard to be used. Default is the\n"
27"                   system clipboard.\n"
28;
29
30// command line args
31static int sArgc;
32static const char *const *sArgv;
33
34// print_usage
35void
36print_usage(bool error)
37{
38	// get nice program name
39	const char *programName = (sArgc > 0 ? sArgv[0] : "resattr");
40	if (const char *lastSlash = strrchr(programName, '/'))
41		programName = lastSlash + 1;
42
43	// print usage
44	fprintf((error ? stderr : stdout), kUsage, programName, programName,
45		programName, programName);
46}
47
48// print_usage_and_exit
49static
50void
51print_usage_and_exit(bool error)
52{
53	print_usage(error);
54	exit(error ? 1 : 0);
55}
56
57// next_arg
58static
59const char*
60next_arg(int argc, const char* const* argv, int& argi, bool dontFail = false)
61{
62	if (argi + 1 >= argc) {
63		if (dontFail)
64			return NULL;
65		print_usage_and_exit(true);
66	}
67
68	return argv[++argi];
69}
70
71// clipboard_clear
72static
73void
74clipboard_clear(BClipboard &clipboard)
75{
76	// clear the data
77	status_t error = clipboard.Clear();
78	if (error != B_OK) {
79		fprintf(stderr, "Failed to clear clipboard data: %s\n",
80			strerror(error));
81		exit(1);
82	}
83}
84
85// clipboard_dump
86static
87void
88clipboard_dump(BClipboard &clipboard)
89{
90	const char *data;
91	ssize_t size;
92	if (clipboard.Data()->FindData("text/plain", B_MIME_TYPE,
93		(const void**)&data, &size) == B_OK) {
94		printf("%.*s\n", (int)size, data);
95	} else
96		clipboard.Data()->PrintToStream();
97}
98
99// clipboard_set
100static
101void
102clipboard_set(BClipboard &clipboard, const char *value)
103{
104	// clear clipboard
105	clipboard_clear(clipboard);
106
107	// add data
108	status_t error = clipboard.Data()->AddData("text/plain", B_MIME_TYPE, value,
109		strlen(value) + 1);
110	if (error != B_OK) {
111		fprintf(stderr, "Failed to add clipboard data: %s\n", strerror(error));
112		exit(1);
113	}
114}
115
116// main
117int
118main(int argc, const char *const *argv)
119{
120	sArgc = argc;
121	sArgv = argv;
122
123	// parameters
124	const char *clipboardName = NULL;
125	const char *command = NULL;
126	const char *value = NULL;
127
128	// parse arguments
129	for (int argi = 1; argi < argc; argi++) {
130		const char *arg = argv[argi];
131		if (arg[0] == '-') {
132			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
133				print_usage_and_exit(false);
134			} else if (strcmp(arg, "-c") == 0) {
135				clipboardName = next_arg(argc, argv, argi);
136			} else {
137				print_usage_and_exit(true);
138			}
139		} else {
140			command = arg;
141			value = next_arg(argc, argv, argi, true);
142		}
143	}
144
145	// check parameters
146	if (!command)
147		print_usage_and_exit(true);
148
149	// create a BApplication on BeOS
150	struct utsname unameInfo;
151	if (uname(&unameInfo) < 0 || strcmp(unameInfo.sysname, "Haiku") != 0)
152		new BApplication("application/x-vnd.haiku.clipboard");
153
154	// init clipboard
155	BClipboard clipboard(clipboardName ? clipboardName : "system");
156
157	// lock clipboard
158	if (!clipboard.Lock()) {
159		fprintf(stderr, "Failed to lock clipboard `%s'\n", clipboard.Name());
160		exit(1);
161	}
162
163	// check, if data exist
164	if (!clipboard.Data()) {
165		fprintf(stderr, "Failed to get data from clipboard `%s'.",
166			clipboard.Name());
167		exit(1);
168	}
169
170	// execute the command
171	bool needsCommit = true;
172	if (strcmp(command, "clear") == 0) {
173		// clear
174		if (value)
175			print_usage_and_exit(true);
176		clipboard_clear(clipboard);
177	} else if (strcmp(command, "dump") == 0) {
178		// dump
179		if (value)
180			print_usage_and_exit(true);
181		clipboard_dump(clipboard);
182		needsCommit = false;
183	} else if (strcmp(command, "set") == 0) {
184		// set
185		if (!value)
186			print_usage_and_exit(true);
187		clipboard_set(clipboard, value);
188	} else
189		print_usage_and_exit(true);
190
191	// commit the change
192	if (needsCommit) {
193		status_t error = clipboard.Commit();
194		if (error != B_OK) {
195			fprintf(stderr, "Failed to commit clipboard data: %s\n",
196				strerror(error));
197			exit(1);
198		}
199	}
200
201	// unlock the clipboard (just for completeness :-)
202	clipboard.Unlock();
203
204	return 0;
205}
206