1/*
2 * Copyright 2004-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		J��r��me Duval
7 *		Axel D��rfler, axeld@pinc-software.de.
8 */
9
10
11#include <getopt.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include <Application.h>
17#include <FileIO.h>
18
19#include "Keymap.h"
20
21
22extern char *__progname;
23static const char *sProgramName = __progname;
24
25
26static void
27usage()
28{
29	printf("usage: %s {-o <output-file>} [-[l|r] | -[b|h|c|d <input-file>]]\n"
30		"  -o, --output       Change output file to output-file (default: "
31			"keymap.out|h).\n"
32		"  -d, --dump         Decompile key map to standard output (can be "
33			"redirected\n"
34		"                     via -o).\n"
35		"  -l, --load         Load key map. If no input-file is specified, it "
36			"will be\n"
37		"                     read from standard input.\n"
38		"  -s, --load-source  Load source key map from standard input when no\n"
39		"                     input-file is specified.\n"
40		"  -r, --restore      Restore system default key map.\n"
41		"  -c, --compile      Compile source keymap to binary.\n"
42		"  -h, --header       Translate source keymap to C++ header.\n",
43		sProgramName);
44}
45
46
47static const char*
48keymap_error(status_t status)
49{
50	if (status == KEYMAP_ERROR_UNKNOWN_VERSION)
51		return "Unknown keymap version";
52
53	return strerror(status);
54}
55
56
57static void
58load_keymap(Keymap& keymap, const char* name, bool source)
59{
60	status_t status;
61	if (source) {
62		if (name != NULL)
63			status = keymap.LoadSource(name);
64		else
65			status = keymap.LoadSource(stdin);
66	} else {
67		if (name != NULL)
68			status = keymap.SetTo(name);
69		else {
70			BFileIO fileIO(stdin);
71			status = keymap.SetTo(fileIO);
72		}
73	}
74
75	if (status != B_OK) {
76		fprintf(stderr, "%s: error when loading the keymap: %s\n", sProgramName,
77			keymap_error(status));
78		exit(1);
79	}
80}
81
82
83int
84main(int argc, char** argv)
85{
86	const char* output = NULL;
87	const char* input = NULL;
88	enum {
89		kUnspecified,
90		kLoadBinary,
91		kLoadText,
92		kSaveText,
93		kRestore,
94		kCompile,
95		kSaveHeader,
96	} mode = kUnspecified;
97
98	static struct option const kLongOptions[] = {
99		{"output", required_argument, 0, 'o'},
100		{"dump", optional_argument, 0, 'd'},
101		{"load", optional_argument, 0, 'l'},
102		{"load-source", optional_argument, 0, 's'},
103		{"restore", no_argument, 0, 'r'},
104		{"compile", optional_argument, 0, 'c'},
105		{"header", optional_argument, 0, 'h'},
106		{"help", no_argument, 0, 'H'},
107		{NULL}
108	};
109
110	int c;
111	while ((c = getopt_long(argc, argv, "o:dblsrchH", kLongOptions,
112			NULL)) != -1) {
113		switch (c) {
114			case 0:
115				break;
116			case 'o':
117				output = optarg;
118				break;
119			case 'd':
120				mode = kSaveText;
121				input = optarg;
122				break;
123			case 'l':
124			case 'b':
125				mode = kLoadBinary;
126				input = optarg;
127				break;
128			case 's':
129				mode = kLoadText;
130				input = optarg;
131				break;
132			case 'r':
133				mode = kRestore;
134				break;
135			case 'c':
136				mode = kCompile;
137				input = optarg;
138				break;
139			case 'h':
140				mode = kSaveHeader;
141				input = optarg;
142				break;
143
144			case 'H':
145			default:
146				mode = kUnspecified;
147				break;
148		}
149	}
150
151	if (argc > optind && input == NULL)
152		input = argv[optind];
153
154	BApplication app("application/x-vnd.Haiku-keymap-cli");
155	Keymap keymap;
156
157	switch (mode) {
158		case kUnspecified:
159			usage();
160			break;
161
162		case kLoadBinary:
163		case kLoadText:
164		{
165			load_keymap(keymap, input, mode == kLoadText);
166
167			status_t status = keymap.SaveAsCurrent();
168			if (status != B_OK) {
169				fprintf(stderr, "%s: error when saving as current: %s",
170					sProgramName, strerror(status));
171				return 1;
172			}
173
174			printf("Key map loaded.\n");
175			break;
176		}
177
178		case kSaveText:
179		{
180			if (input == NULL) {
181				status_t status = keymap.SetToCurrent();
182				if (status != B_OK) {
183					fprintf(stderr, "%s: error while getting keymap: %s!\n",
184						sProgramName, keymap_error(status));
185					return 1;
186				}
187			} else
188				load_keymap(keymap, input, false);
189
190			if (output != NULL)
191				keymap.SaveAsSource(output);
192			else
193				keymap.SaveAsSource(stdout);
194			break;
195		}
196
197		case kRestore:
198			keymap.RestoreSystemDefault();
199			break;
200
201		case kCompile:
202		{
203			load_keymap(keymap, input, true);
204
205			if (output == NULL)
206				output = "keymap.out";
207
208			status_t status = keymap.Save(output);
209			if (status != B_OK) {
210				fprintf(stderr, "%s: error saving \"%s\": %s\n", sProgramName,
211					output, strerror(status));
212				return 1;
213			}
214			break;
215		}
216
217		case kSaveHeader:
218		{
219			load_keymap(keymap, input, true);
220
221			if (output == NULL)
222				output = "keymap.h";
223
224			status_t status = keymap.SaveAsCppHeader(output, input);
225			if (status != B_OK) {
226				fprintf(stderr, "%s: error saving \"%s\": %s\n", sProgramName,
227					output, strerror(status));
228				return 1;
229			}
230			break;
231		}
232	}
233
234	return 0;
235}
236