xHarbour Language Extensions
xHarbour is a fork from Harbour created December 2001. It aims to
follow a more aggressive development path, and be more responsive to
market trends, and users input.
As it stands at this point, xHarbour offers many Syntax extensions over
Harbour and the Clipper language in general, including:
Associative Arrays:
Associative Arrays are like LITE Objects. Properties may be added on the
fly without any declaration, much like new PRIVATE or PUBLIC can be
created by simply assigning a value.
Associative Arrays, may use Objects Syntax (':' operator) or Array Index
Syntax ('[]' operator) with the Property Name as the INDEX.
New Property will automatically be created upon first assignment.
Syntax:
<lValue> := TAssociativeArray()
<AA>[ "<NewProperty>" ] := <xValue>
<AA>:<NewProperty> := <xValue>
<AA>[ "<Property>" ]
<AA>:<Property>
Associative Arrays have LITERAL support like this:
SYNTAX: { <Property> => <Value> [, <PropertyN> => <ValueN> ] }
Hashes
In the past, clipper (and then xharbour) users felt the need to have
what is called "hash" or "associative array" and that is nowadays
provided at language level by all the most modern languages: Perl, PHP,
Python, Ruby, name it. An associative array is an array that bounds a
value (that can be of any variable type allowed by the language) to a
key (that may be of any "orderable" or "distinguishable" variable) in a
1:1 relationship.
An extension has been recently added to add the HASH type as one of the
basic xHarbour type. In other words, hashes are now a rightful type of
xHarbour. They are individuated by the "H" variable type.
Hashes, like arrays, can be managed with both a specific API and by
language constructs.
SWITCH syntax:
SWITCH <Exp>
CASE <Constant>
...
[EXIT]
[More Cases ...]
[DEFAULT]
...
END
NOTE: This syntax is modeled after the C 'switch' flow control. It offers great speed benefit [30-300%] over DO CASE flow control, but is restricted to comparing only constants. Constants maybe: Integers, Longs, or Single Character Strings [much like in C]
WARNING: Those NOT familiar with the C switch flow control, should
understand that unlike DO CASE, you MUST explicitly use the EXIT
statement or else logic will FALL THROUGH to the NEXT CASE, until
stopped at a BREAK, or END statements.
At first this might seem VERY ODD, but it provides great flexibility
exactly like the C model.
See tests/switch.prg to for a sample and to learn how the FALL-THROUGH
logic works.
Multi Threading (MT) Support:
xHarbour supports MT applications. There is still some more work to be
done, but you can already take advantage of this very powerful feature.
Basic sample can be found at tests/mttest.prg
Syntax:
StartThread( @MyThreadFunc() [, xParam1 [,xParamN ] ] )
NOTE: MT Application must link against the MT versions of the Libraries, i.e. vmmt.lib, rtlmt.lib, ppmt.lib, rddmt.lib, dbfntxmt.lib and dbfcdxmt.lib. The full description of MT is beyond the scope of this document.
Portable Sockets Support
The full description is beyond the scope of this document - please refer to samples/sitesvr/sitesvr.prg for a Web Server example.
Perl-5 compatible RegEx
xHarbour includes PCRE which is a full feature, Perl 5 compatible,
Regular
Expression engine. Full feature Search & Replace classes are currently
under
construction, but you may already use the full power of RegEx searches,
new operators, HAS and LIKE.
cExp HAS cPatern|CompiledRegEx => bFound
The HAS operator scans cExp for a any match of the supplied cRegEx
or CompiledRegEx, and returns .T. if found, .F. otherwise.
cExp LIKE cPatern|CompiledRegEx => bLike
The LIKE operator returns .T. if the *complete* cExp is a match, to
the supplied cRegEx or CompiledRegEx, .F. otherwise.
As well as full featured Functions:
HB_Atx( <cRegEx>, <cTargetString> [, lCaseSensitive [, [@]nStart ]
[, [@]nLen ] ] ] ) => cFoundText
RegexComp( cPattern, [bCaseSens [, bNewLine]] ) --> REGEX
HB_Regex( cPattern, cString, [bCaseSens, [, bNewLine]] ) --> aMatches
TRY syntax
TRY
...
[THROW( <Exp> )]
...
CATCH <Id>
...
END
The above is very similar to Clipper BEGIN SEQ, BREAK(), RECOVER USING, END, but is more inline with more "modern" languages, and dismisses the need to worry about Error codeblock.
IN operator
<Exp> IN <Array_or_StringExp> => .T./.F.
The IN operator is very similar to the $ operator, but is valid on
*both* Strings and Arrays. IN is much faster than the equivalent:
aScan( <Array>, <Exp> ) > 0
Variable Parameters syntax
Function <cFuncName>( ... )
The above definition allows this Function to receive up-to 254
parameters. You may retrieve an ARRAY with all the parameters using:
HB_aParams()
The above is appropriate for such functions that may receive any number of generic parameters, which normally will then be processed in a loop, or with hard coded IF statements based on PCount(). Instead the above is much easier to code, requires less memory, and is faster than declaring the parameters.
GLOBAL variables:
GLOBAL <Id1> [,<Id2> [,<IdN>]]
GLOBAL Variables are a new kind of a declared variables. they have
PUBLIC like visibility, but are faster than even STATICs. GLOBALS can be
referenced from other modules using the syntax:
GLOBAL EXTERNAL <Id1> [,<Id2> [,<IdN>]]
GLOBAL Variables have the added benefit of being *directly* accessible from C code too.
Sample code:
//-------------------------------------//
GLOBAL g_MyObject
#include "hbclass.ch"
PROCEDURE Main()
g_MyObject := MyClass()
MyCFunction()
RETURN
CLASS MyClass
METHOD MyMethod INLINE Alert( "MyMethod" )
ENDCLASS
#pragma BEGINDUMP
HB_FUNC( MYCFUNCTION )
{
hb_objSendMsg( &G_MYOBJECT, "MyMethod", 0 );
// Note must be ALL-CAPS!
}
#pragma ENDDUMP
//-------------------------------------//
True C Type Structures
C STRUCTURE <strucName> [Align <align>]
[ MEMBER <memberName> IS <CTYPEDEF> ]
[ MEMBER <memberName[<arrayLength>]> IS <CTYPEDEF> ]
[ MEMBER <memberName> IS <CTYPEDEF>(<arrayLength>) ]
[ MEMBER <memberName> IS|INPLACE <strucName> ]
[ MEMBER <memberName> AS <strucName> ]
[ ... ]
END C STRUCTURE
C Structure can be passed *directly* TO and FROM C code. The full Description is beyond the scope of this document - please refer to cstruct.txt in doc folder.
WITH OBJECT syntax
WITH OBJECT <exp>
...
:<exp>
...
END
HB_QWith() can also be used to retrieve the current WITH OBJECT within a
WITH OBJECT block.
The above syntax not only saves typing, but is also MUCH faster than
equivalent conventional coding.
FOR EACH Syntax:
FOR EACH <Element> IN <Array> // <Element> must be a declared variable.
<Element> // Enumerate value of each respective element in the <exp>.
HB_EnumIndex() returns
[LOOP]
[EXIT]
NEXT
is not only more elegant than:
FOR Counter := 1 TO Len(Array)
Element := Array[Counter]
...
NEXT
but is also MUCH faster - and it also supports enumerating all
properties in an object.
Full access to OLE Servers
CreateObject( "ServerName" ) => oOleObject
Create new instance of an Ole Server.
GetActiveObject( "ServerName" ) => oOleObject
Get existing instance of an Ole Server.
All documented methods and properties of such Server should be directly accessible.
Strings may be indexed like arrays:
<StringExp>[<IndexExp>]
String as Array Index can also accepts a numeric as an assigned value:
<StringExp>[<IndexExp>] := 65 // Same as := 'A'
String Index and all String of 1 character length, automatically carry a secondary CHAR type, which means they are also compatible with numeric operations.
cVar := "hello"; cVar[1] -= 32 // -> "Hello"
Negative Array Index:
Both Arrays and Strings may be indexed with negative numbers (Reversed),
where -1 indexes the LAST Element (or NIL if the Array is empty):
cVar[-1] // => "o"
assuming cVar is the value "Hello" as per above.
Extended macro support:
&cMacro.<suffix>
will compile correctly even if cMacro is a declared var.
WinPorts extended printers support
xHarbour has the ability to print direct to the Windows pserver.
Printing to USB printers is as simple as
Set(24,"WIN:" + printername)
The function GetPrinters() returns a list of all available printers.
#[x]uncommand and #[x]untranslate directives
#uncommand and untranslate directives allow the removal of a given rule from the active rules used by the Pre-Processor. It is very much like the #undefine directive.