1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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"
40 #include "sal/types.h"
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
)) {
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") },
83 { RTL_CONSTASCII_STRINGPARAM(
84 "/officecfg/registry/data/org/openoffice/Office/SFX.xcu") }
86 return !matchList(rUrl
, list
, SAL_N_ELEMENTS(list
));
89 bool passesPositiveList(const OUString
& rUrl
) {
90 static const AsciiString list
[] = {
91 { RTL_CONSTASCII_STRINGPARAM(
92 "/chart2/source/controller/dialogs/res_DataLabel_tmpl.hrc") },
93 { RTL_CONSTASCII_STRINGPARAM(
94 "/chart2/source/controller/dialogs/res_ErrorBar_tmpl.hrc") },
95 { RTL_CONSTASCII_STRINGPARAM(
96 "/chart2/source/controller/dialogs/res_LegendPosition_tmpl.hrc") },
97 { RTL_CONSTASCII_STRINGPARAM(
98 "/chart2/source/controller/dialogs/"
99 "res_SecondaryAxisCheckBoxes_tmpl.hrc") },
100 { RTL_CONSTASCII_STRINGPARAM(
101 "/chart2/source/controller/dialogs/res_Statistic_tmpl.hrc") },
102 { RTL_CONSTASCII_STRINGPARAM(
103 "/chart2/source/controller/dialogs/res_Titlesx_tmpl.hrc") },
104 { RTL_CONSTASCII_STRINGPARAM(
105 "/chart2/source/controller/dialogs/res_Trendline_tmpl.hrc") },
106 { RTL_CONSTASCII_STRINGPARAM(
107 "/chart2/source/controller/menu/MenuItems_tmpl.hrc") },
108 { RTL_CONSTASCII_STRINGPARAM(
109 "/dbaccess/source/ui/dlg/AutoControls_tmpl.hrc") },
110 { RTL_CONSTASCII_STRINGPARAM(
111 "/dbaccess/source/ui/inc/toolbox_tmpl.hrc") },
112 { RTL_CONSTASCII_STRINGPARAM("/description.xml") },
113 { RTL_CONSTASCII_STRINGPARAM("/android/sdremote/res/values/strings.xml") },
114 { RTL_CONSTASCII_STRINGPARAM("/offmgr/inc/offmenu_tmpl.hrc") },
115 { RTL_CONSTASCII_STRINGPARAM(
116 "/offmgr/source/offapp/intro/intro_tmpl.hrc") },
117 { RTL_CONSTASCII_STRINGPARAM("/svx/inc/globlmn_tmpl.hrc") },
118 { RTL_CONSTASCII_STRINGPARAM("/svx/source/intro/intro_tmpl.hrc") },
119 { RTL_CONSTASCII_STRINGPARAM(
120 "/svx/source/unodialogs/textconversiondlgs/"
121 "chinese_direction_tmpl.hrc") },
122 { RTL_CONSTASCII_STRINGPARAM("/sw/source/ui/inc/swacc_tmpl.hrc") },
123 { RTL_CONSTASCII_STRINGPARAM("/sw/source/ui/inc/swmn_tmpl.hrc") },
124 { RTL_CONSTASCII_STRINGPARAM("/sw/source/ui/inc/toolbox_tmpl.hrc") }
126 return matchList(rUrl
, list
, SAL_N_ELEMENTS(list
));
130 const OString
& rInPath
, const OString
& rOutPath
,
131 const OString
& rExecutable
)
133 OStringBuffer
buf(OString(getenv("SOLARVER")));
135 buf
.append(OString(getenv("INPATH_FOR_BUILD")));
137 buf
.append(rExecutable
);
141 buf
.append(rOutPath
);
143 const OString cmd
= buf
.makeStringAndClear();
144 if (system(cmd
.getStr()) != 0)
146 cerr
<< "Error: Failed to execute " << cmd
.getStr() << '\n';
152 const OString
& rProject
, const OString
& rInPath
,
153 const OString
& rPotDir
, const OString
& rOutPath
)
155 //Create directory for po file
159 rPotDir
.copy(0,rPotDir
.lastIndexOf('/')), RTL_TEXTENCODING_UTF8
);
161 if (osl::FileBase::getFileURLFromSystemPath(outDir
, outDirUrl
)
162 != osl::FileBase::E_None
)
164 cerr
<< "Error: Cannot convert pathname to URL in " << __FILE__
<< ", in line " << __LINE__
<< "\n"
165 << " outDir: " << OUStringToOString(outDir
, RTL_TEXTENCODING_ASCII_US
).getStr() << "\n";
168 osl::Directory::createPath(outDirUrl
);
171 //Add header to the po file
172 PoOfstream aPoOutPut
;
173 aPoOutPut
.open(rOutPath
.getStr());
174 if (!aPoOutPut
.isOpen())
177 << "Error: Cannot open po file "
178 << rOutPath
.getStr() << "\n";
182 const sal_Int32 nProjectInd
= rInPath
.indexOf(rProject
);
183 const OString relativPath
=
184 rInPath
.copy(nProjectInd
, rInPath
.lastIndexOf('/')- nProjectInd
);
186 PoHeader
aTmp(relativPath
);
187 aPoOutPut
.writeHeader(aTmp
);
192 const OString
& rProject
, const OUString
& rUrl
,
193 const OString
& rPotDir
, bool bInitPoFile
)
196 char const * extension
;
197 sal_Int32 extensionLength
;
201 static Command
const commands
[] = {
202 { RTL_CONSTASCII_STRINGPARAM(".src"), "transex3", false },
203 { RTL_CONSTASCII_STRINGPARAM(".hrc"), "transex3", true },
204 { RTL_CONSTASCII_STRINGPARAM(".ulf"), "ulfex", false },
205 { RTL_CONSTASCII_STRINGPARAM(".xcu"), "cfgex", false },
206 { RTL_CONSTASCII_STRINGPARAM(".xrm"), "xrmex", false },
207 { RTL_CONSTASCII_STRINGPARAM("description.xml"), "xrmex", true },
208 { RTL_CONSTASCII_STRINGPARAM("strings.xml"), "stringex", true },
209 { RTL_CONSTASCII_STRINGPARAM(".xhp"), "helpex", false },
210 { RTL_CONSTASCII_STRINGPARAM(".properties"), "propex", false },
211 { RTL_CONSTASCII_STRINGPARAM(".ui"), "uiex", false },
212 { RTL_CONSTASCII_STRINGPARAM(".tree"), "treex", false } };
213 for (size_t i
= 0; i
!= SAL_N_ELEMENTS(commands
); ++i
)
215 if (rUrl
.endsWithAsciiL(
216 commands
[i
].extension
, commands
[i
].extensionLength
) &&
217 (commands
[i
].executable
!= "propex" || rUrl
.indexOf("en_US") != -1))
219 if (commands
[i
].positive
? passesPositiveList(rUrl
) : passesNegativeList(rUrl
))
221 //Get input file path
225 if (osl::FileBase::getSystemPathFromFileURL(rUrl
, sInPathTmp
) !=
226 osl::FileBase::E_None
)
228 cerr
<< "osl::FileBase::getSystemPathFromFileURL(" << rUrl
<< ") failed\n";
231 sInPath
= OUStringToOString( sInPathTmp
, RTL_TEXTENCODING_UTF8
);
233 OString sOutPath
= rPotDir
.concat(".pot");
237 InitPoFile(rProject
, sInPath
, rPotDir
, sOutPath
);
239 handleCommand(sInPath
, sOutPath
, commands
[i
].executable
);
248 void handleFilesOfDir(
249 std::vector
<OUString
>& aFiles
, const OString
& rProject
,
250 const OString
& rPotDir
)
252 ///Handle files in lexical order
253 std::sort(aFiles
.begin(), aFiles
.end());
255 typedef std::vector
<OUString
>::const_iterator citer_t
;
257 bool bFirstLocFile
= true; ///< First file in directory which needs localization
259 for( citer_t aIt
= aFiles
.begin(); aIt
!= aFiles
.end(); ++aIt
)
261 if (handleFile( rProject
, *aIt
, rPotDir
, bFirstLocFile
))
263 bFirstLocFile
= false;
269 //Delete pot file if it contain only the header
270 OString sPotFile
= rPotDir
.concat(".pot");
271 PoIfstream
aPOStream( sPotFile
);
273 aPOStream
.readEntry( aPO
);
274 bool bDel
= aPOStream
.eof();
278 if ( system(OString("rm " + sPotFile
).getStr()) != 0 )
281 << "Error: Cannot remove entryless pot file: "
282 << sPotFile
.getStr() << "\n";
289 bool includeProject(const OString
& rProject
) {
290 static OString projects
[] = {
341 for (size_t i
= 0; i
!= SAL_N_ELEMENTS(projects
); ++i
) {
342 if (rProject
== projects
[i
]) {
349 /// Handle one directory in the hierarchy.
351 /// Ignores symlinks and instead explicitly descends into clone/* or src/*,
352 /// as the Cygwin symlinks are not supported by osl::Directory on Windows.
354 /// @param rUrl the absolute file URL of this directory
356 /// @param nLevel 0 if this is either the root directory that contains the
357 /// projects or one of the clone/* or src/* directories that contain the
358 /// additional projects; -1 if this is the clone directory; 1 if this
359 /// is a project directory; 2 if this is a directory inside a project
361 /// @param rProject the name of the project (empty and ignored if nLevel <= 0)
362 /// @param rPotDir the path of pot directory
363 void handleDirectory(
364 const OUString
& rUrl
, int nLevel
,
365 const OString
& rProject
, const OString
& rPotDir
)
367 osl::Directory
dir(rUrl
);
368 if (dir
.open() != osl::FileBase::E_None
) {
370 << "Error: Cannot open directory: " << rUrl
<< '\n';
373 std::vector
<OUString
> aFileNames
;
375 osl::DirectoryItem item
;
376 osl::FileBase::RC e
= dir
.getNextItem(item
);
377 if (e
== osl::FileBase::E_NOENT
) {
380 if (e
!= osl::FileBase::E_None
) {
381 cerr
<< "Error: Cannot read directory\n";
384 osl::FileStatus
stat(
385 osl_FileStatus_Mask_Type
| osl_FileStatus_Mask_FileName
386 | osl_FileStatus_Mask_FileURL
);
387 if (item
.getFileStatus(stat
) != osl::FileBase::E_None
) {
388 cerr
<< "Error: Cannot get file status\n";
391 const OString sDirName
=
392 OUStringToOString(stat
.getFileName(),RTL_TEXTENCODING_UTF8
);
394 case -1: // the clone or src directory
395 if (stat
.getFileType() == osl::FileStatus::Directory
) {
397 stat
.getFileURL(), 0, OString(), rPotDir
);
400 case 0: // a root directory
401 if (stat
.getFileType() == osl::FileStatus::Directory
) {
402 if (includeProject(sDirName
)) {
404 stat
.getFileURL(), 1, sDirName
, rPotDir
.concat("/").concat(sDirName
));
405 } else if ( sDirName
== "clone" ||
408 handleDirectory( stat
.getFileURL(), -1, OString(), rPotDir
);
413 if (stat
.getFileType() == osl::FileStatus::Directory
)
416 stat
.getFileURL(), 2, rProject
, rPotDir
.concat("/").concat(sDirName
));
420 aFileNames
.push_back(stat
.getFileURL());
426 if( !aFileNames
.empty() )
428 handleFilesOfDir( aFileNames
, rProject
, rPotDir
);
431 if (dir
.close() != osl::FileBase::E_None
) {
432 cerr
<< "Error: Cannot close directory\n";
436 //Remove empty pot directory
439 rPotDir
.copy(0,rPotDir
.lastIndexOf('/')), RTL_TEXTENCODING_UTF8
);
441 if (osl::FileBase::getFileURLFromSystemPath(sPoPath
, sPoUrl
)
442 != osl::FileBase::E_None
)
444 cerr
<< "Error: Cannot convert pathname to URL in " << __FILE__
<< ", in line " << __LINE__
<< "\n"
445 << OUStringToOString(sPoPath
, RTL_TEXTENCODING_UTF8
).getStr() << "\n";
448 osl::Directory::remove(sPoUrl
);
451 void handleProjects(char * sSourceRoot
, char const * sDestRoot
)
454 if (!rtl_convertStringToUString(
455 &root16
.pData
, sSourceRoot
, rtl_str_getLength(sSourceRoot
),
456 osl_getThreadTextEncoding(),
457 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
458 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
459 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
461 cerr
<< "Error: Cannot convert pathname to UTF-16\n";
465 if (osl::FileBase::getFileURLFromSystemPath(root16
, rootUrl
)
466 != osl::FileBase::E_None
)
468 cerr
<< "Error: Cannot convert pathname to URL in " << __FILE__
<< ", in line " << __LINE__
<< "\n"
469 << " root16: " << OUStringToOString(root16
, RTL_TEXTENCODING_ASCII_US
).getStr() << "\n";
472 handleDirectory(rootUrl
, 0, OString(), OString(sDestRoot
));
476 SAL_IMPLEMENT_MAIN_WITH_ARGS(argc
, argv
) {
479 << ("localize (c)2001 by Sun Microsystems\n\n"
480 "As part of the L10N framework, localize extracts en-US\n"
481 "strings for translation out of the toplevel modules defined\n"
482 "in projects array in l10ntools/source/localize.cxx.\n\n"
483 "Syntax: localize <source-root> <outfile>\n");
487 handleProjects(argv
[1],argv
[2]);
488 } catch (bool) { //TODO
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */