Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "common.hxx"
21 : #include "sal/config.h"
22 :
23 : #include <cstdio>
24 : #include <cstdlib>
25 : #include <cstring>
26 :
27 : #include "boost/scoped_ptr.hpp"
28 : #include "rtl/strbuf.hxx"
29 :
30 : #include "common.hxx"
31 : #include "export.hxx"
32 : #include "cfgmerge.hxx"
33 : #include "tokens.h"
34 :
35 : void yyerror(char const *);
36 :
37 : namespace {
38 :
39 : namespace global {
40 :
41 0 : OString inputPathname;
42 0 : boost::scoped_ptr< CfgParser > parser;
43 :
44 : }
45 : }
46 :
47 : extern "C" {
48 :
49 0 : FILE * init(int argc, char ** argv) {
50 :
51 0 : HandledArgs aArgs;
52 0 : if ( !Export::handleArguments(argc, argv, aArgs) )
53 : {
54 0 : Export::writeUsage("cfgex","xcu");
55 0 : std::exit(EXIT_FAILURE);
56 : }
57 0 : Export::InitLanguages();
58 0 : global::inputPathname = aArgs.m_sInputFile;
59 :
60 0 : FILE * pFile = std::fopen(global::inputPathname.getStr(), "r");
61 0 : if (pFile == 0) {
62 : std::fprintf(
63 : stderr, "Error: Cannot open file \"%s\"\n",
64 0 : global::inputPathname.getStr() );
65 0 : std::exit(EXIT_FAILURE);
66 : }
67 :
68 0 : if (aArgs.m_bMergeMode) {
69 : global::parser.reset(
70 : new CfgMerge(
71 0 : aArgs.m_sMergeSrc.getStr(), aArgs.m_sOutputFile.getStr(),
72 0 : global::inputPathname));
73 : } else {
74 : global::parser.reset(
75 : new CfgExport(
76 0 : aArgs.m_sOutputFile.getStr(), aArgs.m_sPrj.getStr(),
77 : common::pathnameToken(global::inputPathname.getStr(),
78 0 : aArgs.m_sPrjRoot.getStr())));
79 : }
80 :
81 0 : return pFile;
82 : }
83 :
84 0 : void workOnTokenSet(int nTyp, char * pTokenText) {
85 0 : global::parser->Execute( nTyp, pTokenText );
86 0 : }
87 :
88 : }
89 :
90 : //
91 : // class CfgStackData
92 : //
93 :
94 0 : CfgStackData* CfgStack::Push(const rtl::OString &rTag, const rtl::OString &rId)
95 : {
96 0 : CfgStackData *pD = new CfgStackData( rTag, rId );
97 0 : maList.push_back( pD );
98 0 : return pD;
99 : }
100 :
101 : //
102 : // class CfgStack
103 : //
104 :
105 : /*****************************************************************************/
106 0 : CfgStack::~CfgStack()
107 : /*****************************************************************************/
108 : {
109 0 : for ( size_t i = 0, n = maList.size(); i < n; i++ )
110 0 : delete maList[ i ];
111 0 : maList.clear();
112 0 : }
113 :
114 0 : rtl::OString CfgStack::GetAccessPath( size_t nPos )
115 : {
116 0 : rtl::OStringBuffer sReturn;
117 0 : for (size_t i = 0; i <= nPos; ++i)
118 : {
119 0 : if (i)
120 0 : sReturn.append('.');
121 0 : sReturn.append(maList[i]->GetIdentifier());
122 : }
123 :
124 0 : return sReturn.makeStringAndClear();
125 : }
126 :
127 : /*****************************************************************************/
128 0 : CfgStackData *CfgStack::GetStackData()
129 : /*****************************************************************************/
130 : {
131 0 : if (!maList.empty())
132 0 : return maList[maList.size() - 1];
133 : else
134 0 : return 0;
135 : }
136 :
137 : //
138 : // class CfgParser
139 : //
140 :
141 : /*****************************************************************************/
142 0 : CfgParser::CfgParser()
143 : /*****************************************************************************/
144 : : pStackData( NULL ),
145 0 : bLocalize( sal_False )
146 : {
147 0 : }
148 :
149 0 : CfgParser::~CfgParser()
150 : {
151 0 : }
152 :
153 0 : sal_Bool CfgParser::IsTokenClosed(const rtl::OString &rToken)
154 : {
155 0 : return rToken[rToken.getLength() - 2] == '/';
156 : }
157 :
158 : /*****************************************************************************/
159 0 : void CfgParser::AddText(
160 : rtl::OString &rText,
161 : const rtl::OString &rIsoLang,
162 : const rtl::OString &rResTyp
163 : )
164 : /*****************************************************************************/
165 : {
166 : rText = rText.replaceAll(rtl::OString('\n'), rtl::OString()).
167 : replaceAll(rtl::OString('\r'), rtl::OString()).
168 0 : replaceAll(rtl::OString('\t'), rtl::OString());
169 0 : pStackData->sResTyp = rResTyp;
170 0 : WorkOnText( rText, rIsoLang );
171 0 : pStackData->sText[ rIsoLang ] = rText;
172 0 : }
173 :
174 : /*****************************************************************************/
175 0 : int CfgParser::ExecuteAnalyzedToken( int nToken, char *pToken )
176 : /*****************************************************************************/
177 : {
178 0 : rtl::OString sToken( pToken );
179 :
180 0 : if ( sToken == " " || sToken == "\t" )
181 0 : sLastWhitespace += sToken;
182 :
183 0 : rtl::OString sTokenName;
184 0 : rtl::OString sTokenId;
185 :
186 0 : sal_Bool bOutput = sal_True;
187 :
188 0 : switch ( nToken ) {
189 : case CFG_TOKEN_PACKAGE:
190 : case CFG_TOKEN_COMPONENT:
191 : case CFG_TOKEN_TEMPLATE:
192 : case CFG_TOKEN_CONFIGNAME:
193 : case CFG_TOKEN_OORNAME:
194 : case CFG_TOKEN_OORVALUE:
195 : case CFG_TAG:
196 : case ANYTOKEN:
197 : case CFG_TEXT_START:
198 : {
199 : sTokenName = sToken.getToken(1, '<').getToken(0, '>').
200 0 : getToken(0, ' ');
201 :
202 0 : if ( !IsTokenClosed( sToken )) {
203 0 : rtl::OString sSearch;
204 0 : switch ( nToken ) {
205 : case CFG_TOKEN_PACKAGE:
206 0 : sSearch = "package-id=";
207 0 : break;
208 : case CFG_TOKEN_COMPONENT:
209 0 : sSearch = "component-id=";
210 0 : break;
211 : case CFG_TOKEN_TEMPLATE:
212 0 : sSearch = "template-id=";
213 0 : break;
214 : case CFG_TOKEN_CONFIGNAME:
215 0 : sSearch = "cfg:name=";
216 0 : break;
217 : case CFG_TOKEN_OORNAME:
218 0 : sSearch = "oor:name=";
219 0 : bLocalize = sal_True;
220 0 : break;
221 : case CFG_TOKEN_OORVALUE:
222 0 : sSearch = "oor:value=";
223 0 : break;
224 : case CFG_TEXT_START: {
225 0 : if ( sCurrentResTyp != sTokenName ) {
226 0 : WorkOnResourceEnd();
227 0 : rtl::OString sCur;
228 0 : for( unsigned int i = 0; i < aLanguages.size(); ++i ){
229 0 : sCur = aLanguages[ i ];
230 0 : pStackData->sText[ sCur ] = rtl::OString();
231 0 : }
232 : }
233 0 : sCurrentResTyp = sTokenName;
234 :
235 0 : rtl::OString sTemp = sToken.copy( sToken.indexOf( "xml:lang=" ));
236 0 : sCurrentIsoLang = sTemp.getToken(1, '"');
237 :
238 0 : if ( sCurrentIsoLang == NO_TRANSLATE_ISO )
239 0 : bLocalize = sal_False;
240 :
241 0 : pStackData->sTextTag = sToken;
242 :
243 0 : sCurrentText = "";
244 : }
245 0 : break;
246 : }
247 0 : if ( !sSearch.isEmpty())
248 : {
249 0 : rtl::OString sTemp = sToken.copy( sToken.indexOf( sSearch ));
250 0 : sTokenId = sTemp.getToken(1, '"');
251 : }
252 0 : pStackData = aStack.Push( sTokenName, sTokenId );
253 :
254 0 : if ( sSearch == "cfg:name=" ) {
255 0 : rtl::OString sTemp( sToken.toAsciiUpperCase() );
256 0 : bLocalize = (( sTemp.indexOf( "CFG:TYPE=\"STRING\"" ) != -1 ) &&
257 0 : ( sTemp.indexOf( "CFG:LOCALIZED=\"sal_True\"" ) != -1 ));
258 0 : }
259 : }
260 0 : else if ( sTokenName == "label" ) {
261 0 : if ( sCurrentResTyp != sTokenName ) {
262 0 : WorkOnResourceEnd();
263 0 : rtl::OString sCur;
264 0 : for( unsigned int i = 0; i < aLanguages.size(); ++i ){
265 0 : sCur = aLanguages[ i ];
266 0 : pStackData->sText[ sCur ] = rtl::OString();
267 0 : }
268 : }
269 0 : sCurrentResTyp = sTokenName;
270 : }
271 : }
272 0 : break;
273 : case CFG_CLOSETAG:
274 : {
275 : sTokenName = sToken.getToken(1, '/').getToken(0, '>').
276 0 : getToken(0, ' ');
277 0 : if ( aStack.GetStackData() && ( aStack.GetStackData()->GetTagType() == sTokenName ))
278 : {
279 0 : if (sCurrentText.isEmpty())
280 0 : WorkOnResourceEnd();
281 0 : aStack.Pop();
282 0 : pStackData = aStack.GetStackData();
283 : }
284 : else
285 : {
286 0 : rtl::OString sError( "Misplaced close tag: " );
287 0 : rtl::OString sInFile(" in file ");
288 0 : sError += sToken;
289 0 : sError += sInFile;
290 0 : sError += global::inputPathname;
291 0 : Error( sError );
292 0 : std::exit(EXIT_FAILURE);
293 : }
294 : }
295 0 : break;
296 :
297 : case CFG_TEXTCHAR:
298 0 : sCurrentText += sToken;
299 0 : bOutput = sal_False;
300 0 : break;
301 :
302 : case CFG_TOKEN_NO_TRANSLATE:
303 0 : bLocalize = sal_False;
304 0 : break;
305 : }
306 :
307 0 : if ( !sCurrentText.isEmpty() && nToken != CFG_TEXTCHAR )
308 : {
309 0 : AddText( sCurrentText, sCurrentIsoLang, sCurrentResTyp );
310 0 : Output( sCurrentText );
311 0 : sCurrentText = rtl::OString();
312 0 : pStackData->sEndTextTag = sToken;
313 : }
314 :
315 0 : if ( bOutput )
316 0 : Output( sToken );
317 :
318 0 : if ( sToken != " " && sToken != "\t" )
319 0 : sLastWhitespace = "";
320 :
321 0 : return 1;
322 : }
323 :
324 0 : void CfgExport::Output(const rtl::OString&)
325 : {
326 0 : }
327 :
328 : /*****************************************************************************/
329 0 : int CfgParser::Execute( int nToken, char * pToken )
330 : /*****************************************************************************/
331 : {
332 0 : rtl::OString sToken( pToken );
333 :
334 0 : switch ( nToken ) {
335 : case CFG_TAG:
336 0 : if ( sToken.indexOf( "package-id=" ) != -1 )
337 0 : return ExecuteAnalyzedToken( CFG_TOKEN_PACKAGE, pToken );
338 0 : else if ( sToken.indexOf( "component-id=" ) != -1 )
339 0 : return ExecuteAnalyzedToken( CFG_TOKEN_COMPONENT, pToken );
340 0 : else if ( sToken.indexOf( "template-id=" ) != -1 )
341 0 : return ExecuteAnalyzedToken( CFG_TOKEN_TEMPLATE, pToken );
342 0 : else if ( sToken.indexOf( "cfg:name=" ) != -1 )
343 0 : return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME, pToken );
344 0 : else if ( sToken.indexOf( "oor:name=" ) != -1 )
345 0 : return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME, pToken );
346 0 : else if ( sToken.indexOf( "oor:value=" ) != -1 )
347 0 : return ExecuteAnalyzedToken( CFG_TOKEN_OORVALUE, pToken );
348 0 : break;
349 : }
350 0 : return ExecuteAnalyzedToken( nToken, pToken );
351 : }
352 :
353 0 : void CfgParser::Error(const rtl::OString& rError)
354 : {
355 0 : yyerror(rError.getStr());
356 0 : }
357 :
358 : //
359 : // class CfgOutputParser
360 : //
361 :
362 0 : CfgOutputParser::CfgOutputParser(const rtl::OString &rOutputFile)
363 : {
364 : pOutputStream.open(
365 0 : rOutputFile.getStr(), std::ios_base::out | std::ios_base::trunc);
366 0 : if (!pOutputStream.is_open())
367 : {
368 0 : rtl::OStringBuffer sError(RTL_CONSTASCII_STRINGPARAM("ERROR: Unable to open output file: "));
369 0 : sError.append(rOutputFile);
370 0 : Error(sError.makeStringAndClear());
371 0 : std::exit(EXIT_FAILURE);
372 : }
373 0 : }
374 :
375 : /*****************************************************************************/
376 0 : CfgOutputParser::~CfgOutputParser()
377 : /*****************************************************************************/
378 : {
379 0 : pOutputStream.close();
380 0 : }
381 :
382 : //
383 : // class CfgExport
384 : //
385 :
386 : /*****************************************************************************/
387 0 : CfgExport::CfgExport(
388 : const rtl::OString &rOutputFile,
389 : const rtl::OString &rProject,
390 : const rtl::OString &rFilePath
391 : )
392 : /*****************************************************************************/
393 : : CfgOutputParser( rOutputFile ),
394 : sPrj( rProject ),
395 0 : sPath( rFilePath )
396 : {
397 0 : Export::InitLanguages( false );
398 0 : aLanguages = Export::GetLanguages();
399 0 : }
400 :
401 : /*****************************************************************************/
402 0 : CfgExport::~CfgExport()
403 : /*****************************************************************************/
404 : {
405 0 : }
406 :
407 : /*****************************************************************************/
408 0 : void CfgExport::WorkOnResourceEnd()
409 : /*****************************************************************************/
410 : {
411 0 : if ( bLocalize ) {
412 0 : if ( pStackData->sText[rtl::OString(RTL_CONSTASCII_STRINGPARAM("en-US"))].getLength() )
413 : {
414 0 : rtl::OString sFallback = pStackData->sText[rtl::OString(RTL_CONSTASCII_STRINGPARAM("en-US"))];
415 0 : rtl::OString sXComment = pStackData->sText[rtl::OString(RTL_CONSTASCII_STRINGPARAM("x-comment"))];
416 0 : rtl::OString sLocalId = pStackData->sIdentifier;
417 0 : rtl::OString sGroupId;
418 0 : if ( aStack.size() == 1 ) {
419 0 : sGroupId = sLocalId;
420 0 : sLocalId = "";
421 : }
422 : else {
423 0 : sGroupId = aStack.GetAccessPath( aStack.size() - 2 );
424 : }
425 :
426 0 : for (size_t n = 0; n < aLanguages.size(); n++)
427 : {
428 0 : rtl::OString sCur = aLanguages[ n ];
429 :
430 0 : rtl::OString sText = pStackData->sText[ sCur ];
431 0 : if ( sText.isEmpty())
432 0 : sText = sFallback;
433 :
434 0 : sText = Export::UnquoteHTML( sText );
435 :
436 0 : rtl::OString sOutput( sPrj ); sOutput += "\t";
437 0 : sOutput += sPath;
438 0 : sOutput += "\t0\t";
439 0 : sOutput += pStackData->sResTyp; sOutput += "\t";
440 0 : sOutput += sGroupId; sOutput += "\t";
441 0 : sOutput += sLocalId; sOutput += "\t\t\t0\t";
442 0 : sOutput += sCur;
443 0 : sOutput += "\t";
444 :
445 0 : sOutput += sText; sOutput += "\t";
446 0 : sOutput += sXComment; sOutput += "\t\t\t";
447 :
448 0 : pOutputStream << sOutput.getStr() << '\n';
449 0 : }
450 : }
451 : }
452 0 : }
453 :
454 0 : void CfgExport::WorkOnText(
455 : rtl::OString &rText,
456 : const rtl::OString &rIsoLang
457 : )
458 : {
459 0 : if( rIsoLang.getLength() ) rText = Export::UnquoteHTML( rText );
460 0 : }
461 :
462 :
463 : //
464 : // class CfgMerge
465 : //
466 :
467 0 : CfgMerge::CfgMerge(
468 : const rtl::OString &rMergeSource, const rtl::OString &rOutputFile,
469 : const rtl::OString &rFilename)
470 : : CfgOutputParser( rOutputFile ),
471 : pMergeDataFile( NULL ),
472 : pResData( NULL ),
473 : sFilename( rFilename ),
474 0 : bEnglish( sal_False )
475 : {
476 0 : if (rMergeSource.getLength())
477 : {
478 : pMergeDataFile = new MergeDataFile(
479 0 : rMergeSource, global::inputPathname, true );
480 0 : if (Export::sLanguages.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ALL")))
481 : {
482 0 : Export::SetLanguages( pMergeDataFile->GetLanguages() );
483 0 : aLanguages = pMergeDataFile->GetLanguages();
484 : }
485 0 : else aLanguages = Export::GetLanguages();
486 : }
487 : else
488 0 : aLanguages = Export::GetLanguages();
489 0 : }
490 :
491 : /*****************************************************************************/
492 0 : CfgMerge::~CfgMerge()
493 : /*****************************************************************************/
494 : {
495 0 : delete pMergeDataFile;
496 0 : delete pResData;
497 0 : }
498 :
499 0 : void CfgMerge::WorkOnText(rtl::OString &rText, const rtl::OString& rLangIndex)
500 : {
501 :
502 0 : if ( pMergeDataFile && bLocalize ) {
503 0 : if ( !pResData ) {
504 0 : rtl::OString sLocalId = pStackData->sIdentifier;
505 0 : rtl::OString sGroupId;
506 0 : if ( aStack.size() == 1 ) {
507 0 : sGroupId = sLocalId;
508 0 : sLocalId = rtl::OString();
509 : }
510 : else {
511 0 : sGroupId = aStack.GetAccessPath( aStack.size() - 2 );
512 : }
513 :
514 0 : rtl::OString sPlatform;
515 :
516 0 : pResData = new ResData( sPlatform, sGroupId , sFilename );
517 0 : pResData->sId = sLocalId;
518 0 : pResData->sResTyp = pStackData->sResTyp;
519 : }
520 :
521 0 : if (rLangIndex.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")))
522 0 : bEnglish = sal_True;
523 :
524 0 : PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrysCaseSensitive( pResData );
525 0 : if ( pEntrys ) {
526 0 : rtl::OString sContent;
527 0 : pEntrys->GetText( sContent, STRING_TYP_TEXT, rLangIndex );
528 :
529 0 : if ( Export::isAllowed( rLangIndex ) &&
530 0 : ( sContent != "-" ) && !sContent.isEmpty())
531 : {
532 0 : rText = Export::QuoteHTML( rText );
533 0 : }
534 : }
535 : }
536 0 : }
537 :
538 0 : void CfgMerge::Output(const rtl::OString& rOutput)
539 : {
540 0 : pOutputStream << rOutput.getStr();
541 0 : }
542 :
543 : /*****************************************************************************/
544 0 : void CfgMerge::WorkOnResourceEnd()
545 : /*****************************************************************************/
546 : {
547 :
548 0 : if ( pMergeDataFile && pResData && bLocalize && bEnglish ) {
549 0 : PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrysCaseSensitive( pResData );
550 0 : if ( pEntrys ) {
551 0 : rtl::OString sCur;
552 :
553 0 : for( unsigned int i = 0; i < aLanguages.size(); ++i ){
554 0 : sCur = aLanguages[ i ];
555 :
556 0 : rtl::OString sContent;
557 0 : pEntrys->GetText( sContent, STRING_TYP_TEXT, sCur , sal_True );
558 0 : if (
559 0 : ( !sCur.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")) ) &&
560 :
561 0 : ( sContent != "-" ) && !sContent.isEmpty())
562 : {
563 :
564 0 : rtl::OString sText = Export::QuoteHTML( sContent);
565 :
566 0 : rtl::OString sAdditionalLine( "\t" );
567 :
568 0 : rtl::OString sTextTag = pStackData->sTextTag;
569 0 : rtl::OString sTemp = sTextTag.copy( sTextTag.indexOf( "xml:lang=" ));
570 :
571 0 : sal_Int32 n = 0;
572 0 : rtl::OString sSearch = sTemp.getToken(0, '"', n);
573 0 : sSearch += "\"";
574 0 : sSearch += sTemp.getToken(0, '"', n);
575 0 : sSearch += "\"";
576 :
577 0 : rtl::OString sReplace = sTemp.getToken(0, '"');
578 0 : sReplace += "\"";
579 0 : sReplace += sCur;
580 0 : sReplace += "\"";
581 :
582 0 : sTextTag = sTextTag.replaceFirst(sSearch, sReplace);
583 :
584 0 : sAdditionalLine += sTextTag;
585 0 : sAdditionalLine += sText;
586 0 : sAdditionalLine += pStackData->sEndTextTag;
587 :
588 0 : sAdditionalLine += "\n";
589 0 : sAdditionalLine += sLastWhitespace;
590 :
591 0 : Output( sAdditionalLine );
592 : }
593 0 : }
594 : }
595 : }
596 0 : delete pResData;
597 0 : pResData = NULL;
598 0 : bEnglish = sal_False;
599 0 : }
600 :
601 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|