Application Development with Harbour/Printable version

From Wikibooks, open books for an open world
Jump to navigation Jump to search


Application Development with Harbour

The current, editable version of this book is available in Wikibooks, the open-content textbooks collection, at
https://en.wikibooks.org/wiki/Application_Development_with_Harbour

Permission is granted to copy, distribute, and/or modify this document under the terms of the Creative Commons Attribution-ShareAlike 3.0 License.

Introduction

What is Harbour?[edit | edit source]

Harbour is a modern, high-level, cross-platform computer programming language compiler.

It is a compiler with support for all major platforms. It runs on and creates binaries for DOS, Microsoft Windows, Linux (32 and 64 bit), Unix (32 and 64 bit), BSD, Mac OS X, Windows CE, Pocket PC, Symbian, iOS (iPhone), Android OS, QNX, VxWorks, Ecomstation and Haiku / BeOS using the same source-code and databases.

Harbour is based on Clipper, a compiler for the dBase language, popular in the 1980s and 90s. Although a powerful general-purpose programming language, it was primarily used to create database/business programs. Harbour shares the dBase ancestry with CA-Visual Objects and FoxPro. Harbour is actively maintained. Many features and paradigms have been introduced.

Databases are traditionally stored in DBF-files, Clipper already introduced a plug-in-system for supporting other ways of database-storage and access. Harbour now supports many major relational-database-management-systems.

The Clipper user interface is traditionally text based. Today, Harbour supports GUI-frameworks like Qt and or native MS-Windows controls.

Unlike FoxPro or CA-Visual Objects, Harbour is still backward-compatible with Clipper.

That means, you can take 20 year old code and compile it to make it run on a modern operating system or develop it into a modern GUI-Application or add support for RDBMS. Harbour's strength is not only to keep legacy-projects alive. It is also a good choice for new cross-platform applications, because it is an easy to learn, yet very powerful language.

Amateurs and beginners have an easy start because of the Basic-like language. Professionals enjoy a huge set of functions and programming philosophies.

The open source Harbour license[1] is similar to the GNU General Public License, with an exception supporting commercial applications, so commercial applications can be produced with Harbour and distributed.

History[edit | edit source]

dBase was a database application released in the early 1980s by Ashton Tate. At the time it was very advanced software. One of the major drawbacks was that it was an interpreted language and therefore rather slow. In winter 1985, former Ashton Tate employees founded Nantucket and released Clipper, a dBase compatible compiler that turned dBase-Code into DOS-binaries (.exe) that were much faster and could be distributed to users that did not own dBase.

Clipper was a DOS application that lost much of its significance, when MS Windows gained popularity in the mid 1990s. Computer Associates bought Nantucket but later abandoned Clipper for CA-Visual Objects. Alaska Software developed XBase++, a Windows 32-bit program and Multisoft released FlagShip, a compiler that was capable of compiling Clipper-programms on Windows, Linux and Unix. Those projects extended the Clipper functionality.

The idea of a free open source software Clipper compiler had been floating around for a long time and the subject had often cropped up in discussion on the usenet group comp.lang.clipper when Antonio Linares founded the Harbour project and started the implementation. Since 1999 harbour has become the free implementation of Clipper. In 2001 a fork named xHarbour was created as a commercial distribution.

A Clipper is a type of ship. Sailing the Clipper ship to a Harbour port. Harbour is a synonym to port (where ship docks) Harbour is the port to the Clipper language.

In 2009 Harbour had a huge make over on its website design promoted mainly by Viktor Szakáts and Przemyslaw Czerpak.

References[edit | edit source]


Installation

Installation for Windows[edit | edit source]

