From cca7fb705d93403efb156a38228ee54bd5f9da16 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 22 Apr 2009 06:54:54 +0000 Subject: [PATCH] 2009-04-22 08:48 UTC+0200 Viktor Szakats (harbour.01 syenar hu) + Implemented .po to .hbl conversion inside hbmk2, with incremental feature (.hbl will only be regenerated if any .po file dependencies are newer). This is currently the default, no -inc switch is needed for that. You can specify .po files in the command line, in po= lines in .hbp files, output file is passed via -hbl= option. To handle multiple languages without hassle, you can use ${lng} macro in .po and .hbl filenames, plus pass the list of languages in -lng= option: app_${lng}.po -hbl=lang/${lng}.hbl -lng=en,hu,sk,pl [ Actual .po -> .hbl conversion code was taken from hbi18n tool made by Przemek, with little modifications. ] ! Fixed to check included .res file timestamp, but not parse it. + Added macro support in libs= .hbp lines. --- harbour/ChangeLog | 16 ++++ harbour/utils/hbmk2/hbmk2.prg | 175 +++++++++++++++++++++++++++++++--- 2 files changed, 179 insertions(+), 12 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index b69ca30bcd..f49833c67a 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,22 @@ 2009-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org) */ +2009-04-22 08:48 UTC+0200 Viktor Szakats (harbour.01 syenar hu) + + Implemented .po to .hbl conversion inside hbmk2, with + incremental feature (.hbl will only be regenerated if any + .po file dependencies are newer). This is currently the + default, no -inc switch is needed for that. + You can specify .po files in the command line, in po= + lines in .hbp files, output file is passed via -hbl= option. + To handle multiple languages without hassle, you can use + ${lng} macro in .po and .hbl filenames, plus pass the list + of languages in -lng= option: + app_${lng}.po -hbl=lang/${lng}.hbl -lng=en,hu,sk,pl + [ Actual .po -> .hbl conversion code was taken from hbi18n + tool made by Przemek, with little modifications. ] + ! Fixed to check included .res file timestamp, but not parse it. + + Added macro support in libs= .hbp lines. + 2009-04-21 18:14 UTC+0200 Viktor Szakats (harbour.01 syenar hu) * utils/hbmk2/hbmk2.prg + Added new CPU architecture filters: x86, x86_64, ia64, arm diff --git a/harbour/utils/hbmk2/hbmk2.prg b/harbour/utils/hbmk2/hbmk2.prg index 1857933f65..d3f888ab65 100644 --- a/harbour/utils/hbmk2/hbmk2.prg +++ b/harbour/utils/hbmk2/hbmk2.prg @@ -35,6 +35,7 @@ * bash script with similar purpose for gcc family. * entry point override method and detection code for gcc. * rtlink/blinker link script parsers. + * LoadPOFiles() and GenHbl(). * * See COPYING for licensing terms. * @@ -301,6 +302,9 @@ FUNCTION hbmk( aArgs ) LOCAL s_lHB_PCRE := .T. LOCAL s_lHB_ZLIB := .T. LOCAL s_cMAIN := NIL + LOCAL s_aPO + LOCAL s_cHBL + LOCAL s_aLNG LOCAL s_lCPP := NIL LOCAL s_lSHARED := NIL @@ -821,6 +825,9 @@ FUNCTION hbmk( aArgs ) s_cPROGDIR := NIL s_cPROGNAME := NIL s_cFIRST := NIL + s_aPO := {} + s_cHBL := NIL + s_aLNG := {} /* Collect all command line parameters */ aParams := {} @@ -858,6 +865,7 @@ FUNCTION hbmk( aArgs ) /* Process automatic control files. */ HBP_ProcessAll( lNOHBP,; + @s_aPO,; @s_aLIBUSER,; @s_aLIBUSERGT,; @s_aLIBPATH,; @@ -1022,6 +1030,20 @@ FUNCTION hbmk( aArgs ) HB_SYMBOL_UNUSED( s_nJOBS ) + CASE Left( cParamL, 5 ) == "-lng=" + + cParam := SubStr( cParam, 6 ) + IF ! Empty( cParam ) + s_aLNG := ListToArray( cParam, "," ) + ENDIF + + CASE Left( cParamL, 5 ) == "-hbl=" + + cParam := SubStr( cParam, 6 ) + IF ! Empty( cParam ) + s_cHBL := PathSepToTarget( cParam ) + ENDIF + CASE Left( cParamL, 6 ) == "-main=" IF IsValidHarbourID( cParam := SubStr( cParam, 7 ) ) @@ -1219,6 +1241,7 @@ FUNCTION hbmk( aArgs ) ENDIF HBP_ProcessOne( cParam,; + @s_aPO,; @s_aLIBUSER,; @s_aLIBUSERGT,; @s_aLIBPATH,; @@ -1293,6 +1316,16 @@ FUNCTION hbmk( aArgs ) DEFAULT s_cFIRST TO PathSepToSelf( cParam ) NEXT + CASE FN_ExtGet( cParamL ) == ".po" + + FOR EACH cParam IN FN_Expand( PathProc( cParam, aParam[ _PAR_cFileName ] ) ) + AAdd( s_aPO, PathSepToTarget( cParam ) ) + NEXT + + CASE FN_ExtGet( cParamL ) == ".hbl" + + s_cHBL := PathSepToTarget( cParam ) + OTHERWISE IF ! Empty( cParam ) @@ -2546,6 +2579,10 @@ FUNCTION hbmk( aArgs ) s_aRESSRC_TODO := s_aRESSRC ENDIF + IF Len( s_aPO ) > 0 .AND. ! s_lCLEAN + MakeHBL( s_aPO, s_cHBL, s_aLNG ) + ENDIF + IF Len( s_aRESSRC_TODO ) > 0 .AND. ! Empty( cBin_Res ) .AND. ! s_lCLEAN IF s_lINC .AND. ! s_lQuiet @@ -3115,6 +3152,7 @@ STATIC FUNCTION FindNewerHeaders( cFileName, cParentDir, tTimeParent, lIncTry, l LOCAL tTimeSelf LOCAL tmp LOCAL cNameExtL + LOCAL cExt STATIC s_aExcl := { "windows.h", "ole2.h", "os2.h" } @@ -3135,12 +3173,6 @@ STATIC FUNCTION FindNewerHeaders( cFileName, cParentDir, tTimeParent, lIncTry, l RETURN .F. ENDIF - /* Filter out non-source format inputs for MinGW / windres */ - IF s_cCOMP $ "gcc|gpp|mingw|mingw64|mingwarm|cygwin" .AND. s_cARCH $ "win|wce" .AND. ; - Lower( FN_ExtGet( cFileName ) ) == ".res" - RETURN .F. - ENDIF - /* Don't spend time on some known headers */ cNameExtL := Lower( FN_NameExtGet( cFileName ) ) IF AScan( s_aExcl, { |tmp| Lower( tmp ) == cNameExtL } ) > 0 @@ -3173,6 +3205,15 @@ STATIC FUNCTION FindNewerHeaders( cFileName, cParentDir, tTimeParent, lIncTry, l ENDIF ENDIF + cExt := Lower( FN_ExtGet( cFileName ) ) + + /* Filter out non-source format inputs for MinGW / windres */ + IF s_cCOMP $ "gcc|gpp|mingw|mingw64|mingwarm|cygwin" .AND. s_cARCH $ "win|wce" .AND. cExt == ".res" + RETURN .F. + ENDIF + + /* TODO: Add filter based on extension to avoid binary files */ + /* NOTE: Beef up this section if you need a more intelligent source parser. Notice that this code is meant to process both .prg, .c and .res sources. Please try to keep it simple, @@ -3251,7 +3292,7 @@ STATIC FUNCTION FindLib( cLib, aLIBPATH, cLibExt ) LOCAL cDir LOCAL tmp - /* Check libnames containing dirs */ + /* Check libs in their full paths */ IF s_cCOMP $ "msvc|msvc64|msvcarm|bcc|pocc|pocc64|poccarm|owatcom" IF ! Empty( FN_DirGet( cLib ) ) IF hb_FileExists( cLib := FN_ExtSet( cLib, cLibExt ) ) @@ -3517,12 +3558,12 @@ STATIC FUNCTION ArrayToList( array, cSeparator ) RETURN cString -STATIC FUNCTION ListToArray( cList ) +STATIC FUNCTION ListToArray( cList, cSep ) LOCAL array := {} LOCAL cItem IF ! Empty( cList ) - FOR EACH cItem IN hb_ATokens( cList ) + FOR EACH cItem IN hb_ATokens( cList, cSep ) AAddNotEmpty( array, cItem ) NEXT ENDIF @@ -3771,6 +3812,7 @@ STATIC FUNCTION FN_HasWildcard( cFileName ) #define HBMK_CFG_NAME "hbmk.cfg" STATIC PROCEDURE HBP_ProcessAll( lConfigOnly,; + /* @ */ aPO,; /* @ */ aLIBUSER,; /* @ */ aLIBUSERGT,; /* @ */ aLIBPATH,; @@ -3817,6 +3859,7 @@ STATIC PROCEDURE HBP_ProcessAll( lConfigOnly,; OutStd( "hbmk: Processing configuration: " + cFileName + hb_osNewLine() ) ENDIF HBP_ProcessOne( cFileName,; + @aPO,; @aLIBUSER,; @aLIBUSERGT,; @aLIBPATH,; @@ -3853,6 +3896,7 @@ STATIC PROCEDURE HBP_ProcessAll( lConfigOnly,; OutStd( "hbmk: Processing: " + cFileName + hb_osNewLine() ) ENDIF HBP_ProcessOne( cFileName,; + @aPO,; @aLIBUSER,; @aLIBUSERGT,; @aLIBPATH,; @@ -3886,6 +3930,7 @@ STATIC PROCEDURE HBP_ProcessAll( lConfigOnly,; #define _EOL Chr( 10 ) STATIC PROCEDURE HBP_ProcessOne( cFileName,; + /* @ */ aPO,; /* @ */ aLIBUSER,; /* @ */ aLIBUSERGT,; /* @ */ aLIBPATH,; @@ -3926,9 +3971,17 @@ STATIC PROCEDURE HBP_ProcessOne( cFileName,; cLine := AllTrim( ArchCompFilter( AllTrim( cLine ) ) ) DO CASE + CASE Lower( Left( cLine, Len( "po=" ) ) ) == "po=" ; cLine := SubStr( cLine, Len( "po=" ) + 1 ) + FOR EACH cItem IN hb_ATokens( cLine,, .T. ) + cItem := PathSepToTarget( MacroProc( StrStripQuote( cItem ), FN_DirGet( cFileName ) ) ) + IF AScan( aPO, {|tmp| tmp == cItem } ) == 0 + AAddNotEmpty( aPO, cItem ) + ENDIF + NEXT + CASE Lower( Left( cLine, Len( "libs=" ) ) ) == "libs=" ; cLine := SubStr( cLine, Len( "libs=" ) + 1 ) FOR EACH cItem IN hb_ATokens( cLine,, .T. ) - cItem := PathSepToTarget( StrStripQuote( cItem ) ) + cItem := PathSepToTarget( MacroProc( StrStripQuote( cItem ), FN_DirGet( cFileName ) ) ) IF AScan( aLIBUSER, {|tmp| tmp == cItem } ) == 0 AAddNotEmpty( aLIBUSER, cItem ) ENDIF @@ -4683,6 +4736,99 @@ STATIC FUNCTION rtlnk_process( cCommands, cFileOut, aFileList, aLibList, ; RETURN .T. +/* .hbl generation */ + +#define _LNG_MARKER "${lng}" + +STATIC PROCEDURE MakeHBL( aPO, cHBL, aLNG ) + LOCAL cPO + LOCAL tPO + LOCAL cLNG + LOCAL tLNG + LOCAL aPO_TODO + + IF ! Empty( aPO ) + IF s_lDEBUG + OutStd( "hbmk: PO: in: ", ArrayToList( aPO ), hb_osNewLine() ) + ENDIF + IF Empty( cHBL ) + cHBL := FN_NameGet( aPO[ 1 ] ) + ENDIF + IF Empty( FN_ExtGet( cHBL ) ) + cHBL := FN_ExtSet( cHBL, ".hbl" ) + ENDIF + IF Empty( aLNG ) + tLNG := NIL + hb_FGetDateTime( cHBL, @tLNG ) + aPO_TODO := {} + FOR EACH cPO IN aPO + IF !( _LNG_MARKER $ cPO ) .AND. ( tLNG == NIL .OR. ( hb_FGetDateTime( cPO, @tPO ) .AND. tPO > tLNG ) ) + AAdd( aPO_TODO, cPO ) + ENDIF + NEXT + IF ! Empty( aPO_TODO ) + IF s_lDEBUG + OutStd( "hbmk: PO: ", ArrayToList( aPO_TODO ), "->", cHBL, hb_osNewLine() ) + ENDIF + GenHbl( aPO_TODO, cHBL ) + ENDIF + ELSE + FOR EACH cLNG IN aLNG + tLNG := NIL + hb_FGetDateTime( StrTran( cHBL, _LNG_MARKER, cLNG ), @tLNG ) + aPO_TODO := {} + FOR EACH cPO IN aPO + IF _LNG_MARKER $ cPO .AND. ( tLNG == NIL .OR. ( hb_FGetDateTime( StrTran( cPO, _LNG_MARKER, cLNG ), @tPO ) .AND. tPO > tLNG ) ) + AAdd( aPO_TODO, StrTran( cPO, _LNG_MARKER, cLNG ) ) + ENDIF + NEXT + IF ! Empty( aPO_TODO ) + IF s_lDEBUG + OutStd( "hbmk: PO: ", ArrayToList( aPO_TODO ), "->", StrTran( cHBL, _LNG_MARKER, cLNG ), hb_osNewLine() ) + ENDIF + GenHbl( aPO_TODO, StrTran( cHBL, _LNG_MARKER, cLNG ) ) + ENDIF + NEXT + ENDIF + ENDIF + + RETURN + +STATIC FUNCTION LoadPOFiles( aFiles ) + LOCAL aTrans, aTrans2 + LOCAL cErrorMsg + LOCAL n + + aTrans := __I18N_potArrayLoad( aFiles[ 1 ], @cErrorMsg ) + IF aTrans == NIL + OutStd( "hbmk: .po error: ", cErrorMsg, hb_osNewLine() ) + ENDIF + FOR n := 2 TO Len( aFiles ) + aTrans2 := __I18N_potArrayLoad( aFiles[ n ], @cErrorMsg ) + IF aTrans2 == NIL + OutStd( "hbmk: .po error: ", cErrorMsg, hb_osNewLine() ) + ELSE + __I18N_potArrayJoin( aTrans, aTrans2 ) + ENDIF + NEXT + + RETURN aTrans + +STATIC PROCEDURE GenHbl( aFiles, cFileOut, lEmpty ) + LOCAL cHblBody + LOCAL pI18N + LOCAL aTrans := LoadPOFiles( aFiles ) + + IF ISARRAY( aTrans ) + pI18N := __I18N_hashTable( __I18N_potArrayToHash( aTrans, lEmpty ) ) + cHblBody := HB_I18N_SaveTable( pI18N ) + IF ! hb_memoWrit( cFileOut, cHblBody ) + OutStd( "hbmk: Cannot create file: ", cFileOut, hb_osNewLine() ) + ENDIF + ENDIF + + RETURN + /* Keep this public, it's used from macro. */ FUNCTION hbmk_ARCH() RETURN s_cARCH @@ -4750,7 +4896,7 @@ STATIC PROCEDURE ShowHeader() STATIC PROCEDURE ShowHelp( lLong ) LOCAL aText_Basic := {; - "Syntax: hbmk [options] [] " ,; + "Syntax: hbmk [options] [] " ,; "" ,; "Options:" ,; " -o output file name" ,; @@ -4801,6 +4947,11 @@ STATIC PROCEDURE ShowHelp( lLong ) " -clean clean (in incremental build mode)" ,; " -workdir= working directory for incremental build mode" ,; " (default: arch/comp)" ,; + " -hbl= output .hbl filename. ${lng} macro is accepted in filename" ,; + " -lng= list of languages to be replaced in ${lng} macros in .po" ,; + " filenames and output .hbl filenames. Comma separared list:" ,; + " -lng=en-EN,hu-HU,de" ,; + "" ,; " -hbcmp|-clipper stop after creating the object files" ,; " create link/copy hbmk to hbcmp/clipper for the same effect" ,; " -hbcc stop after creating the object files and accept raw C flags" ,; @@ -4838,7 +4989,7 @@ STATIC PROCEDURE ShowHelp( lLong ) " - .hbp options (they should come in separate lines):" ,; " libs=[], gt=[gtname], prgflags=[Harbour flags]" ,; " cflags=[C compiler flags], resflags=[resource compiler flags]" ,; - " ldflags=[Linker flags], libpaths=[paths]," ,; + " ldflags=[Linker flags], libpaths=[paths], po=[.po files]" ,; " incpaths=[paths], inctrypaths=[paths]" ,; " gui|mt|shared|nulrdd|debug|opt|map|strip|run|inc=[yes|no]" ,; " compr=[yes|no|def|min|max], head=[off|partial|full], echo=" ,;