Version 3.6.0.2, tag libreoffice-3.6.0.2
[LibreOffice.git] / l10ntools / source / localize.cxx
bloba54d096503df653b694430863e35b950d8e6ca7f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include "sal/config.h"
31 #include <cstddef>
32 #include <cstdlib>
33 #include <fstream>
34 #include <iostream>
35 #include <string>
37 #include "boost/noncopyable.hpp"
38 #include "osl/file.h"
39 #include "osl/file.hxx"
40 #include "osl/process.h"
41 #include "osl/thread.h"
42 #include "rtl/oustringostreaminserter.hxx"
43 #include "rtl/string.h"
44 #include "rtl/string.hxx"
45 #include "rtl/textcvt.h"
46 #include "rtl/ustrbuf.hxx"
47 #include "rtl/ustring.h"
48 #include "rtl/ustring.hxx"
49 #include "sal/macros.h"
50 #include "sal/main.h"
51 #include "sal/types.h"
53 using namespace std;
55 namespace {
57 namespace global {
59 std::ofstream output;
63 rtl::OUString getEnvironment(rtl::OUString const & variable) {
64 rtl::OUString value;
65 if (osl_getEnvironment(variable.pData, &value.pData) != osl_Process_E_None)
67 std::cerr
68 << "Error: cannot get environment variable " << variable << '\n';
69 throw false; //TODO
71 return value;
74 class TempFile: private boost::noncopyable {
75 public:
76 TempFile() {
77 if (osl::FileBase::createTempFile(0, 0, &url_) != osl::FileBase::E_None)
79 std::cerr << "osl::FileBase::createTempFile() failed\n";
80 throw false; //TODO
84 ~TempFile() {
85 if (osl::File::remove(url_) != osl::FileBase::E_None) {
86 std::cerr << "Warning: failure removing temporary " << url_ << '\n';
90 rtl::OUString getUrl() const { return url_; }
92 private:
93 rtl::OUString url_;
96 struct AsciiString {
97 char const * string;
98 sal_Int32 length;
101 bool matchList(
102 rtl::OUString const & url, AsciiString const * list, std::size_t length)
104 for (std::size_t i = 0; i != length; ++i) {
105 if (url.endsWithAsciiL(list[i].string, list[i].length)) {
106 return true;
109 return false;
112 bool passesNegativeList(rtl::OUString const & url) {
113 static AsciiString const list[] = {
114 { RTL_CONSTASCII_STRINGPARAM("/dictionaries.xcu") },
115 { RTL_CONSTASCII_STRINGPARAM(
116 "/dictionaries/da_DK/help/da/"
117 "org.openoffice.da.hunspell.dictionaries/page1.xhp") },
118 { RTL_CONSTASCII_STRINGPARAM(
119 "/dictionaries/da_DK/help/da/"
120 "org.openoffice.da.hunspell.dictionaries/page2.xhp") },
121 { RTL_CONSTASCII_STRINGPARAM(
122 "/dictionaries/hu_HU/help/hu/"
123 "org.openoffice.hu.hunspell.dictionaries/page1.xhp") },
124 { RTL_CONSTASCII_STRINGPARAM("/hidother.src") },
125 { RTL_CONSTASCII_STRINGPARAM(
126 "/officecfg/registry/data/org/openoffice/Office/"
127 "Accelerators.xcu") },
128 { RTL_CONSTASCII_STRINGPARAM(
129 "/officecfg/registry/data/org/openoffice/Office/Labels.xcu") },
130 { RTL_CONSTASCII_STRINGPARAM(
131 "/officecfg/registry/data/org/openoffice/Office/SFX.xcu") }
133 return !matchList(url, list, SAL_N_ELEMENTS(list));
136 bool passesPositiveList(rtl::OUString const & url) {
137 static AsciiString const list[] = {
138 { RTL_CONSTASCII_STRINGPARAM(
139 "/chart2/source/controller/dialogs/res_DataLabel_tmpl.hrc") },
140 { RTL_CONSTASCII_STRINGPARAM(
141 "/chart2/source/controller/dialogs/res_ErrorBar_tmpl.hrc") },
142 { RTL_CONSTASCII_STRINGPARAM(
143 "/chart2/source/controller/dialogs/res_LegendPosition_tmpl.hrc") },
144 { RTL_CONSTASCII_STRINGPARAM(
145 "/chart2/source/controller/dialogs/"
146 "res_SecondaryAxisCheckBoxes_tmpl.hrc") },
147 { RTL_CONSTASCII_STRINGPARAM(
148 "/chart2/source/controller/dialogs/res_Statistic_tmpl.hrc") },
149 { RTL_CONSTASCII_STRINGPARAM(
150 "/chart2/source/controller/dialogs/res_Titlesx_tmpl.hrc") },
151 { RTL_CONSTASCII_STRINGPARAM(
152 "/chart2/source/controller/dialogs/res_Trendline_tmpl.hrc") },
153 { RTL_CONSTASCII_STRINGPARAM(
154 "/chart2/source/controller/menu/MenuItems_tmpl.hrc") },
155 { RTL_CONSTASCII_STRINGPARAM(
156 "/dbaccess/source/ui/dlg/AutoControls_tmpl.hrc") },
157 { RTL_CONSTASCII_STRINGPARAM(
158 "/dbaccess/source/ui/inc/toolbox_tmpl.hrc") },
159 { RTL_CONSTASCII_STRINGPARAM("/description.xml") },
160 { RTL_CONSTASCII_STRINGPARAM("/offmgr/inc/offmenu_tmpl.hrc") },
161 { RTL_CONSTASCII_STRINGPARAM(
162 "/offmgr/source/offapp/intro/intro_tmpl.hrc") },
163 { RTL_CONSTASCII_STRINGPARAM("/svx/inc/globlmn_tmpl.hrc") },
164 { RTL_CONSTASCII_STRINGPARAM("/svx/source/intro/intro_tmpl.hrc") },
165 { RTL_CONSTASCII_STRINGPARAM(
166 "/svx/source/unodialogs/textconversiondlgs/"
167 "chinese_direction_tmpl.hrc") },
168 { RTL_CONSTASCII_STRINGPARAM("/sw/source/ui/inc/swacc_tmpl.hrc") },
169 { RTL_CONSTASCII_STRINGPARAM("/sw/source/ui/inc/swmn_tmpl.hrc") },
170 { RTL_CONSTASCII_STRINGPARAM("/sw/source/ui/inc/toolbox_tmpl.hrc") }
172 return matchList(url, list, SAL_N_ELEMENTS(list));
175 void handleCommand(
176 rtl::OUString const & project, rtl::OUString const & projectRoot,
177 rtl::OUString const & url, rtl::OUString const & executable, bool positive)
179 if (positive ? passesPositiveList(url) : passesNegativeList(url)) {
180 rtl::OUString inPath;
181 if (osl::FileBase::getSystemPathFromFileURL(url, inPath) !=
182 osl::FileBase::E_None)
184 std::cerr
185 << "osl::FileBase::getSystemPathFromFileURL(" << url
186 << ") failed\n";
187 throw false; //TODO
189 TempFile temp;
190 rtl::OUString outPath;
191 if (osl::FileBase::getSystemPathFromFileURL(temp.getUrl(), outPath)
192 != osl::FileBase::E_None)
194 std::cerr
195 << "osl::FileBase::getSystemPathFromFileURL(" << temp.getUrl()
196 << ") failed\n";
197 throw false; //TODO
199 rtl::OUStringBuffer buf(
200 getEnvironment(
201 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SOLARVER"))));
202 buf.append('/');
203 buf.append(
204 getEnvironment(
205 rtl::OUString(
206 RTL_CONSTASCII_USTRINGPARAM("INPATH_FOR_BUILD"))));
207 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("/bin/"));
208 buf.append(executable);
209 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" -e -p "));
210 buf.append(project);
211 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" -r "));
212 buf.append(projectRoot);
213 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" -i "));
214 buf.append(inPath);
215 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" -o "));
216 buf.append(outPath);
217 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" -l en-US"));
218 rtl::OString cmd;
219 if (!buf.makeStringAndClear().convertToString(
220 &cmd, osl_getThreadTextEncoding(),
221 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
222 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
224 std::cerr << "Error: Cannot convert command from UTF-16\n";
225 throw false; //TODO
227 if (system(cmd.getStr()) != 0) {
228 std::cerr << "Error: Failed to execute " << cmd.getStr() << '\n';
229 throw false; //TODO
231 rtl::OString outPath8;
232 if (!outPath.convertToString(
233 &outPath8, osl_getThreadTextEncoding(),
234 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
235 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
237 std::cerr << "Error: Cannot convert pathname from UTF-16\n";
238 throw false; //TODO
240 std::ifstream in(outPath8.getStr());
241 if (!in.is_open()) {
242 std::cerr << "Error: Cannot open " << outPath.getStr() << "\n";
243 throw false; //TODO
245 while (!in.eof())
247 std::string s;
248 std::getline(in, s);
249 if (!s.empty())
250 global::output << s << '\n';
252 in.close();
256 void handleFile(
257 rtl::OUString const & project, rtl::OUString const & projectRoot,
258 rtl::OUString const & url)
260 struct Command {
261 char const * extension;
262 sal_Int32 extensionLength;
263 char const * executable;
264 bool positive;
266 static Command const commands[] = {
267 { RTL_CONSTASCII_STRINGPARAM(".src"), "transex3", false },
268 { RTL_CONSTASCII_STRINGPARAM(".hrc"), "transex3", true },
269 { RTL_CONSTASCII_STRINGPARAM(".ulf"), "ulfex", false },
270 { RTL_CONSTASCII_STRINGPARAM(".xcu"), "cfgex", false },
271 { RTL_CONSTASCII_STRINGPARAM(".xrm"), "xrmex", false },
272 { RTL_CONSTASCII_STRINGPARAM(".xml"), "xrmex", true },
273 { RTL_CONSTASCII_STRINGPARAM(".xhp"), "helpex", false },
274 { RTL_CONSTASCII_STRINGPARAM(".properties"), "propex", false } };
275 for (std::size_t i = 0; i != SAL_N_ELEMENTS(commands); ++i) {
276 if (url.endsWithAsciiL(
277 commands[i].extension, commands[i].extensionLength))
279 handleCommand(
280 project, projectRoot, url,
281 rtl::OUString::createFromAscii(commands[i].executable),
282 commands[i].positive);
283 break;
288 bool includeProject(rtl::OUString const & project) {
289 static char const * projects[] = {
290 "accessibility",
291 "avmedia",
292 "basctl",
293 "basic",
294 "chart2",
295 "connectivity",
296 "cui",
297 "dbaccess",
298 "desktop",
299 "dictionaries",
300 "editeng",
301 "extensions",
302 "filter",
303 "forms",
304 "formula",
305 "fpicker",
306 "framework",
307 "helpcontent2",
308 "instsetoo_native",
309 "mysqlc",
310 "nlpsolver",
311 "officecfg",
312 "padmin",
313 "readlicense_oo",
314 "reportbuilder",
315 "reportdesign",
316 "sc",
317 "scaddins",
318 "sccomp",
319 "scp2",
320 "scripting",
321 "sd",
322 "sdext",
323 "setup_native",
324 "sfx2",
325 "shell",
326 "starmath",
327 "svl",
328 "svtools",
329 "svx",
330 "sw",
331 "swext",
332 "sysui",
333 "uui",
334 "vcl",
335 "wizards",
336 "xmlsecurity" };
337 for (std::size_t i = 0; i != SAL_N_ELEMENTS(projects); ++i) {
338 if (project.equalsAscii(projects[i])) {
339 return true;
342 return false;
345 bool excludeDirectory(rtl::OUString const & directory) {
346 // Cf. OUTPATH=* in configure.in:
347 static AsciiString const excluded[] = {
348 { RTL_CONSTASCII_STRINGPARAM("callcatcher") },
349 { RTL_CONSTASCII_STRINGPARAM("unxaig") },
350 { RTL_CONSTASCII_STRINGPARAM("unxand") },
351 { RTL_CONSTASCII_STRINGPARAM("unxdfly") },
352 { RTL_CONSTASCII_STRINGPARAM("unxfbsd") },
353 { RTL_CONSTASCII_STRINGPARAM("unxios") },
354 { RTL_CONSTASCII_STRINGPARAM("unxkfg") },
355 { RTL_CONSTASCII_STRINGPARAM("unxlng") },
356 { RTL_CONSTASCII_STRINGPARAM("unxmac") },
357 { RTL_CONSTASCII_STRINGPARAM("unxnbsd") },
358 { RTL_CONSTASCII_STRINGPARAM("unxobsd") },
359 { RTL_CONSTASCII_STRINGPARAM("unxsog") },
360 { RTL_CONSTASCII_STRINGPARAM("unxsol") },
361 { RTL_CONSTASCII_STRINGPARAM("unxubt") },
362 { RTL_CONSTASCII_STRINGPARAM("wntmsc") } };
363 for (std::size_t i = 0; i != SAL_N_ELEMENTS(excluded); ++i) {
364 if (directory.matchAsciiL(excluded[i].string, excluded[i].length)) {
365 return true;
368 return false;
371 /// Handle one directory in the hierarchy.
373 /// Ignores symlinks and instead explicitly descends into clone/* or src/*,
374 /// as the Cygwin symlinks are not supported by osl::Directory on Windows.
376 /// @param url the absolute file URL of this directory
378 /// @param level 0 if this is either the root directory that contains the
379 /// projects or one of the clone/* or src/* directories that contain the
380 /// additional projects; -1 if this is the clone directory; 1 if this
381 /// is a project directory; 2 if this is a directory inside a project
383 /// @param project the name of the project (empty and ignored if level <= 0)
385 /// @param the relative path back to the project root (empty and ignored if
386 /// level <= 0)
387 void handleDirectory(
388 rtl::OUString const & url, int level, rtl::OUString const & project,
389 rtl::OUString const & projectRoot)
391 osl::Directory dir(url);
392 if (dir.open() != osl::FileBase::E_None) {
393 std::cerr
394 << "Error: Cannot open directory: "
395 << rtl::OUStringToOString(url, osl_getThreadTextEncoding()).getStr()
396 << '\n';
397 throw false; //TODO
399 for (;;) {
400 osl::DirectoryItem item;
401 osl::FileBase::RC e = dir.getNextItem(item);
402 if (e == osl::FileBase::E_NOENT) {
403 break;
405 if (e != osl::FileBase::E_None) {
406 std::cerr << "Error: Cannot read directory\n";
407 throw false; //TODO
409 osl::FileStatus stat(
410 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName
411 | osl_FileStatus_Mask_FileURL);
412 if (item.getFileStatus(stat) != osl::FileBase::E_None) {
413 std::cerr << "Error: Cannot get file status\n";
414 throw false; //TODO
416 switch (level) {
417 case -1: // the clone or src directory
418 if (stat.getFileType() == osl::FileStatus::Directory) {
419 handleDirectory(
420 stat.getFileURL(), 0, rtl::OUString(), rtl::OUString());
422 break;
423 case 0: // a root directory
424 if (stat.getFileType() == osl::FileStatus::Directory) {
425 if (includeProject(stat.getFileName())) {
426 handleDirectory(
427 stat.getFileURL(), 1, stat.getFileName(),
428 rtl::OUString());
429 } else if ( stat.getFileName() == "clone" || stat.getFileName() == "src" )
431 handleDirectory(
432 stat.getFileURL(), -1, rtl::OUString(),
433 rtl::OUString());
436 break;
437 default:
438 if (stat.getFileType() == osl::FileStatus::Directory) {
439 if (level == 2 || !excludeDirectory(stat.getFileName())) {
440 rtl::OUString pr(projectRoot);
441 if (!pr.isEmpty()) {
442 pr += rtl::OUString('/');
444 pr += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".."));
445 handleDirectory(stat.getFileURL(), 2, project, pr);
447 } else {
448 handleFile(project, projectRoot, stat.getFileURL());
450 break;
453 if (dir.close() != osl::FileBase::E_None) {
454 std::cerr << "Error: Cannot close directory\n";
455 throw false; //TODO
459 void handleProjects(char const * root) {
460 rtl::OUString root16;
461 if (!rtl_convertStringToUString(
462 &root16.pData, root, rtl_str_getLength(root),
463 osl_getThreadTextEncoding(),
464 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
465 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
466 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
468 std::cerr << "Error: Cannot convert pathname to UTF-16\n";
469 throw false; //TODO
471 rtl::OUString rootUrl;
472 if (osl::FileBase::getFileURLFromSystemPath(root16, rootUrl)
473 != osl::FileBase::E_None)
475 std::cerr << "Error: Cannot convert pathname to URL\n";
476 throw false; //TODO
478 handleDirectory(rootUrl, 0, rtl::OUString(), rtl::OUString());
483 SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) {
484 if (argc != 3) {
485 std::cerr
486 << ("localize (c)2001 by Sun Microsystems\n\n"
487 "As part of the L10N framework, localize extracts en-US\n"
488 "strings for translation out of the toplevel modules defined\n"
489 "in projects array in l10ntools/source/localize.cxx.\n\n"
490 "Syntax: localize <source-root> <outfile>\n");
491 std::exit(EXIT_FAILURE);
493 global::output.open(argv[2], std::ios_base::out | std::ios_base::trunc);
494 if (!global::output.is_open()) {
495 std::cerr << "Error: Cannot append to " << argv[2] << '\n';
496 std::exit(EXIT_FAILURE);
498 try {
499 handleProjects(argv[1]);
500 } catch (bool) { //TODO
501 return EXIT_FAILURE;
503 global::output.close();
504 return EXIT_SUCCESS;
507 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */