diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 1b5771f668..b17203cdeb 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,21 @@ 2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org) */ +2009-01-26 21:25 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/source/common/hbprintf.c + * harbour/source/codepage/cpeswinm.c + * harbour/source/rdd/usrrdd/example/exlog.prg + * harbour/source/rdd/usrrdd/rdds/logrdd.prg + * harbour/contrib/xhb/dbgfx.prg + * harbour/contrib/xhb/xhb.h + * harbour/contrib/xhb/sprintf.prg + * harbour/contrib/xhb/dbgfxc.c + * harbour/contrib/xhb/hbstruct.prg + * harbour/contrib/xhb/hbstruct.ch + * harbour/contrib/hbmsql/tests/hbmk_b32.bat + * harbour/contrib/hbmsql/tests/hbmk_vc.bat + ! fixed hardcoded CRLF and svn:eol-style attribute + 2009-01-26 21:18 UTC+0100 Viktor Szakats (harbour.01 syenar hu) * source/common/hbprintf.c ! Some fixes to make it compile under BCC. diff --git a/harbour/contrib/xhb/dbgfx.prg b/harbour/contrib/xhb/dbgfx.prg index 6c406d3ce4..fccef42375 100644 --- a/harbour/contrib/xhb/dbgfx.prg +++ b/harbour/contrib/xhb/dbgfx.prg @@ -1,118 +1,118 @@ -/* - * $Id: dbgfx.prg 9738 2008-10-26 07:10:19Z vszakats $ - */ - -/* - * Harbour Project source code: - * Debug Functions - * - * Copyright 2007-2008 Francesco Saverio Giudice - * www - http://www.harbour-project.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). - * - * As a special exception, the Harbour Project gives permission for - * additional uses of the text contained in its release of Harbour. - * - * The exception is that, if you link the Harbour libraries with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the Harbour library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the Harbour - * Project under the name Harbour. If you copy code from other - * Harbour Project or Free Software Foundation releases into a copy of - * Harbour, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for Harbour, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - * - */ - -#include "common.ch" -#include "fileio.ch" - -STATIC s_lToOutDebug := .T. -STATIC s_lToLogFile := .T. -STATIC s_lEmptyLogFile := .T. - -FUNCTION HB_ToOutDebugOnOff( lOnOff ) - LOCAL lOld := s_lToOutDebug - IF hb_isLogical( lOnOff ) - s_lToOutDebug := lOnOff - ENDIF -RETURN lOld - -PROCEDURE HB_ToOutDebug( ... ) - IF s_lToOutDebug - hb_OutDebug( hb_sprintf( ... ) ) - ENDIF -RETURN - -FUNCTION HB_ToLogFileOnOff( lOnOff ) - LOCAL lOld := s_lToLogFile - IF hb_isLogical( lOnOff ) - s_lToLogFile := lOnOff - ENDIF -RETURN lOld - -FUNCTION HB_EmptyLogFileOnOff( lOnOff ) - LOCAL lOld := s_lEmptyLogFile - IF hb_isLogical( lOnOff ) - s_lEmptyLogFile := lOnOff - ENDIF -RETURN lOld - -PROCEDURE HB_ToLogFile( cLogFile, ... ) - LOCAL nHandle - - IF !s_lToLogFile - RETURN - ENDIF - - DEFAULT cLogFile TO "logfile.log" - - IF cLogFile != NIL - - IF !s_lEmptyLogFile .AND. hb_FileExists( cLogFile ) - nHandle := FOpen( cLogFile, FO_READWRITE + FO_SHARED ) - ELSE - nHandle := FCreate( cLogFile ) - s_lEmptyLogFile := .F. - // After I have create it I have to close and open in shared way - IF FError() == 0 .AND. nHandle != F_ERROR - FClose( nHandle ) - nHandle := FOpen( cLogFile, FO_READWRITE + FO_SHARED ) - ENDIF - ENDIF - - // Writing - IF nHandle != F_ERROR - FSeek( nHandle, 0, FS_END ) - FWrite( nHandle, hb_sprintf( ... ) ) - FWrite( nHandle, HB_OSNewLine() ) - FClose( nHandle ) - ENDIF - ENDIF -RETURN +/* + * $Id: dbgfx.prg 9738 2008-10-26 07:10:19Z vszakats $ + */ + +/* + * Harbour Project source code: + * Debug Functions + * + * Copyright 2007-2008 Francesco Saverio Giudice + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "common.ch" +#include "fileio.ch" + +STATIC s_lToOutDebug := .T. +STATIC s_lToLogFile := .T. +STATIC s_lEmptyLogFile := .T. + +FUNCTION HB_ToOutDebugOnOff( lOnOff ) + LOCAL lOld := s_lToOutDebug + IF hb_isLogical( lOnOff ) + s_lToOutDebug := lOnOff + ENDIF +RETURN lOld + +PROCEDURE HB_ToOutDebug( ... ) + IF s_lToOutDebug + hb_OutDebug( hb_sprintf( ... ) ) + ENDIF +RETURN + +FUNCTION HB_ToLogFileOnOff( lOnOff ) + LOCAL lOld := s_lToLogFile + IF hb_isLogical( lOnOff ) + s_lToLogFile := lOnOff + ENDIF +RETURN lOld + +FUNCTION HB_EmptyLogFileOnOff( lOnOff ) + LOCAL lOld := s_lEmptyLogFile + IF hb_isLogical( lOnOff ) + s_lEmptyLogFile := lOnOff + ENDIF +RETURN lOld + +PROCEDURE HB_ToLogFile( cLogFile, ... ) + LOCAL nHandle + + IF !s_lToLogFile + RETURN + ENDIF + + DEFAULT cLogFile TO "logfile.log" + + IF cLogFile != NIL + + IF !s_lEmptyLogFile .AND. hb_FileExists( cLogFile ) + nHandle := FOpen( cLogFile, FO_READWRITE + FO_SHARED ) + ELSE + nHandle := FCreate( cLogFile ) + s_lEmptyLogFile := .F. + // After I have create it I have to close and open in shared way + IF FError() == 0 .AND. nHandle != F_ERROR + FClose( nHandle ) + nHandle := FOpen( cLogFile, FO_READWRITE + FO_SHARED ) + ENDIF + ENDIF + + // Writing + IF nHandle != F_ERROR + FSeek( nHandle, 0, FS_END ) + FWrite( nHandle, hb_sprintf( ... ) ) + FWrite( nHandle, HB_OSNewLine() ) + FClose( nHandle ) + ENDIF + ENDIF +RETURN diff --git a/harbour/contrib/xhb/dbgfxc.c b/harbour/contrib/xhb/dbgfxc.c index 0460a70115..bc266a291f 100644 --- a/harbour/contrib/xhb/dbgfxc.c +++ b/harbour/contrib/xhb/dbgfxc.c @@ -1,133 +1,133 @@ -/* - * $Id: dbgfxc.c 9838 2008-11-05 02:01:15Z druzus $ - */ - -/* - * Harbour Project source code: - * Debug Functions - * - * Copyright 2007-2008 Francesco Saverio Giudice - * www - http://www.harbour-project.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). - * - * As a special exception, the Harbour Project gives permission for - * additional uses of the text contained in its release of Harbour. - * - * The exception is that, if you link the Harbour libraries with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the Harbour library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the Harbour - * Project under the name Harbour. If you copy code from other - * Harbour Project or Free Software Foundation releases into a copy of - * Harbour, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for Harbour, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - * - */ - -#include "hbapi.h" -#include "hbapiitm.h" -#include "hbapifs.h" - -#include "xhb.h" - -static BOOL s_bToOutputDebug = TRUE; -static BOOL s_bToLogFile = TRUE; - -static BOOL s_bEmptyLogFile = TRUE; - -BOOL hb_ToOutDebugOnOff( BOOL bOnOff ) -{ - BOOL bOld = s_bToOutputDebug; - s_bToOutputDebug = bOnOff; - return bOld; -} - -void hb_ToOutDebug( const char * sTraceMsg, ... ) -{ - if( sTraceMsg && s_bToOutputDebug ) - { - char buffer[ 1024 ]; - va_list ap; - - va_start( ap, sTraceMsg ); - vsnprintf( buffer, sizeof( buffer ), sTraceMsg, ap ); - va_end( ap ); - - hb_OutDebug( ( const char * ) buffer, strlen( buffer ) ); - } -} - -BOOL hb_ToLogFileOnOff( BOOL bOnOff ) -{ - BOOL bOld = s_bToLogFile; - s_bToLogFile = bOnOff; - return bOld; -} - -BOOL hb_EmptyLogFile( BOOL bOnOff ) -{ - BOOL bOld = s_bEmptyLogFile; - s_bEmptyLogFile = bOnOff; - return bOld; -} - -void hb_ToLogFile( const char * sFile, const char * sTraceMsg, ... ) -{ - if( s_bToLogFile ) - { - FILE * hFile; - - if( sFile == NULL ) - { - if( s_bEmptyLogFile ) - { - s_bEmptyLogFile = FALSE; - - /* Empty the file if it exists. */ - hFile = hb_fopen( "logfile.log", "w" ); - } - else - hFile = hb_fopen( "logfile.log", "a" ); - } - else - hFile = hb_fopen( sFile, "a" ); - - if( hFile ) - { - va_list ap; - - va_start( ap, sTraceMsg ); - vfprintf( hFile, sTraceMsg, ap ); - va_end( ap ); - - fclose( hFile ); - } - } -} - +/* + * $Id: dbgfxc.c 9838 2008-11-05 02:01:15Z druzus $ + */ + +/* + * Harbour Project source code: + * Debug Functions + * + * Copyright 2007-2008 Francesco Saverio Giudice + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbapi.h" +#include "hbapiitm.h" +#include "hbapifs.h" + +#include "xhb.h" + +static BOOL s_bToOutputDebug = TRUE; +static BOOL s_bToLogFile = TRUE; + +static BOOL s_bEmptyLogFile = TRUE; + +BOOL hb_ToOutDebugOnOff( BOOL bOnOff ) +{ + BOOL bOld = s_bToOutputDebug; + s_bToOutputDebug = bOnOff; + return bOld; +} + +void hb_ToOutDebug( const char * sTraceMsg, ... ) +{ + if( sTraceMsg && s_bToOutputDebug ) + { + char buffer[ 1024 ]; + va_list ap; + + va_start( ap, sTraceMsg ); + vsnprintf( buffer, sizeof( buffer ), sTraceMsg, ap ); + va_end( ap ); + + hb_OutDebug( ( const char * ) buffer, strlen( buffer ) ); + } +} + +BOOL hb_ToLogFileOnOff( BOOL bOnOff ) +{ + BOOL bOld = s_bToLogFile; + s_bToLogFile = bOnOff; + return bOld; +} + +BOOL hb_EmptyLogFile( BOOL bOnOff ) +{ + BOOL bOld = s_bEmptyLogFile; + s_bEmptyLogFile = bOnOff; + return bOld; +} + +void hb_ToLogFile( const char * sFile, const char * sTraceMsg, ... ) +{ + if( s_bToLogFile ) + { + FILE * hFile; + + if( sFile == NULL ) + { + if( s_bEmptyLogFile ) + { + s_bEmptyLogFile = FALSE; + + /* Empty the file if it exists. */ + hFile = hb_fopen( "logfile.log", "w" ); + } + else + hFile = hb_fopen( "logfile.log", "a" ); + } + else + hFile = hb_fopen( sFile, "a" ); + + if( hFile ) + { + va_list ap; + + va_start( ap, sTraceMsg ); + vfprintf( hFile, sTraceMsg, ap ); + va_end( ap ); + + fclose( hFile ); + } + } +} + diff --git a/harbour/contrib/xhb/hbstruct.ch b/harbour/contrib/xhb/hbstruct.ch index 9c5e05568a..cea7de9190 100644 --- a/harbour/contrib/xhb/hbstruct.ch +++ b/harbour/contrib/xhb/hbstruct.ch @@ -1,82 +1,82 @@ -/* - * $Id: hbstruct.ch 9505 2008-09-25 11:16:49Z toninhofwi $ - */ - -/* - * Harbour Project source code: - * Header file for cross-compatibility between different Harbour flavours - * - * Copyright 1999-2007 {list of individual authors and e-mail addresses} - * www - http://www.harbour-project.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). - * - * As a special exception, the Harbour Project gives permission for - * additional uses of the text contained in its release of Harbour. - * - * The exception is that, if you link the Harbour libraries with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the Harbour library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the Harbour - * Project under the name Harbour. If you copy code from other - * Harbour Project or Free Software Foundation releases into a copy of - * Harbour, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for Harbour, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - * - */ - -#ifndef _H_STRUCTURE -#define _H_STRUCTURE - -#xcommand STRUCTURE ; - => ; - #ifdef _TSTRUCT_ ;; - #undef _TSTRUCT_ ;; - #endif ;; - #define _TSTRUCT_ ;; - := HB_Hash() ;; - HB_HCaseMatch( , .f. ) - -#xcommand MEMBER ; - [ AS ] ; - [ INIT ] ; - => ; - HB_HashAddMember( {<(cName)>}, <(type)>, , _TSTRUCT_ ) - -#xcommand MEMBER ; - [ AS ] ; - [ INIT ] ; - => ; - HB_HashAddMember( {<(cName)>}, <(type)>, , _TSTRUCT_ ) - -#xcommand ENDSTRUCTURE => HB_HAutoAdd( _TSTRUCT_, .f. ) - - -#translate DESTROY STRUCTURE => := nil - -#endif +/* + * $Id: hbstruct.ch 9505 2008-09-25 11:16:49Z toninhofwi $ + */ + +/* + * Harbour Project source code: + * Header file for cross-compatibility between different Harbour flavours + * + * Copyright 1999-2007 {list of individual authors and e-mail addresses} + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef _H_STRUCTURE +#define _H_STRUCTURE + +#xcommand STRUCTURE ; + => ; + #ifdef _TSTRUCT_ ;; + #undef _TSTRUCT_ ;; + #endif ;; + #define _TSTRUCT_ ;; + := HB_Hash() ;; + HB_HCaseMatch( , .f. ) + +#xcommand MEMBER ; + [ AS ] ; + [ INIT ] ; + => ; + HB_HashAddMember( {<(cName)>}, <(type)>, , _TSTRUCT_ ) + +#xcommand MEMBER ; + [ AS ] ; + [ INIT ] ; + => ; + HB_HashAddMember( {<(cName)>}, <(type)>, , _TSTRUCT_ ) + +#xcommand ENDSTRUCTURE => HB_HAutoAdd( _TSTRUCT_, .f. ) + + +#translate DESTROY STRUCTURE => := nil + +#endif diff --git a/harbour/contrib/xhb/hbstruct.prg b/harbour/contrib/xhb/hbstruct.prg index 99740f1fc8..61c92c124d 100644 --- a/harbour/contrib/xhb/hbstruct.prg +++ b/harbour/contrib/xhb/hbstruct.prg @@ -1,120 +1,120 @@ -/* - * $Id: hbstruct.ch 9505 2008-09-25 11:16:49Z toninhofwi $ - */ - -/* - * Harbour Project source code: - * Header file for cross-compatibility between different Harbour flavours - * - * Copyright 1999-2007 {list of individual authors and e-mail addresses} - * www - http://www.harbour-project.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). - * - * As a special exception, the Harbour Project gives permission for - * additional uses of the text contained in its release of Harbour. - * - * The exception is that, if you link the Harbour libraries with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the Harbour library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the Harbour - * Project under the name Harbour. If you copy code from other - * Harbour Project or Free Software Foundation releases into a copy of - * Harbour, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for Harbour, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - * - */ - -procedure HB_HashAddMember( aName, cType, uInit, oObj ) - - local cName - - if !( cType == nil ) - - switch Upper( Left( cType, 1 ) ) - - case "S" // STRING - - if uInit == nil - uInit = "" - endif - - exit - - case "N" // NUMERIC - - if uInit == nil - uInit = 0 - endif - - exit - - case "L" // LOGICAL - - if uInit == nil - uInit = .f. - endif - - exit - - case "D" // DATE - - if uInit == nil - uInit = CtoD( "" ) - endif - - exit - - case "C" // CODEBLOCK - - if uInit == nil - uInit = { || nil } - endif - - exit - - case "A" // ARRAY - - if uInit == nil - uInit = {} - endif - - exit - - case "O" // OBJECT - exit - - end switch - - endif - - for each cName in aName - oObj[ cName ] = uInit - next - -return +/* + * $Id: hbstruct.ch 9505 2008-09-25 11:16:49Z toninhofwi $ + */ + +/* + * Harbour Project source code: + * Header file for cross-compatibility between different Harbour flavours + * + * Copyright 1999-2007 {list of individual authors and e-mail addresses} + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +procedure HB_HashAddMember( aName, cType, uInit, oObj ) + + local cName + + if !( cType == nil ) + + switch Upper( Left( cType, 1 ) ) + + case "S" // STRING + + if uInit == nil + uInit = "" + endif + + exit + + case "N" // NUMERIC + + if uInit == nil + uInit = 0 + endif + + exit + + case "L" // LOGICAL + + if uInit == nil + uInit = .f. + endif + + exit + + case "D" // DATE + + if uInit == nil + uInit = CtoD( "" ) + endif + + exit + + case "C" // CODEBLOCK + + if uInit == nil + uInit = { || nil } + endif + + exit + + case "A" // ARRAY + + if uInit == nil + uInit = {} + endif + + exit + + case "O" // OBJECT + exit + + end switch + + endif + + for each cName in aName + oObj[ cName ] = uInit + next + +return diff --git a/harbour/contrib/xhb/sprintf.prg b/harbour/contrib/xhb/sprintf.prg index e057ea49b7..d1b53897a5 100644 --- a/harbour/contrib/xhb/sprintf.prg +++ b/harbour/contrib/xhb/sprintf.prg @@ -1,207 +1,207 @@ -/* - * $Id: sprintf.prg 9693 2008-10-20 06:47:13Z vszakats $ - */ - -/* - * xHarbour Project source code: - * hb_sprintf() function - * - * Copyright 2003 Mauricio Abre - * www - http://www.xharbour.org - * www - http://www.harbour-project.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). - * - * As a special exception, the Harbour Project gives permission for - * additional uses of the text contained in its release of Harbour. - * - * The exception is that, if you link the Harbour libraries with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the Harbour library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the Harbour - * Project under the name Harbour. If you copy code from other - * Harbour Project or Free Software Foundation releases into a copy of - * Harbour, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for Harbour, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - * - */ - -#include "common.ch" - -FUNCTION hb_sprintf( ... ) - LOCAL aPar, cReturn, nPar, nPos, cTok - LOCAL nLen := 0, lUnsigned, l0 := .F., lSign := .F., nDec, xVal - LOCAL cString - - aPar := HB_aParams() - cReturn := "" - cString := aPar[1] - nPar := 2 - - DO WHILE !Empty( cString ) - - nPos := Len( cString ) + 1 - cTok := NIL - - IF '%' $ cString - nPos := At( '%', cString ) - cTok := '%' - ENDIF - IF '\' $ cString .AND. At( '\', cString ) < nPos - nPos := At( '\', cString ) - cTok := '\' - ENDIF - - cReturn += Left( cString, nPos - 1 ) - - DO CASE - CASE cTok == NIL - EXIT - - CASE cTok == '\' - - SWITCH SubStr( cString, ++nPos, 1 ) - CASE 't' - cReturn += ' ' - EXIT - - CASE 'n' - cReturn += Chr( 13 ) - EXIT - - CASE 'r' - cReturn += Chr( 10 ) - EXIT - - OTHERWISE - cReturn += SubStr( cString, nPos, 1 ) - EXIT - ENDSWITCH - - CASE cTok == '%' - lUnsigned := .F. - - SWITCH SubStr( cString, ++nPos, 1 ) - CASE '%' - cReturn += '%' - EXIT - - CASE '+' - cString := Left( cString, nPos - 1 ) + SubStr( cString, nPos + 1 ) - nPos := At( '%', cString ) - 1 - lSign := .T. - EXIT - - CASE '0' - cString := Left( cString, nPos - 1 ) + SubStr( cString, nPos + 1 ) - nPos := At( '%', cString ) - 1 - l0 := .T. - EXIT - - CASE '1' - CASE '2' - CASE '3' - CASE '4' - CASE '5' - CASE '6' - CASE '7' - CASE '8' - CASE '9' - nLen := Val( SubStr( cString, nPos ) ) - cTok := Left( cString, nPos - 1 ) - DO WHILE SubStr( cString, nPos, 1 ) $ '1234567890.' - nPos++ - ENDDO - cString := cTok + SubStr( cString, nPos ) - nPos := At( '%', cString ) - 1 - EXIT - - CASE 'u' - lUnsigned := .T. - nPos++ - - CASE 'd' - CASE 'l' - CASE 'f' - CASE 'i' - xVal := aPar[nPar++] - IF !ISNUMBER( xVal ) - xVal := 0 - ENDIF - IF nLen != 0 - IF nLen - Int( nLen ) > 0.0 - nDec := Str( nLen ) - DO WHILE Right( nDec, 1 ) == '0' - nDec := Left( nDec, Len( nDec ) - 1 ) - END - nDec := Val( SubStr( nDec, At( '.', nDec ) + 1 ) ) - ELSE - nDec := 0 - ENDIF - cTok := Str( IIF( lUnsigned, Abs( xVal ), xVal ), nLen, nDec ) - ELSE - cTok := hb_NToS( IIF( lUnsigned, Abs( xVal ), xVal ) ) - ENDIF - IF l0 - IF '-' $ cTok .AND. Left( cTok, 1 ) != '-' - cTok := StrTran( cTok, '-', ' ' ) - cTok := '-' + SubStr( cTok, 2 ) - ENDIF - cTok := StrTran( cTok, ' ', '0' ) - l0 := .F. - ENDIF - IF lSign .AND. Left( cTok, 1 ) != '-' - IF nLen == 0 - cTok := '+' + cTok - ELSE - cTok := '+' + SubStr( cTok, 2 ) - ENDIF - lSign := .F. - ENDIF - nLen := 0 - cReturn += cTok - EXIT - - CASE 'c' - CASE 's' - IF nLen == 0 - nLen := Len( hb_cStr( aPar[nPar] ) ) - ENDIF - cReturn += PadL( hb_cStr( aPar[nPar++] ), nLen ) - nLen := 0 - l0 := .F. - lSign := .F. - EXIT - - ENDSWITCH - ENDCASE - - cString := SubStr( cString, nPos + 1 ) - ENDDO - -RETURN cReturn +/* + * $Id: sprintf.prg 9693 2008-10-20 06:47:13Z vszakats $ + */ + +/* + * xHarbour Project source code: + * hb_sprintf() function + * + * Copyright 2003 Mauricio Abre + * www - http://www.xharbour.org + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "common.ch" + +FUNCTION hb_sprintf( ... ) + LOCAL aPar, cReturn, nPar, nPos, cTok + LOCAL nLen := 0, lUnsigned, l0 := .F., lSign := .F., nDec, xVal + LOCAL cString + + aPar := HB_aParams() + cReturn := "" + cString := aPar[1] + nPar := 2 + + DO WHILE !Empty( cString ) + + nPos := Len( cString ) + 1 + cTok := NIL + + IF '%' $ cString + nPos := At( '%', cString ) + cTok := '%' + ENDIF + IF '\' $ cString .AND. At( '\', cString ) < nPos + nPos := At( '\', cString ) + cTok := '\' + ENDIF + + cReturn += Left( cString, nPos - 1 ) + + DO CASE + CASE cTok == NIL + EXIT + + CASE cTok == '\' + + SWITCH SubStr( cString, ++nPos, 1 ) + CASE 't' + cReturn += ' ' + EXIT + + CASE 'n' + cReturn += Chr( 13 ) + EXIT + + CASE 'r' + cReturn += Chr( 10 ) + EXIT + + OTHERWISE + cReturn += SubStr( cString, nPos, 1 ) + EXIT + ENDSWITCH + + CASE cTok == '%' + lUnsigned := .F. + + SWITCH SubStr( cString, ++nPos, 1 ) + CASE '%' + cReturn += '%' + EXIT + + CASE '+' + cString := Left( cString, nPos - 1 ) + SubStr( cString, nPos + 1 ) + nPos := At( '%', cString ) - 1 + lSign := .T. + EXIT + + CASE '0' + cString := Left( cString, nPos - 1 ) + SubStr( cString, nPos + 1 ) + nPos := At( '%', cString ) - 1 + l0 := .T. + EXIT + + CASE '1' + CASE '2' + CASE '3' + CASE '4' + CASE '5' + CASE '6' + CASE '7' + CASE '8' + CASE '9' + nLen := Val( SubStr( cString, nPos ) ) + cTok := Left( cString, nPos - 1 ) + DO WHILE SubStr( cString, nPos, 1 ) $ '1234567890.' + nPos++ + ENDDO + cString := cTok + SubStr( cString, nPos ) + nPos := At( '%', cString ) - 1 + EXIT + + CASE 'u' + lUnsigned := .T. + nPos++ + + CASE 'd' + CASE 'l' + CASE 'f' + CASE 'i' + xVal := aPar[nPar++] + IF !ISNUMBER( xVal ) + xVal := 0 + ENDIF + IF nLen != 0 + IF nLen - Int( nLen ) > 0.0 + nDec := Str( nLen ) + DO WHILE Right( nDec, 1 ) == '0' + nDec := Left( nDec, Len( nDec ) - 1 ) + END + nDec := Val( SubStr( nDec, At( '.', nDec ) + 1 ) ) + ELSE + nDec := 0 + ENDIF + cTok := Str( IIF( lUnsigned, Abs( xVal ), xVal ), nLen, nDec ) + ELSE + cTok := hb_NToS( IIF( lUnsigned, Abs( xVal ), xVal ) ) + ENDIF + IF l0 + IF '-' $ cTok .AND. Left( cTok, 1 ) != '-' + cTok := StrTran( cTok, '-', ' ' ) + cTok := '-' + SubStr( cTok, 2 ) + ENDIF + cTok := StrTran( cTok, ' ', '0' ) + l0 := .F. + ENDIF + IF lSign .AND. Left( cTok, 1 ) != '-' + IF nLen == 0 + cTok := '+' + cTok + ELSE + cTok := '+' + SubStr( cTok, 2 ) + ENDIF + lSign := .F. + ENDIF + nLen := 0 + cReturn += cTok + EXIT + + CASE 'c' + CASE 's' + IF nLen == 0 + nLen := Len( hb_cStr( aPar[nPar] ) ) + ENDIF + cReturn += PadL( hb_cStr( aPar[nPar++] ), nLen ) + nLen := 0 + l0 := .F. + lSign := .F. + EXIT + + ENDSWITCH + ENDCASE + + cString := SubStr( cString, nPos + 1 ) + ENDDO + +RETURN cReturn diff --git a/harbour/contrib/xhb/xhb.h b/harbour/contrib/xhb/xhb.h index 19ca2ea0e4..cd7df28c4d 100644 --- a/harbour/contrib/xhb/xhb.h +++ b/harbour/contrib/xhb/xhb.h @@ -1,73 +1,73 @@ -/* - * $Id: hbcompat.h 9702 2008-10-21 20:19:00Z druzus $ - */ - -/* - * Harbour Project source code: - * Header file for C functions in xhb contrib folder - * - * Copyright 2008 {list of individual authors and e-mail addresses} - * www - http://www.harbour-project.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). - * - * As a special exception, the Harbour Project gives permission for - * additional uses of the text contained in its release of Harbour. - * - * The exception is that, if you link the Harbour libraries with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the Harbour library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the Harbour - * Project under the name Harbour. If you copy code from other - * Harbour Project or Free Software Foundation releases into a copy of - * Harbour, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for Harbour, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - * - */ - -#ifndef HB_XHB_H_ -#define HB_XHB_H_ - -#include "hbsetup.h" - -HB_EXTERN_BEGIN - -/* functions in hboutdbg.c */ -extern HB_EXPORT BOOL hb_OutDebugName( PHB_ITEM pName ); -extern HB_EXPORT void hb_OutDebug( const char * szMsg, ULONG ulMsgLen ); - -/* functions in dbgfxc.c */ -extern HB_EXPORT BOOL hb_ToOutDebugOnOff( BOOL bOnOff ); -extern HB_EXPORT void hb_ToOutDebug( const char * sTraceMsg, ... ); -extern HB_EXPORT BOOL hb_ToLogFileOnOff( BOOL bOnOff ); -extern HB_EXPORT BOOL hb_EmptyLogFile( BOOL bOnOff ); -extern HB_EXPORT void hb_ToLogFile( const char * sFile, const char * sTraceMsg, ... ); - -HB_EXTERN_END - -#endif +/* + * $Id: hbcompat.h 9702 2008-10-21 20:19:00Z druzus $ + */ + +/* + * Harbour Project source code: + * Header file for C functions in xhb contrib folder + * + * Copyright 2008 {list of individual authors and e-mail addresses} + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef HB_XHB_H_ +#define HB_XHB_H_ + +#include "hbsetup.h" + +HB_EXTERN_BEGIN + +/* functions in hboutdbg.c */ +extern HB_EXPORT BOOL hb_OutDebugName( PHB_ITEM pName ); +extern HB_EXPORT void hb_OutDebug( const char * szMsg, ULONG ulMsgLen ); + +/* functions in dbgfxc.c */ +extern HB_EXPORT BOOL hb_ToOutDebugOnOff( BOOL bOnOff ); +extern HB_EXPORT void hb_ToOutDebug( const char * sTraceMsg, ... ); +extern HB_EXPORT BOOL hb_ToLogFileOnOff( BOOL bOnOff ); +extern HB_EXPORT BOOL hb_EmptyLogFile( BOOL bOnOff ); +extern HB_EXPORT void hb_ToLogFile( const char * sFile, const char * sTraceMsg, ... ); + +HB_EXTERN_END + +#endif diff --git a/harbour/source/common/hbprintf.c b/harbour/source/common/hbprintf.c index 8056320103..aa97f41176 100644 --- a/harbour/source/common/hbprintf.c +++ b/harbour/source/common/hbprintf.c @@ -1,1087 +1,1087 @@ -/* - * $Id: dbfnsx1.c 10062 2009-01-17 02:35:29Z druzus $ - */ - -/* - * Harbour Project source code: - * hb_sprintf() function. - * - * Copyright 2008 Przemyslaw Czerpak - * www - http://www.harbour-project.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). - * - * As a special exception, the Harbour Project gives permission for - * additional uses of the text contained in its release of Harbour. - * - * The exception is that, if you link the Harbour libraries with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the Harbour library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the Harbour - * Project under the name Harbour. If you copy code from other - * Harbour Project or Free Software Foundation releases into a copy of - * Harbour, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for Harbour, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - * - */ - -#if 0 - -/* -patterm format: - '%' [*] [] [.] [] - - */ - -/* -The folowwing conversions are not explicitly supported: - A, a - E, e - G, g - These are (long) double conversions. If necessary they can be easy added. - Now they are simply redirected to F, f conversions. - - C (or Lc) - S (or Ls) - These are wide character conversions and needs locale settings. - -double conversion if not necessary can be disabled to not create unnencessary -overhead and/or references to math library by - #define __NO_DOUBLE__ -It can be also greatly optimized anyhow it will increase dependences list and -reduce portability. -Internally 'long double' is used for all calculations. If some platforms do -not support it then it can be eliminated by - #define __NO_LONGDOUBLE__ - -If positional parameters are not necessary then support for them can be -disabled by - #define __NO_ARGPOS__ -In such case this code neither allocates memory nor extensively use stack -as memory buffer. All conversions are done "on the fly". If memory -allocations or stack size is not a problem then some parts can be easy -optimized. -*/ - -/* #define __NO_DOUBLE__ */ -/* #define __NO_LONGDOUBLE__ */ -/* #define __NO_ARGPOS__ */ -/* #define __NO_LONGLONG__ */ - -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#if defined(__DJGPP__) -# include -_LIB_VERSION_TYPE _LIB_VERSION = _XOPEN_; -#else -# include -#endif - -#include "hbmath.h" - -#include -#if defined( __GNUC__ ) -#include -#endif -#include -#include -#ifndef __NO_ARGPOS__ -# include /* malloc()/realloc()/free() */ -#endif - -#if defined(__cplusplus) -# define _EXTERN_C extern "C" -#else -# define _EXTERN_C extern -#endif - -#if defined( __GNUC__ ) -_EXTERN_C int hb_snprintf_c( char *buffer, size_t bufsize, const char *format, ... ) - __attribute__ (( format (printf, 3, 4))); -#else - -#define strnlen( s, maxlen ) \ - ( { size_t n = maxlen, size = 0; \ - while( n < maxlen && s[ size ] ) \ - ++size; \ - size; \ - } ) - -#endif - -#define _F_ALTERNATE 0x01 /* only for: o xX aA eE fF gG */ -#define _F_ZEROPADED 0x02 /* only for: d i o u xX aA eE fF gG */ -#define _F_LEFTADJUSTED 0x04 /* clears _F_ZEROPADED */ -#define _F_SPACE 0x08 /* only for signed num conversions: d i fF aA eE gG */ -#define _F_SIGN 0x10 /* only for signed num conversions: d i fF aA eE gG, clears _F_SPACE */ - -#define _ARGBUF_SIZE 16 - -#define _L_UNDEF_ 0 -#define _L_CHAR_ 1 -#define _L_SHORT_ 2 -#define _L_LONG_ 3 -#define _L_LONGLONG_ 4 -#define _L_INTMAX_ 5 -#define _L_SIZE_ 6 -#define _L_PTRDIFF_ 7 -#define _L_DOUBLE_ 8 -#define _L_LONGDOUBLE_ 9 - -#ifndef __NO_DOUBLE__ -# ifndef __NO_LONGDOUBLE__ -# define _x_long_dbl long double -# define _POWD( x, y ) powl( x, y ) -# define _MODFD( x, p ) modfl( x, p ) -# else -# define _x_long_dbl double -# define _POWD( x, y ) pow( x, y ) -# define _MODFD( x, p ) modf( x, p ) -# endif -# define _x_double double -#else -# define _x_long_dbl int -# define _x_double int -#endif -#ifndef __NO_LONGLONG__ -# define _x_longlong long long -# define _x_ulonglong unsigned long long -#else -# define _x_longlong long -# define _x_ulonglong unsigned long -#endif -#define _x_int int -#define _x_uint unsigned int -#define _x_ulong unsigned long -#define _x_long long -#define _x_intmax_t intmax_t -#define _x_uintmax_t uintmax_t -#define _x_size_t size_t -#define _x_ptrdiff_t ptrdiff_t -#define _x_ptr void * -#define _x_str char * -#define _x_intptr int * - -#define v_x_int 1 -#define v_x_uint 2 -#define v_x_long 3 -#define v_x_ulong 4 -#define v_x_longlong 5 -#define v_x_ulonglong 6 -#define v_x_intmax_t 7 -#define v_x_uintmax_t 8 -#define v_x_size_t 9 -#define v_x_ptrdiff_t 10 -#define v_x_ptr 11 -#define v_x_str 12 -#define v_x_intptr 13 -#define v_x_double 14 -#define v_x_long_dbl 15 - -typedef union { - _x_int as_x_int; - _x_uint as_x_uint; - _x_long as_x_long; - _x_ulong as_x_ulong; - _x_longlong as_x_longlong; - _x_ulonglong as_x_ulonglong; - _x_intmax_t as_x_intmax_t; - _x_uintmax_t as_x_uintmax_t; - _x_size_t as_x_size_t; - _x_ptrdiff_t as_x_ptrdiff_t; - _x_ptr as_x_ptr; - _x_str as_x_str; - _x_intptr as_x_intptr; - _x_double as_x_double; - _x_long_dbl as_x_long_dbl; -} x_type; - -typedef struct { - int id; - x_type value; -} v_param; - -#ifdef __NO_ARGPOS__ - -/* this version does not support positional parameters (f.e. '%1$d') - * they can be added but it will force allocating additional - * memory block in heap or stack and making second pass for - * format decoding/coping. - * so we will use only this simple macro which ignores parameter - * positions. - */ -#define va_arg_n( va, type, n ) va_arg( va, type ) - -/* on some systems where each parameter allocates memory with - * the same size in function stack frame this simple macro can - * be used. - */ - -/* -#define va_arg_n( va, type, n ) \ - ( { \ - type result; \ - if( n == 0 ) \ - result = va_arg( va, type ); \ - else \ - { \ - int count = (n); \ - va_list ap; \ - va_start( ap, format ); \ - do \ - result = va_arg( ap, type ); \ - while( --count > 0 ); \ - va_end( ap ); \ - } \ - result; \ - } ) -*/ - -#else - -#define va_arg_n( va, type, n ) \ - ( { \ - type result; \ - if( n == 0 ) \ - { \ - result = va_arg( va, type ); \ - } \ - else \ - { \ - if( maxarg == 0 ) \ - { \ - repeat = 1; \ - memset( argbuf, 0, sizeof( argbuf ) ); \ - } \ - if( repeat ) \ - { \ - if( n > maxarg ) \ - maxarg = n; \ - if( n > argbuf_size ) \ - { \ - int prev_size = argbuf_size; \ - argbuf_size = n + _ARGBUF_SIZE; \ - if( argbuf_size == _ARGBUF_SIZE ) \ - arglst = memcpy( malloc( argbuf_size * sizeof( v_param ) ), \ - argbuf, sizeof( argbuf ) ); \ - else \ - arglst = realloc( arglst, argbuf_size * sizeof( v_param ) ); \ - memset( &arglst[ prev_size ], 0, ( argbuf_size - prev_size ) * \ - sizeof( v_param ) ); \ - argbuf_size += _ARGBUF_SIZE; \ - } \ - arglst[ n - 1 ].id = (v##type); \ - result = ( type ) 0; \ - } \ - else \ - { \ - result = arglst[ n - 1 ].value.as##type; \ - } \ - } \ - result; \ - } ) - -#define va_arg_fill( va ) \ - do { \ - int iArg; \ - va_start( va, format ); \ - for( iArg = 0; iArg < maxarg; ++iArg ) \ - { \ - switch( arglst[ iArg ].id ) \ - { \ - case v_x_uint: \ - arglst[ iArg ].value.as_x_uint = va_arg( va, _x_uint ); \ - break; \ - case v_x_long: \ - arglst[ iArg ].value.as_x_long = va_arg( va, _x_long ); \ - break; \ - case v_x_ulong: \ - arglst[ iArg ].value.as_x_ulong = va_arg( va, _x_ulong ); \ - break; \ - case v_x_longlong: \ - arglst[ iArg ].value.as_x_longlong = va_arg( va, _x_longlong ); \ - break; \ - case v_x_ulonglong: \ - arglst[ iArg ].value.as_x_ulonglong = va_arg( va, _x_ulonglong ); \ - break; \ - case v_x_intmax_t: \ - arglst[ iArg ].value.as_x_intmax_t = va_arg( va, _x_intmax_t ); \ - break; \ - case v_x_uintmax_t: \ - arglst[ iArg ].value.as_x_uintmax_t = va_arg( va, _x_uintmax_t ); \ - break; \ - case v_x_size_t: \ - arglst[ iArg ].value.as_x_size_t = va_arg( va, _x_size_t ); \ - break; \ - case v_x_ptrdiff_t: \ - arglst[ iArg ].value.as_x_ptrdiff_t = va_arg( va, _x_ptrdiff_t ); \ - break; \ - case v_x_ptr: \ - arglst[ iArg ].value.as_x_ptr = va_arg( va, _x_ptr ); \ - break; \ - case v_x_str: \ - arglst[ iArg ].value.as_x_str = va_arg( va, _x_str ); \ - break; \ - case v_x_intptr: \ - arglst[ iArg ].value.as_x_intptr = va_arg( va, _x_intptr ); \ - break; \ - case v_x_double: \ - arglst[ iArg ].value.as_x_double = va_arg( va, _x_double ); \ - break; \ - case v_x_long_dbl: \ - arglst[ iArg ].value.as_x_long_dbl = va_arg( va, _x_long_dbl ); \ - break; \ - default: \ - arglst[ iArg ].value.as_x_int = va_arg( va, _x_int ); \ - break; \ - } \ - } \ - va_end( va ); \ - } while( 0 ) - -#endif - -static char get_decimal( char c, const char **format, int *result ) -{ - *result = c - '0'; - while( ( c = *(*format)++ ) >= '0' && c <= '9' ) - *result = *result * 10 + ( c - '0' ); - - return c; -} - -static size_t put_octal( char *buffer, size_t bufsize, size_t size, - uintmax_t value, int flags, int width, int precision ) -{ - uintmax_t v = value; - int nums = 0, n; - char c; - - while( v ) - { - ++nums; - v >>= 3; - } - if( precision > nums ) - nums = precision; - else if( flags & _F_ALTERNATE ) - ++nums; - else if( nums == 0 && precision != 0 ) - ++nums; - width -= nums; - - if( ( flags & _F_LEFTADJUSTED ) == 0 ) - { - while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ( flags & _F_ZEROPADED ) ? '0' : ' '; - ++size; - --width; - } - } - if( nums ) - { - n = nums; - do - { - c = ( char ) ( value & 0x7 ) + '0'; - value >>= 3; - --n; - if( size + n < bufsize ) - buffer[ size + n ] = c; - } - while( n ); - size += nums; - } - while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - --width; - } - - return size; -} - -static size_t put_dec( char *buffer, size_t bufsize, size_t size, - uintmax_t value, int flags, int width, int precision, - int sign ) -{ - uintmax_t v = value; - int nums = 0, n; - char c; - - while( v ) - { - ++nums; - v /= 10; - } - if( precision > nums ) - nums = precision; - else if( nums == 0 && precision != 0 ) - ++nums; - if( ( flags & ( _F_SPACE | _F_SIGN ) ) || sign ) - width--; - if( ( flags & ( _F_LEFTADJUSTED | _F_ZEROPADED ) ) == _F_ZEROPADED && - width > nums ) - nums = width; - width -= nums; - - if( ( flags & _F_LEFTADJUSTED ) == 0 ) - { - while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - --width; - } - } - if( ( flags & ( _F_SPACE | _F_SIGN ) ) || sign ) - { - if( size < bufsize ) - buffer[ size ] = sign ? '-' : ( flags & _F_SIGN ? '+' : ' ' ); - ++size; - } - if( nums ) - { - n = nums; - do - { - c = ( char ) ( value % 10 ) + '0'; - value /= 10; - --n; - if( size + n < bufsize ) - buffer[ size + n ] = c; - } - while( n ); - size += nums; - } - while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - --width; - } - - return size; -} - -#ifndef __NO_DOUBLE__ -static size_t put_dbl( char *buffer, size_t bufsize, size_t size, - _x_long_dbl value, int flags, int width, int precision ) -{ - _x_long_dbl dInt, dFract; - int sign, nums = 0, n; - char c; - - if( precision < 0 ) - precision = 6; - /* signbit() needs _GNU_SOURCE defined. If it's not available on given - * platform then it can be replaced by 'value < 0' but in such case - * -0.0 will be shown as 0.0 - */ -#if defined( __GNUC__ ) - sign = signbit( value ); -#else - sign = value < 0; -#endif - if( sign ) - value = - value; - - /* Round the number to given precision. - * powl() is of course faster when precision is big but it is libm - * (-lm link switch) function so we will make small trick here and - * calculate it in a loop - */ -#if 0 - value += _POWD( 10, -precision ) / 2; -#else - n = precision; - dFract = 1; - while( --n >= 0 ) - dFract /= 10; - value += dFract / 2; -#endif - - dFract = _MODFD( value, &dInt ); - width -= precision; - if( ( flags & ( _F_SPACE | _F_SIGN ) ) || sign ) - width--; - if( precision > 0 || ( flags & _F_ALTERNATE ) ) - width--; - value = dInt; - do - { - ++nums; - _MODFD( value / 10 + 0.01, &value ); - } - while( value >= 1 ); - width -= nums; - c = ( ( flags & ( _F_SPACE | _F_SIGN ) ) || sign ) ? - ( buffer[ size ] = sign ? '-' : ( flags & _F_SIGN ? '+' : ' ' ) ) : 0; - if( ( flags & _F_LEFTADJUSTED ) == 0 && width > 0 ) - { - if( c && ( flags & _F_ZEROPADED ) ) - { - if( size < bufsize ) - buffer[ size ] = c; - ++size; - c = 0; - } - do - { - if( size < bufsize ) - buffer[ size ] = ( flags & _F_ZEROPADED ) ? '0' : ' '; - ++size; - } - while( --width > 0 ); - } - if( c ) - { - if( size < bufsize ) - buffer[ size ] = sign ? '-' : ( flags & _F_SIGN ? '+' : ' ' ); - ++size; - } - - n = nums; - do - { - value = _MODFD( dInt / 10 + 0.01, &dInt ) * 10; - c = '0' + ( char ) ( value + 0.01 ); - --n; - if( size + n < bufsize ) - buffer[ size + n ] = c; - } - while( n ); - size += nums; - - if( precision > 0 || ( flags & _F_ALTERNATE ) ) - { - if( size < bufsize ) - buffer[ size ] = '.'; - ++size; - while( precision > 0 ) - { - dFract = _MODFD( dFract * 10, &dInt ); - c = '0' + ( char ) ( dInt + 0.01 ); - if( size < bufsize ) - buffer[ size ] = c; - ++size; - --precision; - } - } - while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - --width; - } - - return size; -} -#endif - -static size_t put_hex( char *buffer, size_t bufsize, size_t size, - uintmax_t value, int flags, int width, int precision, - int upper ) -{ - uintmax_t v = value; - int nums = 0, n; - char c; - - while( v ) - { - ++nums; - v >>= 4; - } - if( precision > nums ) - nums = precision; - else if( nums == 0 && precision != 0 ) - ++nums; - if( ( flags & _F_ALTERNATE ) && value ) - width -= 2; - width -= nums; - - if( ( flags & _F_LEFTADJUSTED ) == 0 ) - { - while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ( flags & _F_ZEROPADED ) ? '0' : ' '; - ++size; - --width; - } - } - if( ( flags & _F_ALTERNATE ) && value ) - { - if( size < bufsize ) - buffer[ size ] = '0'; - ++size; - if( size < bufsize ) - buffer[ size ] = upper ? 'X' : 'x'; - ++size; - } - if( nums ) - { - n = nums; - do - { - c = ( char ) ( value & 0x0f ) + '0'; - if( c > '9' ) - c += upper ? 'A' - '9' - 1 : 'a' - '9' - 1; - value >>= 4; - --n; - if( size + n < bufsize ) - buffer[ size + n ] = c; - } - while( n ); - size += nums; - } - while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - --width; - } - - return size; -} - -static size_t put_str( char *buffer, size_t bufsize, size_t size, - const char * str, int flags, int width, int precision ) -{ - if( !str ) - str = "(null)"; - if( precision < 0 ) - precision = ( int ) strlen( str ); - else if( precision > 0 ) - /* strnlen() is GNU extension. It needs _GNU_SOURCE - * macro defined before including header files. If this - * function does not exist on some platform then can be - * easy replaced by this macro: - * #define strnlen( s, maxlen ) \ - * ( { size_t n = maxlen, size = 0; \ - * while( n < maxlen && s[ size ] ) \ - * ++size; \ - * size; \ - * } ) - */ - precision = ( int ) strnlen( str, precision ); - - width -= precision; - if( ( flags & _F_LEFTADJUSTED ) == 0 ) while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - --width; - } - while( precision > 0 ) - { - if( size < bufsize ) - buffer[ size ] = *str++; - ++size; - --precision; - } - while( width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - --width; - } - - return size; -} - -int hb_snprintf_c( char * buffer, size_t bufsize, const char * format, ... ) -{ - va_list args; - size_t size; - char c; -#ifndef __NO_ARGPOS__ - const char * fmt_start = format; - v_param argbuf[ _ARGBUF_SIZE ]; - v_param * arglst = argbuf; - int argbuf_size = _ARGBUF_SIZE; - int repeat = 1; - int maxarg = 0; -#endif - - -#ifndef __NO_ARGPOS__ - while( repeat ) - { - repeat = 0; - if( maxarg > 0 ) - va_arg_fill( args ); - format = fmt_start; -#endif - va_start( args, format ); - size = 0; - - do - { - c = *format++; - if( c == '%' ) - { - const char * pattern = format; - - c = *format++; - if( c != 0 && c != '%' ) - { - /* decode pattern */ - int param = 0, flags = 0, width = -1, precision = -1, length, - value = 0, stop = 0; - v_param argval; - - /* parameter position */ - if( c >= '1' && c <= '9' ) - { - c = get_decimal( c, &format, &value ); - if( c == '$' ) - { - param = value; - value = 0; - c = *format++; - } - else - stop = 1; - } - - /* flags */ - while( !stop ) switch( c ) - { - case '#': - flags |= _F_ALTERNATE; - c = *format++; - break; - case '0': - flags |= _F_ZEROPADED; - c = *format++; - break; - case '-': - flags |= _F_LEFTADJUSTED; - c = *format++; - break; - case ' ': - flags |= _F_SPACE; - c = *format++; - break; - case '+': - flags |= _F_SIGN; - c = *format++; - break; -#if _SUSV2_COMPAT_ - case '\'': /* group with locale thousands' grouping characters */ - c = *format++; - break; -#endif - default: - stop = 1; - break; - } - - /* field width */ - if( value != 0 ) - width = value; - else if( c == '*' ) - { - c = *format++; - if( c >= '0' && c <= '9' ) - { - c = get_decimal( c, &format, &value ); - if( c == '$' ) - { - width = va_arg_n( args, _x_int, value ); - c = *format++; - } - /* else error, wrong format */ - } - else - width = va_arg( args, int ); - } - else if( c >= '0' && c <= '9' ) - c = get_decimal( c, &format, &width ); - - /* precision */ - if( c == '.' ) - { - precision = 0; - c = *format++; - if( c == '*' ) - { - c = *format++; - if( c >= '0' && c <= '9' ) - { - c = get_decimal( c, &format, &value ); - if( c == '$' ) - { - precision = va_arg_n( args, _x_int, value ); - c = *format++; - } - /* else error, wrong format */ - } - else - precision = va_arg( args, int ); - } - else if( c >= '0' && c <= '9' ) - c = get_decimal( c, &format, &precision ); - } - - /* length modifier */ - switch( c ) - { - case 'h': - c = *format++; - if( c == 'h' ) - { - length = _L_CHAR_; - c = *format++; - } - else - length = _L_SHORT_; - break; - case 'l': - c = *format++; - if( c == 'l' ) - { - length = _L_LONGLONG_; - c = *format++; - } - else - length = _L_LONG_; - break; - case 'L': - length = _L_LONGDOUBLE_; - c = *format++; - break; - case 'j': - length = _L_INTMAX_; - c = *format++; - break; - case 'z': - length = _L_SIZE_; - c = *format++; - break; - case 't': - length = _L_PTRDIFF_; - c = *format++; - break; - default: - length = _L_UNDEF_; - break; - } - - /* conversion specifier */ - - switch( c ) - { -#ifndef __NO_DOUBLE__ - case 'a': - case 'A': - case 'e': - case 'E': - case 'g': - case 'G': - /* redirect above conversion to 'f' or 'F' type to keep - * valid parameters order - */ - c = ( c == 'a' || c == 'e' || c == 'g' ) ? 'f' : 'F'; - /* no break; */ - case 'f': /* double decimal notation */ - case 'F': /* double decimal notation */ - if( length == _L_LONGDOUBLE_ ) - argval.value.as_x_long_dbl = va_arg_n( args, _x_long_dbl, param ); - else - argval.value.as_x_long_dbl = va_arg_n( args, _x_double, param ); - if( isnan( argval.value.as_x_long_dbl ) ) - size = put_str( buffer, bufsize, size, - c == 'f' ? - ( flags & _F_SIGN ? "+nan": "nan" ) : - ( flags & _F_SIGN ? "+NAN": "NAN" ) , - flags, width, -1 ); - else if( isinf( argval.value.as_x_long_dbl ) > 0 ) - size = put_str( buffer, bufsize, size, - c == 'f' ? - ( flags & _F_SIGN ? "+inf": "inf" ) : - ( flags & _F_SIGN ? "+INF": "INF" ), - flags, width, -1 ); - else if( isinf( argval.value.as_x_long_dbl ) < 0 ) - size = put_str( buffer, bufsize, size, - c == 'f' ? "-inf" : "-INF", - flags, width, -1 ); - else - size = put_dbl( buffer, bufsize, size, argval.value.as_x_long_dbl, - flags, width, precision ); - continue; -#endif - case 'd': - case 'i': /* signed int decimal conversion */ - if( length == _L_CHAR_ ) - argval.value.as_x_intmax_t = ( unsigned char ) va_arg_n( args, _x_int, param ); - else if( length == _L_SHORT_ ) - argval.value.as_x_intmax_t = ( unsigned short ) va_arg_n( args, _x_int, param ); - else if( length == _L_LONG_ ) - argval.value.as_x_intmax_t = va_arg_n( args, _x_long, param ); - else if( length == _L_LONGLONG_ ) - argval.value.as_x_intmax_t = va_arg_n( args, _x_longlong, param ); - else if( length == _L_INTMAX_ ) - argval.value.as_x_intmax_t = va_arg_n( args, _x_intmax_t, param ); - else if( length == _L_SIZE_ ) - argval.value.as_x_intmax_t = va_arg_n( args, _x_size_t, param ); - else if( length == _L_PTRDIFF_ ) - argval.value.as_x_intmax_t = va_arg_n( args, _x_ptrdiff_t, param ); - else - argval.value.as_x_intmax_t = va_arg_n( args, _x_int, param ); - argval.value.as_x_uintmax_t = argval.value.as_x_intmax_t < 0 - ? -argval.value.as_x_intmax_t : argval.value.as_x_intmax_t; - size = put_dec( buffer, bufsize, size, argval.value.as_x_uintmax_t, - flags, width, precision, argval.value.as_x_intmax_t < 0 ); - continue; - case 'o': /* unsigned int octal conversion */ - case 'u': /* unsigned int decimal conversion */ - case 'x': /* unsigned int hexadecimal conversion */ - case 'X': /* unsigned int hexadecimal conversion */ - if( length == _L_CHAR_ ) - argval.value.as_x_uintmax_t = ( unsigned char ) va_arg_n( args, _x_int, param ); - else if( length == _L_SHORT_ ) - argval.value.as_x_uintmax_t = ( unsigned short ) va_arg_n( args, _x_int, param ); - else if( length == _L_LONG_ ) - argval.value.as_x_uintmax_t = va_arg_n( args, _x_ulong, param ); - else if( length == _L_LONGLONG_ ) - argval.value.as_x_uintmax_t = va_arg_n( args, _x_ulonglong, param ); - else if( length == _L_INTMAX_ ) - argval.value.as_x_uintmax_t = va_arg_n( args, _x_uintmax_t, param ); - else if( length == _L_SIZE_ ) - argval.value.as_x_uintmax_t = va_arg_n( args, _x_size_t, param ); - else if( length == _L_PTRDIFF_ ) - argval.value.as_x_uintmax_t = va_arg_n( args, _x_ptrdiff_t, param ); - else - argval.value.as_x_uintmax_t = va_arg_n( args, _x_uint, param ); - - if( c == 'o' ) - size = put_octal( buffer, bufsize, size, argval.value.as_x_uintmax_t, - flags, width, precision ); - else if( c == 'u' ) - size = put_dec( buffer, bufsize, size, argval.value.as_x_uintmax_t, - flags & ~( _F_SPACE | _F_SIGN ), - width, precision, 0 ); - else - size = put_hex( buffer, bufsize, size, argval.value.as_x_uintmax_t, - flags, width, precision, c == 'X' ); - continue; - case 'p': /* void * pointer */ - argval.value.as_x_ptr = va_arg_n( args, _x_ptr, param ); - if( argval.value.as_x_ptr ) - size = put_hex( buffer, bufsize, size, ( unsigned long ) argval.value.as_x_ptr, - flags | _F_ALTERNATE, width, precision, 0 ); - else - size = put_str( buffer, bufsize, size, "(nil)", - flags, width, -1 ); - continue; - case 'c': /* signed int casted to unsigned char */ - if( ( flags & _F_LEFTADJUSTED ) == 0 ) while( --width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - } - c = ( unsigned char ) va_arg_n( args, _x_int, param ); - if( size < bufsize ) - buffer[ size ] = c; - ++size; - while( --width > 0 ) - { - if( size < bufsize ) - buffer[ size ] = ' '; - ++size; - } - continue; - case 's': /* const char * */ - argval.value.as_x_str = va_arg_n( args, _x_str, param ); - size = put_str( buffer, bufsize, size, argval.value.as_x_str, - flags, width, precision ); - continue; - case 'n': /* store current result size in int * arg */ - /* This is very danger feature in *printf() functions - * family very often used by hackers to create buffer - * overflows. It can also cause unintentional memory - * corruption by programmers typo in pattern so if it's - * not strictly necessary it's good to disable it. - */ - *( va_arg_n( args, _x_intptr, param ) ) = ( int ) size; - continue; - case '%': /* store % consuming arguments % */ - break; - default: /* error, wrong format, store pattern */ - format = pattern; - c = '%'; - break; - } - } - } - - /* ISO C99 defines that when size is 0 and buffer is NULL we should - * return number of characters that would have been written in case - * the output string has been large enough without trailing 0. - * Many implementations always returns number of characters necessary - * to hold the string even if the above condition is not true so the - * returned value can be used to check if buffer was large enough - * and if not to allocate bigger buffer. Let's do the same. - */ - if( size < bufsize ) - buffer[ size ] = c; - ++size; - } - while( c != 0 ); - - va_end( args ); - -#ifndef __NO_ARGPOS__ - } - if( arglst != argbuf ) - free( argbuf ); -#endif - - /* always set trailing \0 !!! */ - if( bufsize ) - buffer[ bufsize - 1 ] = 0; - - return ( int ) size; -} - -#endif +/* + * $Id: dbfnsx1.c 10062 2009-01-17 02:35:29Z druzus $ + */ + +/* + * Harbour Project source code: + * hb_sprintf() function. + * + * Copyright 2008 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#if 0 + +/* +patterm format: + '%' [*] [] [.] [] + + */ + +/* +The folowwing conversions are not explicitly supported: + A, a + E, e + G, g + These are (long) double conversions. If necessary they can be easy added. + Now they are simply redirected to F, f conversions. + + C (or Lc) + S (or Ls) + These are wide character conversions and needs locale settings. + +double conversion if not necessary can be disabled to not create unnencessary +overhead and/or references to math library by + #define __NO_DOUBLE__ +It can be also greatly optimized anyhow it will increase dependences list and +reduce portability. +Internally 'long double' is used for all calculations. If some platforms do +not support it then it can be eliminated by + #define __NO_LONGDOUBLE__ + +If positional parameters are not necessary then support for them can be +disabled by + #define __NO_ARGPOS__ +In such case this code neither allocates memory nor extensively use stack +as memory buffer. All conversions are done "on the fly". If memory +allocations or stack size is not a problem then some parts can be easy +optimized. +*/ + +/* #define __NO_DOUBLE__ */ +/* #define __NO_LONGDOUBLE__ */ +/* #define __NO_ARGPOS__ */ +/* #define __NO_LONGLONG__ */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#if defined(__DJGPP__) +# include +_LIB_VERSION_TYPE _LIB_VERSION = _XOPEN_; +#else +# include +#endif + +#include "hbmath.h" + +#include +#if defined( __GNUC__ ) +#include +#endif +#include +#include +#ifndef __NO_ARGPOS__ +# include /* malloc()/realloc()/free() */ +#endif + +#if defined(__cplusplus) +# define _EXTERN_C extern "C" +#else +# define _EXTERN_C extern +#endif + +#if defined( __GNUC__ ) +_EXTERN_C int hb_snprintf_c( char *buffer, size_t bufsize, const char *format, ... ) + __attribute__ (( format (printf, 3, 4))); +#else + +#define strnlen( s, maxlen ) \ + ( { size_t n = maxlen, size = 0; \ + while( n < maxlen && s[ size ] ) \ + ++size; \ + size; \ + } ) + +#endif + +#define _F_ALTERNATE 0x01 /* only for: o xX aA eE fF gG */ +#define _F_ZEROPADED 0x02 /* only for: d i o u xX aA eE fF gG */ +#define _F_LEFTADJUSTED 0x04 /* clears _F_ZEROPADED */ +#define _F_SPACE 0x08 /* only for signed num conversions: d i fF aA eE gG */ +#define _F_SIGN 0x10 /* only for signed num conversions: d i fF aA eE gG, clears _F_SPACE */ + +#define _ARGBUF_SIZE 16 + +#define _L_UNDEF_ 0 +#define _L_CHAR_ 1 +#define _L_SHORT_ 2 +#define _L_LONG_ 3 +#define _L_LONGLONG_ 4 +#define _L_INTMAX_ 5 +#define _L_SIZE_ 6 +#define _L_PTRDIFF_ 7 +#define _L_DOUBLE_ 8 +#define _L_LONGDOUBLE_ 9 + +#ifndef __NO_DOUBLE__ +# ifndef __NO_LONGDOUBLE__ +# define _x_long_dbl long double +# define _POWD( x, y ) powl( x, y ) +# define _MODFD( x, p ) modfl( x, p ) +# else +# define _x_long_dbl double +# define _POWD( x, y ) pow( x, y ) +# define _MODFD( x, p ) modf( x, p ) +# endif +# define _x_double double +#else +# define _x_long_dbl int +# define _x_double int +#endif +#ifndef __NO_LONGLONG__ +# define _x_longlong long long +# define _x_ulonglong unsigned long long +#else +# define _x_longlong long +# define _x_ulonglong unsigned long +#endif +#define _x_int int +#define _x_uint unsigned int +#define _x_ulong unsigned long +#define _x_long long +#define _x_intmax_t intmax_t +#define _x_uintmax_t uintmax_t +#define _x_size_t size_t +#define _x_ptrdiff_t ptrdiff_t +#define _x_ptr void * +#define _x_str char * +#define _x_intptr int * + +#define v_x_int 1 +#define v_x_uint 2 +#define v_x_long 3 +#define v_x_ulong 4 +#define v_x_longlong 5 +#define v_x_ulonglong 6 +#define v_x_intmax_t 7 +#define v_x_uintmax_t 8 +#define v_x_size_t 9 +#define v_x_ptrdiff_t 10 +#define v_x_ptr 11 +#define v_x_str 12 +#define v_x_intptr 13 +#define v_x_double 14 +#define v_x_long_dbl 15 + +typedef union { + _x_int as_x_int; + _x_uint as_x_uint; + _x_long as_x_long; + _x_ulong as_x_ulong; + _x_longlong as_x_longlong; + _x_ulonglong as_x_ulonglong; + _x_intmax_t as_x_intmax_t; + _x_uintmax_t as_x_uintmax_t; + _x_size_t as_x_size_t; + _x_ptrdiff_t as_x_ptrdiff_t; + _x_ptr as_x_ptr; + _x_str as_x_str; + _x_intptr as_x_intptr; + _x_double as_x_double; + _x_long_dbl as_x_long_dbl; +} x_type; + +typedef struct { + int id; + x_type value; +} v_param; + +#ifdef __NO_ARGPOS__ + +/* this version does not support positional parameters (f.e. '%1$d') + * they can be added but it will force allocating additional + * memory block in heap or stack and making second pass for + * format decoding/coping. + * so we will use only this simple macro which ignores parameter + * positions. + */ +#define va_arg_n( va, type, n ) va_arg( va, type ) + +/* on some systems where each parameter allocates memory with + * the same size in function stack frame this simple macro can + * be used. + */ + +/* +#define va_arg_n( va, type, n ) \ + ( { \ + type result; \ + if( n == 0 ) \ + result = va_arg( va, type ); \ + else \ + { \ + int count = (n); \ + va_list ap; \ + va_start( ap, format ); \ + do \ + result = va_arg( ap, type ); \ + while( --count > 0 ); \ + va_end( ap ); \ + } \ + result; \ + } ) +*/ + +#else + +#define va_arg_n( va, type, n ) \ + ( { \ + type result; \ + if( n == 0 ) \ + { \ + result = va_arg( va, type ); \ + } \ + else \ + { \ + if( maxarg == 0 ) \ + { \ + repeat = 1; \ + memset( argbuf, 0, sizeof( argbuf ) ); \ + } \ + if( repeat ) \ + { \ + if( n > maxarg ) \ + maxarg = n; \ + if( n > argbuf_size ) \ + { \ + int prev_size = argbuf_size; \ + argbuf_size = n + _ARGBUF_SIZE; \ + if( argbuf_size == _ARGBUF_SIZE ) \ + arglst = memcpy( malloc( argbuf_size * sizeof( v_param ) ), \ + argbuf, sizeof( argbuf ) ); \ + else \ + arglst = realloc( arglst, argbuf_size * sizeof( v_param ) ); \ + memset( &arglst[ prev_size ], 0, ( argbuf_size - prev_size ) * \ + sizeof( v_param ) ); \ + argbuf_size += _ARGBUF_SIZE; \ + } \ + arglst[ n - 1 ].id = (v##type); \ + result = ( type ) 0; \ + } \ + else \ + { \ + result = arglst[ n - 1 ].value.as##type; \ + } \ + } \ + result; \ + } ) + +#define va_arg_fill( va ) \ + do { \ + int iArg; \ + va_start( va, format ); \ + for( iArg = 0; iArg < maxarg; ++iArg ) \ + { \ + switch( arglst[ iArg ].id ) \ + { \ + case v_x_uint: \ + arglst[ iArg ].value.as_x_uint = va_arg( va, _x_uint ); \ + break; \ + case v_x_long: \ + arglst[ iArg ].value.as_x_long = va_arg( va, _x_long ); \ + break; \ + case v_x_ulong: \ + arglst[ iArg ].value.as_x_ulong = va_arg( va, _x_ulong ); \ + break; \ + case v_x_longlong: \ + arglst[ iArg ].value.as_x_longlong = va_arg( va, _x_longlong ); \ + break; \ + case v_x_ulonglong: \ + arglst[ iArg ].value.as_x_ulonglong = va_arg( va, _x_ulonglong ); \ + break; \ + case v_x_intmax_t: \ + arglst[ iArg ].value.as_x_intmax_t = va_arg( va, _x_intmax_t ); \ + break; \ + case v_x_uintmax_t: \ + arglst[ iArg ].value.as_x_uintmax_t = va_arg( va, _x_uintmax_t ); \ + break; \ + case v_x_size_t: \ + arglst[ iArg ].value.as_x_size_t = va_arg( va, _x_size_t ); \ + break; \ + case v_x_ptrdiff_t: \ + arglst[ iArg ].value.as_x_ptrdiff_t = va_arg( va, _x_ptrdiff_t ); \ + break; \ + case v_x_ptr: \ + arglst[ iArg ].value.as_x_ptr = va_arg( va, _x_ptr ); \ + break; \ + case v_x_str: \ + arglst[ iArg ].value.as_x_str = va_arg( va, _x_str ); \ + break; \ + case v_x_intptr: \ + arglst[ iArg ].value.as_x_intptr = va_arg( va, _x_intptr ); \ + break; \ + case v_x_double: \ + arglst[ iArg ].value.as_x_double = va_arg( va, _x_double ); \ + break; \ + case v_x_long_dbl: \ + arglst[ iArg ].value.as_x_long_dbl = va_arg( va, _x_long_dbl ); \ + break; \ + default: \ + arglst[ iArg ].value.as_x_int = va_arg( va, _x_int ); \ + break; \ + } \ + } \ + va_end( va ); \ + } while( 0 ) + +#endif + +static char get_decimal( char c, const char **format, int *result ) +{ + *result = c - '0'; + while( ( c = *(*format)++ ) >= '0' && c <= '9' ) + *result = *result * 10 + ( c - '0' ); + + return c; +} + +static size_t put_octal( char *buffer, size_t bufsize, size_t size, + uintmax_t value, int flags, int width, int precision ) +{ + uintmax_t v = value; + int nums = 0, n; + char c; + + while( v ) + { + ++nums; + v >>= 3; + } + if( precision > nums ) + nums = precision; + else if( flags & _F_ALTERNATE ) + ++nums; + else if( nums == 0 && precision != 0 ) + ++nums; + width -= nums; + + if( ( flags & _F_LEFTADJUSTED ) == 0 ) + { + while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ( flags & _F_ZEROPADED ) ? '0' : ' '; + ++size; + --width; + } + } + if( nums ) + { + n = nums; + do + { + c = ( char ) ( value & 0x7 ) + '0'; + value >>= 3; + --n; + if( size + n < bufsize ) + buffer[ size + n ] = c; + } + while( n ); + size += nums; + } + while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + --width; + } + + return size; +} + +static size_t put_dec( char *buffer, size_t bufsize, size_t size, + uintmax_t value, int flags, int width, int precision, + int sign ) +{ + uintmax_t v = value; + int nums = 0, n; + char c; + + while( v ) + { + ++nums; + v /= 10; + } + if( precision > nums ) + nums = precision; + else if( nums == 0 && precision != 0 ) + ++nums; + if( ( flags & ( _F_SPACE | _F_SIGN ) ) || sign ) + width--; + if( ( flags & ( _F_LEFTADJUSTED | _F_ZEROPADED ) ) == _F_ZEROPADED && + width > nums ) + nums = width; + width -= nums; + + if( ( flags & _F_LEFTADJUSTED ) == 0 ) + { + while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + --width; + } + } + if( ( flags & ( _F_SPACE | _F_SIGN ) ) || sign ) + { + if( size < bufsize ) + buffer[ size ] = sign ? '-' : ( flags & _F_SIGN ? '+' : ' ' ); + ++size; + } + if( nums ) + { + n = nums; + do + { + c = ( char ) ( value % 10 ) + '0'; + value /= 10; + --n; + if( size + n < bufsize ) + buffer[ size + n ] = c; + } + while( n ); + size += nums; + } + while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + --width; + } + + return size; +} + +#ifndef __NO_DOUBLE__ +static size_t put_dbl( char *buffer, size_t bufsize, size_t size, + _x_long_dbl value, int flags, int width, int precision ) +{ + _x_long_dbl dInt, dFract; + int sign, nums = 0, n; + char c; + + if( precision < 0 ) + precision = 6; + /* signbit() needs _GNU_SOURCE defined. If it's not available on given + * platform then it can be replaced by 'value < 0' but in such case + * -0.0 will be shown as 0.0 + */ +#if defined( __GNUC__ ) + sign = signbit( value ); +#else + sign = value < 0; +#endif + if( sign ) + value = - value; + + /* Round the number to given precision. + * powl() is of course faster when precision is big but it is libm + * (-lm link switch) function so we will make small trick here and + * calculate it in a loop + */ +#if 0 + value += _POWD( 10, -precision ) / 2; +#else + n = precision; + dFract = 1; + while( --n >= 0 ) + dFract /= 10; + value += dFract / 2; +#endif + + dFract = _MODFD( value, &dInt ); + width -= precision; + if( ( flags & ( _F_SPACE | _F_SIGN ) ) || sign ) + width--; + if( precision > 0 || ( flags & _F_ALTERNATE ) ) + width--; + value = dInt; + do + { + ++nums; + _MODFD( value / 10 + 0.01, &value ); + } + while( value >= 1 ); + width -= nums; + c = ( ( flags & ( _F_SPACE | _F_SIGN ) ) || sign ) ? + ( buffer[ size ] = sign ? '-' : ( flags & _F_SIGN ? '+' : ' ' ) ) : 0; + if( ( flags & _F_LEFTADJUSTED ) == 0 && width > 0 ) + { + if( c && ( flags & _F_ZEROPADED ) ) + { + if( size < bufsize ) + buffer[ size ] = c; + ++size; + c = 0; + } + do + { + if( size < bufsize ) + buffer[ size ] = ( flags & _F_ZEROPADED ) ? '0' : ' '; + ++size; + } + while( --width > 0 ); + } + if( c ) + { + if( size < bufsize ) + buffer[ size ] = sign ? '-' : ( flags & _F_SIGN ? '+' : ' ' ); + ++size; + } + + n = nums; + do + { + value = _MODFD( dInt / 10 + 0.01, &dInt ) * 10; + c = '0' + ( char ) ( value + 0.01 ); + --n; + if( size + n < bufsize ) + buffer[ size + n ] = c; + } + while( n ); + size += nums; + + if( precision > 0 || ( flags & _F_ALTERNATE ) ) + { + if( size < bufsize ) + buffer[ size ] = '.'; + ++size; + while( precision > 0 ) + { + dFract = _MODFD( dFract * 10, &dInt ); + c = '0' + ( char ) ( dInt + 0.01 ); + if( size < bufsize ) + buffer[ size ] = c; + ++size; + --precision; + } + } + while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + --width; + } + + return size; +} +#endif + +static size_t put_hex( char *buffer, size_t bufsize, size_t size, + uintmax_t value, int flags, int width, int precision, + int upper ) +{ + uintmax_t v = value; + int nums = 0, n; + char c; + + while( v ) + { + ++nums; + v >>= 4; + } + if( precision > nums ) + nums = precision; + else if( nums == 0 && precision != 0 ) + ++nums; + if( ( flags & _F_ALTERNATE ) && value ) + width -= 2; + width -= nums; + + if( ( flags & _F_LEFTADJUSTED ) == 0 ) + { + while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ( flags & _F_ZEROPADED ) ? '0' : ' '; + ++size; + --width; + } + } + if( ( flags & _F_ALTERNATE ) && value ) + { + if( size < bufsize ) + buffer[ size ] = '0'; + ++size; + if( size < bufsize ) + buffer[ size ] = upper ? 'X' : 'x'; + ++size; + } + if( nums ) + { + n = nums; + do + { + c = ( char ) ( value & 0x0f ) + '0'; + if( c > '9' ) + c += upper ? 'A' - '9' - 1 : 'a' - '9' - 1; + value >>= 4; + --n; + if( size + n < bufsize ) + buffer[ size + n ] = c; + } + while( n ); + size += nums; + } + while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + --width; + } + + return size; +} + +static size_t put_str( char *buffer, size_t bufsize, size_t size, + const char * str, int flags, int width, int precision ) +{ + if( !str ) + str = "(null)"; + if( precision < 0 ) + precision = ( int ) strlen( str ); + else if( precision > 0 ) + /* strnlen() is GNU extension. It needs _GNU_SOURCE + * macro defined before including header files. If this + * function does not exist on some platform then can be + * easy replaced by this macro: + * #define strnlen( s, maxlen ) \ + * ( { size_t n = maxlen, size = 0; \ + * while( n < maxlen && s[ size ] ) \ + * ++size; \ + * size; \ + * } ) + */ + precision = ( int ) strnlen( str, precision ); + + width -= precision; + if( ( flags & _F_LEFTADJUSTED ) == 0 ) while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + --width; + } + while( precision > 0 ) + { + if( size < bufsize ) + buffer[ size ] = *str++; + ++size; + --precision; + } + while( width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + --width; + } + + return size; +} + +int hb_snprintf_c( char * buffer, size_t bufsize, const char * format, ... ) +{ + va_list args; + size_t size; + char c; +#ifndef __NO_ARGPOS__ + const char * fmt_start = format; + v_param argbuf[ _ARGBUF_SIZE ]; + v_param * arglst = argbuf; + int argbuf_size = _ARGBUF_SIZE; + int repeat = 1; + int maxarg = 0; +#endif + + +#ifndef __NO_ARGPOS__ + while( repeat ) + { + repeat = 0; + if( maxarg > 0 ) + va_arg_fill( args ); + format = fmt_start; +#endif + va_start( args, format ); + size = 0; + + do + { + c = *format++; + if( c == '%' ) + { + const char * pattern = format; + + c = *format++; + if( c != 0 && c != '%' ) + { + /* decode pattern */ + int param = 0, flags = 0, width = -1, precision = -1, length, + value = 0, stop = 0; + v_param argval; + + /* parameter position */ + if( c >= '1' && c <= '9' ) + { + c = get_decimal( c, &format, &value ); + if( c == '$' ) + { + param = value; + value = 0; + c = *format++; + } + else + stop = 1; + } + + /* flags */ + while( !stop ) switch( c ) + { + case '#': + flags |= _F_ALTERNATE; + c = *format++; + break; + case '0': + flags |= _F_ZEROPADED; + c = *format++; + break; + case '-': + flags |= _F_LEFTADJUSTED; + c = *format++; + break; + case ' ': + flags |= _F_SPACE; + c = *format++; + break; + case '+': + flags |= _F_SIGN; + c = *format++; + break; +#if _SUSV2_COMPAT_ + case '\'': /* group with locale thousands' grouping characters */ + c = *format++; + break; +#endif + default: + stop = 1; + break; + } + + /* field width */ + if( value != 0 ) + width = value; + else if( c == '*' ) + { + c = *format++; + if( c >= '0' && c <= '9' ) + { + c = get_decimal( c, &format, &value ); + if( c == '$' ) + { + width = va_arg_n( args, _x_int, value ); + c = *format++; + } + /* else error, wrong format */ + } + else + width = va_arg( args, int ); + } + else if( c >= '0' && c <= '9' ) + c = get_decimal( c, &format, &width ); + + /* precision */ + if( c == '.' ) + { + precision = 0; + c = *format++; + if( c == '*' ) + { + c = *format++; + if( c >= '0' && c <= '9' ) + { + c = get_decimal( c, &format, &value ); + if( c == '$' ) + { + precision = va_arg_n( args, _x_int, value ); + c = *format++; + } + /* else error, wrong format */ + } + else + precision = va_arg( args, int ); + } + else if( c >= '0' && c <= '9' ) + c = get_decimal( c, &format, &precision ); + } + + /* length modifier */ + switch( c ) + { + case 'h': + c = *format++; + if( c == 'h' ) + { + length = _L_CHAR_; + c = *format++; + } + else + length = _L_SHORT_; + break; + case 'l': + c = *format++; + if( c == 'l' ) + { + length = _L_LONGLONG_; + c = *format++; + } + else + length = _L_LONG_; + break; + case 'L': + length = _L_LONGDOUBLE_; + c = *format++; + break; + case 'j': + length = _L_INTMAX_; + c = *format++; + break; + case 'z': + length = _L_SIZE_; + c = *format++; + break; + case 't': + length = _L_PTRDIFF_; + c = *format++; + break; + default: + length = _L_UNDEF_; + break; + } + + /* conversion specifier */ + + switch( c ) + { +#ifndef __NO_DOUBLE__ + case 'a': + case 'A': + case 'e': + case 'E': + case 'g': + case 'G': + /* redirect above conversion to 'f' or 'F' type to keep + * valid parameters order + */ + c = ( c == 'a' || c == 'e' || c == 'g' ) ? 'f' : 'F'; + /* no break; */ + case 'f': /* double decimal notation */ + case 'F': /* double decimal notation */ + if( length == _L_LONGDOUBLE_ ) + argval.value.as_x_long_dbl = va_arg_n( args, _x_long_dbl, param ); + else + argval.value.as_x_long_dbl = va_arg_n( args, _x_double, param ); + if( isnan( argval.value.as_x_long_dbl ) ) + size = put_str( buffer, bufsize, size, + c == 'f' ? + ( flags & _F_SIGN ? "+nan": "nan" ) : + ( flags & _F_SIGN ? "+NAN": "NAN" ) , + flags, width, -1 ); + else if( isinf( argval.value.as_x_long_dbl ) > 0 ) + size = put_str( buffer, bufsize, size, + c == 'f' ? + ( flags & _F_SIGN ? "+inf": "inf" ) : + ( flags & _F_SIGN ? "+INF": "INF" ), + flags, width, -1 ); + else if( isinf( argval.value.as_x_long_dbl ) < 0 ) + size = put_str( buffer, bufsize, size, + c == 'f' ? "-inf" : "-INF", + flags, width, -1 ); + else + size = put_dbl( buffer, bufsize, size, argval.value.as_x_long_dbl, + flags, width, precision ); + continue; +#endif + case 'd': + case 'i': /* signed int decimal conversion */ + if( length == _L_CHAR_ ) + argval.value.as_x_intmax_t = ( unsigned char ) va_arg_n( args, _x_int, param ); + else if( length == _L_SHORT_ ) + argval.value.as_x_intmax_t = ( unsigned short ) va_arg_n( args, _x_int, param ); + else if( length == _L_LONG_ ) + argval.value.as_x_intmax_t = va_arg_n( args, _x_long, param ); + else if( length == _L_LONGLONG_ ) + argval.value.as_x_intmax_t = va_arg_n( args, _x_longlong, param ); + else if( length == _L_INTMAX_ ) + argval.value.as_x_intmax_t = va_arg_n( args, _x_intmax_t, param ); + else if( length == _L_SIZE_ ) + argval.value.as_x_intmax_t = va_arg_n( args, _x_size_t, param ); + else if( length == _L_PTRDIFF_ ) + argval.value.as_x_intmax_t = va_arg_n( args, _x_ptrdiff_t, param ); + else + argval.value.as_x_intmax_t = va_arg_n( args, _x_int, param ); + argval.value.as_x_uintmax_t = argval.value.as_x_intmax_t < 0 + ? -argval.value.as_x_intmax_t : argval.value.as_x_intmax_t; + size = put_dec( buffer, bufsize, size, argval.value.as_x_uintmax_t, + flags, width, precision, argval.value.as_x_intmax_t < 0 ); + continue; + case 'o': /* unsigned int octal conversion */ + case 'u': /* unsigned int decimal conversion */ + case 'x': /* unsigned int hexadecimal conversion */ + case 'X': /* unsigned int hexadecimal conversion */ + if( length == _L_CHAR_ ) + argval.value.as_x_uintmax_t = ( unsigned char ) va_arg_n( args, _x_int, param ); + else if( length == _L_SHORT_ ) + argval.value.as_x_uintmax_t = ( unsigned short ) va_arg_n( args, _x_int, param ); + else if( length == _L_LONG_ ) + argval.value.as_x_uintmax_t = va_arg_n( args, _x_ulong, param ); + else if( length == _L_LONGLONG_ ) + argval.value.as_x_uintmax_t = va_arg_n( args, _x_ulonglong, param ); + else if( length == _L_INTMAX_ ) + argval.value.as_x_uintmax_t = va_arg_n( args, _x_uintmax_t, param ); + else if( length == _L_SIZE_ ) + argval.value.as_x_uintmax_t = va_arg_n( args, _x_size_t, param ); + else if( length == _L_PTRDIFF_ ) + argval.value.as_x_uintmax_t = va_arg_n( args, _x_ptrdiff_t, param ); + else + argval.value.as_x_uintmax_t = va_arg_n( args, _x_uint, param ); + + if( c == 'o' ) + size = put_octal( buffer, bufsize, size, argval.value.as_x_uintmax_t, + flags, width, precision ); + else if( c == 'u' ) + size = put_dec( buffer, bufsize, size, argval.value.as_x_uintmax_t, + flags & ~( _F_SPACE | _F_SIGN ), + width, precision, 0 ); + else + size = put_hex( buffer, bufsize, size, argval.value.as_x_uintmax_t, + flags, width, precision, c == 'X' ); + continue; + case 'p': /* void * pointer */ + argval.value.as_x_ptr = va_arg_n( args, _x_ptr, param ); + if( argval.value.as_x_ptr ) + size = put_hex( buffer, bufsize, size, ( unsigned long ) argval.value.as_x_ptr, + flags | _F_ALTERNATE, width, precision, 0 ); + else + size = put_str( buffer, bufsize, size, "(nil)", + flags, width, -1 ); + continue; + case 'c': /* signed int casted to unsigned char */ + if( ( flags & _F_LEFTADJUSTED ) == 0 ) while( --width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + } + c = ( unsigned char ) va_arg_n( args, _x_int, param ); + if( size < bufsize ) + buffer[ size ] = c; + ++size; + while( --width > 0 ) + { + if( size < bufsize ) + buffer[ size ] = ' '; + ++size; + } + continue; + case 's': /* const char * */ + argval.value.as_x_str = va_arg_n( args, _x_str, param ); + size = put_str( buffer, bufsize, size, argval.value.as_x_str, + flags, width, precision ); + continue; + case 'n': /* store current result size in int * arg */ + /* This is very danger feature in *printf() functions + * family very often used by hackers to create buffer + * overflows. It can also cause unintentional memory + * corruption by programmers typo in pattern so if it's + * not strictly necessary it's good to disable it. + */ + *( va_arg_n( args, _x_intptr, param ) ) = ( int ) size; + continue; + case '%': /* store % consuming arguments % */ + break; + default: /* error, wrong format, store pattern */ + format = pattern; + c = '%'; + break; + } + } + } + + /* ISO C99 defines that when size is 0 and buffer is NULL we should + * return number of characters that would have been written in case + * the output string has been large enough without trailing 0. + * Many implementations always returns number of characters necessary + * to hold the string even if the above condition is not true so the + * returned value can be used to check if buffer was large enough + * and if not to allocate bigger buffer. Let's do the same. + */ + if( size < bufsize ) + buffer[ size ] = c; + ++size; + } + while( c != 0 ); + + va_end( args ); + +#ifndef __NO_ARGPOS__ + } + if( arglst != argbuf ) + free( argbuf ); +#endif + + /* always set trailing \0 !!! */ + if( bufsize ) + buffer[ bufsize - 1 ] = 0; + + return ( int ) size; +} + +#endif diff --git a/harbour/source/rdd/usrrdd/example/exlog.prg b/harbour/source/rdd/usrrdd/example/exlog.prg index 3d018f4d27..93c798a20b 100644 --- a/harbour/source/rdd/usrrdd/example/exlog.prg +++ b/harbour/source/rdd/usrrdd/example/exlog.prg @@ -1,92 +1,92 @@ -/* - * $Id: exfcm.prg 9551 2008-10-05 18:13:15Z vszakats $ - */ - -#include "common.ch" -#include "dbinfo.ch" -#include "hbusrrdd.ch" - -// Request for LOGRDD rdd driver -REQUEST LOGRDD - -// Here put Request for RDD you want to inherit then add -// function hb_LogRddInherit() (see at bottom) -REQUEST DBFCDX - -PROCEDURE Main() - - // Set LOGRDD as default RDD otherwise I have to set explicitly use - // with DRIVER option - RDDSetDefault( "LOGRDD" ) - // Adding Memofile Info - rddInfo( RDDI_MEMOVERSION, DB_MEMOVER_CLIP, "LOGRDD" ) - - // Define Log File Name and position - hb_LogRddLogFileName( "logs\changes.log" ) - // Define Tag to add for each line logged - hb_LogRddTag( NETNAME() + "\" + hb_USERNAME() ) - // Activate Logging, it can be stopped/started at any moment - hb_LogRddActive( .T. ) - - // Uncomment next command to change logged string that I have to return to standard LOGRDD file - // hb_LogRddMsgLogBlock( {|cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3| MyToString( cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3 ) } ) - - // Uncomment next command to change standard destination of my logged string - // hb_LogRddUserLogBlock( {|cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3| hb_toOutDebug( MyToString( cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3 ) + "\n\r" ) } ) - - // Start program logic - - // Open a table with logging (default RDD is LOGRDD) - USE test - field->name := "Francesco" - CLOSE - - // Open a table without logging - - USE test VIA "DBFCDX" - APPEND BLANK - field->name := "Francesco" - - RETURN - -STATIC FUNCTION MyToString( cCmd, nWA, xPar1, xPar2, xPar3 ) - LOCAL cString - - DO CASE - CASE cCmd == "CREATE" - // Parameters received: xPar1 = aOpenInfo - cString := xPar1[ UR_OI_NAME ] - CASE cCmd == "CREATEFIELDS" - // Parameters received: xPar1 = aStruct - cString := hb_ValToExp( xPar1 ) - CASE cCmd == "OPEN" - // Parameters received: xPar1 = aOpenInfo - // cString := 'Table : "' + xPar1[ UR_OI_NAME ] + '", Alias : "' + Alias() + '", WorkArea : ' + LTrim( Str( nWA ) ) - // In this example I don't want to log Open Command - CASE cCmd == "CLOSE" - // Parameters received: xPar1 = cTableName, xPar2 = cAlias - //cString := 'Table : "' + xPar1 + '", Alias : "' + xPar2 + '", WorkArea : ' + LTrim( Str( nWA ) ) - // In this example I don't want to log Close Command - CASE cCmd == "APPEND" - // Parameters received: xPar1 = lUnlockAll - cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) - CASE cCmd == "DELETE" - // Parameters received: none - cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) - CASE cCmd == "RECALL" - // Parameters received: none - cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) - CASE cCmd == "PUTVALUE" - // Parameters received: xPar1 = nField, xPar2 = xValue, xPar3 = xOldValue -#ifndef __XHARBOUR__ - HB_SYMBOL_UNUSED( xPar3 ) // Here don't log previous value -#endif - cString := Alias() + "(" + LTrim( Str( RecNo() ) ) + ")->" + PadR( FieldName( xPar1 ), 10 ) + " := " + hb_LogRddValueToText( xPar2 ) - CASE cCmd == "ZAP" - // Parameters received: none - cString := 'Alias : "' + Alias() + ' Table : "' + dbInfo( DBI_FULLPATH ) + '"' - ENDCASE - RETURN cString - -FUNCTION hb_LogRddInherit() - RETURN "DBFCDX" +/* + * $Id: exfcm.prg 9551 2008-10-05 18:13:15Z vszakats $ + */ + +#include "common.ch" +#include "dbinfo.ch" +#include "hbusrrdd.ch" + +// Request for LOGRDD rdd driver +REQUEST LOGRDD + +// Here put Request for RDD you want to inherit then add +// function hb_LogRddInherit() (see at bottom) +REQUEST DBFCDX + +PROCEDURE Main() + + // Set LOGRDD as default RDD otherwise I have to set explicitly use + // with DRIVER option + RDDSetDefault( "LOGRDD" ) + // Adding Memofile Info + rddInfo( RDDI_MEMOVERSION, DB_MEMOVER_CLIP, "LOGRDD" ) + + // Define Log File Name and position + hb_LogRddLogFileName( "logs\changes.log" ) + // Define Tag to add for each line logged + hb_LogRddTag( NETNAME() + "\" + hb_USERNAME() ) + // Activate Logging, it can be stopped/started at any moment + hb_LogRddActive( .T. ) + + // Uncomment next command to change logged string that I have to return to standard LOGRDD file + // hb_LogRddMsgLogBlock( {|cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3| MyToString( cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3 ) } ) + + // Uncomment next command to change standard destination of my logged string + // hb_LogRddUserLogBlock( {|cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3| hb_toOutDebug( MyToString( cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3 ) + "\n\r" ) } ) + + // Start program logic + + // Open a table with logging (default RDD is LOGRDD) + USE test + field->name := "Francesco" + CLOSE + + // Open a table without logging + + USE test VIA "DBFCDX" + APPEND BLANK + field->name := "Francesco" + + RETURN + +STATIC FUNCTION MyToString( cCmd, nWA, xPar1, xPar2, xPar3 ) + LOCAL cString + + DO CASE + CASE cCmd == "CREATE" + // Parameters received: xPar1 = aOpenInfo + cString := xPar1[ UR_OI_NAME ] + CASE cCmd == "CREATEFIELDS" + // Parameters received: xPar1 = aStruct + cString := hb_ValToExp( xPar1 ) + CASE cCmd == "OPEN" + // Parameters received: xPar1 = aOpenInfo + // cString := 'Table : "' + xPar1[ UR_OI_NAME ] + '", Alias : "' + Alias() + '", WorkArea : ' + LTrim( Str( nWA ) ) + // In this example I don't want to log Open Command + CASE cCmd == "CLOSE" + // Parameters received: xPar1 = cTableName, xPar2 = cAlias + //cString := 'Table : "' + xPar1 + '", Alias : "' + xPar2 + '", WorkArea : ' + LTrim( Str( nWA ) ) + // In this example I don't want to log Close Command + CASE cCmd == "APPEND" + // Parameters received: xPar1 = lUnlockAll + cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) + CASE cCmd == "DELETE" + // Parameters received: none + cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) + CASE cCmd == "RECALL" + // Parameters received: none + cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) + CASE cCmd == "PUTVALUE" + // Parameters received: xPar1 = nField, xPar2 = xValue, xPar3 = xOldValue +#ifndef __XHARBOUR__ + HB_SYMBOL_UNUSED( xPar3 ) // Here don't log previous value +#endif + cString := Alias() + "(" + LTrim( Str( RecNo() ) ) + ")->" + PadR( FieldName( xPar1 ), 10 ) + " := " + hb_LogRddValueToText( xPar2 ) + CASE cCmd == "ZAP" + // Parameters received: none + cString := 'Alias : "' + Alias() + ' Table : "' + dbInfo( DBI_FULLPATH ) + '"' + ENDCASE + RETURN cString + +FUNCTION hb_LogRddInherit() + RETURN "DBFCDX" diff --git a/harbour/source/rdd/usrrdd/rdds/logrdd.prg b/harbour/source/rdd/usrrdd/rdds/logrdd.prg index c9d3b87781..eb2b2e64fd 100644 --- a/harbour/source/rdd/usrrdd/rdds/logrdd.prg +++ b/harbour/source/rdd/usrrdd/rdds/logrdd.prg @@ -1,489 +1,489 @@ -/* - * $Id: rlcdx.prg 9754 2008-10-27 22:40:04Z vszakats $ - */ - -/* - * Harbour Project source code: - * LOGRDD - * - * Copyright 2009 Francesco Saverio Giudice - * www - http://www.harbour-project.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). - * - * As a special exception, the Harbour Project gives permission for - * additional uses of the text contained in its release of Harbour. - * - * The exception is that, if you link the Harbour libraries with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the Harbour library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by the Harbour - * Project under the name Harbour. If you copy code from other - * Harbour Project or Free Software Foundation releases into a copy of - * Harbour, as the General Public License permits, the exception does - * not apply to the code that you add in this way. To avoid misleading - * anyone as to the status of such modified files, you must delete - * this exception notice from them. - * - * If you write modifications of your own for Harbour, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. - * - */ - -/* - * A simple RDD which introduce logging to file. It inheriths from - * any existent RDD but if you write / replace / delete something - * on tables it writes changes in a log file. - * An example is avalaible at - * harbour/source/rdd/usrrdd/example/exlog.prg - */ - -#include "rddsys.ch" -#ifdef __XHARBOUR__ - #include "usrrdd.ch" - #xtranslate hb_valtoexp( => cStr( -#else - #include "hbusrrdd.ch" -#endif -#include "common.ch" -#include "fileio.ch" -#include "dbinfo.ch" - -#define ARRAY_FILENAME 1 -#define ARRAY_FHANDLE 2 -#define ARRAY_TAG 3 -#define ARRAY_ACTIVE 4 -#define ARRAY_RDDNAME 5 -#define ARRAY_MSGLOGBLOCK 6 -#define ARRAY_USERLOGBLOCK 7 - -ANNOUNCE LOGRDD -DYNAMIC HB_LOGRDDINHERIT /* To be defined at user level */ - -STATIC FUNCTION LOGRDD_INIT( nRDD ) - LOCAL lActive, cFileName, cTag, cRDDName - - /* Defaults */ - cFileName := "changes.log" - lActive := .F. - #ifdef __XHARBOUR__ - cTag := NETNAME() + "\" + NETNAME( 1 ) - #else - cTag := NETNAME() + "\" + hb_USERNAME() - #endif - cRDDName := hb_LogRddInherit() - - /* Log File will be open later so user can change parameters */ - - /* Store data in RDD cargo */ - /* cFileName, nHandle, cTag, lActive, cRDDName, bMsgLogBlock, bUserLogBlock */ - USRRDD_RDDDATA( nRDD, { cFileName, NIL, cTag, lActive, cRDDName, NIL, NIL } ) - -RETURN SUCCESS - -STATIC FUNCTION LOGRDD_EXIT( nRDD ) - LOCAL aRDDData := USRRDD_RDDDATA( nRDD ) - - /* Closing log file */ - IF aRDDData[ ARRAY_FHANDLE ] != NIL - FClose( aRDDData[ ARRAY_FHANDLE ] ) - aRDDData[ ARRAY_FHANDLE ] := NIL - ENDIF - -RETURN SUCCESS - -// Create database from current WA fields definition -STATIC FUNCTION LOGRDD_CREATE( nWA, aOpenInfo ) - LOCAL nResult := UR_SUPER_CREATE( nWA, aOpenInfo ) - IF nResult == SUCCESS - ToLog( "CREATE", nWA, aOpenInfo ) - ENDIF - RETURN nResult - -// Creating fields for new DBF - dbCreate() in current workarea -STATIC FUNCTION LOGRDD_CREATEFIELDS( nWA, aStruct ) - LOCAL nResult := UR_SUPER_CREATEFIELDS( nWA, aStruct ) - IF nResult == SUCCESS - ToLog( "CREATEFIELDS", nWA, aStruct ) - ENDIF - RETURN nResult - -// Open workarea -STATIC FUNCTION LOGRDD_OPEN( nWA, aOpenInfo ) - LOCAL nResult := UR_SUPER_OPEN( nWA, aOpenInfo ) - IF nResult == SUCCESS - ToLog( "OPEN", nWA, aOpenInfo ) - ENDIF - RETURN nResult - -// Close workarea -STATIC FUNCTION LOGRDD_CLOSE( nWA ) - LOCAL cFile := dbInfo( DBI_FULLPATH ) - LOCAL cAlias := Alias() - LOCAL nResult := UR_SUPER_CLOSE( nWA ) - IF nResult == SUCCESS - ToLog( "CLOSE", nWA, cFile, cAlias ) - ENDIF - RETURN nResult - -STATIC FUNCTION LOGRDD_APPEND( nWA, lUnlockAll ) - LOCAL nResult := UR_SUPER_APPEND( nWA, lUnlockAll ) - IF nResult == SUCCESS - ToLog( "APPEND", nWA, lUnlockAll ) - ENDIF - RETURN nResult - -STATIC FUNCTION LOGRDD_DELETE( nWA ) - LOCAL nResult := UR_SUPER_DELETE( nWA ) - IF nResult == SUCCESS - ToLog( "DELETE", nWA ) - ENDIF - RETURN nResult - -STATIC FUNCTION LOGRDD_RECALL( nWA ) - LOCAL nResult := UR_SUPER_RECALL( nWA ) - IF nResult == SUCCESS - ToLog( "RECALL", nWA ) - ENDIF - RETURN nResult - -STATIC FUNCTION LOGRDD_PUTVALUE( nWA, nField, xValue ) - LOCAL xOldValue := FieldGet( nField ) - LOCAL nResult := UR_SUPER_PUTVALUE( nWA, nField, xValue ) - - //Log Only Changes - IF !( xOldValue == xValue ) - ToLog( "PUTVALUE", nWA, nField, xValue, xOldValue ) - ENDIF - RETURN nResult - -STATIC FUNCTION LOGRDD_ZAP( nWA ) - LOCAL nResult := UR_SUPER_ZAP( nWA ) - IF nResult == SUCCESS - ToLog( "ZAP", nWA ) - ENDIF - RETURN nResult - -/* Force linking DBFCDX from which our RDD inherits */ -REQUEST DBFCDX - -/* - * This function have to exist in all RDD and then name have to be in - * format: _GETFUNCTABLE - */ -FUNCTION LOGRDD_GETFUNCTABLE( pFuncCount, pFuncTable, pSuperTable, nRddID ) - LOCAL cSuperRDD := hb_LogRddInherit() /* We are inheriting from a User Defined RDD */ - LOCAL aMyFunc[ UR_METHODCOUNT ] - - aMyFunc[ UR_INIT ] := ( @LOGRDD_INIT() ) - aMyFunc[ UR_EXIT ] := ( @LOGRDD_EXIT() ) - aMyFunc[ UR_CREATE ] := ( @LOGRDD_CREATE() ) - aMyFunc[ UR_CREATEFIELDS ] := ( @LOGRDD_CREATEFIELDS() ) - aMyFunc[ UR_OPEN ] := ( @LOGRDD_OPEN() ) - aMyFunc[ UR_CLOSE ] := ( @LOGRDD_CLOSE() ) - aMyFunc[ UR_APPEND ] := ( @LOGRDD_APPEND() ) - aMyFunc[ UR_DELETE ] := ( @LOGRDD_DELETE() ) - aMyFunc[ UR_RECALL ] := ( @LOGRDD_RECALL() ) - aMyFunc[ UR_PUTVALUE ] := ( @LOGRDD_PUTVALUE() ) - aMyFunc[ UR_ZAP ] := ( @LOGRDD_ZAP() ) - -RETURN USRRDD_GETFUNCTABLE( pFuncCount, pFuncTable, pSuperTable, nRddID, ; - cSuperRDD, aMyFunc ) - -INIT PROCEDURE _LOGRDD_INIT() - rddRegister( "LOGRDD", RDT_FULL ) - RETURN - -/* -------------------------------------------------- */ -/* USER UTILITY FUNCTIONS */ -/* -------------------------------------------------- */ - -FUNCTION hb_LogRddLogFileName( cFileName ) - LOCAL nRDD, aRDDList - LOCAL aRDDData - LOCAL cOldFileName - - aRDDList := RDDLIST( RDT_FULL ) - nRDD := AScan( aRDDList, "LOGRDD" ) - - IF nRDD > 0 - - nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO - - aRDDData := USRRDD_RDDDATA( nRDD ) - - cOldFileName := aRDDData[ ARRAY_FILENAME ] - - IF HB_ISSTRING( cFileName ) - aRDDData[ ARRAY_FILENAME ] := cFileName - ENDIF - - ENDIF - RETURN cOldFileName - -FUNCTION hb_LogRddTag( cTag ) - LOCAL nRDD, aRDDList - LOCAL aRDDData - LOCAL cOldTag - - aRDDList := RDDLIST( RDT_FULL ) - nRDD := AScan( aRDDList, "LOGRDD" ) - - IF nRDD > 0 - - nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO - - aRDDData := USRRDD_RDDDATA( nRDD ) - - cOldTag := aRDDData[ ARRAY_TAG ] - - IF HB_ISSTRING( cTag ) - aRDDData[ ARRAY_TAG ] := cTag - ENDIF - - ENDIF - RETURN cOldTag - -FUNCTION hb_LogRddActive( lActive ) - LOCAL nRDD, aRDDList - LOCAL aRDDData - LOCAL lOldActive - - aRDDList := RDDLIST( RDT_FULL ) - nRDD := AScan( aRDDList, "LOGRDD" ) - - IF nRDD > 0 - - nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO - - aRDDData := USRRDD_RDDDATA( nRDD ) - - lOldActive := aRDDData[ ARRAY_ACTIVE ] - - IF HB_ISLOGICAL( lActive ) - aRDDData[ ARRAY_ACTIVE ] := lActive - ENDIF - - ENDIF - RETURN lOldActive - -FUNCTION hb_LogRddMsgLogBlock( bMsgLogBlock ) - LOCAL nRDD, aRDDList - LOCAL aRDDData - LOCAL bOldMsgLogBlock - - aRDDList := RDDLIST( RDT_FULL ) - nRDD := AScan( aRDDList, "LOGRDD" ) - - IF nRDD > 0 - - nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO - - aRDDData := USRRDD_RDDDATA( nRDD ) - - bOldMsgLogBlock := aRDDData[ ARRAY_MSGLOGBLOCK ] - - IF HB_ISBLOCK( bMsgLogBlock ) - aRDDData[ ARRAY_MSGLOGBLOCK ] := bMsgLogBlock - ENDIF - - ENDIF - RETURN bOldMsgLogBlock - -FUNCTION hb_LogRddUserLogBlock( bUserLogBlock ) - LOCAL nRDD, aRDDList - LOCAL aRDDData - LOCAL bOldUserLogBlock - - aRDDList := RDDLIST( RDT_FULL ) - nRDD := AScan( aRDDList, "LOGRDD" ) - - IF nRDD > 0 - - nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO - - aRDDData := USRRDD_RDDDATA( nRDD ) - - bOldUserLogBlock := aRDDData[ ARRAY_MSGLOGBLOCK ] - - IF HB_ISBLOCK( bUserLogBlock ) - aRDDData[ ARRAY_USERLOGBLOCK ] := bUserLogBlock - ENDIF - - ENDIF - RETURN bOldUserLogBlock - -#ifdef __XHARBOUR__ -FUNCTION hb_LogRddValueToText( uValue ) - - LOCAL cType := ValType( uValue ) - LOCAL cText := ValToPrg( uValue ) - - RETURN "[" + cType + "]>>>" + cText + "<<<" -#else -FUNCTION hb_LogRddValueToText( uValue ) - - LOCAL cType := ValType( uValue ) - LOCAL cText - - DO CASE - CASE cType == "C" - cText := hb_StrToExp( uValue ) - - CASE cType == "N" - cText := hb_NToS( uValue ) - - CASE cType == "D" - cText := DToS( uValue ) - cText := "0d" + iif( Empty( cText ), "00000000", cText ) - - OTHERWISE - cText := hb_ValToStr( uValue ) - ENDCASE - - RETURN "[" + cType + "]>>>" + cText + "<<<" -#endif - -/* -------------------------------------------------- */ -/* LOCAL UTILITY FUNCTIONS */ -/* -------------------------------------------------- */ - -STATIC PROCEDURE OpenLogFile( nWA ) - LOCAL aRDDData := USRRDD_RDDDATA( USRRDD_ID( nWA ) ) - LOCAL cFileName := aRDDData[ ARRAY_FILENAME ] - LOCAL nHandle := aRDDData[ ARRAY_FHANDLE ] - LOCAL lActive := aRDDData[ ARRAY_ACTIVE ] - - //TraceLog( "nHandle " + cStr( nHandle ) ) - - IF lActive .AND. nHandle == NIL - - /* Open Access Log File */ - IF File( cFileName ) - nHandle := FOpen( cFileName, FO_READWRITE + FO_SHARED ) - ELSE - nHandle := FCreate( cFileName ) - /* Close and reopen in shared mode */ - IF FError() == 0 .AND. nHandle > 0 - FClose( nHandle ) - nHandle := FOpen( cFileName, FO_READWRITE + FO_SHARED ) - ENDIF - ENDIF - IF FError() == 0 .AND. nHandle > 0 - /* Move to end of file */ - FSeek( nHandle, 0, FS_END ) - ELSE - nHandle := NIL - ENDIF - - aRDDData[ ARRAY_FHANDLE ] := nHandle - - ENDIF - RETURN - -STATIC FUNCTION ToString( cCmd, nWA, xPar1, xPar2, xPar3 ) - LOCAL cString - - DO CASE - CASE cCmd == "CREATE" - // Parameters received: xPar1 = aOpenInfo - cString := xPar1[ UR_OI_NAME ] - CASE cCmd == "CREATEFIELDS" - // Parameters received: xPar1 = aStruct - cString := hb_ValToExp( xPar1 ) - CASE cCmd == "OPEN" - // Parameters received: xPar1 = aOpenInfo - cString := 'Table : "' + xPar1[ UR_OI_NAME ] + '", Alias : "' + Alias() + '", WorkArea : ' + LTrim( Str( nWA ) ) - CASE cCmd == "CLOSE" - // Parameters received: xPar1 = cTableName, xPar2 = cAlias - cString := 'Table : "' + xPar1 + '", Alias : "' + xPar2 + '", WorkArea : ' + LTrim( Str( nWA ) ) - CASE cCmd == "APPEND" - // Parameters received: xPar1 = lUnlockAll - cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) - CASE cCmd == "DELETE" - // Parameters received: none - cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) - CASE cCmd == "RECALL" - // Parameters received: none - cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) - CASE cCmd == "PUTVALUE" - // Parameters received: xPar1 = nField, xPar2 = xValue, xPar3 = xOldValue -#ifndef __XHARBOUR__ - HB_SYMBOL_UNUSED( xPar3 ) // Here don't log previous value -#endif - cString := Alias() + "(" + LTrim( Str( RecNo() ) ) + ")->" + PadR( FieldName( xPar1 ), 10 ) + " := " + hb_LogRddValueToText( xPar2 ) - CASE cCmd == "ZAP" - // Parameters received: none - cString := 'Alias : "' + Alias() + ' Table : "' + dbInfo( DBI_FULLPATH ) + '"' - ENDCASE - RETURN cString - -STATIC PROCEDURE ToLog( cCmd, nWA, xPar1, xPar2, xPar3 ) - LOCAL aRDDData := USRRDD_RDDDATA( USRRDD_ID( nWA ) ) - LOCAL lActive := aRDDData[ ARRAY_ACTIVE ] - LOCAL nHandle, cTag, cRDDName, bMsgLogBlock, bUserLogBlock, cLog - - // Check if logging system is active - IF lActive - - cTag := aRDDData[ ARRAY_TAG ] - cRDDName := aRDDData[ ARRAY_RDDNAME ] - bUserLogBlock := aRDDData[ ARRAY_USERLOGBLOCK ] - - // If not defined a User codeblock - IF !HB_ISBLOCK( bUserLogBlock ) - - nHandle := aRDDData[ ARRAY_FHANDLE ] - - // If log file is not already open I open now - IF nHandle == NIL - OpenLogFile( nWA ) - ENDIF - - IF nHandle != NIL - - bMsgLogBlock := aRDDData[ ARRAY_MSGLOGBLOCK ] - - // If defined a codeblock I send to user infos and he has to return a formatted string - // Look at local ToString() function for details - IF HB_ISBLOCK( bMsgLogBlock ) - cLog := Eval( bMsgLogBlock, cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3 ) - ELSE - cLog := DToS( Date() ) + " " + Time() + " " + cTag + ": " + PadR( cRDDName + "_" + cCmd, 20 ) + " - " + ToString( cCmd, nWA, xPar1, xPar2, xPar3 ) - ENDIF - // Log to file only if cLog is a valid string - IF HB_ISSTRING( cLog ) - FWrite( nHandle, cLog + hb_OSNewLine() ) - ENDIF - ENDIF - - ELSE - - // Otherwise I send all to user that is responsible to log everywhere - Eval( bUserLogBlock, cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3 ) - - ENDIF - - ENDIF - RETURN - +/* + * $Id: rlcdx.prg 9754 2008-10-27 22:40:04Z vszakats $ + */ + +/* + * Harbour Project source code: + * LOGRDD + * + * Copyright 2009 Francesco Saverio Giudice + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +/* + * A simple RDD which introduce logging to file. It inheriths from + * any existent RDD but if you write / replace / delete something + * on tables it writes changes in a log file. + * An example is avalaible at + * harbour/source/rdd/usrrdd/example/exlog.prg + */ + +#include "rddsys.ch" +#ifdef __XHARBOUR__ + #include "usrrdd.ch" + #xtranslate hb_valtoexp( => cStr( +#else + #include "hbusrrdd.ch" +#endif +#include "common.ch" +#include "fileio.ch" +#include "dbinfo.ch" + +#define ARRAY_FILENAME 1 +#define ARRAY_FHANDLE 2 +#define ARRAY_TAG 3 +#define ARRAY_ACTIVE 4 +#define ARRAY_RDDNAME 5 +#define ARRAY_MSGLOGBLOCK 6 +#define ARRAY_USERLOGBLOCK 7 + +ANNOUNCE LOGRDD +DYNAMIC HB_LOGRDDINHERIT /* To be defined at user level */ + +STATIC FUNCTION LOGRDD_INIT( nRDD ) + LOCAL lActive, cFileName, cTag, cRDDName + + /* Defaults */ + cFileName := "changes.log" + lActive := .F. + #ifdef __XHARBOUR__ + cTag := NETNAME() + "\" + NETNAME( 1 ) + #else + cTag := NETNAME() + "\" + hb_USERNAME() + #endif + cRDDName := hb_LogRddInherit() + + /* Log File will be open later so user can change parameters */ + + /* Store data in RDD cargo */ + /* cFileName, nHandle, cTag, lActive, cRDDName, bMsgLogBlock, bUserLogBlock */ + USRRDD_RDDDATA( nRDD, { cFileName, NIL, cTag, lActive, cRDDName, NIL, NIL } ) + +RETURN SUCCESS + +STATIC FUNCTION LOGRDD_EXIT( nRDD ) + LOCAL aRDDData := USRRDD_RDDDATA( nRDD ) + + /* Closing log file */ + IF aRDDData[ ARRAY_FHANDLE ] != NIL + FClose( aRDDData[ ARRAY_FHANDLE ] ) + aRDDData[ ARRAY_FHANDLE ] := NIL + ENDIF + +RETURN SUCCESS + +// Create database from current WA fields definition +STATIC FUNCTION LOGRDD_CREATE( nWA, aOpenInfo ) + LOCAL nResult := UR_SUPER_CREATE( nWA, aOpenInfo ) + IF nResult == SUCCESS + ToLog( "CREATE", nWA, aOpenInfo ) + ENDIF + RETURN nResult + +// Creating fields for new DBF - dbCreate() in current workarea +STATIC FUNCTION LOGRDD_CREATEFIELDS( nWA, aStruct ) + LOCAL nResult := UR_SUPER_CREATEFIELDS( nWA, aStruct ) + IF nResult == SUCCESS + ToLog( "CREATEFIELDS", nWA, aStruct ) + ENDIF + RETURN nResult + +// Open workarea +STATIC FUNCTION LOGRDD_OPEN( nWA, aOpenInfo ) + LOCAL nResult := UR_SUPER_OPEN( nWA, aOpenInfo ) + IF nResult == SUCCESS + ToLog( "OPEN", nWA, aOpenInfo ) + ENDIF + RETURN nResult + +// Close workarea +STATIC FUNCTION LOGRDD_CLOSE( nWA ) + LOCAL cFile := dbInfo( DBI_FULLPATH ) + LOCAL cAlias := Alias() + LOCAL nResult := UR_SUPER_CLOSE( nWA ) + IF nResult == SUCCESS + ToLog( "CLOSE", nWA, cFile, cAlias ) + ENDIF + RETURN nResult + +STATIC FUNCTION LOGRDD_APPEND( nWA, lUnlockAll ) + LOCAL nResult := UR_SUPER_APPEND( nWA, lUnlockAll ) + IF nResult == SUCCESS + ToLog( "APPEND", nWA, lUnlockAll ) + ENDIF + RETURN nResult + +STATIC FUNCTION LOGRDD_DELETE( nWA ) + LOCAL nResult := UR_SUPER_DELETE( nWA ) + IF nResult == SUCCESS + ToLog( "DELETE", nWA ) + ENDIF + RETURN nResult + +STATIC FUNCTION LOGRDD_RECALL( nWA ) + LOCAL nResult := UR_SUPER_RECALL( nWA ) + IF nResult == SUCCESS + ToLog( "RECALL", nWA ) + ENDIF + RETURN nResult + +STATIC FUNCTION LOGRDD_PUTVALUE( nWA, nField, xValue ) + LOCAL xOldValue := FieldGet( nField ) + LOCAL nResult := UR_SUPER_PUTVALUE( nWA, nField, xValue ) + + //Log Only Changes + IF !( xOldValue == xValue ) + ToLog( "PUTVALUE", nWA, nField, xValue, xOldValue ) + ENDIF + RETURN nResult + +STATIC FUNCTION LOGRDD_ZAP( nWA ) + LOCAL nResult := UR_SUPER_ZAP( nWA ) + IF nResult == SUCCESS + ToLog( "ZAP", nWA ) + ENDIF + RETURN nResult + +/* Force linking DBFCDX from which our RDD inherits */ +REQUEST DBFCDX + +/* + * This function have to exist in all RDD and then name have to be in + * format: _GETFUNCTABLE + */ +FUNCTION LOGRDD_GETFUNCTABLE( pFuncCount, pFuncTable, pSuperTable, nRddID ) + LOCAL cSuperRDD := hb_LogRddInherit() /* We are inheriting from a User Defined RDD */ + LOCAL aMyFunc[ UR_METHODCOUNT ] + + aMyFunc[ UR_INIT ] := ( @LOGRDD_INIT() ) + aMyFunc[ UR_EXIT ] := ( @LOGRDD_EXIT() ) + aMyFunc[ UR_CREATE ] := ( @LOGRDD_CREATE() ) + aMyFunc[ UR_CREATEFIELDS ] := ( @LOGRDD_CREATEFIELDS() ) + aMyFunc[ UR_OPEN ] := ( @LOGRDD_OPEN() ) + aMyFunc[ UR_CLOSE ] := ( @LOGRDD_CLOSE() ) + aMyFunc[ UR_APPEND ] := ( @LOGRDD_APPEND() ) + aMyFunc[ UR_DELETE ] := ( @LOGRDD_DELETE() ) + aMyFunc[ UR_RECALL ] := ( @LOGRDD_RECALL() ) + aMyFunc[ UR_PUTVALUE ] := ( @LOGRDD_PUTVALUE() ) + aMyFunc[ UR_ZAP ] := ( @LOGRDD_ZAP() ) + +RETURN USRRDD_GETFUNCTABLE( pFuncCount, pFuncTable, pSuperTable, nRddID, ; + cSuperRDD, aMyFunc ) + +INIT PROCEDURE _LOGRDD_INIT() + rddRegister( "LOGRDD", RDT_FULL ) + RETURN + +/* -------------------------------------------------- */ +/* USER UTILITY FUNCTIONS */ +/* -------------------------------------------------- */ + +FUNCTION hb_LogRddLogFileName( cFileName ) + LOCAL nRDD, aRDDList + LOCAL aRDDData + LOCAL cOldFileName + + aRDDList := RDDLIST( RDT_FULL ) + nRDD := AScan( aRDDList, "LOGRDD" ) + + IF nRDD > 0 + + nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO + + aRDDData := USRRDD_RDDDATA( nRDD ) + + cOldFileName := aRDDData[ ARRAY_FILENAME ] + + IF HB_ISSTRING( cFileName ) + aRDDData[ ARRAY_FILENAME ] := cFileName + ENDIF + + ENDIF + RETURN cOldFileName + +FUNCTION hb_LogRddTag( cTag ) + LOCAL nRDD, aRDDList + LOCAL aRDDData + LOCAL cOldTag + + aRDDList := RDDLIST( RDT_FULL ) + nRDD := AScan( aRDDList, "LOGRDD" ) + + IF nRDD > 0 + + nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO + + aRDDData := USRRDD_RDDDATA( nRDD ) + + cOldTag := aRDDData[ ARRAY_TAG ] + + IF HB_ISSTRING( cTag ) + aRDDData[ ARRAY_TAG ] := cTag + ENDIF + + ENDIF + RETURN cOldTag + +FUNCTION hb_LogRddActive( lActive ) + LOCAL nRDD, aRDDList + LOCAL aRDDData + LOCAL lOldActive + + aRDDList := RDDLIST( RDT_FULL ) + nRDD := AScan( aRDDList, "LOGRDD" ) + + IF nRDD > 0 + + nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO + + aRDDData := USRRDD_RDDDATA( nRDD ) + + lOldActive := aRDDData[ ARRAY_ACTIVE ] + + IF HB_ISLOGICAL( lActive ) + aRDDData[ ARRAY_ACTIVE ] := lActive + ENDIF + + ENDIF + RETURN lOldActive + +FUNCTION hb_LogRddMsgLogBlock( bMsgLogBlock ) + LOCAL nRDD, aRDDList + LOCAL aRDDData + LOCAL bOldMsgLogBlock + + aRDDList := RDDLIST( RDT_FULL ) + nRDD := AScan( aRDDList, "LOGRDD" ) + + IF nRDD > 0 + + nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO + + aRDDData := USRRDD_RDDDATA( nRDD ) + + bOldMsgLogBlock := aRDDData[ ARRAY_MSGLOGBLOCK ] + + IF HB_ISBLOCK( bMsgLogBlock ) + aRDDData[ ARRAY_MSGLOGBLOCK ] := bMsgLogBlock + ENDIF + + ENDIF + RETURN bOldMsgLogBlock + +FUNCTION hb_LogRddUserLogBlock( bUserLogBlock ) + LOCAL nRDD, aRDDList + LOCAL aRDDData + LOCAL bOldUserLogBlock + + aRDDList := RDDLIST( RDT_FULL ) + nRDD := AScan( aRDDList, "LOGRDD" ) + + IF nRDD > 0 + + nRDD -- // HACK: Possibly an error of nRDD value in UR_INIT() ? - TODO + + aRDDData := USRRDD_RDDDATA( nRDD ) + + bOldUserLogBlock := aRDDData[ ARRAY_MSGLOGBLOCK ] + + IF HB_ISBLOCK( bUserLogBlock ) + aRDDData[ ARRAY_USERLOGBLOCK ] := bUserLogBlock + ENDIF + + ENDIF + RETURN bOldUserLogBlock + +#ifdef __XHARBOUR__ +FUNCTION hb_LogRddValueToText( uValue ) + + LOCAL cType := ValType( uValue ) + LOCAL cText := ValToPrg( uValue ) + + RETURN "[" + cType + "]>>>" + cText + "<<<" +#else +FUNCTION hb_LogRddValueToText( uValue ) + + LOCAL cType := ValType( uValue ) + LOCAL cText + + DO CASE + CASE cType == "C" + cText := hb_StrToExp( uValue ) + + CASE cType == "N" + cText := hb_NToS( uValue ) + + CASE cType == "D" + cText := DToS( uValue ) + cText := "0d" + iif( Empty( cText ), "00000000", cText ) + + OTHERWISE + cText := hb_ValToStr( uValue ) + ENDCASE + + RETURN "[" + cType + "]>>>" + cText + "<<<" +#endif + +/* -------------------------------------------------- */ +/* LOCAL UTILITY FUNCTIONS */ +/* -------------------------------------------------- */ + +STATIC PROCEDURE OpenLogFile( nWA ) + LOCAL aRDDData := USRRDD_RDDDATA( USRRDD_ID( nWA ) ) + LOCAL cFileName := aRDDData[ ARRAY_FILENAME ] + LOCAL nHandle := aRDDData[ ARRAY_FHANDLE ] + LOCAL lActive := aRDDData[ ARRAY_ACTIVE ] + + //TraceLog( "nHandle " + cStr( nHandle ) ) + + IF lActive .AND. nHandle == NIL + + /* Open Access Log File */ + IF File( cFileName ) + nHandle := FOpen( cFileName, FO_READWRITE + FO_SHARED ) + ELSE + nHandle := FCreate( cFileName ) + /* Close and reopen in shared mode */ + IF FError() == 0 .AND. nHandle > 0 + FClose( nHandle ) + nHandle := FOpen( cFileName, FO_READWRITE + FO_SHARED ) + ENDIF + ENDIF + IF FError() == 0 .AND. nHandle > 0 + /* Move to end of file */ + FSeek( nHandle, 0, FS_END ) + ELSE + nHandle := NIL + ENDIF + + aRDDData[ ARRAY_FHANDLE ] := nHandle + + ENDIF + RETURN + +STATIC FUNCTION ToString( cCmd, nWA, xPar1, xPar2, xPar3 ) + LOCAL cString + + DO CASE + CASE cCmd == "CREATE" + // Parameters received: xPar1 = aOpenInfo + cString := xPar1[ UR_OI_NAME ] + CASE cCmd == "CREATEFIELDS" + // Parameters received: xPar1 = aStruct + cString := hb_ValToExp( xPar1 ) + CASE cCmd == "OPEN" + // Parameters received: xPar1 = aOpenInfo + cString := 'Table : "' + xPar1[ UR_OI_NAME ] + '", Alias : "' + Alias() + '", WorkArea : ' + LTrim( Str( nWA ) ) + CASE cCmd == "CLOSE" + // Parameters received: xPar1 = cTableName, xPar2 = cAlias + cString := 'Table : "' + xPar1 + '", Alias : "' + xPar2 + '", WorkArea : ' + LTrim( Str( nWA ) ) + CASE cCmd == "APPEND" + // Parameters received: xPar1 = lUnlockAll + cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) + CASE cCmd == "DELETE" + // Parameters received: none + cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) + CASE cCmd == "RECALL" + // Parameters received: none + cString := Alias() + "->RecNo() = " + LTrim( Str( RecNo() ) ) + CASE cCmd == "PUTVALUE" + // Parameters received: xPar1 = nField, xPar2 = xValue, xPar3 = xOldValue +#ifndef __XHARBOUR__ + HB_SYMBOL_UNUSED( xPar3 ) // Here don't log previous value +#endif + cString := Alias() + "(" + LTrim( Str( RecNo() ) ) + ")->" + PadR( FieldName( xPar1 ), 10 ) + " := " + hb_LogRddValueToText( xPar2 ) + CASE cCmd == "ZAP" + // Parameters received: none + cString := 'Alias : "' + Alias() + ' Table : "' + dbInfo( DBI_FULLPATH ) + '"' + ENDCASE + RETURN cString + +STATIC PROCEDURE ToLog( cCmd, nWA, xPar1, xPar2, xPar3 ) + LOCAL aRDDData := USRRDD_RDDDATA( USRRDD_ID( nWA ) ) + LOCAL lActive := aRDDData[ ARRAY_ACTIVE ] + LOCAL nHandle, cTag, cRDDName, bMsgLogBlock, bUserLogBlock, cLog + + // Check if logging system is active + IF lActive + + cTag := aRDDData[ ARRAY_TAG ] + cRDDName := aRDDData[ ARRAY_RDDNAME ] + bUserLogBlock := aRDDData[ ARRAY_USERLOGBLOCK ] + + // If not defined a User codeblock + IF !HB_ISBLOCK( bUserLogBlock ) + + nHandle := aRDDData[ ARRAY_FHANDLE ] + + // If log file is not already open I open now + IF nHandle == NIL + OpenLogFile( nWA ) + ENDIF + + IF nHandle != NIL + + bMsgLogBlock := aRDDData[ ARRAY_MSGLOGBLOCK ] + + // If defined a codeblock I send to user infos and he has to return a formatted string + // Look at local ToString() function for details + IF HB_ISBLOCK( bMsgLogBlock ) + cLog := Eval( bMsgLogBlock, cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3 ) + ELSE + cLog := DToS( Date() ) + " " + Time() + " " + cTag + ": " + PadR( cRDDName + "_" + cCmd, 20 ) + " - " + ToString( cCmd, nWA, xPar1, xPar2, xPar3 ) + ENDIF + // Log to file only if cLog is a valid string + IF HB_ISSTRING( cLog ) + FWrite( nHandle, cLog + hb_OSNewLine() ) + ENDIF + ENDIF + + ELSE + + // Otherwise I send all to user that is responsible to log everywhere + Eval( bUserLogBlock, cTag, cRDDName, cCmd, nWA, xPar1, xPar2, xPar3 ) + + ENDIF + + ENDIF + RETURN +