From ce44121edc0858241c0b7be76f077b2a6759e63f Mon Sep 17 00:00:00 2001 From: Mindaugas Kavaliauskas Date: Fri, 23 Nov 2007 01:55:37 +0000 Subject: [PATCH] 2007-11-23 03:55 UTC+0200 Mindaugas Kavaliauskas (dbtopas/at/dbtopas.lt) * harbour/source/include/hbcompdf.h * harbour/source/include/hbexprop.h * harbour/source/include/hbexprb.c * harbour/source/compiler/cmdcheck.c * harbour/source/compiler/hbmain.c + added i18n support Implemented -j[filename] switch to indicate output filename. Default filename is .pot. If switch -o is used, this file is created in speficied output path. Output file format is compatible with 'gettext' utils, but not all available features are implemented. Harbour level function HB_i18nGettext( cText [, cContext ] ) sould be used to indicate translatable strings. All this commit is commented using #ifdef HB_I18N_SUPPORT and is in development stage. Please, do not use it yet. --- harbour/ChangeLog | 17 ++ harbour/include/hbcompdf.h | 23 +++ harbour/include/hbexprb.c | 20 +++ harbour/include/hbexprop.h | 4 + harbour/source/compiler/cmdcheck.c | 18 +++ harbour/source/compiler/hbmain.c | 249 +++++++++++++++++++++++++++++ 6 files changed, 331 insertions(+) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 1085776bbb..7c20cfbbe3 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,23 @@ 2002-12-01 13:30 UTC+0100 Foo Bar */ +2007-11-23 03:55 UTC+0200 Mindaugas Kavaliauskas (dbtopas/at/dbtopas.lt) + * harbour/source/include/hbcompdf.h + * harbour/source/include/hbexprop.h + * harbour/source/include/hbexprb.c + * harbour/source/compiler/cmdcheck.c + * harbour/source/compiler/hbmain.c + + added i18n support + Implemented -j[filename] switch to indicate output filename. Default + filename is .pot. If switch -o is used, this file + is created in speficied output path. + Output file format is compatible with 'gettext' utils, but not all + available features are implemented. + Harbour level function HB_i18nGettext( cText [, cContext ] ) sould be + used to indicate translatable strings. + All this commit is commented using #ifdef HB_I18N_SUPPORT and is in + development stage. Please, do not use it yet. + 2007-11-23 01:28 UTC+0100 Viktor Szakats (harbour.01 syenar.hu) + gtwvg/common.mak + gtwvg/make_b32.bat diff --git a/harbour/include/hbcompdf.h b/harbour/include/hbcompdf.h index c41d23a3e8..06a9ac90c4 100644 --- a/harbour/include/hbcompdf.h +++ b/harbour/include/hbcompdf.h @@ -551,6 +551,24 @@ typedef struct HB_MACRO_ /* a macro compiled pcode container */ #define HB_COMP_PARAM pComp #define HB_COMP_DECL HB_COMP_PTR HB_COMP_PARAM +#ifdef HB_I18N_SUPPORT +typedef struct _HB_I18NSTRING +{ + char* szText; + char* szContext; + UINT uiLine; + UINT* pLine; + UINT uiLineCount; +} HB_I18NSTRING, * PHB_I18NSTRING; + +typedef struct _HB_I18NTABLE +{ + PHB_I18NSTRING pString; + ULONG uiCount; + ULONG uiAllocated; +} HB_I18NTABLE, * PHB_I18NTABLE; +#endif + typedef struct _HB_COMP_LEX { PHB_PP_STATE pPP; @@ -604,6 +622,11 @@ typedef struct _HB_COMP PHB_FNAME pFileName; PHB_FNAME pOutPath; PHB_FNAME pPpoPath; +#ifdef HB_I18N_SUPPORT + PHB_FNAME pI18nFileName; + PHB_I18NTABLE pI18n; + BOOL fI18n; +#endif void ( * outStdFunc ) ( void *, const char* ); void ( * outErrFunc ) ( void *, const char* ); diff --git a/harbour/include/hbexprb.c b/harbour/include/hbexprb.c index f34cf52cea..8e28cb924b 100644 --- a/harbour/include/hbexprb.c +++ b/harbour/include/hbexprb.c @@ -1643,6 +1643,26 @@ static HB_EXPR_FUNC( hb_compExprUseFunCall ) { hb_compExprReduceUPPER( pSelf, HB_COMP_PARAM ); } +#ifdef HB_I18N_SUPPORT +#ifndef HB_MACRO_SUPPORT + else if( strcmp( "HB_I18NGETTEXT", pName->value.asSymbol ) == 0 && usCount ) + { + HB_EXPR_PTR pArg = pParms->value.asList.pExprList; + + // TODO: do we need to add empty string also? + // TODO: add context, line number + if( HB_COMP_PARAM->fI18n && pArg->ExprType == HB_ET_STRING && pArg->ulLength > 0 ) + { + if( usCount == 2 && pArg->pNext->ExprType == HB_ET_STRING && pArg->pNext->ulLength > 0 ) + hb_compI18nAdd( HB_COMP_PARAM, pArg->value.asString.string, + pArg->pNext->value.asString.string, HB_COMP_PARAM->currLine ); + else + hb_compI18nAdd( HB_COMP_PARAM, pArg->value.asString.string, NULL, + HB_COMP_PARAM->currLine ); + } + } +#endif +#endif } } break; diff --git a/harbour/include/hbexprop.h b/harbour/include/hbexprop.h index e8390eb63b..4bd38a0a94 100644 --- a/harbour/include/hbexprop.h +++ b/harbour/include/hbexprop.h @@ -198,6 +198,10 @@ extern BOOL hb_compExprReduceSTOD( HB_EXPR_PTR pSelf, USHORT usCount, HB_COMP_DE extern BOOL hb_compExprReduceCTOD( HB_EXPR_PTR, HB_COMP_DECL ); extern BOOL hb_compExprReduceUPPER( HB_EXPR_PTR, HB_COMP_DECL ); +#ifdef HB_I18N_SUPPORT +extern void hb_compI18nAdd( HB_COMP_DECL, const char* szText, const char* szContext, UINT uiLine ); +#endif + HB_EXTERN_END #endif /* HB_EXPROP_H_ */ diff --git a/harbour/source/compiler/cmdcheck.c b/harbour/source/compiler/cmdcheck.c index d24c5f4dfc..7b4c067c18 100644 --- a/harbour/source/compiler/cmdcheck.c +++ b/harbour/source/compiler/cmdcheck.c @@ -342,6 +342,15 @@ static void hb_compChkEnvironVar( HB_COMP_DECL, char *szSwitch ) hb_pp_addSearchPath( HB_COMP_PARAM->pLex->pPP, s + 1, FALSE ); break; +#ifdef HB_I18N_SUPPORT + case 'j': + case 'J': + HB_COMP_PARAM->fI18n = TRUE; + if( s[ 1 ] ) + HB_COMP_PARAM->pI18nFileName = hb_fsFNameSplit( s + 1 ); + break; +#endif + case 'k': case 'K': { @@ -754,6 +763,15 @@ void hb_compChkCompilerSwitch( HB_COMP_DECL, int iArg, char *Args[] ) j = strlen( Args[i] ); continue; +#ifdef HB_I18N_SUPPORT + case 'j': + case 'J': + Args[i] += ( j - 1 ); + hb_compChkEnvironVar( HB_COMP_PARAM, Args[i] ); + j = strlen( Args[i] ); + continue; +#endif + case 'k': case 'K': Args[i] += ( j - 1 ); diff --git a/harbour/source/compiler/hbmain.c b/harbour/source/compiler/hbmain.c index 376c926a7d..f9f7155db1 100644 --- a/harbour/source/compiler/hbmain.c +++ b/harbour/source/compiler/hbmain.c @@ -4010,6 +4010,228 @@ void hb_compCodeBlockRewind( HB_COMP_DECL ) } } +#ifdef HB_I18N_SUPPORT +/* ============================ I18N ============================ */ +PHB_I18NTABLE hb_compI18nCreate( void ) +{ + PHB_I18NTABLE pI18n; + + pI18n = ( PHB_I18NTABLE ) hb_xgrab( sizeof( HB_I18NTABLE ) ); + pI18n->pString = NULL; + pI18n->uiCount = 0; + pI18n->uiAllocated = 0; + return pI18n; +} + + +void hb_compI18nFree( PHB_I18NTABLE pI18n ) +{ + UINT ui; + + if( pI18n->pString ) + { + for( ui = 0; ui < pI18n->uiCount; ui++ ) + { + if( pI18n->pString[ ui ].szText ) + hb_xfree( pI18n->pString[ ui ].szText ); + + if( pI18n->pString[ ui ].szContext ) + hb_xfree( pI18n->pString[ ui ].szContext ); + + if( pI18n->pString[ ui ].pLine ) + hb_xfree( pI18n->pString[ ui ].pLine ); + } + hb_xfree( pI18n->pString ); + } + hb_xfree( pI18n ); +} + +static int hb_compI18nCompare( PHB_I18NSTRING pString, const char* pText, const char* pContext ) +{ + int i; + + i = strcmp( pString->szText, pText ); + + if( i == 0 ) + { + if( pContext ) + { + if( pString->szContext ) + return strcmp( pString->szContext, pContext ); + else + return -1; + } + else + { + if( pString->szContext ) + return 1; + else + return 0; + } + } + return i; +} + + +void hb_compI18nAdd( HB_COMP_DECL, const char* szText, const char* szContext, UINT uiLine ) +{ + PHB_I18NTABLE pI18n; + PHB_I18NSTRING pString; + UINT uiLeft, uiRight, uiMiddle; + int iCompare; + + pI18n = HB_COMP_PARAM->pI18n; + + if( ! pI18n ) + return; + + if( pI18n->uiCount >= pI18n->uiAllocated ) + { + if( pI18n->pString ) + { + pI18n->uiAllocated += 32; + pI18n->pString = ( PHB_I18NSTRING ) hb_xrealloc( pI18n->pString, sizeof( HB_I18NSTRING ) + * pI18n->uiAllocated ); + } + else + { + pI18n->pString = ( PHB_I18NSTRING ) hb_xgrab( sizeof( HB_I18NSTRING ) * 32 ); + pI18n->uiAllocated = 32; + } + } + + uiLeft = 0; + uiRight = pI18n->uiCount; + + while( uiLeft < uiRight ) + { + uiMiddle = ( uiLeft + uiRight ) >> 1; + + iCompare = hb_compI18nCompare( & pI18n->pString[ uiMiddle ], szText, szContext ); + + if( iCompare == 0 ) + { + pString = & pI18n->pString[ uiMiddle ]; + + if( pString->pLine ) + { + pString->pLine = ( UINT* ) hb_xrealloc( pString->pLine, ( pString->uiLineCount + 1 ) * sizeof( UINT ) ); + pString->pLine[ pString->uiLineCount ] = uiLine; + pString->uiLineCount++; + } + else + { + pString->pLine = ( UINT* ) hb_xgrab( sizeof( UINT ) ); + pString->pLine[ 0 ] = uiLine; + pString->uiLineCount = 1; + } + return; + } + else if( iCompare < 0 ) + uiLeft = uiMiddle + 1; + else + uiRight = uiMiddle; + } + + memmove( & pI18n->pString[ uiLeft + 1 ], & pI18n->pString[ uiLeft ], ( pI18n->uiCount - uiLeft ) * sizeof( PHB_I18NSTRING ) ); + + pString = & pI18n->pString[ uiLeft ]; + pString->szText = ( char* ) hb_xgrab( strlen( szText ) + 1 ); + strcpy( pString->szText, szText ); + if( szContext ) + { + pString->szContext = ( char* ) hb_xgrab( strlen( szContext ) + 1 ); + strcpy( pString->szContext, szContext ); + } + else + pString->szContext = NULL; + pString->uiLine = uiLine; + pString->pLine = NULL; + pString->uiLineCount = 0; + + pI18n->uiCount++; +} + + +BOOL hb_compI18nSave( HB_COMP_DECL ) +{ + PHB_I18NTABLE pI18n; + PHB_I18NSTRING pString; + HB_FNAME pFileName; + char szFileName[ _POSIX_PATH_MAX + 1 ]; + char* szText; + UINT uiIndex, uiLine; + FILE* file; + + pI18n = HB_COMP_PARAM->pI18n; + + pFileName.szPath = pFileName.szName = pFileName.szExtension = pFileName.szDrive = NULL; + + if( HB_COMP_PARAM->pOutPath ) + { + pFileName.szDrive = HB_COMP_PARAM->pOutPath->szDrive; + pFileName.szPath = HB_COMP_PARAM->pOutPath->szPath; + } + + if( HB_COMP_PARAM->pI18nFileName ) + { + if( HB_COMP_PARAM->pI18nFileName->szName ) + pFileName.szName = HB_COMP_PARAM->pI18nFileName->szName; + + if( HB_COMP_PARAM->pI18nFileName->szExtension ) + pFileName.szExtension = HB_COMP_PARAM->pI18nFileName->szExtension; + + if( HB_COMP_PARAM->pI18nFileName->szPath ) + { + pFileName.szDrive = HB_COMP_PARAM->pI18nFileName->szDrive; + pFileName.szPath = HB_COMP_PARAM->pI18nFileName->szPath; + } + } + + if( ! pFileName.szName ) + pFileName.szName = HB_COMP_PARAM->pFileName->szName; + + if( ! pFileName.szExtension ) + pFileName.szExtension = ".pot"; + + hb_fsFNameMerge( szFileName, & pFileName ); + + file = hb_fopen( szFileName, "wb" ); + + if( ! file ) + { + /* TODO: do we need to interupt compilation ? */ + hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_CREATE_OUTPUT, szFileName, NULL ); + return FALSE; + } + + szText = hb_verHarbour(); + fprintf( file, "#\n# This file is generated by: %s\n#\n\n", szText ); + hb_xfree( szText ); + + strcpy( szFileName, HB_COMP_PARAM->pFileName->szName ); + + for( uiIndex = 0; uiIndex < pI18n->uiCount; uiIndex++ ) + { + pString = & pI18n->pString[ uiIndex ]; + + fprintf( file, "#: %s:%d", szFileName, pString->uiLine ); + + for( uiLine = 0; uiLine < pString->uiLineCount; uiLine++ ) + fprintf( file, " %s:%d", szFileName, pString->pLine[ uiLine ] ); + + fprintf( file, "\n#, c-format\n" ); + + if( pString->szContext ) + fprintf( file, "msgctxt \"%s\"\n", pString->szContext ); + + fprintf( file, "msgid \"%s\"\nmsgstr \"\"\n\n", pString->szText ); + } + + fclose( file ); + return TRUE; +} +#endif /* ************************************************************************* */ @@ -4133,6 +4355,20 @@ void hb_compCompileEnd( HB_COMP_DECL ) hb_compSwitchKill( HB_COMP_PARAM ); hb_compElseIfKill( HB_COMP_PARAM ); +#ifdef HB_I18N_SUPPORT + if( HB_COMP_PARAM->pI18n ) + { + hb_compI18nFree( HB_COMP_PARAM->pI18n ); + HB_COMP_PARAM->pI18n = NULL; + } + + if( HB_COMP_PARAM->pI18nFileName ) + { + hb_xfree( HB_COMP_PARAM->pI18nFileName ); + HB_COMP_PARAM->pI18nFileName = NULL; + } +#endif + if( HB_COMP_PARAM->pMainFileName ) { if( HB_COMP_PARAM->pFileName != HB_COMP_PARAM->pMainFileName ) @@ -4318,6 +4554,13 @@ static int hb_compCompile( HB_COMP_DECL, const char * szPrg, int iFileType ) hb_compOutStd( HB_COMP_PARAM, buffer ); } +#ifdef HB_I18N_SUPPORT + if( HB_COMP_PARAM->fI18n ) + { + HB_COMP_PARAM->pI18n = hb_compI18nCreate(); + } +#endif + /* Generate the starting procedure frame */ if( HB_COMP_PARAM->fStartProc ) { @@ -4500,6 +4743,12 @@ static int hb_compCompile( HB_COMP_DECL, const char * szPrg, int iFileType ) } hb_compGenOutput( HB_COMP_PARAM, HB_COMP_PARAM->iLanguage ); +#ifdef HB_I18N_SUPPORT + if( HB_COMP_PARAM->pI18n ) + { + hb_compI18nSave( HB_COMP_PARAM ); + } +#endif } } }