libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / tools / locale / collectcatkeys.cpp
blob78ded2deb696abc96565069d482b319c1f8ebbd5
1 /*
2 * Copyright 2003-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Oliver Tappe, zooey@hirschkaefer.de
7 * Adrien Destugues, pulkomandy@gmail.com
8 */
11 #include <cctype>
12 #include <cerrno>
13 #include <cstdio>
14 #include <cstdlib>
16 #include <Entry.h>
17 #include <File.h>
18 #include <PlainTextCatalog.h>
19 #include "RegExp.h"
20 #include <StorageDefs.h>
21 #include <String.h>
24 using BPrivate::PlainTextCatalog;
27 bool showKeys = false;
28 bool showSummary = false;
29 bool showWarnings = false;
30 const char *inputFile = NULL;
31 BString outputFile;
32 const char *catalogSig = NULL;
33 const char *catalogLang = "English";
34 BString rxString("B_CATKEY\\s*");
37 BString str, ctx, cmt;
38 bool haveID;
39 int32 id;
42 PlainTextCatalog *catalog = NULL;
45 void
46 usage()
48 fprintf(stderr,
49 "usage: collectcatkeys [-pvw] [-r <regex>] [-o <outfile>] "
50 "[-l <catalogLanguage>]\n"
51 " -s <catalogSig> <prepCppFile>\n"
52 "options:\n"
53 " -l <catalogLang>\tlanguage of the target-catalog (default is "
54 "English)\n"
55 " -o <outfile>\t\texplicitly specifies the name of the output-file\n"
56 " -p\t\t\tprint keys as they are found\n"
57 " -r <regex>\t\tchanges the regex used by the key-scanner to the one "
58 "given,\n"
59 " \t\t\tthe default is: ");
60 fprintf(stderr, "%s", rxString.String());
61 fprintf(stderr,"\n -s <catalogSig>\tsignature of the target-catalog\n"
62 " -v\t\t\tbe verbose, show summary\n"
63 " -w\t\t\tshow warnings about catalog-accesses that couldn't be "
64 " resolved completely\n");
65 exit(-1);
69 bool
70 fetchStr(const char *&in, BString &str, bool lookForID)
72 int parLevel = 0;
73 while (isspace(*in) || *in == '(') {
74 if (*in == '(')
75 parLevel++;
76 in++;
78 if (*in == '"') {
79 bool inString = true;
80 bool quoted = false;
81 in++;
82 while (parLevel >= 0 && inString)
84 // Collect string content until we find a quote marking end of
85 // string (skip escaped quotes)
86 while (*in != '"' || quoted)
88 str.Append(in, 1);
89 if (*in == '\\' && !quoted)
90 quoted = true ;
91 else
92 quoted = false ;
93 in++;
95 in++;
97 inString = false;
99 // Strip all whitespace until we find a closing parenthesis, or the
100 // beginning of another string
101 while (isspace(*in) || *in == ')') {
102 if (*in == ')') {
103 if (parLevel == 0)
104 return true;
105 parLevel--;
108 in++;
111 if (*in == '"') {
112 inString = true;
113 in++;
116 } else {
117 if (!memcmp(in, "__null", 6)) {
118 // NULL is preprocessed into __null, which we parse as ""
119 in += 6;
120 } else if (lookForID && (isdigit(*in) || *in == '-' || *in == '+')) {
121 // try to parse an ID (a long):
122 errno = 0;
123 char *next;
124 id = strtol(in, &next, 10);
125 if (id != 0 || errno == 0) {
126 haveID = true;
127 in = next;
129 } else
130 return false;
132 while (isspace(*in) || *in == ')') {
133 if (*in == ')') {
134 if (!parLevel)
135 return true;
136 parLevel--;
138 in++;
141 return true;
145 bool
146 fetchKey(const char *&in)
148 str = ctx = cmt = "";
149 haveID = false;
150 // fetch native string or id:
151 if (!fetchStr(in, str, true)) {
152 return false;
154 if (*in == ',') {
155 in++;
156 // fetch context:
157 if (!fetchStr(in, ctx, false)) {
158 fprintf(stderr,"Context parsing error\n");
159 return false;
161 if (*in == ',') {
162 in++;
163 // fetch comment:
164 if (!fetchStr(in, cmt, false))
166 fprintf(stderr,"Comment parsing error\n");
167 return false;
171 return true;
175 void
176 collectAllCatalogKeys(BString& inputStr)
178 RegExp rx;
179 struct regexp *rxprg = rx.Compile(rxString.String());
180 if (rx.InitCheck() != B_OK) {
181 fprintf(stderr, "regex-compilation error %s\n", rx.ErrorString());
182 return;
184 status_t res;
185 const char *in = inputStr.String();
186 while (rx.RunMatcher(rxprg, in)) {
187 const char *start = rxprg->startp[0];
188 in = rxprg->endp[0];
189 if (fetchKey(in)) {
190 if (haveID) {
191 if (showKeys)
192 printf("CatKey(%d)\n", id);
193 res = catalog->SetString(id, "");
194 if (res != B_OK) {
195 fprintf(stderr, "Collectcatkeys: couldn't add key %d - "
196 "error: %s\n", id, strerror(res));
197 exit(-1);
199 } else {
200 if (showKeys) {
201 printf("CatKey(\"%s\", \"%s\", \"%s\")\n", str.String(),
202 ctx.String(), cmt.String());
204 res = catalog->SetString(str.String(), str.String(),
205 ctx.String(), cmt.String());
206 if (res != B_OK) {
207 fprintf(stderr, "couldn't add key %s,%s,%s - error: %s\n",
208 str.String(), ctx.String(), cmt.String(),
209 strerror(res));
210 exit(-1);
213 } else if (showWarnings) {
214 const char *end = strchr(in, ';');
215 BString match;
216 if (end)
217 match.SetTo(start, end-start+1);
218 else {
219 // can't determine end of statement, we output next 40 chars
220 match.SetTo(start, 40);
222 fprintf(stderr, "Warning: couldn't resolve catalog-access:\n\t%s\n",
223 match.String());
230 main(int argc, char **argv)
232 while ((++argv)[0]) {
233 if (argv[0][0] == '-' && argv[0][1] != '-') {
234 char *arg = argv[0] + 1;
235 char c;
236 while ((c = *arg++) != '\0') {
237 if (c == 'p')
238 showKeys = true;
239 else if (c == 'l')
240 catalogLang = (++argv)[0];
241 else if (c == 's')
242 catalogSig = (++argv)[0];
243 else if (c == 'v')
244 showSummary = true;
245 else if (c == 'w')
246 showWarnings = true;
247 else if (c == 'o') {
248 outputFile = (++argv)[0];
249 break;
250 } else if (c == 'r') {
251 rxString = (++argv)[0];
252 break;
255 } else if (!strcmp(argv[0], "--help")) {
256 usage();
257 } else {
258 if (!inputFile)
259 inputFile = argv[0];
260 else
261 usage();
264 if (!outputFile.Length() && inputFile) {
265 // generate default output-file from input-file by replacing
266 // the extension with '.catkeys':
267 outputFile = inputFile;
268 int32 dot = outputFile.FindLast('.');
269 if (dot >= B_OK)
270 outputFile.Truncate(dot);
271 outputFile << ".catkeys";
273 if (!inputFile || !catalogSig || !outputFile.Length() || !catalogLang)
274 usage();
276 BFile inFile;
277 status_t res = inFile.SetTo(inputFile, B_READ_ONLY);
278 if (res != B_OK) {
279 fprintf(stderr, "unable to open inputfile %s - error: %s\n", inputFile,
280 strerror(res));
281 exit(-1);
283 off_t sz;
284 inFile.GetSize(&sz);
285 if (sz > 0) {
286 BString inputStr;
287 char *buf = inputStr.LockBuffer(sz);
288 off_t rsz = inFile.Read(buf, sz);
289 if (rsz < sz) {
290 fprintf(stderr, "couldn't read %Ld bytes from %s (got only %Ld)\n",
291 sz, inputFile, rsz);
292 exit(-1);
294 inputStr.UnlockBuffer(rsz);
295 catalog = new PlainTextCatalog(inputFile, catalogSig, catalogLang);
296 collectAllCatalogKeys(inputStr);
297 res = catalog->WriteToFile(outputFile.String());
298 if (res != B_OK) {
299 fprintf(stderr, "couldn't write catalog to %s - error: %s\n",
300 outputFile.String(), strerror(res));
301 exit(-1);
303 if (showSummary) {
304 int32 count = catalog->CountItems();
305 if (count)
306 fprintf(stderr, "%d key%s found and written to %s\n",
307 count, (count==1 ? "": "s"), outputFile.String());
308 else
309 fprintf(stderr, "no keys found\n");
311 delete catalog;
314 // BEntry inEntry(inputFile);
315 // inEntry.Remove();
317 return res;