Stop leaking all ScPostIt instances.
[LibreOffice.git] / l10ntools / source / localize.cxx
blob5bd55b43d92882abf88b5a5dbe7979defd1577b2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include <cstddef>
23 #include <cstdlib>
24 #include <iostream>
25 #include <string>
26 #include <vector>
27 #include <algorithm>
29 #include "osl/file.h"
30 #include "osl/file.hxx"
31 #include "osl/thread.h"
32 #include "rtl/string.h"
33 #include "rtl/string.hxx"
34 #include "rtl/textcvt.h"
35 #include "rtl/strbuf.hxx"
36 #include "rtl/ustring.h"
37 #include "rtl/ustring.hxx"
38 #include "sal/macros.h"
39 #include "sal/main.h"
40 #include "sal/types.h"
42 #include "po.hxx"
44 using namespace std;
46 namespace {
48 struct AsciiString {
49 char const * string;
50 sal_Int32 length;
53 bool matchList(
54 const OUString& rUrl, const AsciiString* pList, size_t nLength)
56 for (size_t i = 0; i != nLength; ++i) {
57 if (rUrl.endsWithAsciiL(pList[i].string, pList[i].length)) {
58 return true;
61 return false;
64 bool passesNegativeList(const OUString& rUrl) {
65 static const AsciiString list[] = {
66 { RTL_CONSTASCII_STRINGPARAM("/dictionaries.xcu") },
67 { RTL_CONSTASCII_STRINGPARAM(
68 "/dictionaries/da_DK/help/da/help.tree") },
69 { RTL_CONSTASCII_STRINGPARAM(
70 "/dictionaries/da_DK/help/da/"
71 "org.openoffice.da.hunspell.dictionaries/page1.xhp") },
72 { RTL_CONSTASCII_STRINGPARAM(
73 "/dictionaries/da_DK/help/da/"
74 "org.openoffice.da.hunspell.dictionaries/page2.xhp") },
75 { RTL_CONSTASCII_STRINGPARAM(
76 "/dictionaries/hu_HU/help/hu/help.tree") },
77 { RTL_CONSTASCII_STRINGPARAM(
78 "/dictionaries/hu_HU/help/hu/"
79 "org.openoffice.hu.hunspell.dictionaries/page1.xhp") },
80 { RTL_CONSTASCII_STRINGPARAM(
81 "/officecfg/registry/data/org/openoffice/Office/"
82 "Accelerators.xcu") }
84 return !matchList(rUrl, list, SAL_N_ELEMENTS(list));
87 bool passesPositiveList(const OUString& rUrl) {
88 static const AsciiString list[] = {
89 { RTL_CONSTASCII_STRINGPARAM(
90 "/chart2/source/controller/dialogs/res_DataLabel_tmpl.hrc") },
91 { RTL_CONSTASCII_STRINGPARAM(
92 "/chart2/source/controller/dialogs/res_ErrorBar_tmpl.hrc") },
93 { RTL_CONSTASCII_STRINGPARAM(
94 "/chart2/source/controller/dialogs/res_LegendPosition_tmpl.hrc") },
95 { RTL_CONSTASCII_STRINGPARAM(
96 "/chart2/source/controller/dialogs/"
97 "res_SecondaryAxisCheckBoxes_tmpl.hrc") },
98 { RTL_CONSTASCII_STRINGPARAM(
99 "/chart2/source/controller/dialogs/res_Titlesx_tmpl.hrc") },
100 { RTL_CONSTASCII_STRINGPARAM(
101 "/dbaccess/source/ui/dlg/AutoControls_tmpl.hrc") },
102 { RTL_CONSTASCII_STRINGPARAM(
103 "/dbaccess/source/ui/inc/toolbox_tmpl.hrc") },
104 { RTL_CONSTASCII_STRINGPARAM("/description.xml") },
105 { RTL_CONSTASCII_STRINGPARAM("/android/sdremote/res/values/strings.xml") },
106 { RTL_CONSTASCII_STRINGPARAM("/svx/inc/globlmn_tmpl.hrc") },
107 { RTL_CONSTASCII_STRINGPARAM("/sw/source/ui/inc/misc.hrc") }
109 return matchList(rUrl, list, SAL_N_ELEMENTS(list));
112 void handleCommand(
113 const OString& rInPath, const OString& rOutPath,
114 const OString& rExecutable)
116 OStringBuffer buf(OString(getenv("WORKDIR_FOR_BUILD")));
117 buf.append("/LinkTarget/Executable/");
118 buf.append(rExecutable);
119 buf.append(" -i ");
120 buf.append(rInPath);
121 buf.append(" -o ");
122 buf.append(rOutPath);
124 const OString cmd = buf.makeStringAndClear();
125 if (system(cmd.getStr()) != 0)
127 cerr << "Error: Failed to execute " << cmd.getStr() << '\n';
128 throw false; //TODO
132 void InitPoFile(
133 const OString& rProject, const OString& rInPath,
134 const OString& rPotDir, const OString& rOutPath )
136 //Create directory for po file
138 OUString outDir =
139 OStringToOUString(
140 rPotDir.copy(0,rPotDir.lastIndexOf('/')), RTL_TEXTENCODING_UTF8);
141 OUString outDirUrl;
142 if (osl::FileBase::getFileURLFromSystemPath(outDir, outDirUrl)
143 != osl::FileBase::E_None)
145 cerr << "Error: Cannot convert pathname to URL in " << __FILE__ << ", in line " << __LINE__ << "\n"
146 << " outDir: " << OUStringToOString(outDir, RTL_TEXTENCODING_ASCII_US).getStr() << "\n";
147 throw false; //TODO
149 osl::Directory::createPath(outDirUrl);
152 //Add header to the po file
153 PoOfstream aPoOutPut;
154 aPoOutPut.open(rOutPath.getStr());
155 if (!aPoOutPut.isOpen())
157 cerr
158 << "Error: Cannot open po file "
159 << rOutPath.getStr() << "\n";
160 throw false; //TODO
163 const sal_Int32 nProjectInd = rInPath.indexOf(rProject);
164 const OString relativPath =
165 rInPath.copy(nProjectInd, rInPath.lastIndexOf('/')- nProjectInd);
167 PoHeader aTmp(relativPath);
168 aPoOutPut.writeHeader(aTmp);
169 aPoOutPut.close();
172 bool handleFile(
173 const OString& rProject, const OUString& rUrl,
174 const OString& rPotDir, bool bInitPoFile )
176 struct Command {
177 char const * extension;
178 sal_Int32 extensionLength;
179 OString executable;
180 bool positive;
182 static Command const commands[] = {
183 { RTL_CONSTASCII_STRINGPARAM(".src"), "transex3", false },
184 { RTL_CONSTASCII_STRINGPARAM(".hrc"), "transex3", true },
185 { RTL_CONSTASCII_STRINGPARAM(".ulf"), "ulfex", false },
186 { RTL_CONSTASCII_STRINGPARAM(".xcu"), "cfgex", false },
187 { RTL_CONSTASCII_STRINGPARAM(".xrm"), "xrmex", false },
188 { RTL_CONSTASCII_STRINGPARAM("description.xml"), "xrmex", true },
189 { RTL_CONSTASCII_STRINGPARAM(".xhp"), "helpex", false },
190 { RTL_CONSTASCII_STRINGPARAM(".properties"), "propex", false },
191 { RTL_CONSTASCII_STRINGPARAM(".ui"), "uiex", false },
192 { RTL_CONSTASCII_STRINGPARAM(".tree"), "treex", false } };
193 for (size_t i = 0; i != SAL_N_ELEMENTS(commands); ++i)
195 if (rUrl.endsWithAsciiL(
196 commands[i].extension, commands[i].extensionLength) &&
197 (commands[i].executable != "propex" || rUrl.indexOf("en_US") != -1))
199 if (commands[i].positive ? passesPositiveList(rUrl) : passesNegativeList(rUrl))
201 //Get input file path
202 OString sInPath;
204 OUString sInPathTmp;
205 if (osl::FileBase::getSystemPathFromFileURL(rUrl, sInPathTmp) !=
206 osl::FileBase::E_None)
208 cerr << "osl::FileBase::getSystemPathFromFileURL(" << rUrl << ") failed\n";
209 throw false; //TODO
211 sInPath = OUStringToOString( sInPathTmp, RTL_TEXTENCODING_UTF8 );
213 OString sOutPath = rPotDir.concat(".pot");
215 if ( bInitPoFile )
217 InitPoFile(rProject, sInPath, rPotDir, sOutPath);
219 handleCommand(sInPath, sOutPath, commands[i].executable);
220 return true;
222 break;
225 return false;
228 void handleFilesOfDir(
229 std::vector<OUString>& aFiles, const OString& rProject,
230 const OString& rPotDir )
232 ///Handle files in lexical order
233 std::sort(aFiles.begin(), aFiles.end());
235 typedef std::vector<OUString>::const_iterator citer_t;
237 bool bFirstLocFile = true; ///< First file in directory which needs localization
239 for( citer_t aIt = aFiles.begin(); aIt != aFiles.end(); ++aIt )
241 if (handleFile( rProject, *aIt, rPotDir, bFirstLocFile))
243 bFirstLocFile = false;
247 if( !bFirstLocFile )
249 //Delete pot file if it contain only the header
250 OString sPotFile = rPotDir.concat(".pot");
251 PoIfstream aPOStream( sPotFile );
252 PoEntry aPO;
253 aPOStream.readEntry( aPO );
254 bool bDel = aPOStream.eof();
255 aPOStream.close();
256 if( bDel )
258 if ( system(OString("rm " + sPotFile).getStr()) != 0 )
260 cerr
261 << "Error: Cannot remove entryless pot file: "
262 << sPotFile.getStr() << "\n";
263 throw false; //TODO
269 bool includeProject(const OString& rProject) {
270 static const OString projects[] = {
271 "accessibility",
272 "avmedia",
273 "basctl",
274 "basic",
275 "chart2",
276 "connectivity",
277 "cui",
278 "dbaccess",
279 "desktop",
280 "dictionaries",
281 "editeng",
282 "extensions",
283 "extras",
284 "filter",
285 "forms",
286 "formula",
287 "fpicker",
288 "framework",
289 "helpcontent2",
290 "instsetoo_native",
291 "librelogo",
292 "mysqlc",
293 "nlpsolver",
294 "officecfg",
295 "padmin",
296 "readlicense_oo",
297 "reportbuilder",
298 "reportdesign",
299 "sc",
300 "scaddins",
301 "sccomp",
302 "scp2",
303 "sd",
304 "sdext",
305 "setup_native",
306 "sfx2",
307 "shell",
308 "starmath",
309 "svl",
310 "svtools",
311 "svx",
312 "sw",
313 "swext",
314 "sysui",
315 "tubes",
316 "uui",
317 "vcl",
318 "wizards",
319 "xmlsecurity" };
320 for (size_t i = 0; i != SAL_N_ELEMENTS(projects); ++i) {
321 if (rProject == projects[i]) {
322 return true;
325 return false;
328 /// Handle one directory in the hierarchy.
330 /// Ignores symlinks and instead explicitly descends into clone/* or src/*,
331 /// as the Cygwin symlinks are not supported by osl::Directory on Windows.
333 /// @param rUrl the absolute file URL of this directory
335 /// @param nLevel 0 if this is either the root directory that contains the
336 /// projects or one of the clone/* or src/* directories that contain the
337 /// additional projects; -1 if this is the clone directory; 1 if this
338 /// is a project directory; 2 if this is a directory inside a project
340 /// @param rProject the name of the project (empty and ignored if nLevel <= 0)
341 /// @param rPotDir the path of pot directory
342 void handleDirectory(
343 const OUString& rUrl, int nLevel,
344 const OString& rProject, const OString& rPotDir)
346 osl::Directory dir(rUrl);
347 if (dir.open() != osl::FileBase::E_None) {
348 cerr
349 << "Error: Cannot open directory: " << rUrl << '\n';
350 throw false; //TODO
352 std::vector<OUString> aFileNames;
353 for (;;) {
354 osl::DirectoryItem item;
355 osl::FileBase::RC e = dir.getNextItem(item);
356 if (e == osl::FileBase::E_NOENT) {
357 break;
359 if (e != osl::FileBase::E_None) {
360 cerr << "Error: Cannot read directory\n";
361 throw false; //TODO
363 osl::FileStatus stat(
364 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName
365 | osl_FileStatus_Mask_FileURL);
366 if (item.getFileStatus(stat) != osl::FileBase::E_None) {
367 cerr << "Error: Cannot get file status\n";
368 throw false; //TODO
370 const OString sDirName =
371 OUStringToOString(stat.getFileName(),RTL_TEXTENCODING_UTF8);
372 switch (nLevel) {
373 case -1: // the clone or src directory
374 if (stat.getFileType() == osl::FileStatus::Directory) {
375 handleDirectory(
376 stat.getFileURL(), 0, OString(), rPotDir);
378 break;
379 case 0: // a root directory
380 if (stat.getFileType() == osl::FileStatus::Directory) {
381 if (includeProject(sDirName)) {
382 handleDirectory(
383 stat.getFileURL(), 1, sDirName, rPotDir.concat("/").concat(sDirName));
384 } else if ( sDirName == "clone" ||
385 sDirName == "src" )
387 handleDirectory( stat.getFileURL(), -1, OString(), rPotDir);
390 break;
391 default:
392 if (stat.getFileType() == osl::FileStatus::Directory)
394 handleDirectory(
395 stat.getFileURL(), 2, rProject, rPotDir.concat("/").concat(sDirName));
397 else
399 aFileNames.push_back(stat.getFileURL());
401 break;
405 if( !aFileNames.empty() )
407 handleFilesOfDir( aFileNames, rProject, rPotDir );
410 if (dir.close() != osl::FileBase::E_None) {
411 cerr << "Error: Cannot close directory\n";
412 throw false; //TODO
415 //Remove empty pot directory
416 OUString sPoPath =
417 OStringToOUString(
418 rPotDir.copy(0,rPotDir.lastIndexOf('/')), RTL_TEXTENCODING_UTF8);
419 OUString sPoUrl;
420 if (osl::FileBase::getFileURLFromSystemPath(sPoPath, sPoUrl)
421 != osl::FileBase::E_None)
423 cerr << "Error: Cannot convert pathname to URL in " << __FILE__ << ", in line " << __LINE__ << "\n"
424 << OUStringToOString(sPoPath, RTL_TEXTENCODING_UTF8).getStr() << "\n";
425 throw false; //TODO
427 osl::Directory::remove(sPoUrl);
430 void handleProjects(char * sSourceRoot, char const * sDestRoot)
432 OUString root16;
433 if (!rtl_convertStringToUString(
434 &root16.pData, sSourceRoot, rtl_str_getLength(sSourceRoot),
435 osl_getThreadTextEncoding(),
436 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
437 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
438 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
440 cerr << "Error: Cannot convert pathname to UTF-16\n";
441 throw false; //TODO
443 OUString rootUrl;
444 if (osl::FileBase::getFileURLFromSystemPath(root16, rootUrl)
445 != osl::FileBase::E_None)
447 cerr << "Error: Cannot convert pathname to URL in " << __FILE__ << ", in line " << __LINE__ << "\n"
448 << " root16: " << OUStringToOString(root16, RTL_TEXTENCODING_ASCII_US).getStr() << "\n";
449 throw false; //TODO
451 handleDirectory(rootUrl, 0, OString(), OString(sDestRoot));
455 SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) {
456 if (argc != 3) {
457 cerr
458 << ("localize (c)2001 by Sun Microsystems\n\n"
459 "As part of the L10N framework, localize extracts en-US\n"
460 "strings for translation out of the toplevel modules defined\n"
461 "in projects array in l10ntools/source/localize.cxx.\n\n"
462 "Syntax: localize <source-root> <outfile>\n");
463 exit(EXIT_FAILURE);
465 try {
466 handleProjects(argv[1],argv[2]);
467 } catch (bool) { //TODO
468 return EXIT_FAILURE;
470 return EXIT_SUCCESS;
473 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */