fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / l10ntools / source / localize.cxx
blob5c107a6a3a6b203d004be350214ffb05f66cfff4
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 "/dbaccess/source/ui/inc/toolbox_tmpl.hrc") },
95 { RTL_CONSTASCII_STRINGPARAM("/description.xml") },
96 { RTL_CONSTASCII_STRINGPARAM("/svx/inc/globlmn_tmpl.hrc") },
97 { RTL_CONSTASCII_STRINGPARAM("/sw/source/uibase/inc/redline_tmpl.hrc") }
99 return matchList(rUrl, list, SAL_N_ELEMENTS(list));
102 void handleCommand(
103 const OString& rInPath, const OString& rOutPath,
104 const OString& rExecutable)
106 OStringBuffer buf(OString(getenv("WORKDIR_FOR_BUILD")));
107 buf.append("/LinkTarget/Executable/");
108 buf.append(rExecutable);
109 buf.append(" -i ");
110 buf.append(rInPath);
111 buf.append(" -o ");
112 buf.append(rOutPath);
114 const OString cmd = buf.makeStringAndClear();
115 if (system(cmd.getStr()) != 0)
117 cerr << "Error: Failed to execute " << cmd.getStr() << '\n';
118 throw false; //TODO
122 void InitPoFile(
123 const OString& rProject, const OString& rInPath,
124 const OString& rPotDir, const OString& rOutPath )
126 //Create directory for po file
128 OUString outDir =
129 OStringToOUString(
130 rPotDir.copy(0,rPotDir.lastIndexOf('/')), RTL_TEXTENCODING_UTF8);
131 OUString outDirUrl;
132 if (osl::FileBase::getFileURLFromSystemPath(outDir, outDirUrl)
133 != osl::FileBase::E_None)
135 cerr
136 << ("Error: Cannot convert pathname to URL in " __FILE__
137 ", in line ")
138 << __LINE__ << "\n outDir: "
139 << OUStringToOString(outDir, RTL_TEXTENCODING_ASCII_US).getStr()
140 << "\n";
141 throw false; //TODO
143 osl::Directory::createPath(outDirUrl);
146 //Add header to the po file
147 PoOfstream aPoOutPut;
148 aPoOutPut.open(rOutPath.getStr());
149 if (!aPoOutPut.isOpen())
151 cerr
152 << "Error: Cannot open po file "
153 << rOutPath.getStr() << "\n";
154 throw false; //TODO
157 const sal_Int32 nProjectInd = rInPath.indexOf(rProject);
158 const OString relativPath =
159 rInPath.copy(nProjectInd, rInPath.lastIndexOf('/')- nProjectInd);
161 PoHeader aTmp(relativPath);
162 aPoOutPut.writeHeader(aTmp);
163 aPoOutPut.close();
166 bool handleFile(
167 const OString& rProject, const OUString& rUrl,
168 const OString& rPotDir, bool bInitPoFile )
170 struct Command {
171 char const * extension;
172 sal_Int32 extensionLength;
173 OString executable;
174 bool positive;
176 static Command const commands[] = {
177 { RTL_CONSTASCII_STRINGPARAM(".src"), "transex3", false },
178 { RTL_CONSTASCII_STRINGPARAM(".hrc"), "transex3", true },
179 { RTL_CONSTASCII_STRINGPARAM(".ulf"), "ulfex", false },
180 { RTL_CONSTASCII_STRINGPARAM(".xcu"), "cfgex", false },
181 { RTL_CONSTASCII_STRINGPARAM(".xrm"), "xrmex", false },
182 { RTL_CONSTASCII_STRINGPARAM("description.xml"), "xrmex", true },
183 { RTL_CONSTASCII_STRINGPARAM(".xhp"), "helpex", false },
184 { RTL_CONSTASCII_STRINGPARAM(".properties"), "propex", false },
185 { RTL_CONSTASCII_STRINGPARAM(".ui"), "uiex", false },
186 { RTL_CONSTASCII_STRINGPARAM(".tree"), "treex", false } };
187 for (size_t i = 0; i != SAL_N_ELEMENTS(commands); ++i)
189 if (rUrl.endsWithAsciiL(
190 commands[i].extension, commands[i].extensionLength) &&
191 (commands[i].executable != "propex" || rUrl.indexOf("en_US") != -1))
193 if (commands[i].positive ? passesPositiveList(rUrl) : passesNegativeList(rUrl))
195 //Get input file path
196 OString sInPath;
198 OUString sInPathTmp;
199 if (osl::FileBase::getSystemPathFromFileURL(rUrl, sInPathTmp) !=
200 osl::FileBase::E_None)
202 cerr << "osl::FileBase::getSystemPathFromFileURL(" << rUrl << ") failed\n";
203 throw false; //TODO
205 sInPath = OUStringToOString( sInPathTmp, RTL_TEXTENCODING_UTF8 );
207 OString sOutPath = rPotDir.concat(".pot");
209 if ( bInitPoFile )
211 InitPoFile(rProject, sInPath, rPotDir, sOutPath);
213 handleCommand(sInPath, sOutPath, commands[i].executable);
214 return true;
216 break;
219 return false;
222 void handleFilesOfDir(
223 std::vector<OUString>& aFiles, const OString& rProject,
224 const OString& rPotDir )
226 ///Handle files in lexical order
227 std::sort(aFiles.begin(), aFiles.end());
229 typedef std::vector<OUString>::const_iterator citer_t;
231 bool bFirstLocFile = true; ///< First file in directory which needs localization
233 for( citer_t aIt = aFiles.begin(); aIt != aFiles.end(); ++aIt )
235 if (handleFile( rProject, *aIt, rPotDir, bFirstLocFile))
237 bFirstLocFile = false;
241 if( !bFirstLocFile )
243 //Delete pot file if it contain only the header
244 OString sPotFile = rPotDir.concat(".pot");
245 PoIfstream aPOStream( sPotFile );
246 PoEntry aPO;
247 aPOStream.readEntry( aPO );
248 bool bDel = aPOStream.eof();
249 aPOStream.close();
250 if( bDel )
252 if ( system(OString("rm " + sPotFile).getStr()) != 0 )
254 cerr
255 << "Error: Cannot remove entryless pot file: "
256 << sPotFile.getStr() << "\n";
257 throw false; //TODO
263 bool includeProject(const OString& rProject) {
264 static const char *projects[] = {
265 "accessibility",
266 "avmedia",
267 "basctl",
268 "basic",
269 "chart2",
270 "connectivity",
271 "cui",
272 "dbaccess",
273 "desktop",
274 "dictionaries",
275 "editeng",
276 "extensions",
277 "extras",
278 "filter",
279 "forms",
280 "formula",
281 "fpicker",
282 "framework",
283 "helpcontent2",
284 "instsetoo_native",
285 "librelogo",
286 "mysqlc",
287 "nlpsolver",
288 "officecfg",
289 "readlicense_oo",
290 "reportbuilder",
291 "reportdesign",
292 "sc",
293 "scaddins",
294 "sccomp",
295 "scp2",
296 "sd",
297 "sdext",
298 "setup_native",
299 "sfx2",
300 "shell",
301 "starmath",
302 "svl",
303 "svtools",
304 "svx",
305 "sw",
306 "swext",
307 "sysui",
308 "tubes",
309 "uui",
310 "vcl",
311 "wizards",
312 "xmlsecurity" };
313 for (size_t i = 0; i != SAL_N_ELEMENTS(projects); ++i) {
314 if (rProject == projects[i]) {
315 return true;
318 return false;
321 /// Handle one directory in the hierarchy.
323 /// Ignores symlinks and instead explicitly descends into clone/* or src/*,
324 /// as the Cygwin symlinks are not supported by osl::Directory on Windows.
326 /// @param rUrl the absolute file URL of this directory
328 /// @param nLevel 0 if this is either the root directory that contains the
329 /// projects or one of the clone/* or src/* directories that contain the
330 /// additional projects; -1 if this is the clone directory; 1 if this
331 /// is a project directory; 2 if this is a directory inside a project
333 /// @param rProject the name of the project (empty and ignored if nLevel <= 0)
334 /// @param rPotDir the path of pot directory
335 void handleDirectory(
336 const OUString& rUrl, int nLevel,
337 const OString& rProject, const OString& rPotDir)
339 osl::Directory dir(rUrl);
340 if (dir.open() != osl::FileBase::E_None) {
341 cerr
342 << "Error: Cannot open directory: " << rUrl << '\n';
343 throw false; //TODO
345 std::vector<OUString> aFileNames;
346 for (;;) {
347 osl::DirectoryItem item;
348 osl::FileBase::RC e = dir.getNextItem(item);
349 if (e == osl::FileBase::E_NOENT) {
350 break;
352 if (e != osl::FileBase::E_None) {
353 cerr << "Error: Cannot read directory\n";
354 throw false; //TODO
356 osl::FileStatus stat(
357 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName
358 | osl_FileStatus_Mask_FileURL);
359 if (item.getFileStatus(stat) != osl::FileBase::E_None) {
360 cerr << "Error: Cannot get file status\n";
361 throw false; //TODO
363 const OString sDirName =
364 OUStringToOString(stat.getFileName(),RTL_TEXTENCODING_UTF8);
365 switch (nLevel) {
366 case -1: // the clone or src directory
367 if (stat.getFileType() == osl::FileStatus::Directory) {
368 handleDirectory(
369 stat.getFileURL(), 0, OString(), rPotDir);
371 break;
372 case 0: // a root directory
373 if (stat.getFileType() == osl::FileStatus::Directory) {
374 if (includeProject(sDirName)) {
375 handleDirectory(
376 stat.getFileURL(), 1, sDirName, rPotDir.concat("/").concat(sDirName));
377 } else if ( sDirName == "clone" ||
378 sDirName == "src" )
380 handleDirectory( stat.getFileURL(), -1, OString(), rPotDir);
383 break;
384 default:
385 if (stat.getFileType() == osl::FileStatus::Directory)
387 handleDirectory(
388 stat.getFileURL(), 2, rProject, rPotDir.concat("/").concat(sDirName));
390 else
392 aFileNames.push_back(stat.getFileURL());
394 break;
398 if( !aFileNames.empty() )
400 handleFilesOfDir( aFileNames, rProject, rPotDir );
403 if (dir.close() != osl::FileBase::E_None) {
404 cerr << "Error: Cannot close directory\n";
405 throw false; //TODO
408 //Remove empty pot directory
409 OUString sPoPath =
410 OStringToOUString(
411 rPotDir.copy(0,rPotDir.lastIndexOf('/')), RTL_TEXTENCODING_UTF8);
412 OUString sPoUrl;
413 if (osl::FileBase::getFileURLFromSystemPath(sPoPath, sPoUrl)
414 != osl::FileBase::E_None)
416 cerr
417 << ("Error: Cannot convert pathname to URL in " __FILE__
418 ", in line ")
419 << __LINE__ << "\n"
420 << OUStringToOString(sPoPath, RTL_TEXTENCODING_UTF8).getStr()
421 << "\n";
422 throw false; //TODO
424 osl::Directory::remove(sPoUrl);
427 void handleProjects(char * sSourceRoot, char const * sDestRoot)
429 OUString root16;
430 if (!rtl_convertStringToUString(
431 &root16.pData, sSourceRoot, rtl_str_getLength(sSourceRoot),
432 osl_getThreadTextEncoding(),
433 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
434 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
435 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
437 cerr << "Error: Cannot convert pathname to UTF-16\n";
438 throw false; //TODO
440 OUString rootUrl;
441 if (osl::FileBase::getFileURLFromSystemPath(root16, rootUrl)
442 != osl::FileBase::E_None)
444 cerr
445 << ("Error: Cannot convert pathname to URL in " __FILE__
446 ", in line ")
447 << __LINE__ << "\n root16: "
448 << OUStringToOString(root16, RTL_TEXTENCODING_ASCII_US).getStr()
449 << "\n";
450 throw false; //TODO
452 handleDirectory(rootUrl, 0, OString(), OString(sDestRoot));
456 SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) {
457 if (argc != 3) {
458 cerr
459 << ("localize (c)2001 by Sun Microsystems\n\n"
460 "As part of the L10N framework, localize extracts en-US\n"
461 "strings for translation out of the toplevel modules defined\n"
462 "in projects array in l10ntools/source/localize.cxx.\n\n"
463 "Syntax: localize <source-root> <outfile>\n");
464 exit(EXIT_FAILURE);
466 try {
467 handleProjects(argv[1],argv[2]);
468 } catch (bool) { //TODO
469 return EXIT_FAILURE;
471 return EXIT_SUCCESS;
474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */