1/*
2** Copyright 2003, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved.
3** Distributed under the terms of the MIT License.
4*/
5
6#include <cstdio>
7#include <cstdlib>
8#include <vector>
9
10#include <Entry.h>
11#include <File.h>
12#include <String.h>
13
14#include <EditableCatalog.h>
15#include <DefaultCatalog.h>
16#include <HashMapCatalog.h>
17
18
19using BPrivate::CatKey;
20using BPrivate::DefaultCatalog;
21using BPrivate::EditableCatalog;
22using BPrivate::HashMapCatalog;
23using std::vector;
24
25
26void
27usage()
28{
29	fprintf(stderr,
30		"usage: linkcatkeys [-v] [-t(a|f|r)] [-o <outfile>] [-l <catalogLang>]\n"
31		"                   -s <catalogSig> <catalogFiles>\n"
32		"options:\n"
33		"  -l <catalogLang>\tlanguage of the target-catalog (default is English)\n"
34		"  -o <outfile>\t\texplicitly specifies the name of the output-file\n"
35		"  -s <catalogSig>\tsignature of the target-catalog\n"
36		"  -t(a|f|r)\t\tspecifies target of resulting catalog (-tf is default)\n"
37		"           \t\ta => write catalog as an attribute (to output-file)\n"
38		"           \t\tf => write catalog into the output-file\n"
39		"           \t\tr => write catalog as a resource (to output-file)\n"
40		"  -v\t\t\tbe verbose, show summary\n");
41	exit(-1);
42}
43
44
45int
46main(int argc, char **argv)
47{
48	bool showSummary = false;
49	bool showWarnings = false;
50	vector<const char *> inputFiles;
51	BString outputFile("default.catalog");
52	enum TargetType {
53		TARGET_ATTRIBUTE,
54		TARGET_FILE,
55		TARGET_RESOURCE
56	};
57	TargetType outputTarget = TARGET_FILE;
58	const char *catalogSig = NULL;
59	BString catalogLang("English");
60	status_t res;
61	while ((++argv)[0]) {
62		if (argv[0][0] == '-' && argv[0][1] != '-') {
63			char *arg = argv[0] + 1;
64			char c;
65			while ((c = *arg++) != '\0') {
66				if (c == 's')
67					catalogSig = (++argv)[0];
68				else if (c == 'l')
69					catalogLang = (++argv)[0];
70				else if (c == 'v')
71					showSummary = true;
72				else if (c == 'w')
73					showWarnings = true;
74				else if (c == 'o') {
75					outputFile = (++argv)[0];
76					break;
77				}
78				else if (c == 't') {
79					switch(*arg) {
80						case 'a': outputTarget = TARGET_ATTRIBUTE; break;
81						case 'f': outputTarget = TARGET_FILE; break;
82						case 'r': outputTarget = TARGET_RESOURCE; break;
83						default: usage();
84					}
85				}
86			}
87		} else if (!strcmp(argv[0], "--help")) {
88			usage();
89		} else {
90			inputFiles.push_back(argv[0]);
91		}
92	}
93	if (inputFiles.empty() || !catalogSig || !outputFile.Length())
94		usage();
95
96	EditableCatalog targetCatalog("Default", catalogSig, catalogLang.String());
97	if ((res = targetCatalog.InitCheck()) != B_OK) {
98		fprintf(stderr, "couldn't construct target-catalog %s - error: %s\n",
99			outputFile.String(), strerror(res));
100		exit(-1);
101	}
102	DefaultCatalog* targetCatImpl
103		= dynamic_cast<DefaultCatalog*>(targetCatalog.CatalogData());
104	if (!targetCatImpl) {
105		fprintf(stderr, "couldn't access impl of target-catalog %s\n",
106			outputFile.String());
107		exit(-1);
108	}
109
110	uint32 count = inputFiles.size();
111	for( uint32 i=0; i<count; ++i) {
112		EditableCatalog inputCatalog("plaintext", catalogSig, "native");
113		if ((res = inputCatalog.ReadFromFile(inputFiles[i])) != B_OK) {
114			fprintf(stderr, "couldn't load source-catalog %s - error: %s\n",
115				inputFiles[i], strerror(res));
116			exit(-1);
117		}
118		HashMapCatalog* inputCatImpl
119			= dynamic_cast<HashMapCatalog*>(inputCatalog.CatalogData());
120		if (!inputCatImpl) {
121			fprintf(stderr, "couldn't access impl of input-catalog %s\n",
122				inputFiles[i]);
123			exit(-1);
124		}
125
126		// now walk over all entries in input-catalog and add them to
127		// target catalog, unless they already exist there.
128		HashMapCatalog::CatWalker walker(inputCatImpl);
129		while (!walker.AtEnd()) {
130			const CatKey &plainTextKey(walker.GetKey());
131			BString keyString, keyComment, keyContext;
132			plainTextKey.GetStringParts(&keyString,&keyComment,&keyContext);
133			const CatKey fixedCatKey(keyString.String(), keyComment.String(),
134					keyContext.String());
135
136			if (!targetCatImpl->GetString(fixedCatKey))
137				targetCatImpl->SetRawString(fixedCatKey, walker.GetValue());
138			walker.Next();
139		}
140	}
141
142	switch(outputTarget) {
143		case TARGET_ATTRIBUTE: {
144			BEntry entry(outputFile.String());
145			entry_ref eref;
146			entry.GetRef(&eref);
147			res = targetCatalog.WriteToAttribute(eref);
148			if (res != B_OK) {
149				fprintf(stderr,
150					"couldn't write target-attribute to %s - error: %s\n",
151					outputFile.String(), strerror(res));
152				exit(-1);
153			}
154			break;
155		}
156		case TARGET_RESOURCE: {
157			BEntry entry(outputFile.String());
158			entry_ref eref;
159			entry.GetRef(&eref);
160			res = targetCatalog.WriteToResource(eref);
161			if (res != B_OK) {
162				fprintf(stderr,
163					"couldn't write target-resource to %s - error: %s\n",
164					outputFile.String(), strerror(res));
165				exit(-1);
166			}
167			break;
168		}
169		default: {
170			res = targetCatalog.WriteToFile(outputFile.String());
171			if (res != B_OK) {
172				fprintf(stderr,
173					"couldn't write target-catalog to %s - error: %s\n",
174					outputFile.String(), strerror(res));
175				exit(-1);
176			}
177			break;
178		}
179	}
180	if (showSummary) {
181		int32 count = targetCatalog.CountItems();
182		if (count) {
183			fprintf(stderr, "%" B_PRId32 " key%s found and written to %s\n",
184				count, (count==1 ? "": "s"), outputFile.String());
185		} else
186			fprintf(stderr, "no keys found\n");
187	}
188
189	return res;
190}
191