-Go to https://sourceforge.net/projects/harbour-project/files/binaries-windows/3.0.0/ for version 3.0 (download harbour-3.0.0-win.exe), or head to https://sourceforge.net/projects/harbour-project/files/binaries-windows/nightly/harbour-nightly-win.exe/download for the latest Nightly Build (a more up-to-date version)
-Download and Install harbour-3.0.0-win.exe or harbour-nightly-win.exe and choose a destination folder - for example C:\hb30 if you downloaded version 3.0 (we'll assume you did so in the rest of the chapter)

HelloWorld test
-Open a CMD window (Go to Windows -> click on the "Start" button -> Type "cmd.exe" in the search box)
-Type "cd C:\hb30\tests" (without the quotes) on the cmd window and press "Enter"
-Type "C:\hb30\bin\hbmk2 hello.prg" (again, without the quotes) and press "Enter"
-Type "hello.exe" and press "Enter" (You should see "Hello world!" appears on the screen upon execution of the program)

The code of hello.prg looks like this:

PROCEDURE Main()
? "Hello world!"
RETURN


Harbour Overview

Unlike Java which is intended to be write once, run anywhere, Harbour aims to be write once, compile anywhere. As the same compiler is available for all of the above operating systems, there is no need for recoding to produce identical products for different platforms, except when operating system dependent features are used. Cross-compiling is supported with MinGW32. Under Microsoft Windows, Harbour is more stable but less well-documented than Clipper, but has multi-platform capability and is more transparent, customizable and can run from a USB flash drive.

Under Linux and Windows Mobile, Clipper source code can be compiled with Harbour with very little adaptation. Most software originally written to run on Xbase++, Flagship, FoxPro, xHarbour and others dialects can be compiled with Harbor with some adaptation. As 2010 many efforts have been made to turn the transition from other xBase dialects easier.

Harbour can use the following C compilers, among others: GCC, MinGW, Clang, ICC, Microsoft Visual C++ (6.0+), Borland C++, Watcom C, Pelles C and Sun Studio.

Harbour can make use of multiple Graphic Terminal emulations, including console drivers, and Hybrid Console/GUIs, such as GTWvt, and GTWvg.

Harbour supports external GUIs, free (e.g. HWGui, MiniGUI and Qt) and commercial (e.g. FiveWin, Xailer). HBQt is a library provinding bindings to Qt. HBIDE application included in official distribution and SVN repository is a sample of HBQt potencial.

Harbour is 100% Clipper-compatible[1] and supports many language syntax extensions including greatly extended run-time libraries such as OLE, Blat, OpenSSL, FreeImage, GD, TIP, Tpathy, PCRE, HbZip (zlib and bzip2), cURL, Cairo, its own implementation of CA-Tools and NanFor libraries and many others. Harbour has an active development community and extensive third party support.

Any xBase language provides a very productive way to build business and data intensive applications. Harbour is not an exception.

Macro Operator (runtime compiler)[edit | edit source]

One of the most powerful features of xBase languages is the Macro Operator '&'. Harbour's implementation of the Macro Operator allows for runtime compilation of any valid Harbour expression. Such a compiled expression may be used as a VALUE, i.e. the right side of an assignment (rvalue), but more interestingly, such a compiled expression may be used to resolve the left side (lvalue) of an assignment, i.e. PRIVATE, or PUBLIC variables, or a database FIELD.

Additionally, the Macro Operator may compile and execute function calls, complete assignments, or even list of arguments, and the result of the macro may be used to resolve any of the above contexts in the compiled application. In other words, any Harbour application may be extended and modified at runtime to compile and execute additional code on-demand.

Latest Macro compiler can compile any valid Harbour code including code to pre-process before compile.

Syntax:

 &( ... )

The text value of the expression '...' will be compiled, and the value resulting from the execution of the compiled code is the result.

 &SomeId

is the short form for &( SomeId ).

 &SomeId.postfix

is the short form of &( SomeId + "postfix" ).

Object Oriented Programming[edit | edit source]

Programming in an OOP style is a broader issue than a specific library or a specific interface, but OOP programming is something many Clipper programmers have come to expect. CA-Clipper 5.2 and especially 5.3 added a number of base classes, and a matching OOP syntax. Libraries such as CLASSy, Fivewin, Clip4Win, and TopClass provide additional OOP functionality.

Harbour has OOP extensions with full support for classes including inheritance, based on CLASSy syntax. OOP syntax in Harbour is very similar to that of earlier Clipper class libraries so it should be possible to maintain legacy Clipper code with minimal changes.

Syntax and semantics[edit | edit source]

Harbour as every xBase language is case insensitive and can optionally accept keywords written just by first four characters.

Built-in data types[edit | edit source]

Harbour has 6 scalar types : Nil, String, Date, Logical, Number, Pointer, and 4 complex types: Array, Object, CodeBlock, and Hash. A scalar holds a single value, such as a string, number, or reference to any other type. Arrays are ordered lists of scalars or complex types, indexed by number, starting at 1. Hashes, or associative arrays, are unordered collections of any type values indexed by their associated key, which may be of any scalar or complex type.

Literal (static) representation of scalar types:

  • Nil: NIL
  • String: "hello", 'hello', [hello]
  • Date: 0d20100405
  • Logical: .T., .F.
  • Number: 1, 1.1, -1, 0xFF

Complex Types may also be represent as literal values:

  • Array: { "String"", 1, { "Nested Array" }, .T., FunctionCall(), @FunctionPointer() }
  • CodeBlock: { |Arg1, ArgN| Arg1 := ArgN + OuterVar + FunctionCall() }
  • Hash: { "Name" => "John", 1 => "Numeric key", { "Nested" => "Hash" } }

Hashes may use any type including other Hashes as the Key for any element. Hashes and Arrays may contain any type as the Value of any member, including nesting arrays, and Hashes.

Codeblocks may have references to Variables of the Procedure/Function>method in which it was defined. Such Codeblocks may be returned as a value, or by means of an argument passed BY REFERENCE, in such case the Codeblock will "outlive" the routine in which it was defined, and any variables it references, will be a DETACHED variable.

Detached variables will maintain their value for as long as a Codeblock referencing them still exists. Such values will be shared with any other Codeblock which may have access to those same variables. If the Codeblock did not outlive its containing routine, and will be evaluated within the life time of the routine in which it is defined, changes to its Detached Variables(s) by means of its evaluation, will be reflected back at its parent routine.

Codeblocks can be evaluated any number of times, by means of the Eval( BlockExp ) function.

Variables[edit | edit source]

All types can be assigned to named variables. Named variable identifiers are 1 to 63 characters long, start with [A-Z|_] and further consist of the characters [A-Z|0-9|_] up to a maximum of 63 characters. Named variables are not case sensitive.

Variables have one of the following scopes:

  • LOCAL: Visible only within the routine which declared it. Value is lost upon exit of the routine.
  • STATIC: Visible only within the routine which declared it. Value is preserved for subsequent invocations of the routine. If a STATIC variable is declared before any Procedure/Function/Method is defined, it has a MODULE scope, and is visible within any routine defined within that same source file, it will maintain its life for the duration of the application life time.
  • PRIVATE: Visible within the routine which declared it, and all routines called by that routine.
  • PUBLIC: Visible by all routines in the same application.

LOCAL and STATIC are resolved at compile time, and thus are much faster than PRIVATE and PUBLIC variables which are dynamic entities accessed by means of a runtime Symbol table. For this same reason, LOCAL and STATIC variables are not exposed to the Macro compiler, and any macro code which attempts to reference them will generate a runtime error.

Due to the dynamic nature of PRIVATE and PUBLIC variables, they can be created and destroyed at runtime, can be accessed and modified by means of runtime macros, and can be accessed and modified by Codeblocks created on the fly.

References[edit | edit source]


Control Structures

Loops[edit | edit source]

WHILE[edit | edit source]

[DO] WHILE condition
    ...
    [LOOP]
    [EXIT]
END[DO]

FOR[edit | edit source]

FOR var := init_exp TO end_expr [STEP step_expr]
    ...
    [LOOP]
    [EXIT]
NEXT

FOR EACH[edit | edit source]

FOR EACH var IN collection_expr
    ...
    [HB_EnumIndex()]
    [LOOP]
    [EXIT]
NEXT

IF[edit | edit source]

IF condition
    ...
[ELSEIF condition]
    ...
[ELSE]
    ...
END[IF]

SWITCH[edit | edit source]

SWITCH condition
    CASE literal_expr
        ...
        [EXIT]
    [CASE literal_expr]
        ...
        [EXIT]
    [DEFAULT]
        ...
END

BEGIN SEQUENCE[edit | edit source]

BEGIN SEQUENCE
    ...
    [BREAK]
    [Break([expression])]
[RECOVER [USING var]]
    ...
END [SEQUENCE]


Programming with Functions

A harbour function looks like this.


FUNCTION calculateSum(a,b)
LOCAL sum := a + b
RETURN sum

If you want to use above function calculateSum() you can simply do for example:
sumTwoNumbers := calculateSum(2,4) //The value 6 is saved in sumTwoNumbers
? sumTwoNumbers //prints the value of sumTwoNumbers

Step by step instructions to produce above result:
-Create a file called SumTwoNumbers.prg in directory C:\hb30\tests and open this file.
-Put the following code in this file:

******************SumTwoNumbers.prg
PROCEDURE Main()
Local sumTwoNumbers := calculateSum(2,4)
? sumTwoNumbers
RETURN

FUNCTION calculateSum(a,b)
LOCAL sum := a + b
RETURN sum
*****************

-C:\hb30\bin\hbmk2.exe SumTwoNumbers.prg
-SumTwoNumbers.exe //if right you see number "6"


Object Oriented Programming

What is object oriented programming?[edit | edit source]

To understand what object oriented programming is, we need to understand what classes and objects are, and what the differences between them are. You could say that a class is a blueprint to make objects. A metaphor for this is: A map for building a car is the class. The map is not the car itself, but a way to describe how the car should be made. The car with a specific implementation is the object. For example the map for building a car describes characteristics like color, shape/size, weight, and behaviour like steering, switch on/off light.

Here is a class template:

   [CREATE] CLASS <cClassName> [ FROM | INHERIT <cSuperClass1> [, ... ,<cSuperClassN>] ]
             [ MODULE FRIENDLY ] [ STATIC ] [ FUNCTION <cFuncName> ]

   [HIDDEN:]
      [ CLASSDATA | CLASSVAR  | CLASS VAR <DataName1>]
      [ DATA | VAR  <DataName1> [,<DataNameN>] [ AS <type> ] [ INIT <uValue> ]
             [[EXPORTED | VISIBLE] | [PROTECTED] | [HIDDEN]] [READONLY | RO] ]
      ...
      [ METHOD <MethodName>( [<params,...>] ) [CONSTRUCTOR] ]
      [ METHOD <MethodName>( [<params,...>] ) INLINE <Code,...> ]
      [ METHOD <MethodName>( [<params,...>] ) BLOCK  <CodeBlock> ]
      [ METHOD <MethodName>( [<params,...>] ) EXTERN <funcName>([<args,...>]) ]
      [ METHOD <MethodName>( [<params,...>] ) SETGET ]
      [ METHOD <MethodName>( [<params,...>] ) VIRTUAL ]
      [ METHOD <MethodName>( [<params,...>] ) OPERATOR <op> ]
      [ ERROR HANDLER <MethodName>( [<params,...>] ) ]
      [ ON ERROR <MethodName>( [<params,...>] ) ]
      ...
   [PROTECTED:]
      ...
   [VISIBLE:]
   [EXPORTED:]
      ...

   [FRIEND CLASS <ClassName,...>]
   [FRIEND FUNCTION <FuncName,...>]

   [SYNC METHOD <cSyncMethod>]

   ENDCLASS [ LOCK | LOCKED ]


Database Connectivity

How to Create and Fill a DBF File[edit | edit source]

Step 1: Create a file DbTests.prg

Step 2: Write the following code in that file DbTests.prg:

PROCEDURE Main()
? "DbTests"
CREATE testdbstructure
RETURN

Step 3: Compile and run DbTests.prg

This code in Clipper displays a message on the screen and creates a new database structure file named testdbstructure - you should see that a testdbstructure.dbf is created in the same directory as DbTests.prg, this DBF file is a where columns names of other dbffiles are described in rows

The columns of this testdbstructure are FIELD_NAME, FIELD_TYPE, FIELD_LEN, FIELD_DEC.

Step 4: Create 3 rows which has a FIELD_NAME, FIELD_TYPE, FIELD_LEN, FIELD_DEC and then close the current dbf file

PROCEDURE Main()
? "DbTests"
CREATE testdbstructure
APPEND BLANK
FIELD->FIELD_NAME := "ContactId"
FIELD->FIELD_TYPE := "N"
FIELD->FIELD_LEN  := 2
FIELD->FIELD_DEC  := 0
APPEND BLANK
FIELD->FIELD_NAME := "Name"
FIELD->FIELD_TYPE := "C"
FIELD->FIELD_LEN  := 20
FIELD->FIELD_DEC  := 0
APPEND BLANK
FIELD->FIELD_NAME := "Email"
FIELD->FIELD_TYPE := "C"
FIELD->FIELD_LEN  := 20
FIELD->FIELD_DEC  := 0
CLOSE
RETURN

The code uses the APPEND BLANK command to add three new blank records to the table.

The code then uses the "->" operator to access the fields in the table and define the field values. For example, the command "FIELD->FIELD_NAME := "ContactId"" sets the value of the "FIELD_NAME" field in the first record to "ContactId". The other two commands define the values ​​of the "Name" and "Email" fields in the remaining records.

Finally, the "Main" procedure ends with the "CLOSE" command, which closes the table, and the "RETURN" command, which returns control to the main program or procedure that called it.

Tip: to view the contents of a DBF file you can use GNumeric (http://www.gnumeric.org/) or LibreOffice Calc (http://www.libreoffice.org/) - most spreadsheet programs support DBF files.

Step 5: Create a dbf file with the name contacts.dbf from the testdbstructure.dbf. The columns of contacs.dbf are now the FIELD_NAME rows of testdbstructure.dbf. And then put in some testdata in Contacts.dbf

PROCEDURE Main()
? "DbTests"
CREATE testdbstructure
APPEND BLANK
FIELD->FIELD_NAME := "ContactId"
FIELD->FIELD_TYPE := "N"
FIELD->FIELD_LEN  := 2
FIELD->FIELD_DEC  := 0
APPEND BLANK
FIELD->FIELD_NAME := "Name"
FIELD->FIELD_TYPE := "C"
FIELD->FIELD_LEN  := 20
FIELD->FIELD_DEC  := 0
APPEND BLANK
FIELD->FIELD_NAME := "Email"
FIELD->FIELD_TYPE := "C"
FIELD->FIELD_LEN  := 20
FIELD->FIELD_DEC  := 0
CLOSE
CREATE Contacts FROM testdbstructure
APPEND BLANK
REPLACE ContactId WITH 1
REPLACE Name WITH "Peter Smith"
REPLACE Email WITH "peter123@email.nl"
APPEND BLANK
REPLACE ContactId WITH 2
REPLACE Name WITH "Michael Jones" 
REPLACE Email WITH "michael123@email.nl"
RETURN

Use LibreOffice Calc to open and see the content of the file Contacts.dbf.

RDDs and Database Connectivity[edit | edit source]

https://harbourlanguage.blogspot.com/2010/06/understanding-harbour-rdd.html


Understanding Workareas

What is a workarea in the Clipper/Harbour language?[edit | edit source]

Let us for a moment think back at the old times when commonly used computers had no mouse and GUI. Nevertheless, if we wanted to use several tables for a task, we had to use some way to tell the computer which tables he should consider. Let us take for example a library. Oversimplifying, we need to use at least three tables to manage it (one for the books, one for the customers and one for the loans).

We might issue these commands:

       SELECT 1
       USE Books
       SELECT 2
       USE Customers
       SELECT 3
       USE Loans
       SELECT Books

We might visualize the result as the three windows in the picture below:

Here the command SELECT works like clicking on a window to activate it, and the workareas themselves look like windows having a number (the workarea number) and a name (the workarea alias).

To close workareas one uses one of the following commands:

  • CLOSE
  • CLOSE ALL
  • USE

Why should you want to use workareas?[edit | edit source]

Workareas are the natural way of managing database tables in dBASE [...]

Examples of workareas[edit | edit source]

As we've seen above, we can use the following workareas in program to manage a library:

  • Books workarea: a table to store information about the books in the library (fields could include book title, author, publication date, ISBN, etc.)
  • Customers workarea: a table to store information about the library's customers (fields could include customer ID, customer name, address, contact information, membership status, etc.)
  • Loans workarea: a table to track information about book loans (fields could include loan date, due date, customer ID, book ID, return status, etc.)


HbIDE

From https://hbide.vouch.info/: hbIDE is an open-source, multi-platform Integrated Development Environment (IDE) hosted inside Harbour's SVN repository.

The revision number is displayed in the titlebar of the main window, and according to the download page https://hbide.vouch.info/downloads.htm the most recent version is v1.0 r17110 09Nov2011, which makes it almost 12 years old now, yet it implements many functionalities eliminating the need of switching between multiple tools and a consistent interface.