Nice blog, thanks to your efforts dedicated to Harbour ( and special thank for your notice about my humble web page )
"Multiple themes" is a nice feature. My favorite is "Sidebar" and I have a little suggestion: because your blog will expand quickly, your sidebar too will be a list long drawn out. Instead of a simple list, ( if possible ) a tree structure may be more convenient. Such as:
Regarding your request: me too, I want accompanying to you with a little and humble work.
I'm not sure this is useful and is worth to interest of you and community.
If you have some ideas as sample please inform me; I will be happy if anything I can make for Harbour people.
Code: Select all
/*
Understanding Harbour extended Field Types
Type Short
Code Name Width (Bytes) Description
---- ------- ----------------- -------------------------------------------------------------------
D Date 3, 4 or 8 Date
M Memo 4 or 8 Memo
+ AutoInc 4 Auto increment
= ModTime 8 Last modified date & time of this record
^ RowVers 8 Row version number; modification count of this record
@ DayTime 8 Date & Time
I Integer 1, 2, 3, 4 or 8 Signed Integer ( Width : )" },;
T Time 4 or 8 Only time (if width is 4 ) or Date & Time (if width is 8 ) (?)
V Variant 3, 4, 6 or more Variable type Field
Y Currency 8 64 bit integer with implied 4 decimal
B Double 8 Floating point / 64 bit binary
Program : ExFldTps.prg
Author : Bicahi Esgici ( esgici <at> gmail.com )
All rights reserved.
2011.10.12
*/
PROCEDURE Main()
LOCAL aOperations := { { "Width", "Testing Field Widths" },;
{ "Numeric Limits", "Determining Numeric Limits" },;
{ "Integer Limits", "Determining Integer Limits" },;
{ "Set/Get", "Set & read back field values" },;
{ "Conversion", "Convert and test signed to integer" }},;
a1Oper := {},;
n1Oper := 1
LOCAL aFldTypes := { { "D", "Date", "Date ( Width : 3, 4 or 8 )" } ,;
{ "M", "Memo", "Memo ( Width : 4 or 8 )" },;
{ "+", "AutoInc", "Auto increment ( Width : 4 )" },;
{ "=", "ModTime", "Last modified date & time of this record ( Width : 8 )" },;
{ "^", "RowVers", "Row version number; modification count of this record ( Width : 8 )" },;
{ "@", "DayTime", "Date & Time ( Width : 8 )" },;
{ "I", "Integer", "Signed Integer ( Width : 1, 2, 3, 4 or 8 )" },;
{ "T", "Time", "Only time (if width is 4 ) or Date & Time (if width is 8 )" },;
{ "V", "Variant", "Variable type (!) Field ( Width : 3, 4, 6 or more)" },;
{ "Y", "Currency", "Integer 64 bit with implied 4 decimal" },;
{ "B", "Double", "Floating point / 64 bit binary ( Width : 8 )" } },;
a1Type := {},;
n1Type := 1,;
n2Type := 1
LOCAL nMColumn := 0,; // Menu Column No
nMRow := 0 // Menu Row No
SET WRAP ON
SET MESSAGE TO 22 CENTER
SET CENTURY ON
SetMode( 25, 80 ) // Win-7 ???
WHILE n1Oper > 0
CLS
nMSutn := 0
FOR EACH a1Oper IN aOperations
@ 0, nMSutn PROMPT a1Oper[ 1 ] MESSAGE a1Oper[ 2 ]
nMSutn += LEN( a1Oper[ 1 ] ) + 1
NEXT
MENU TO n1Oper
SWITCH n1Oper
CASE 0
EXIT
CASE 1 // Testing Field Widths
n1Type := 1
WHILE n1Type > 0
@ 1,0 CLEAR TO 24, 80
nMRow := 2
FOR EACH a1Type IN aFldTypes
@ nMRow++, 0 PROMPT a1Type[ 2 ] MESSAGE a1Type[ 3 ]
NEXT a1Type
MENU TO n1Type
IF n1Type > 0
@ 1,0 CLEAR TO 24, 80
@ 1, 0 SAY aFldTypes[ n1Type, 2 ] COLOR "B/W"
FT_Widths( aFldTypes[ n1Type ] )
ENDIF
ENDDO n1Type
EXIT
CASE 2 // Determining Numeric Limits
NumLimits()
EXIT
CASE 3 // Determining Integer Limits
IntLimits()
EXIT
CASE 4 // Set & read back field values
n2Type := 1
WHILE n2Type > 0
@ 1,0 CLEAR TO 24, 80
nMRow := 2
FOR EACH a1Type IN aFldTypes
@ nMRow++, 36 PROMPT a1Type[ 2 ] MESSAGE a1Type[ 3 ]
NEXT
MENU TO n2Type
IF n2Type > 0
V_SetGet( aFldTypes[ n2Type ] )
ENDIF
ENDDO n1Type
EXIT
CASE 5 // Convert and test signed to integer
SignChng()
EXIT
END SWITCH
ENDDO n1Oper
RETURN // Main()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE FT_Widths( a1Type ) // Testing Field Widths
LOCAL cType := a1Type[ 1 ],;
nFldNo := 0,;
aStru1 := {},;
aStru2 := {},;
aStru3 := { { 'FldType', "C", 1, 0 },; // Type of field
{ 'WidtSpec', "N", 2, 0 },; // Specified width
{ 'Dec_Spec', "N", 2, 0 },; // Specified decimal
{ 'WidtAppl', "N", 2, 0 },; // Applied (by Harbour) width
{ 'Dec_Max', "N", 2, 0 },; // Computed maximum dec
{ 'Result', "C", 1, 0 } }
FOR nFldNo := 1 TO 32
AADD( aStru1, { "X" + STRZERO( nFldNo, 2 ), cType, nFldNo, 0 } )
NEXT nFldNo
DBCREATE( "Widths", aStru1 )
USE Widths
aStru2 := DBSTRUCT()
IF cType $ "IYB"
AEVAL( aStru2, { | a1, i1 | aStru2[ i1, 4 ] := aStru2[ i1, 3 ] - 1 } )
ENDIF
USE
DBCREATE( "Widths", aStru2 )
USE Widths
aStru2 := DBSTRUCT()
USE
DBCREATE( "Widths", aStru3 )
USE Widths
FOR nFldNo := 1 TO 32
DBAPPEND()
REPLACE FldType WITH aStru1[ nFldNo, 2 ],;
WidtSpec WITH aStru1[ nFldNo, 3 ],;
Dec_Spec WITH aStru1[ nFldNo, 4 ],;
WidtAppl WITH aStru2[ nFldNo, 3 ],;
Dec_Max WITH aStru2[ nFldNo, 4 ],;
Result WITH IF( aStru1[ nFldNo, 3 ] # aStru2[ nFldNo, 3 ], "-", "+" )
NEXT nFldNo
DBGOTOP()
BROWSE()
USE
RETURN // FT_Widths()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE NumLimits() // Determining Numeric Limits
LOCAL mBayt := 0,;
nBit := 0,;
nExpo := 0
* nExpos := { 8, 16, 24, 32, 64 }
SET ALTE TO N_Limits
SET ALTE ON
? SPACE(9), "Unsigned ( Always + )"
? "-- ------ ---------------------------"
FOR nBayt := 1 TO 8
nBit := nBayt * 8
nExpo := 2^nBit
? STR( nBayt, 2 ), "2^" + PADL( nBit, 2) + " : ", TRANSFORM( nExpo, "99,999,999,999,999,999,999" )
NEXT nBayt
?
?
? PADC( "Signed ( - / + )", 80 )
? "-- ------ -----------------------------------------------------"
FOR nBayt := 1 TO 8
nBit := nBayt * 8
nExpo := 2^nBit
? STR( nBayt, 2 ), "2^" + PADL( nBit, 2) + " : ", TRANSFORM( - nExpo / 2, "99,999,999,999,999,999,999" )+;
".."+;
LTRIM( TRANSFORM( nExpo / 2 - 1, "99,999,999,999,999,999,999" ) )
NEXT nBayt
SET ALTE OFF
SET ALTE TO
MEMOEDIT( MEMOREAD( "N_Limits.TXT" ) )
RETURN // NumLimits()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE IntLimits() // Determining Integer Limits
LOCAL nFldNo := 0,;
aStru4 := { { 'MNMX', "C", 7, 0 },;
{ 'INT1', "I", 1, 0 },;
{ 'INT2', "I", 2, 0 },;
{ 'INT3', "I", 3, 0 },;
{ 'INT4', "I", 4, 0 },;
{ 'INT8', "I", 8, 0 } }
DBCREATE( "IntLimits", aStru4 )
USE IntLimits
DBAPPEND()
REPLACE MNMX WITH "Minimum" ,;
INT1 WITH -2^7 ,;
INT2 WITH -2^15 ,;
INT3 WITH -2^23 ,;
INT4 WITH -2^31 ,;
INT8 WITH -2^63
DBAPPEND()
REPLACE MNMX WITH "Maximum" ,;
INT1 WITH 2^7 - 1 ,;
INT2 WITH 2^15 - 1 ,;
INT3 WITH 2^23 - 1 ,;
INT4 WITH 2^31 - 1 ,;
INT8 WITH 2^63 - 513 // < 513 ---> "Error DBFNTX/1021 Data width error"
DBGOTOP()
@ 1,0 CLEAR TO 24, 80
SET ALTE TO IntLimits
SET ALTE ON
WHILE !EOF()
?
? MNMX
? '--------'
FOR nFldNo := 2 TO 6
? FIELDNAME( nFldNo ), ": ", LTRIM( TRANSFORM( FIELDGET( nFldNo ), "99,999,999,999,999,999,999" ) )
NEXT nFldNo
?
SKIP
ENDDO
SET ALTE OFF
SET ALTE TO
MEMOEDIT( MEMOREAD( "IntLimits.txt" ) )
USE
RETURN // IntLimits()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE SG_NoType() // Testing NoType ( Variant ) field type
LOCAL aStru5 := { { "Initial", "C", 19, 0 },;
{ "Internal", "V", 19, 0 },;
{ "ReadBack", "C", 19, 0 },;
{ "ReadBackTp", "C", 1, 0 } }
DBCREATE( "SG_NoType", aStru5 )
USE SG_NoType
DBAPPEND()
REPLACE Initial WITH "String", Internal WITH "String"
DBAPPEND()
REPLACE Initial WITH "12345", Internal WITH 12345
DBAPPEND()
REPLACE Initial WITH DTOC( DATE() ), Internal WITH DATE()
DBAPPEND()
REPLACE Initial WITH ".T.", Internal WITH .T.
REPLACE ALL ReadBack WITH HB_ValToStr( Internal ), ReadBackTp WITH VALTYPE( Internal )
DBGOTOP()
BROWSE()
USE
RETURN // SG_NoType()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE V_SetGet( aType ) // Set & read back field values
LOCAL cType := aType[ 1 ]
@ 1,0 CLEAR TO 24, 80
SWITCH cType
CASE "D" // Date
SG_Date()
EXIT
CASE "M" // Memo
SG_Memo()
EXIT
CASE "+" // AutoInc
Alert( "Read Only" )
EXIT
CASE "=" // ModTime
Alert( "Read Only" )
EXIT
CASE "^" // RowVers
Alert( "Read Only" )
EXIT
CASE "@" // DayTime
SG_DayTime()
EXIT
CASE "I" // Integer
SG_Integers()
EXIT
CASE "T" // Time
SG_DayTime()
EXIT
CASE "V" // Variant
SG_NoType()
EXIT
CASE "Y" // Currency
SG_Currency()
EXIT
CASE "B" // Double
SG_Double()
EXIT
END SWITCH
RETURN // V_SetGet()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE SG_Date() // Date : Compare set / get
LOCAL aStru6 := { { "Initial", "D", 8, 0 } ,;
{ "Internal3", "D", 3, 0 } ,;
{ "Internal4", "D", 4, 0 } ,;
{ "Internal8", "D", 8, 0 } ,;
{ "ReadBack3", "C", 12, 0 } ,;
{ "ReadBack4", "C", 12, 0 } ,;
{ "ReadBack8", "C", 12, 0 } }
DBCREATE( "SG_Date", aStru6 )
USE SG_Date
DBAPPEND()
REPLACE Initial WITH DATE() - ( 66 * 365 + 66 / 4 ),;
Internal3 WITH Initial ,;
Internal4 WITH Initial ,;
Internal8 WITH Initial ,;
ReadBack3 WITH HB_ValToStr( Internal3 ) ,;
ReadBack4 WITH HB_ValToStr( Internal4 ) ,;
ReadBack8 WITH HB_ValToStr( Internal8 )
DBGOTOP()
BROWSE()
USE
RETURN // SG_Date()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE SG_Memo() // Set / Get test for MEMO fields
LOCAL aStru7 := { { "MEMO_4", "M", 4, 0 } ,;
{ "MEMO_10", "M", 10, 0 } }
DBCREATE( "SG_Memo", aStru7 )
USE SG_Memo
DBAPPEND()
REPLACE MEMO_4 WITH "MEMO field with width 4",;
MEMO_10 WITH "MEMO field with width 4"
DBGOTOP()
BROWSE()
USE
RETURN // SG_Date()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE SG_DayTime() // Set / Get test for DayTime fields
LOCAL aStru8 := { { "ModTim", "=", 8, 0 } ,;
{ "DaTime", "@", 8, 0 } ,; //
{ "Time_8", "T", 8, 0 } ,;
{ "Time_4", "T", 4, 0 } ,;
{ "Time_C", "C", 12, 0 } }
DBCREATE( "SG_Datime", aStru8 )
USE SG_Datime
DBAPPEND()
* REPLACE DaTime WITH DATE() // ==> Error DBFNTX/1020 Data type error: DATIME
* REPLACE Time_4 WITH SECO() / TIME() // ==> Error DBFNTX/1020 Data type error: DATIME
* REPLACE Time_8 WITH TIME() // ==> Error DBFNTX/1020 Data type error: TIME_8
* DBAPPEND()
* REPLACE DaTime WITH ModTim // ==> 0000-00-00 00:00:00.000
* REPLACE Time_4 WITH ModTim // ==> Error DBFNTX/1020 Data type error: TIME_4
* REPLACE Time_8 WITH ModTim // ==> 0000-00-00 00:00:00.000
REPLACE DaTime WITH ModTim,; // ==> > 0000-00-00 00:00:00.000
Time_8 WITH ModTim,; // ==> > 0000-00-00 00:00:00.000
Time_C WITH TIME()
DBGOTOP()
BROWSE()
USE
RETURN // SG_DayTime()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE SG_Integers() // Set / Get test for INTEGER fields
LOCAL nRecno := 0,;
aStru9 := { { 'INT1', "I", 1, 0 },;
{ 'NUM1', "N", 4, 0 },;
{ 'EQL1', "L", 1, 0 },;
{ 'INT11', "I", 1, 1 },;
{ 'NUM11', "N", 5, 1 },;
{ 'EQL11', "L", 1, 0 },;
{ 'INT2', "I", 2, 0 },;
{ 'NUM2', "N", 8, 0 },;
{ 'EQL2', "L", 1, 0 },;
{ 'INT22', "I", 8, 2 },;
{ 'NUM22', "N",12, 2 },;
{ 'EQL22', "L", 1, 0 },;
{ 'INT3', "I", 3, 0 },;
{ 'NUM3', "N", 8, 0 },;
{ 'EQL3', "L", 1, 0 },;
{ 'INT32', "I", 3, 2 },;
{ 'NUM32', "N",12, 2 },;
{ 'EQL32', "L", 1, 0 },;
{ 'INT4', "I", 4, 0 },;
{ 'NUM4', "N",12, 0 },;
{ 'EQL4', "L", 1, 0 },;
{ 'INT42', "I", 4, 2 },;
{ 'NUM42', "N",14, 2 },;
{ 'EQL42', "L", 1, 0 },;
{ 'INT8', "I", 8, 0 },;
{ 'NUM8', "N",21, 0 },;
{ 'EQL8', "L", 1, 0 },;
{ 'INT84', "I", 8, 4 },;
{ 'NUM84', "N",21, 4 },;
{ 'EQL84', "L", 1, 0 } }
DBCREATE( "SG_Integers", aStru9 )
USE SG_Integers
FOR nRecno := 1 TO 18
DBAPPEND()
NEXT nRecno
REPL ALL INT1 WITH INT( HB_RANDOM( -2^7 , 2^7 - 1 )) ,;
INT11 WITH INT( HB_RANDOM( -2^7 , 2^7 - 1 )) / 10 ,;
INT2 WITH INT( HB_RANDOM( -2^15, 2^15 - 1 )) ,;
INT22 WITH INT( HB_RANDOM( -2^15, 2^15 - 1 )) ,;
INT3 WITH INT( HB_RANDOM( -2^23, 2^23 - 1 )) ,;
INT32 WITH INT( HB_RANDOM( -2^23, 2^23 - 1 )) / 100 ,;
INT4 WITH INT( HB_RANDOM( -2^31, 2^31 - 1 )) ,;
INT42 WITH INT( HB_RANDOM( -2^31, 2^31 - 1 )) / 100 ,;
INT8 WITH INT( HB_RANDOM( -2^63, 2^63 - 513 )) ,;
INT84 WITH INT( HB_RANDOM( -2^63, 2^63 - 513 )) / 10000
REPL ALL NUM1 WITH INT1, EQL1 WITH NUM1 = INT1 ,;
NUM11 WITH INT11, EQL11 WITH NUM11 = INT11 ,;
NUM2 WITH INT2, EQL2 WITH NUM2 = INT2 ,;
NUM22 WITH INT22, EQL22 WITH NUM22 = INT22 ,;
NUM3 WITH INT3, EQL3 WITH NUM3 = INT3 ,;
NUM32 WITH INT32, EQL32 WITH NUM32 = INT32 ,;
NUM4 WITH INT4, EQL4 WITH NUM4 = INT4 ,;
NUM42 WITH INT42, EQL42 WITH NUM42 = INT42 ,;
NUM8 WITH INT8, EQL8 WITH NUM8 = INT8 ,;
NUM84 WITH INT84, EQL84 WITH NUM84 = INT84
DBGOTOP()
BROWSE()
USE
RETURN // SG_Integers()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE SG_Currency() // Set / Get test for CURRENCY fields
LOCAL aStru10 := { { "Currenc", "Y", 8, 4 } ,;
{ "NUM2D", "N", 21, 2 } ,;
{ "NUM4D", "N", 21, 4 } ,;
{ "NUM6D", "N", 23, 6 } ,;
{ "NUM8D", "N", 25, 8 } }
DBCREATE( "SG_Curncy", aStru10 )
USE SG_Curncy
FOR nRecno := 1 TO 100
DBAPPEND()
REPLACE Currenc WITH HB_RANDOM( -2^53, 2^53 ) / 10000 ,;
NUM2D WITH Currenc ,;
NUM4D WITH Currenc ,;
NUM6D WITH Currenc ,;
NUM8D WITH Currenc
NEXT nRecno
DBGOTOP()
BROWSE()
USE
RETURN // SG_Currency()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE SG_Double() // Set / Get test for DOUBLE ( BINARY ) fields
LOCAL nRecno := 0
LOCAL aStru11 := { { "Double", "B", 8, 4 } ,;
{ "NUM2D", "N", 21, 2 } ,;
{ "NUM4D", "N", 21, 4 } ,;
{ "NUM6D", "N", 23, 6 } ,;
{ "NUM8D", "N", 25, 8 } }
DBCREATE( "SG_Double", aStru11 )
USE SG_Double
FOR nRecno := 1 TO 100
DBAPPEND()
REPLACE Double WITH HB_RANDOM( -2^53, 2^53 ) / 10000 ,;
NUM2D WITH Double ,;
NUM4D WITH Double ,;
NUM6D WITH Double ,;
NUM8D WITH Double
NEXT nRecno
DBGOTOP()
BROWSE()
USE
RETURN // SG_Double()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE SignChng() // Convert and test signed to integer
LOCAL nRecno := 0
LOCAL aStru12 := { { 'NUM1', "N", 3, 0 },;
{ 'INT1', "I", 1, 0 },;
{ 'RET1', "N", 3, 0 },;
{ 'EQL1', "L", 1, 0 },;
{ 'NUM2', "N", 6, 0 },;
{ 'INT2', "I", 2, 0 },;
{ 'RET2', "N", 6, 0 },;
{ 'EQL2', "L", 1, 0 },;
{ 'NUM3', "N", 9, 0 },;
{ 'INT3', "I", 3, 0 },;
{ 'RET3', "N", 9, 0 },;
{ 'EQL3', "L", 1, 0 },;
{ 'NUM4', "N", 11, 0 },;
{ 'INT4', "I", 4, 0 },;
{ 'RET4', "N", 11, 0 },;
{ 'EQL4', "L", 1, 0 },;
{ 'NUM8', "N", 21, 0 },;
{ 'INT8', "I", 8, 0 },;
{ 'RET8', "N", 21, 0 },;
{ 'EQL8', "L", 1, 0 } }
DBCREATE( "SignChng", aStru12 )
USE SignChng
FOR nRecno := 1 TO 100
DBAPPEND()
REPLACE NUM1 WITH HB_RANDOM( 0, 2^8 - 1 ), INT1 WITH NUM1 - 2^7 , RET1 WITH INT1 + 2^7, EQL1 WITH NUM1 = RET1 ,;
NUM2 WITH HB_RANDOM( 0, 2^16 - 1 ), INT2 WITH NUM2 - 2^15, RET2 WITH INT2 + 2^15, EQL2 WITH NUM2 = RET2 ,;
NUM3 WITH HB_RANDOM( 0, 2^24 - 1 ), INT3 WITH NUM3 - 2^23, RET3 WITH INT3 + 2^23, EQL3 WITH NUM3 = RET3 ,;
NUM4 WITH HB_RANDOM( 0, 2^32 - 1 ), INT4 WITH NUM4 - 2^31, RET4 WITH INT4 + 2^31, EQL4 WITH NUM4 = RET4 ,;
NUM8 WITH HB_RANDOM( 0, 2^64 - 1 ), INT8 WITH NUM8 - 2^63, RET8 WITH INT8 + 2^63, EQL8 WITH NUM8 = RET8
NEXT nRecno
DBGOTOP()
BROWSE()
USE
RETURN // SignChng()
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._