1 /* 2 ** Copyright 2003, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved. 3 ** Distributed under the terms of the OpenBeOS License. 4 */ 5 6 #include <cctype> 7 #include <cerrno> 8 #include <cstdio> 9 #include <cstdlib> 10 11 #include <Catalog.h> 12 using namespace BPrivate; 13 #include <Entry.h> 14 #include <File.h> 15 #include "RegExp.h" 16 #include <String.h> 17 18 bool showKeys = false; 19 bool showSummary = false; 20 bool showWarnings = false; 21 const char *inputFile = NULL; 22 BString outputFile; 23 const char *catalogSig = NULL; 24 const char *catalogLang = "English"; 25 BString rxString("be_catalog\\s*->\\s*GetString\\s*"); 26 27 28 BString str, ctx, cmt; 29 bool haveID; 30 int32 id; 31 32 33 EditableCatalog *catalog = NULL; 34 35 36 void 37 usage() 38 { 39 fprintf(stderr, 40 "usage: collectcatkeys [-pvw] [-r <regex>] [-o <outfile>] [-l <catalogLanguage>]\n" 41 " -s <catalogSig> <prepCppFile>\n" 42 "options:\n" 43 " -l <catalogLang>\tlanguage of the target-catalog (default is English)\n" 44 " -o <outfile>\t\texplicitly specifies the name of the output-file\n" 45 " -p\t\t\tprint keys as they are found\n" 46 " -r <regex>\t\tchanges the regex used by the key-scanner to the one given,\n" 47 " \t\t\tthe default is: be_catalog\\s*->\\s*GetString\\s*\n" 48 " -s <catalogSig>\tsignature of the target-catalog\n" 49 " -v\t\t\tbe verbose, show summary\n" 50 " -w\t\t\tshow warnings about catalog-accesses that couldn't be resolved completely\n"); 51 exit(-1); 52 } 53 54 55 bool 56 fetchStr(const char *&in, BString &str, bool lookForID) 57 { 58 int parLevel = 0; 59 while(isspace(*in) || *in == '(') { 60 if (*in == '(') 61 parLevel++; 62 in++; 63 } 64 if (*in == '"') { 65 in++; 66 bool quoted = false; 67 while (*in != '"' || quoted) { 68 if (quoted) { 69 if (*in == 'n') 70 str.Append("\n",1); 71 else if (*in == 't') 72 str.Append("\t",1); 73 else if (*in == '"') 74 str.Append("\"",1); 75 else 76 // dump quote from unknown quoting-sequence: 77 str.Append(in,1); 78 quoted = false; 79 } else { 80 quoted = (*in == '\\'); 81 if (!quoted) 82 str.Append(in,1); 83 } 84 in++; 85 } 86 in++; 87 } else if (!memcmp(in, "__null", 6)) { 88 // NULL is preprocessed into __null, which we parse as "" 89 in += 6; 90 } else if (lookForID && (isdigit(*in) || *in == '-' || *in == '+')) { 91 // try to parse an ID (a long): 92 errno = 0; 93 char *next; 94 id = strtol(in, &next, 10); 95 if (id != 0 || errno == 0) { 96 haveID = true; 97 in = next; 98 } 99 } else 100 return false; 101 while(isspace(*in) || *in == ')') { 102 if (*in == ')') { 103 if (!parLevel) 104 return true; 105 parLevel--; 106 } 107 in++; 108 } 109 return true; 110 } 111 112 113 bool 114 fetchKey(const char *&in) 115 { 116 str = ctx = cmt = ""; 117 haveID = false; 118 // fetch native string or id: 119 if (!fetchStr(in, str, true)) 120 return false; 121 if (*in == ',') { 122 in++; 123 // fetch context: 124 if (!fetchStr(in, ctx, false)) 125 return false; 126 if (*in == ',') { 127 in++; 128 // fetch comment: 129 if (!fetchStr(in, cmt, false)) 130 return false; 131 } 132 } 133 return true; 134 } 135 136 137 void 138 collectAllCatalogKeys(BString& inputStr) 139 { 140 RegExp rx; 141 struct regexp *rxprg = rx.Compile(rxString.String()); 142 if (rx.InitCheck() != B_OK) { 143 fprintf(stderr, "regex-compilation error %s\n", rx.ErrorString()); 144 return; 145 } 146 status_t res; 147 const char *in = inputStr.String(); 148 while(rx.RunMatcher(rxprg, in)) { 149 const char *start = rxprg->startp[0]; 150 in = rxprg->endp[0]; 151 if (fetchKey(in)) { 152 if (haveID) { 153 if (showKeys) 154 printf("CatKey(%ld)\n", id); 155 res = catalog->SetString(id, ""); 156 if (res != B_OK) { 157 fprintf(stderr, "couldn't add key %ld - error: %s\n", 158 id, strerror(res)); 159 exit(-1); 160 } 161 } else { 162 if (showKeys) 163 printf("CatKey(\"%s\", \"%s\", \"%s\")\n", str.String(), 164 ctx.String(), cmt.String()); 165 res = catalog->SetString(str.String(), str.String(), ctx.String(), cmt.String()); 166 if (res != B_OK) { 167 fprintf(stderr, "couldn't add key %s,%s,%s - error: %s\n", 168 str.String(), ctx.String(), cmt.String(), strerror(res)); 169 exit(-1); 170 } 171 } 172 } else if (showWarnings) { 173 const char *end = strchr(in, ';'); 174 BString match; 175 if (end) 176 match.SetTo(start, end-start+1); 177 else 178 // can't determine end of statement, we output next 40 characters 179 match.SetTo(start, 40); 180 fprintf(stderr, "Warning: couldn't resolve catalog-access:\n\t%s\n", 181 match.String()); 182 } 183 } 184 } 185 186 187 int 188 main(int argc, char **argv) 189 { 190 while ((++argv)[0]) { 191 if (argv[0][0] == '-' && argv[0][1] != '-') { 192 char *arg = argv[0] + 1; 193 char c; 194 while ((c = *arg++) != '\0') { 195 if (c == 'p') 196 showKeys = true; 197 else if (c == 'l') 198 catalogLang = (++argv)[0]; 199 else if (c == 's') 200 catalogSig = (++argv)[0]; 201 else if (c == 'v') 202 showSummary = true; 203 else if (c == 'w') 204 showWarnings = true; 205 else if (c == 'o') { 206 outputFile = (++argv)[0]; 207 break; 208 } 209 else if (c == 'r') { 210 rxString = (++argv)[0]; 211 break; 212 } 213 } 214 } else if (!strcmp(argv[0], "--help")) { 215 usage(); 216 } else { 217 if (!inputFile) 218 inputFile = argv[0]; 219 else 220 usage(); 221 } 222 } 223 if (!outputFile.Length() && inputFile) { 224 // generate default output-file from input-file by replacing 225 // the extension with '.catkeys': 226 outputFile = inputFile; 227 int32 dot = outputFile.FindLast('.'); 228 if (dot >= B_OK) 229 outputFile.Truncate(dot); 230 outputFile << ".catkeys"; 231 } 232 if (!inputFile || !catalogSig || !outputFile.Length() || !catalogLang) 233 usage(); 234 235 BFile inFile; 236 status_t res = inFile.SetTo(inputFile, B_READ_ONLY); 237 if (res != B_OK) { 238 fprintf(stderr, "unable to open inputfile %s - error: %s\n", inputFile, 239 strerror(res)); 240 exit(-1); 241 } 242 off_t sz; 243 inFile.GetSize(&sz); 244 if (sz > 0) { 245 BString inputStr; 246 char *buf = inputStr.LockBuffer(sz); 247 off_t rsz = inFile.Read(buf, sz); 248 if (rsz < sz) { 249 fprintf(stderr, "couldn't read %Ld bytes from %s (got only %Ld)\n", 250 sz, inputFile, rsz); 251 exit(-1); 252 } 253 inputStr.UnlockBuffer(rsz); 254 catalog = new EditableCatalog("Default", catalogSig, catalogLang); 255 collectAllCatalogKeys(inputStr); 256 res = catalog->WriteToFile(outputFile.String()); 257 if (res != B_OK) { 258 fprintf(stderr, "couldn't write catalog to %s - error: %s\n", 259 outputFile.String(), strerror(res)); 260 exit(-1); 261 } 262 if (showSummary) { 263 int32 count = catalog->CountItems(); 264 if (count) 265 fprintf(stderr, "%ld key%s found and written to %s\n", 266 count, (count==1 ? "": "s"), outputFile.String()); 267 else 268 fprintf(stderr, "no keys found\n"); 269 } 270 delete catalog; 271 } 272 273 // BEntry inEntry(inputFile); 274 // inEntry.Remove(); 275 276 return res; 277 } 278