2008-12-11 19:48 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)

* harbour/include/hbthread.h
  * harbour/source/vm/thread.c
    + added hb_atomic_set(), hb_atomic_get(), hb_atomic_inc() and
      hb_atomic_dec() functions which operates on HB_COUNTER or smaller
      type if it's necessary for some platforms which can be access/assign
      increment/decrement in MT safe atom operations.
      hb_atomic_dec() returns true if counter is 0 after decrementation

  * harbour/include/hbatomic.h
    ! fixed compilation in Linux and OpenWatcom

  * harbour/include/hbapiitm.h
  * harbour/source/rtl/itemseri.c
    + make hb_itemSerialize() and hb_itemDeserialize() public functions
    ! fixed serialization items with internal item references

  * harbour/source/vm/hvm.c
    * release memvars after closing RDDs

  * harbour/source/debug/dbgentry.c
    ! fixed buffer overflow reported by Rodrigo

  * harbour/source/vm/macro.c
  * harbour/source/compiler/hbmain.c
    * formatting

  * harbour/include/hbexprb.c
    ! fixed wrongly recognized functions with HB_I18N_ prefix as
      HB_I18N_GETTEXT()

  * harbour/include/hbapi.h
  * harbour/include/hbstack.h
  * harbour/include/hbthread.h
  * harbour/source/vm/estack.c
  * harbour/source/vm/thread.c
  * harbour/source/vm/hvm.c
    + added support for I18N in HVM.
      Each thread can have it's own i18n set.
      When new thread is created then it inherits i18n set from parent
      thread and both uses the same set (please remember about it if you
      will want to make some direct modifications on active i18n set
      internals).
      When thread change active i18n set then it effects only this thread
      and new threads which will be create later. It does not change i18n
      in other existing threads.
    + added functions to set/get pointer to active i18n set in HVM
         void * hb_vmI18N( void )
         void   hb_vmSetI18N( void * )

  * harbour/include/hbapi.h
  * harbour/source/rtl/hbi18n.c
    + added i18n module. Now only for internal Harbour usage without support
      for optional switching to alternative implementations.
      I'll add such functionality later when I will work on native gettext
      support.

      The following public .prg functions has been added:
         HB_I18N_GETTEXT[_STRICT]( <cMsgID> [, <cContext> ] )
               -> <cTranslatedMsgID> | <cMsgID>
         HB_I18N_NGETTEXT[_STRICT]( <nValue>, <cMsgID> | <acMsgID> ;
                                    [, <cContext> ] )
               -> <cTranslatedMsgID> | <cMsgID> | <acMsgID>[ <nIndex> ]
      This is minimal support necessary for .prg code which has to exists
      in each i18n module working with Harbour.

      The following functions had been added as public C API:
         PHB_ITEM hb_i18n_gettext( PHB_ITEM pMsgID, PHB_ITEM pContext )
         PHB_ITEM hb_i18n_ngettext( PHB_ITEM pNum,
                                    PHB_ITEM pMsgID, PHB_ITEM pContext )

      The following functions had been added as private HVM C API:
         void   hb_i18n_init( void )
         void   hb_i18n_exit( void )
         void   hb_i18n_release( void * cargo )
         void * hb_i18n_alloc( void * cargo )
      They have to be supported by alternative i18n modules

      The following functions has been added to manage Harbour i18n
      translations sets:

         HB_I18N_CREATE()
                  -> <pI18N>
            Creates new empty I18N translation set

         HB_I18N_CODEPAGE( [<pI18N>,] [<cNewCP>], [<lBase>], [<lTranslate>] )
                  -> <cOldCP>
            Gets or sets Harbour codepage used by translation set
            <pI18N> - I18N translation set,
                      if it's not given then currently active I18N set is used
            <cNewCP> - new CP ID. Must be linked with application
            <lBase> - when it's .T. then get/set base massages CP instead of
                      translated massages CP
            <lTranslate> - if it's .T. then translate base (<lBase>==.T.) or
                           final messages in I18N set from previous CP to
                           given one. Base messages translation in synced
                           with context ID translation.

         HB_I18N_PLURALFORM( [<pI18N>,] [<cNewForm>|<bNewForm>], [<lBase>] )
                  -> <cOldForm>|<bOldForm>
            Gets or sets plural form used for final or base messages
            <pI18N> - I18N translation set,
                      if it's not given then currently active I18N set is used
            <cNewForm> - language ID of plural form, f.e.: "EN", "PL", "LT".
                         Now only three above are supported. Please add rules
                         for other languages to source/rtl/hbi18n.c.
            <bNewForm> - codeblock used to calculate plural form indexes.
                         can be used instead of character representation but
                         it's not storred in serialized I18N set
            <lBase> - when it's .T. then get/set base massages plural form
                      instead of translated massages one.

         HB_I18N_DESCRIPTION( [<pI18N>,] [<cNewDescription>] )
                  -> <cOldDescription>
            Gets or sets translation set description. After serialization
            up to 32 bytes is stored in header which can be easy used to
            determinate type of translation file.
            <pI18N> - I18N translation set,
                      if it's not given then currently active I18N set is used
            <cNewDescription> - new description

         HB_I18N_ADDTEXT( <pI18N>, <cMsgID>, <cTrans> | <acTrans> [, <cContext> ] )
                  -> NIL
            Adds new message with translation to i18n translation set
            <pI18N> - I18N translation set
            <cMsgID> - original message
            <cTrans> - translated message
            <acTrans> - array with translated messages used for plural forms
            <cContext> - message context

         HB_I18N_SET( [ <pI18N> | NIL ] )
                  -> <lActive>
            Sets given I18N translation set as default one used by
            HB_I18N_[N]GETTEXT[_STRICT]() functions or remove translation
            set for calling thread when passed parameter is NIL
            <pI18N> - I18N translation set
            Returns logical value which is .T. when i18n set is active

         HB_I18N_SAVETABLE( [<pI18N>] )
                  -> <cTable>
            Returns I18N translation as string item which can be stored
            in file or database
            <pI18N> - I18N translation set, if it's not given then currently
                      active I18N set is used

         HB_I18N_RESTORETABLE( <cTable> )
                  -> <pI18N> | NIL
            Restores I18N translation set from strin item.
            <cTable> - I18N translation set in string representation
            On success it returns new <pI18N> set otherwise NIL if <cTable>
            is not valid item created by HB_I18N_SAVETABLE() or it's corrupted.

         HB_I18N_HEADERSIZE()
                  -> <nHeaderSize>
            Returns size of header used by i18n serialized version

         HB_I18N_CHEK( <cTable> | <cHeader> [, @<cDescription> ] )
                  -> <lValid>
            <cTable> - i18n translation set serialized by HB_I18N_SAVETABLE
            <cHeader> - header of i18n translation set
                        ( LEFT( <cTable>, HB_I18N_HEADERSIZE() )
            <cDescription> - optional parameter passed by reference where
                             will be sored i18n translation set description
                             extracted from valid header
            Returns logical value indicating if given table or header is
            valid serialized by HB_I18N_SAVETABLE() data. It does not
            decode the table though it validates size and control sums.

      These functions are optional and some future alternative implementations
      may not support all of them and/or may provide some other functions.

    + added unofficial .prg function __I18N_HASHTABLE() which allows to
      access hash table used by i18n translation set or create new translation
      set with given hash table. It's helper functions for developers which
      will work on Harbour i18n tools and should not be used by Harbour users.

      Unlike original gettext Harbour allows to use language with many
      plural forms as base one. In such case programmer should activate
      at application startup default i18n translation set with base plural
      form valid for base application language, f.e. by:
         pI18N := hb_i18n_create()
         hb_i18n_pluralForm( pI18N, <cLangID> | <bForm>, .t. )
         hb_i18n_set( pI18N )
      .prg code example:

         #xtranslate _( <x,...> ) => hb_i18n_gettext_strict( <x> )
         #xtranslate _N( <x,...> ) => hb_i18n_ngettext_strict( <x> )

         proc main()
            local pI18N, i

            pI18N := hb_i18n_create()
            hb_i18n_pluralForm( pI18N, "PL", .t. )
            hb_i18n_set( pI18N )

            for i := 0 to 30
               ? i, _N( i, {"grosz", "grosze", "groszy"} )
               if i > 0 .and. i % 10 == 0
                  wait
               endif
            next
         return

      In .pot files created during compilation by Harbour with -j option
      for above code we have the following entries for message with plural
      forms:
            msgid "grosz"
            msgid_plural "grosze"
            msgid_plural2 "groszy"
            msgstr[0] ""
      The msgid_plural2 (and others if language has more plural forms)
      is Harbour extension which is not gettext compatible.


      The above implementation is base version but should be fully functional.
      Now we will need functions to safe/read i18n files and tools to mange
      .pot files: merge them, edit translations, create final binary i18n
      translation sets. Because we are using gettext compatible .pot files
      then for some of such jobs we can use original gettext tools but we
      need at least function which will create translation set from one or
      more .pot files.
      We should also agree some default localization(s) for files containing
      translated data, their name convention and environment variable(s)
      to set default language. It's not strictly necessary and each user
      can have his own implementation but it would help in adding new
      translations by final users to any Harbour application which will
      respect them. We can use LANG envvar to extract preferred language
      and use the same path as executed application looking for files
      <appname>-<lang>.hil files though it may create some problems for
      OSes which support only 8.3 file names so we can also define that
      HB_I18N envvar has higher priority and points to expected translation
      file.

  * harbour/include/hbextern.ch
    - removed old __i18n_*() functions
    + added current i18n functions
This commit is contained in:
Przemyslaw Czerpak
2008-12-11 18:47:46 +00:00
parent e0d79bbb7a
commit fa31aa6f70
16 changed files with 1413 additions and 230 deletions

View File

@@ -8,6 +8,243 @@
2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
*/
2008-12-11 19:48 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/include/hbthread.h
* harbour/source/vm/thread.c
+ added hb_atomic_set(), hb_atomic_get(), hb_atomic_inc() and
hb_atomic_dec() functions which operates on HB_COUNTER or smaller
type if it's necessary for some platforms which can be access/assign
increment/decrement in MT safe atom operations.
hb_atomic_dec() returns true if counter is 0 after decrementation
* harbour/include/hbatomic.h
! fixed compilation in Linux and OpenWatcom
* harbour/include/hbapiitm.h
* harbour/source/rtl/itemseri.c
+ make hb_itemSerialize() and hb_itemDeserialize() public functions
! fixed serialization items with internal item references
* harbour/source/vm/hvm.c
* release memvars after closing RDDs
* harbour/source/debug/dbgentry.c
! fixed buffer overflow reported by Rodrigo
* harbour/source/vm/macro.c
* harbour/source/compiler/hbmain.c
* formatting
* harbour/include/hbexprb.c
! fixed wrongly recognized functions with HB_I18N_ prefix as
HB_I18N_GETTEXT()
* harbour/include/hbapi.h
* harbour/include/hbstack.h
* harbour/include/hbthread.h
* harbour/source/vm/estack.c
* harbour/source/vm/thread.c
* harbour/source/vm/hvm.c
+ added support for I18N in HVM.
Each thread can have it's own i18n set.
When new thread is created then it inherits i18n set from parent
thread and both uses the same set (please remember about it if you
will want to make some direct modifications on active i18n set
internals).
When thread change active i18n set then it effects only this thread
and new threads which will be create later. It does not change i18n
in other existing threads.
+ added functions to set/get pointer to active i18n set in HVM
void * hb_vmI18N( void )
void hb_vmSetI18N( void * )
* harbour/include/hbapi.h
* harbour/source/rtl/hbi18n.c
+ added i18n module. Now only for internal Harbour usage without support
for optional switching to alternative implementations.
I'll add such functionality later when I will work on native gettext
support.
The following public .prg functions has been added:
HB_I18N_GETTEXT[_STRICT]( <cMsgID> [, <cContext> ] )
-> <cTranslatedMsgID> | <cMsgID>
HB_I18N_NGETTEXT[_STRICT]( <nValue>, <cMsgID> | <acMsgID> ;
[, <cContext> ] )
-> <cTranslatedMsgID> | <cMsgID> | <acMsgID>[ <nIndex> ]
This is minimal support necessary for .prg code which has to exists
in each i18n module working with Harbour.
The following functions had been added as public C API:
PHB_ITEM hb_i18n_gettext( PHB_ITEM pMsgID, PHB_ITEM pContext )
PHB_ITEM hb_i18n_ngettext( PHB_ITEM pNum,
PHB_ITEM pMsgID, PHB_ITEM pContext )
The following functions had been added as private HVM C API:
void hb_i18n_init( void )
void hb_i18n_exit( void )
void hb_i18n_release( void * cargo )
void * hb_i18n_alloc( void * cargo )
They have to be supported by alternative i18n modules
The following functions has been added to manage Harbour i18n
translations sets:
HB_I18N_CREATE()
-> <pI18N>
Creates new empty I18N translation set
HB_I18N_CODEPAGE( [<pI18N>,] [<cNewCP>], [<lBase>], [<lTranslate>] )
-> <cOldCP>
Gets or sets Harbour codepage used by translation set
<pI18N> - I18N translation set,
if it's not given then currently active I18N set is used
<cNewCP> - new CP ID. Must be linked with application
<lBase> - when it's .T. then get/set base massages CP instead of
translated massages CP
<lTranslate> - if it's .T. then translate base (<lBase>==.T.) or
final messages in I18N set from previous CP to
given one. Base messages translation in synced
with context ID translation.
HB_I18N_PLURALFORM( [<pI18N>,] [<cNewForm>|<bNewForm>], [<lBase>] )
-> <cOldForm>|<bOldForm>
Gets or sets plural form used for final or base messages
<pI18N> - I18N translation set,
if it's not given then currently active I18N set is used
<cNewForm> - language ID of plural form, f.e.: "EN", "PL", "LT".
Now only three above are supported. Please add rules
for other languages to source/rtl/hbi18n.c.
<bNewForm> - codeblock used to calculate plural form indexes.
can be used instead of character representation but
it's not storred in serialized I18N set
<lBase> - when it's .T. then get/set base massages plural form
instead of translated massages one.
HB_I18N_DESCRIPTION( [<pI18N>,] [<cNewDescription>] )
-> <cOldDescription>
Gets or sets translation set description. After serialization
up to 32 bytes is stored in header which can be easy used to
determinate type of translation file.
<pI18N> - I18N translation set,
if it's not given then currently active I18N set is used
<cNewDescription> - new description
HB_I18N_ADDTEXT( <pI18N>, <cMsgID>, <cTrans> | <acTrans> [, <cContext> ] )
-> NIL
Adds new message with translation to i18n translation set
<pI18N> - I18N translation set
<cMsgID> - original message
<cTrans> - translated message
<acTrans> - array with translated messages used for plural forms
<cContext> - message context
HB_I18N_SET( [ <pI18N> | NIL ] )
-> <lActive>
Sets given I18N translation set as default one used by
HB_I18N_[N]GETTEXT[_STRICT]() functions or remove translation
set for calling thread when passed parameter is NIL
<pI18N> - I18N translation set
Returns logical value which is .T. when i18n set is active
HB_I18N_SAVETABLE( [<pI18N>] )
-> <cTable>
Returns I18N translation as string item which can be stored
in file or database
<pI18N> - I18N translation set, if it's not given then currently
active I18N set is used
HB_I18N_RESTORETABLE( <cTable> )
-> <pI18N> | NIL
Restores I18N translation set from strin item.
<cTable> - I18N translation set in string representation
On success it returns new <pI18N> set otherwise NIL if <cTable>
is not valid item created by HB_I18N_SAVETABLE() or it's corrupted.
HB_I18N_HEADERSIZE()
-> <nHeaderSize>
Returns size of header used by i18n serialized version
HB_I18N_CHEK( <cTable> | <cHeader> [, @<cDescription> ] )
-> <lValid>
<cTable> - i18n translation set serialized by HB_I18N_SAVETABLE
<cHeader> - header of i18n translation set
( LEFT( <cTable>, HB_I18N_HEADERSIZE() )
<cDescription> - optional parameter passed by reference where
will be sored i18n translation set description
extracted from valid header
Returns logical value indicating if given table or header is
valid serialized by HB_I18N_SAVETABLE() data. It does not
decode the table though it validates size and control sums.
These functions are optional and some future alternative implementations
may not support all of them and/or may provide some other functions.
+ added unofficial .prg function __I18N_HASHTABLE() which allows to
access hash table used by i18n translation set or create new translation
set with given hash table. It's helper functions for developers which
will work on Harbour i18n tools and should not be used by Harbour users.
Unlike original gettext Harbour allows to use language with many
plural forms as base one. In such case programmer should activate
at application startup default i18n translation set with base plural
form valid for base application language, f.e. by:
pI18N := hb_i18n_create()
hb_i18n_pluralForm( pI18N, <cLangID> | <bForm>, .t. )
hb_i18n_set( pI18N )
.prg code example:
#xtranslate _( <x,...> ) => hb_i18n_gettext_strict( <x> )
#xtranslate _N( <x,...> ) => hb_i18n_ngettext_strict( <x> )
proc main()
local pI18N, i
pI18N := hb_i18n_create()
hb_i18n_pluralForm( pI18N, "PL", .t. )
hb_i18n_set( pI18N )
for i := 0 to 30
? i, _N( i, {"grosz", "grosze", "groszy"} )
if i > 0 .and. i % 10 == 0
wait
endif
next
return
In .pot files created during compilation by Harbour with -j option
for above code we have the following entries for message with plural
forms:
msgid "grosz"
msgid_plural "grosze"
msgid_plural2 "groszy"
msgstr[0] ""
The msgid_plural2 (and others if language has more plural forms)
is Harbour extension which is not gettext compatible.
The above implementation is base version but should be fully functional.
Now we will need functions to safe/read i18n files and tools to mange
.pot files: merge them, edit translations, create final binary i18n
translation sets. Because we are using gettext compatible .pot files
then for some of such jobs we can use original gettext tools but we
need at least function which will create translation set from one or
more .pot files.
We should also agree some default localization(s) for files containing
translated data, their name convention and environment variable(s)
to set default language. It's not strictly necessary and each user
can have his own implementation but it would help in adding new
translations by final users to any Harbour application which will
respect them. We can use LANG envvar to extract preferred language
and use the same path as executed application looking for files
<appname>-<lang>.hil files though it may create some problems for
OSes which support only 8.3 file names so we can also define that
HB_I18N envvar has higher priority and points to expected translation
file.
* harbour/include/hbextern.ch
- removed old __i18n_*() functions
+ added current i18n functions
2008-12-09 12:46 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com)
* harbour/contrib/gtwvg/makefile
* harbour/contrib/gtwvg/common.mak

View File

@@ -1001,6 +1001,19 @@ extern void hb_idleState( void ); /* services a single idle state */
extern void hb_idleReset( void ); /* services a single idle state */
extern void hb_idleSleep( double dSeconds ); /* sleep for a given time serving idle task */
/* I18N public API */
extern PHB_ITEM hb_i18n_ngettext( PHB_ITEM pNum, PHB_ITEM pMsgID, PHB_ITEM pContext );
extern PHB_ITEM hb_i18n_gettext( PHB_ITEM pMsgID, PHB_ITEM pContext );
/* I18N internal HVM API */
#if defined( _HB_API_INTERNAL_ ) || defined( _HB_I18N_INTERNAL_ )
extern void * hb_vmI18N( void );
extern void hb_vmSetI18N( void * );
extern void hb_i18n_init( void );
extern void hb_i18n_exit( void );
extern void hb_i18n_release( void * cargo );
extern void * hb_i18n_alloc( void * cargo );
#endif /* _HB_API_INTERNAL_ || _HB_I18N_INTERNAL_ */
/* misc */
extern HB_EXPORT char * hb_verPlatform( void ); /* retrieves a newly allocated buffer containing platform version */
extern HB_EXPORT char * hb_verCompiler( void ); /* retrieves a newly allocated buffer containing compiler version */

View File

@@ -178,6 +178,9 @@ extern HB_EXPORT PHB_ITEM hb_itemValToStr ( PHB_ITEM pItem ); /* Convert any
extern HB_EXPORT char * hb_itemPadConv ( PHB_ITEM pItem, ULONG * pulSize, BOOL * bFreeReq );
extern HB_EXPORT void hb_itemSwap ( PHB_ITEM pItem1, PHB_ITEM pItem2 );
extern HB_EXPORT char * hb_itemSerialize( PHB_ITEM pItem, BOOL fNumSize, ULONG *pulSize );
extern HB_EXPORT PHB_ITEM hb_itemDeserialize( const char ** pBufferPtr, ULONG * pulSize );
#if defined( _HB_API_INTERNAL_ )
# define hb_itemSetNil( item ) do { \

View File

@@ -63,7 +63,7 @@
#if defined( __SVR4 )
# include <thread.h>
#endif
#if defined( HB_OS_UNIX )
#if defined( HB_OS_UNIX ) && !defined( __WATCOMC__ )
# include <sched.h>
#endif
@@ -258,7 +258,7 @@ HB_EXTERN_BEGIN
# endif /* ???CPU?? */
#endif
#endif /* __GNUC__ */
#if defined( HB_OS_WIN_32 )
@@ -332,7 +332,7 @@ HB_EXTERN_BEGIN
# define HB_SPINLOCK_RELEASE(l) OSSpinLockUnlock(l)
# endif
#endif
#endif /* HB_OS_??? */
HB_EXTERN_END

View File

@@ -1770,10 +1770,10 @@ static HB_EXPR_FUNC( hb_compExprUseFunCall )
else if( strncmp( "HB_I18N_", pName->value.asSymbol, 8 ) == 0 )
{
HB_EXPR_PTR pArg = pParms->value.asList.pExprList, pCount = NULL;
BOOL fStrict, fNoop, fPlural, fUnknown;
BOOL fStrict, fNoop, fPlural, fI18nFunc;
ULONG ulPos = 8;
fStrict = fNoop = fPlural = fUnknown = FALSE;
fStrict = fNoop = fPlural = fI18nFunc = FALSE;
if( pName->value.asSymbol[ ulPos ] == 'N' )
{
fPlural = TRUE;
@@ -1786,16 +1786,14 @@ static HB_EXPR_FUNC( hb_compExprUseFunCall )
{
++ulPos;
if( strcmp( "STRICT", &pName->value.asSymbol[ ulPos ] ) == 0 )
fStrict = TRUE;
fI18nFunc = fStrict = TRUE;
else if( strcmp( "NOOP", &pName->value.asSymbol[ ulPos ] ) == 0 )
fNoop = TRUE;
else
fUnknown = TRUE;
fI18nFunc = fNoop = TRUE;
}
else if( pName->value.asSymbol[ ulPos ] )
fUnknown = TRUE;
else if( !pName->value.asSymbol[ ulPos ] )
fI18nFunc = TRUE;
}
if( !fUnknown )
if( fI18nFunc )
{
int iWarning = 0;
HB_EXPR_PTR pBadParam = NULL;

View File

@@ -543,10 +543,23 @@ EXTERNAL __MVXRELEASE
EXTERNAL __EINSTVAR52
EXTERNAL __EINSTVAR53
EXTERNAL __I18N_SAVE
EXTERNAL __I18N_LOAD
EXTERNAL __I18N_LOADFROMMEMORY
EXTERNAL __I18N_GETTEXT
/* i18n */
EXTERNAL HB_I18N_GETTEXT
EXTERNAL HB_I18N_GETTEXT_STRICT
EXTERNAL HB_I18N_NGETTEXT
EXTERNAL HB_I18N_NGETTEXT_STRICT
EXTERNAL HB_I18N_CREATE
EXTERNAL HB_I18N_CODEPAGE
EXTERNAL HB_I18N_PLURALFORM
EXTERNAL HB_I18N_DESCRIPTION
EXTERNAL HB_I18N_ADDTEXT
EXTERNAL HB_I18N_SET
EXTERNAL HB_I18N_SAVETABLE
EXTERNAL HB_I18N_RESTORETABLE
EXTERNAL HB_I18N_HEADERSIZE
EXTERNAL HB_I18N_CHECK
EXTERNAL __I18N_HASHTABLE
/* The debugger interface */

View File

@@ -168,6 +168,7 @@ typedef struct
char szDate[ 9 ]; /* last returned date from _pards() yyyymmdd format */
void * pCDP; /* current codepage module */
void * pLang; /* current language module */
void * pI18N; /* current I18N module */
void * hGT; /* current GT module */
int iTSD; /* number of allocated TSD holders */
PHB_TSD_HOLDER pTSD; /* thread specific data holder */
@@ -322,6 +323,8 @@ extern void * hb_stackGetCDP( void );
extern void hb_stackSetCDP( void * );
extern void * hb_stackGetLang( void );
extern void hb_stackSetLang( void * );
extern void * hb_stackGetI18N( void );
extern void hb_stackSetI18N( void * );
extern void hb_stackIsStackRef( void *, PHB_TSD_FUNC );
@@ -369,6 +372,8 @@ extern void hb_stackIsStackRef( void *, PHB_TSD_FUNC );
#define hb_stackSetCDP( p ) do { hb_stack.pCDP = ( p ); } while ( 0 )
#define hb_stackGetLang( ) ( hb_stack.pLang )
#define hb_stackSetLang( p ) do { hb_stack.pLang = ( p ); } while ( 0 )
#define hb_stackGetI18N( ) ( hb_stack.pI18N )
#define hb_stackSetI18N( p ) do { hb_stack.pI18N = ( p ); } while ( 0 )
#define hb_stackId( ) ( ( void * ) &hb_stack )
#if defined( HB_MT_VM )

View File

@@ -275,6 +275,7 @@ typedef struct _HB_THREADSTATE
const char * pszLang;
const char * pszDefRDD;
PHB_SET_STRUCT pSet;
void * pI18N;
void * hGT;
void * pStackId;
BOOL fActive;
@@ -295,10 +296,17 @@ extern void hb_threadExit( void );
extern PHB_THREADSTATE hb_threadStateNew( void );
/* atomic oprtations */
void hb_atomic_set( volatile HB_COUNTER * pCounter, HB_COUNTER value );
HB_COUNTER hb_atomic_get( volatile HB_COUNTER * pCounter );
void hb_atomic_inc( volatile HB_COUNTER * pCounter );
BOOL hb_atomic_dec( volatile HB_COUNTER * pCounter ); /* returns TRUE when counter reach after decrementation */
/* Critical sections or fast non recursive MUTEXes */
extern void hb_threadEnterCriticalSection( HB_CRITICAL_T * critical );
extern void hb_threadLeaveCriticalSection( HB_CRITICAL_T * critical );
/* conditional variables */
extern BOOL hb_threadCondSignal( HB_COND_T * cond );
extern BOOL hb_threadCondBroadcast( HB_COND_T * cond );
extern BOOL hb_threadCondWait( HB_COND_T * cond, HB_CRITICAL_T * mutex );

View File

@@ -2388,7 +2388,7 @@ void hb_compGenStaticName( const char *szVarName, HB_COMP_DECL )
BYTE bGlobal = 0;
PFUNCTION pFunc;
int iVar;
if( ! HB_COMP_PARAM->fStartProc && HB_COMP_PARAM->functions.iCount <= 1 )
{
/* Variable declaration is outside of function/procedure body.

View File

@@ -1014,7 +1014,7 @@ static int hb_dbgEvalSubstituteVar( HB_WATCHPOINT *watch, char *szWord, int nSta
t[ nStart + 6 ] = '0' + ( char ) ( ( j + 1 ) / 10 );
t[ nStart + 7 ] = '0' + ( char ) ( ( j + 1 ) % 10 );
t[ nStart + 8 ] = ']';
hb_strncpy( t + nStart + 9, watch->szExpr + nStart + nLen, strlen( watch->szExpr ) - nLen + 1 - nStart );
hb_strncpy( t + nStart + 9, watch->szExpr + nStart + nLen, strlen( watch->szExpr ) - nLen - nStart );
FREE( watch->szExpr );
watch->szExpr = t;
return nStart + 9;

File diff suppressed because it is too large Load Diff

View File

@@ -153,7 +153,7 @@ typedef struct _HB_CYCLIC_REF
struct _HB_CYCLIC_REF * pNext;
} HB_CYCLIC_REF, * PHB_CYCLIC_REF;
static ULONG hb_deserializeItem( PHB_ITEM pItem, UCHAR * pBuffer,
static ULONG hb_deserializeItem( PHB_ITEM pItem, const UCHAR * pBuffer,
ULONG ulOffset, PHB_CYCLIC_REF pRef );
static BOOL hb_itemSerialValueRef( PHB_CYCLIC_REF * pRefPtr, void * value,
@@ -276,6 +276,9 @@ static ULONG hb_itemSerialSize( PHB_ITEM pItem, BOOL fNumSize, PHB_CYCLIC_REF *
USHORT uiClass;
const char * szVal;
if( HB_IS_BYREF( pItem ) )
pItem = hb_itemUnRef( pItem );
switch( hb_itemType( pItem ) )
{
case HB_IT_NIL:
@@ -409,6 +412,9 @@ static ULONG hb_serializeItem( PHB_ITEM pItem, BOOL fNumSize, UCHAR * pBuffer,
const char * szVal;
ULONG ulRef, ulLen, u;
if( HB_IS_BYREF( pItem ) )
pItem = hb_itemUnRef( pItem );
switch( hb_itemType( pItem ) )
{
case HB_IT_NIL:
@@ -701,7 +707,8 @@ static ULONG hb_serializeItem( PHB_ITEM pItem, BOOL fNumSize, UCHAR * pBuffer,
return ulOffset;
}
static ULONG hb_deserializeHash( PHB_ITEM pItem, UCHAR * pBuffer, ULONG ulOffset,
static ULONG hb_deserializeHash( PHB_ITEM pItem,
const UCHAR * pBuffer, ULONG ulOffset,
ULONG ulLen, PHB_CYCLIC_REF pRef )
{
hb_hashNew( pItem );
@@ -740,7 +747,8 @@ static ULONG hb_deserializeHash( PHB_ITEM pItem, UCHAR * pBuffer, ULONG ulOffset
return ulOffset;
}
static ULONG hb_deserializeArray( PHB_ITEM pItem, UCHAR * pBuffer, ULONG ulOffset,
static ULONG hb_deserializeArray( PHB_ITEM pItem,
const UCHAR * pBuffer, ULONG ulOffset,
ULONG ulLen, PHB_CYCLIC_REF pRef )
{
ULONG u;
@@ -753,7 +761,7 @@ static ULONG hb_deserializeArray( PHB_ITEM pItem, UCHAR * pBuffer, ULONG ulOffse
return ulOffset;
}
static ULONG hb_deserializeItem( PHB_ITEM pItem, UCHAR * pBuffer,
static ULONG hb_deserializeItem( PHB_ITEM pItem, const UCHAR * pBuffer,
ULONG ulOffset, PHB_CYCLIC_REF pRef )
{
ULONG ulLen, ulPad;
@@ -953,8 +961,8 @@ static ULONG hb_deserializeItem( PHB_ITEM pItem, UCHAR * pBuffer,
case HB_SERIAL_OBJ:
{
char * szClass, * szFunc;
szClass = ( char * ) &pBuffer[ ulOffset ];
const char * szClass, * szFunc;
szClass = ( const char * ) &pBuffer[ ulOffset ];
ulLen = strlen( szClass );
szFunc = szClass + ulLen + 1;
ulOffset = hb_deserializeItem( pItem, pBuffer,
@@ -971,10 +979,10 @@ static ULONG hb_deserializeItem( PHB_ITEM pItem, UCHAR * pBuffer,
return ulOffset;
}
static BOOL hb_deserializeTest( UCHAR ** pBufferPtr, ULONG * pulSize,
static BOOL hb_deserializeTest( const UCHAR ** pBufferPtr, ULONG * pulSize,
ULONG ulOffset, PHB_CYCLIC_REF * pRefPtr )
{
UCHAR * pBuffer = * pBufferPtr;
const UCHAR * pBuffer = * pBufferPtr;
ULONG ulSize = * pulSize, ulLen = 0;
if( ulSize == 0 )
@@ -1153,9 +1161,9 @@ static BOOL hb_deserializeTest( UCHAR ** pBufferPtr, ULONG * pulSize,
}
/*
* These function will be public in the future [druzus]
* public API functions
*/
static char * hb_itemSerial( PHB_ITEM pItem, BOOL fNumSize, ULONG *pulSize )
char * hb_itemSerialize( PHB_ITEM pItem, BOOL fNumSize, ULONG *pulSize )
{
PHB_CYCLIC_REF pRef = NULL;
ULONG ulSize = hb_itemSerialSize( pItem, fNumSize, &pRef, 0 );
@@ -1172,16 +1180,13 @@ static char * hb_itemSerial( PHB_ITEM pItem, BOOL fNumSize, ULONG *pulSize )
return ( char * ) pBuffer;
}
/*
* These function will be public in the future [druzus]
*/
static PHB_ITEM hb_itemDeserial( char ** pBufferPtr, ULONG * pulSize )
PHB_ITEM hb_itemDeserialize( const char ** pBufferPtr, ULONG * pulSize )
{
PHB_CYCLIC_REF pRef = NULL;
UCHAR * pBuffer = ( UCHAR * ) *pBufferPtr;
const UCHAR * pBuffer = ( const UCHAR * ) *pBufferPtr;
PHB_ITEM pItem = NULL;
if( !pulSize || hb_deserializeTest( ( UCHAR ** ) pBufferPtr, pulSize, 0, &pRef ) )
if( !pulSize || hb_deserializeTest( ( const UCHAR ** ) pBufferPtr, pulSize, 0, &pRef ) )
{
pItem = hb_itemNew( NULL );
hb_deserializeItem( pItem, pBuffer, 0, pRef );
@@ -1198,7 +1203,7 @@ HB_FUNC( HB_SERIALIZE )
if( pItem )
{
ULONG ulSize;
char * pBuffer = hb_itemSerial( pItem, ISLOG( 2 ) && hb_parl( 2 ), &ulSize );
char * pBuffer = hb_itemSerialize( pItem, ISLOG( 2 ) && hb_parl( 2 ), &ulSize );
hb_retclen_buffer( pBuffer, ulSize );
}
}
@@ -1210,9 +1215,9 @@ HB_FUNC( HB_DESERIALIZE )
if( ulSize )
{
char * pBuffer = hb_parc( 1 );
const char * pBuffer = hb_parc( 1 );
pItem = hb_itemDeserial( &pBuffer, &ulSize );
pItem = hb_itemDeserialize( &pBuffer, &ulSize );
if( pItem )
{
hb_itemReturn( pItem );

View File

@@ -945,6 +945,20 @@ void hb_stackSetLang( void * pLang )
hb_stack.pLang = pLang;
}
#undef hb_stackGetI18N
void * hb_stackGetI18N( void )
{
HB_STACK_TLS_PRELOAD
return hb_stack.pI18N;
}
#undef hb_stackSetI18N
void hb_stackSetI18N( void * pI18N )
{
HB_STACK_TLS_PRELOAD
hb_stack.pI18N = pI18N;
}
#undef hb_stackItemBasePtr
PHB_ITEM ** hb_stackItemBasePtr( void )
{

View File

@@ -752,6 +752,9 @@ void hb_vmThreadInit( void * Cargo )
hb_cdpSelectID( pState->pszCDP );
hb_langSelectID( pState->pszLang );
hb_vmSetI18N( pState->pI18N );
pState->pI18N = NULL;
if( pState->pSet )
{
/* TODO: add set sharing */
@@ -814,6 +817,7 @@ void hb_vmThreadQuit( void )
hb_rddCloseAll(); /* close all workareas */
hb_stackRemove( 1 ); /* clear stack items, leave only initial symbol item */
hb_memvarsClear(); /* clear all PUBLIC (and PRIVATE if any) variables */
hb_vmSetI18N( NULL ); /* remove i18n translation table */
#ifndef HB_NO_DEBUG
hb_vmDebuggerExit( FALSE ); /* deactivate debugger */
#endif
@@ -885,6 +889,8 @@ void hb_vmInit( BOOL bStartMainProc )
s_VMFlags = hb_cmdargProcessVM( &s_VMCancelKey, &s_VMCancelKeyEx );
hb_inkeySetCancelKeys( s_VMCancelKey, s_VMCancelKeyEx );
hb_i18n_init(); /* initialize i18n module */
#ifndef HB_NO_PROFILER
/* Initialize opcodes profiler support arrays */
{
@@ -1021,8 +1027,6 @@ int hb_vmQuit( void )
hb_itemClear( hb_stackReturnItem() );
hb_stackRemove( 1 ); /* clear stack items, leave only initial symbol item */
hb_memvarsClear(); /* clear all PUBLIC (and PRIVATE if any) variables */
/* intentionally here to allow executing object destructors for all
* cross referenced items before we release classy subsystem
*/
@@ -1034,7 +1038,12 @@ int hb_vmQuit( void )
hb_stackSetActionRequest( 0 );
hb_rddCloseAll(); /* close all workareas */
hb_rddShutDown(); /* remove all registered RDD drivers */
hb_memvarsClear(); /* clear all PUBLIC (and PRIVATE if any) variables */
hb_vmSetI18N( NULL ); /* remove i18n translation table */
hb_i18n_exit(); /* unregister i18n module */
hb_itemClear( hb_stackReturnItem() );
hb_gcCollectAll( TRUE );
#ifndef HB_NO_DEBUG
/* deactivate debugger */
hb_vmDebuggerExit( TRUE );
@@ -8020,6 +8029,21 @@ void hb_vmSetLang( PHB_LANG pLang )
hb_stackSetLang( ( void * ) pLang );
}
void * hb_vmI18N( void )
{
HB_STACK_TLS_PRELOAD
return hb_stackGetI18N();
}
void hb_vmSetI18N( void * pI18N )
{
HB_STACK_TLS_PRELOAD
hb_i18n_release( hb_stackGetI18N() );
hb_stackSetI18N( pI18N );
}
#if defined( HB_MT_VM )
# define HB_XVM_RETURN \
if( hb_vmThreadRequest ) \

View File

@@ -939,7 +939,7 @@ char * hb_macroGetType( HB_ITEM_PTR pItem )
if( struMacro.pError )
{
ULONG ulGenCode;
ulGenCode = hb_errGetGenCode( struMacro.pError );
if( ulGenCode == EG_NOVAR || ulGenCode == EG_NOALIAS )
{

View File

@@ -59,6 +59,7 @@
#include "hbvmopt.h"
#include "hbthread.h"
#include "hbatomic.h"
#include "hbapiitm.h"
#include "hbapierr.h"
#include "hbapicdp.h"
@@ -196,6 +197,87 @@ ULONG _hb_gettid( void )
}
#endif
/*
* atomic increment/decrement operations
*/
#if !defined( HB_MT_VM )
void hb_atomic_set( volatile HB_COUNTER * pCounter, HB_COUNTER value )
{
*pCounter = value;
}
HB_COUNTER hb_atomic_get( volatile HB_COUNTER * pCounter )
{
return *pCounter;
}
void hb_atomic_inc( volatile HB_COUNTER * pCounter )
{
++( *pCounter );
}
BOOL hb_atomic_dec( volatile HB_COUNTER * pCounter )
{
return --( *pCounter ) == 0;
}
#elif defined( HB_ATOM_INC ) && defined( HB_ATOM_DEC ) && \
defined( HB_ATOM_GET ) && defined( HB_ATOM_SET )
void hb_atomic_set( volatile HB_COUNTER * pCounter, HB_COUNTER value )
{
HB_ATOM_SET( pCounter, value );
}
HB_COUNTER hb_atomic_get( volatile HB_COUNTER * pCounter )
{
return HB_ATOM_GET( pCounter );
}
void hb_atomic_inc( volatile HB_COUNTER * pCounter )
{
HB_ATOM_INC( pCounter );
}
BOOL hb_atomic_dec( volatile HB_COUNTER * pCounter )
{
return HB_ATOM_DEC( pCounter ) == 0;
}
#else
static HB_CRITICAL_NEW( s_atomicMtx );
void hb_atomic_set( volatile HB_COUNTER * pCounter, HB_COUNTER value )
{
/* NOTE: on some platforms it may be necessary to protect this
* by cirtical section, f.e. when HB_COUNTER cannot be accessed
* using single memory access by CPU.
*/
*pCounter = value;
}
HB_COUNTER hb_atomic_get( volatile HB_COUNTER * pCounter )
{
/* NOTE: on some platforms it may be necessary to protect this
* by cirtical section, f.e. when HB_COUNTER cannot be accessed
* using single memory access by CPU.
*/
return *pCounter;
}
void hb_atomic_inc( volatile HB_COUNTER * pCounter )
{
hb_threadEnterCriticalSection( &s_atomicMtx );
++( *pCounter );
hb_threadLeaveCriticalSection( &s_atomicMtx );
}
BOOL hb_atomic_dec( volatile HB_COUNTER * pCounter )
{
BOOL fResult;
hb_threadEnterCriticalSection( &s_atomicMtx );
fResult = --( *pCounter ) == 0;
hb_threadLeaveCriticalSection( &s_atomicMtx );
return fResult;
}
#endif
void hb_threadEnterCriticalSection( HB_CRITICAL_T * critical )
{
#if !defined( HB_MT_VM )
@@ -480,6 +562,11 @@ static HB_GARBAGE_FUNC( hb_threadDestructor )
hb_itemRelease( pThread->pResult );
pThread->pResult = NULL;
}
if( pThread->pI18N )
{
hb_i18n_release( pThread->pI18N );
pThread->pI18N = NULL;
}
if( pThread->pSet )
{
hb_setRelease( pThread->pSet );
@@ -657,6 +744,7 @@ HB_FUNC( HB_THREADSTART )
pThread->pszCDP = hb_cdpID();
pThread->pszLang = hb_langID();
pThread->pI18N = hb_i18n_alloc( hb_vmI18N() );
pThread->pszDefRDD = hb_stackRDD()->szDefaultRDD;
pThread->pSet = hb_setClone( hb_stackSetStruct() );
pThread->pParams = hb_arrayBaseParams();