Clipper Tutorial: a Guide to Open Source Clipper(s)

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

Quite a lot of people were interested in this page (it was the most visited page in my former website) and so I feel that I must complete it. This page disappeared when GeoCities was closed (in fact it still contains some broken links to GeoCities pages), and it has been reloaded thank to some requests I got, for example on Facebook. There you can find the "Harbour MiniGUI" group (and now I Plan to produce a group for this page too).

I found the following Facebook groups related to this topic:

  • Harbour MiniGUI
  • Harbour Project
  • CA-Clipper - Harbour - XBase - Dbase Programmers

When (and if) finished, it will prove a complete guide to Open Source Clipper programming. However, this page is still very incomplete. Recently (it is now 16/12/2014) I noticed a new Wikibook on a subject similar to this: http://en.wikibooks.org/wiki/Category:Application_Development_with_Harbour

I just threw in some stuff, for the moment. This page is derived from what I call the "hubbub version". As a newbie to Wikibooks, I did not yet properly format the few sources in this page (and I wonder if I can recover the syntax highlighting...). If you check it, you will see misplaced links and so... this page definitely needs proofreading!

A former version of this 'ebook' :-) is at http://www.geocities.ws/povigna/computer/clipper.html (I'd like to thank W. Birula for making me know it).

Some sections are missing. Illustrations are missing. I will try to upload all the rest next time I connect... (note written 16.56 02/06/2012, Italian time).

I'd like to see this tutorial grow! If someone on the newsgroup comp.lang.clipper or on the mailing lists HarbourUsers (http://lists.harbour-project.org/mailman/listinfo/harbourusers) would give me help or clues. To apologize for its incompletedness, I can only say that this page contains everything I know about Clipper and xBase programming (in a given moment... I always try to learn new things...).

I tried to adhere to the classical tutorials' bottom-up approach of showing all the basic function via very simple examples. The plan to include some bigger examples, with the top-down approach (how do I deal with this problem?) is suggested, but not yet pursued...

I have decided to name this tutorial "a Guide to Open Source Clipper(s)" and not "a Guide to Open Source xBase" because I like the name Clipper, and as you can see by watching at the open source compilers I discuss (Clip and (x)Harbour) the influence of the name Clipper is great. Only X2c doesn't recall the name Clipper.

This Guide was born when I followed a small project (the port of an old Summer 87 application to Windows) and I saw the many Clipper compatible open source compilers available, but noticed also that there were no good tutorials and that the books about Clipper/xBase/Visual Objects and so on couldn't be found in any bookstore (not even in libraries!).

Thanks to bpd2000 for the nice link he provided.

Michele Povigna

Open Source and licenses[edit]

Let's define 'Open Source': it is software distributed with the source code that anybody can study, modify for their own needs and redistribute. It is often also free (it costs nothing).

If you want to know more, go to www.opensource.org, and http://en.wikipedia.org/wiki/Open_source.

Harbour, xHarbour and Clip are released under the GNU General Public License (GPL) plus an option that allow the users to distribute the applications they develop under the license they wish (if they were to follow strictly the GPL they would have had to distribute their applications under the GPL). The GPL is the license adopted by the GNU project, and it makes it perhaps the most famous Open Source license because an entire operating system is released under it - the OS that is commonly referred to by the name of its kernel, Linux, and that some people call GNU/Linux.

Links for "what is the GNU Project?", "what is the General Public License?", "what is Linux?".

For more informations visit http://www.gnu.org/gnu/thegnuproject.html and http://en.wikipedia.org/wiki/GNU, http://www.fsf.org/licensing/licenses/gpl.html, http://www.linux.org/.

In addition to the GPL, Clip offers optionally a commercial license. The user can choose which license applies to his installation.

x2c is released under the Apache license. The most important software released under the Apache license is Apache, a widely used open source web server.

http://en.wikipedia.org/wiki/Apache_HTTP_server and http://en.wikipedia.org/wiki/Apache_License.

http://en.wikibooks.org/wiki/Wikibooks:Creative_Commons_Attribution-ShareAlike_3.0_Unported_License

Some curiosities and a little history[edit]

Definition of 'clipper' translated and adapted from two Italian encyclopaedias: «sailing vessel with three or five masts, sharp prow, large, square sails, gross tonnage 600-1200.». Thus a "clipper" was a kind of ship, used in the second half of the XIX century. The choice of this name, and of other names such as "Harbour" and "Flagship", suggests that xBase programmers might have a distinctive maritime vocation. The first Clipper was built in Baltimore in 1746. During the War of American Independence, the Baltimore Clipper had great development. Other ships then took the name of Clipper though there was little similarity (except for the width of the canopy) with the first. From 1840 onwards, Clippers became especially famous for the gold rush and for the famous "tea and wool races". Although at that time regular steamships were already navigating, the Clippers maintained slightly higher average speeds of the fastest steamers. In 1854 the Clipper Lightning by Donald Mc Kay covered the distance from Boston to Liverpool in 13 days, 19 hours and a half (a record time for a vessel). The famous English Clipper Cutty Sark, one of the fastest sailing ships of all time, launched in 1869, traveled 363 miles in 24 hours. Another famous Clipper, the Melbourne, used to transport passengers, launched in 1875, travelled from England to Australia in 81 days. The golden age of Clippers ended around 1880.

A few links to expand on this type of Clipper:

http://www.titanic-nautical.com/Clipper-Ships-Wiki.html w:Donald_McKay w:Lightning_(clipper) w:Clipper_route

According to my Italian dictionary, "clipper" has two other meanings: "(aviation) big airplane for trans-Atlantic flights" - see http://www.flyingclippers.com/transoceanic.html and "(electronics) electronic device to reduce the amplitude of a wave" - see http://www.daenotes.com/electronics/devices-circuits/clipper-clamper, http://www.daenotes.com/electronics/digital-electronics/clipper-circuits.

The legend about the name "Clipper" is reported at http://www.ghservices.com/gregh/clipper/story.htm. The name was chosen because the idea of a compiler for the dBase language was conceived in a Malibu restaurant, Nantucket Lighthouse (hence the name of the company) which had pictures of clipper ships on its napkins, by Barry ReBell and Brian Russell having lunch there.

xBase ANSI standard: http://www.fghoche.com/Xbaseus.htm, http://www.fghoche.com/whatxb.htm.

http://cbbrowne.com/info/xbase.html.

http://linux.techass.com/projects/xdb/xbasedocs/xbase_c1.html.

http://www.underflap.com/clipper/.

Today there is a free dBase clone: http://dollybase.sourceforge.net/. (The reference to the sheep "Dolly", clonated in 1997, looks quite overt...).

At the moment, the commercial software available comprehends CA-Clipper 5.3x, Alaska Xbase++, CA-Visual Objects, Multisoft Flagship, Microsoft FoxPro, Visual dBase, Harbour.

The May 1998 issue of the Italian magazine PC Professionale in a review for Borland Visual dBase 7 started by summarizing its "glorious" history:

«dBase III has been the workhorse of the programmers of the '80s, then gave way to other instruments, especially in the transition from MS-DOS to Windows 3.1, but it never left the scene, it even had visual developments. The seventh version of the scion of that language, fiercer than ever, is thirty-two bits, supports ActiveX controls, remote SQL databases and a renewed and productive work environment.

It is unusual for programmers who have been in business for several years to never have heard of dBase. The first version of this product was a sort of Visual Basic of the 80s: it freed developers from the complications of access to database files and the interface was easy to use as it could be DOS, thanks to the automatic instructions completion and effective online help. Since then much water has passed under the bridges and dBase programmers had access to a first compiler, graphical interfaces, and even then a migration of the syntax to an object oriented approach.»

The author, Michele Costabile, noted also that:

«The difference between programmable databases (Access, FoxPro) and traditional development tools (Visual Basic, Delphi) is becoming largely a matter of nuances: the first were born as a language built around a database, and the latters have come to assimilate structurally database support.»

According to Dev (a programmers' Italian magazine), the Harbour Project was started by Antonio Linares, author of FiveWin, about 1998 with an original name as Five and that the project started on a CVS server named harbour.joca.es.

Getting Started[edit]

Other sites to visit & files to download[edit]

The article on Freshmeat at the address http://freshmeat.net/articles/view/307/, Non-SQL Databases for Linux, is a good starting point for our xBase study. If you discover that you like very much xBase, have a look at http://www.reocities.com/tablizer/xbasefan.htm, a page for xBase fans.

A set of Norton Guides, including documentation for Clipper from Summer 87 to Clipper 5.3, and also for Clip-4-Win version 3.0, Blinker 5.1, Harbour 0.37, and other tools is located in this good website worth a visit: http://www.clipx.net/norton.php. The last Harbour installs a Norton Guide file (namely in the path c:\hb31\examples\gfspell\spell.ng). A Norton Guide Viewer for Windows by Dave Pearson can be downloaded at his website http://www.davep.org/norton-guides/

discovered a pair of basic tutorials - yet complete - in Spanish (being Italian, I can read and understand Spanish without too much trouble...). One is contained in this page: http://www.elguille.info/Clipper/manual.htm (if you know Spanish and want to print it, it's about 50 pages long). The second tutorial is compressed in a zip you can download from http://mx.geocities.com/maghtin/manuals.htm (the file is named clipper5.zip and it contains a 33-page pdf file).

http://www.ousob.com/norton.php

I will surf to know what's in The Oasis (http://www.the-oasis.net/). They included a link to this Guide and seem to have a large archive of Clipper material.

http://www.elektrosoft.it/tutorials/harbour-how-to/harbour-how-to.asp

Giovanni Di Maria's wrote a tutorial, which is the as far as I know the only effort done by an Italian (other than me) at providing to the community informations about Harbour programming. Di Maria did a great job, although perhaps it would be more correct to call it a 'cookbook' and not a 'tutorial'.

http://vivaclipper.wordpress.com/ (edited by bpd2000)

http://harbourlanguage.blogspot.it/2011/01/understanding-harbour-library.html

http://www.ghservices.com/gregh/clipper/

On the 4th of December Stuart Aitken published a link to a new tutorial, Harbour and HMG Guide: http://www.flamelily.net/index.html - http://www.harbour-guide.com/

http://www.mozzarellaincarrozza.it/harbour/page/5/

Clipper Tutorial[edit]

Please note: if anybody will add his work to this stuff, the Clipper tutorial should contain only 'standard' code that would compile on Harbour, xHarbour and Clip. Compiler-specific code should be placed somewhere else.

The helloworld application line by line[edit]

Let's try to highlight the parts of helloworld:

 function MAIN
 * This is an example
 clear
 ?"Hello, the weather is fine today"
 return

(in GeoCities this and all other sources were highlighted by the on-line service CodeColorizer at http://www.chami.com/colorizer/).

We will comment each line of the helloworld program.

function MAIN

The first line defines a function named MAIN. Defining such a function is not compulsory with Harbour, as if it is missed errors would occur during compilation, but I will keep it to make sure the examples work with all compilers.

We will learn later how to define and use functions and procedures.

* This is an example

The second line is a comment. Commenting your programs will help you when you are to modify them later. If they aren't commenting, modifying them will be a very hard task. It will be much more difficult if you are to modify programs written by others if they didn't comment them: figuring out what a program does using only its code is very difficult and even the most clean programming language may prove to be write-only if not properly commented.

You can write comments in many different styles: using an asterisk (*), two sweeps (//), a double ampersand (&&) or a couple sweep-asterisk (/*) and asterisk-sweep (*/), as you see below:

* This is a comment...
// ...and so is this...
&& ...and this.
/* This is an example of the fourth commenting style,
which may span over several lines.*/

The second and the fourth commenting styles are derived from the C programming language, the first and the third are peculiar of the Clipper/xBase standard.

clear

No, the purpose of this command is not to make the source code clear (that would be too easy! It is up to us to write clear source code, and to do so we must comment it well), but instead to clean the screen. :-) You could also use clear screen or cls, although these two commands are not exactly the same of this clear (the difference will be clear later, when we can GET the point - then, you could also appreciate the pun in this paragraph - but will more likely not).

? "Hello, the weather is fine today"

The ? is a command which means print. In the BASIC programming language, it is also an abbreviation for its print command (the syntax of xBase is quite similar to that of the BASIC programming language).

In this case ? print the string Hello, the weather is fine today. Please note that the string

return

Return is used to terminate the function. We will explain later what the return exactly does.

The compilation process[edit]

A flowchart of the compilation process (kindly supplied by Wojtek Birula).

hbmk2 was created to support all shells, all compilers on all platforms, also to replace old 'bld.bat' solution, while staying compatible with existing hbmk script features and options.

Data Types in General (and Their Operators)[edit]

  • string
  • number
  • date
  • boolean
  • array
  • memo

Let us see a little program that shows the use of the most common data types.

I wanted to show, in this example, a computation of π instead of that of √2, but xBase misses the ArcTan function. We may solve this problem by importing it from an external library, or by supplying it ourselves. (Both ways should be pursued in this tutorial).

The last two data types, are a bit different from the preceding: "Memo" is not very useful when used outside of a database, and the arrays cannot be used in databases.

This alternate highlighting is from the web service at the URL http://tohtml.com/Clipper/.

 && example of compilation command
 && A:\>c:\hb31\bin\hbmk2 -quiet -oc:\test.exe test.prg -run
 
 && please note that this example has not a MAIN function: I found that Harbour 3.0 can compile it anyway
 
 && an example of string concatenation
 ? "Hello" + " " + "World!"
 
 && let us do now a few numerical computations, integer numbers are a good starting point
 ? 5+13
 ? 12*8
 
 ? 3/2
 SET DECIMALS TO 15
 sqrt2=sqrt(2) && computing the square root of 2...
 ? sqrt2 && ... and printing it
 
 && ? caporetto && it would lament with
 && Error BASE/1003  Variable does not exist: CAPORETTO
 && Called from TEST(8)
 
 && as xBase is not good at history, let us revise it: http://www.historyofwar.org/articles/battles_caporetto.html,  http://www.firstworldwar.com/battles/caporetto.htm
 caporetto := ctod("10-24-1917")
 a := date() && system date
 ? a + 1 && tomorrow's date
 
 ? a - caporetto && this will tell us how many days have passed since Caporetto's battle (difference between two dates)
 
 SET DECIMALS TO 2
 ? (a - caporetto) / 365
 ??" years have passed since Caporetto's battle"
 
 ? 1+1=3
 && it will print ".F.", that is, "FALSE" (of course...)
 
 && The following two instructions should be discussed for expand on the subject of operator precedence
 ? 1/2+2^3*sqr(25)-3^2
 ? 1/2+2^3*(sqr(25)-3^2)

Now, consider this example about arrays...

 && C:\hb31\bin\hbmk2 -quiet -oc:\test.exe mesi.prg -run
 DECLARE months [12]
 ? LEN (months)
 && We shall now load some data into our arrays
 PRIVATE month_names: = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
 PRIVATE months: = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
 
 && Let us make some output (using a FOR loop - see below)
 FOR I: = 1 TO LEN (months)
 ? month_names [i], "is", months [i], "days long."
 NEXT

Boolean Algebra & Flow Control[edit]

IF, ELSE, ENDIF[edit]

   ? Time()
   // CToN source is numconv.prg, library is libct.
   IF CToN( SubStr( Time(), 1, 2 ) ) < 18
      ? "Good day"
   ELSE
      ? "Good evening"
   ENDIF

DO WHILE, EXIT, LOOP, ENDDO[edit]

To repeatedly execute a series of statements (loop body) while a condition is true (i.e. its result is .T.).

Loops come in several flavours: the pre-tested loop, the post-tested loop, and the definite iteration, which is done via a count-controlled loop (usually called a for loop). In practice, we may have a middle-tested loop as well, but no specific syntax for it... we need to put an EXIT statement within an already existing loop body to get this one. The next program we will key in is of some interest for the mathematicians (Real Programmers aren't afraid of maths, do you know this famous adage?)

Here is it:

 && Function MAIN LOCAL number, sum, n 
 && An anonymous contributor renamed the variable "num" into "number", increasing this short program readability, but the line above would give
 && Error E0030  Syntax error "syntax error at 'LOCAL'"
 Function MAIN
 LOCAL number, sum, n
 CLS 
 ? "Let's sum up the first n odd numbers." 
 INPUT "How many numbers shall I sum up? " TO n 
 sum=0 
 number=1 
 DO WHILE number <= 2*n    
  sum=sum+number    
  number=number+2 
 ENDDO 
 ? "The sum requested is ", sum

As you can see, this looping statement is similar to the IF statement: both of them are ended by a END-corresponding statement, both of them contains a logical espression.

This looping statement will continue until its condition remains true (will evaluate to .T.).

The two instructions it repeats are sum=sum+num and num=num+2. The second is fundamental: if it wasn't there or was wrong (for example if you keyed in num=num/2), the condition would not evaluate to .F. and the program would not stop its execution (this is called infinite looping). When this happens to you, press the keys Ctrl and C at the same time. This should convince the computer to give his attention to you instead of running the loop.

The programs above is a nice example of how an extremely methodical calculator without any creativity would attack the problem of summing up the first n odd numbers. Notes about the creative approach to it can be found at this address: http://betterexplained.com/articles/techniques-for-adding-the-numbers-1-to-100/ (along with the usual anedocte about Gauss' show off about it in elementary school).

The WHILE looping statement is said to have the control expression in its head,opposed to the Pascal REPEAT-UNTIL looping statement (a post-test loop) which has the control of the condition in its tail (these are the Italian computer science slang for pre- and post- tested loops, aren't they funny?). How does the xBase/Clipper say REPEAT-UNTIL? It doesn't. Here is how to emulate it (copied & pasted from the Norton Guide):

LOCAL lMore := .T.
DO WHILE lMore
loopbody
lMore := condition
ENDDO

As you see, we first set a variable to be true, enter the loop, and specify the condition at the end of the loop, to make sure its body is executed at least once.

Here is an example, equivalent to the one at the pascal_repeat_until_loop page in tutorialspoint.com.

LOCAL a := 10
LOCAL lMore := .T.

   DO WHILE lMore
      ? 'value of a: ', a
      a := a + 1
      lMore := ( a != 20 )
   ENDDO

But the code above changed the condition. If we didn't want this to happen, we can simply negate the condition we'd use in the Pascal code:

repeat loopbody until condition

becomes then:

LOCAL a := 10
LOCAL lMore := .T.

   DO WHILE lMore
      ? 'value of a: ', a
      a := a + 1
      lMore := .NOT. ( a = 20 ) // also lMore := ! ( a = 20 )
   ENDDO

Let us now see this kind of loop:

 DO WHILE .T. 
 ? "I won't stop." 
 ENDDO

This loop prints "I won't stop." as long as 'true' is... true. It is thus called an infinite loop because the ending condition will never be satisfied. It is the first example of control flaw studied in computer science classes. By definition, you incur in an infinite loop every time you specify a tautology as the condition to be checked. It is not always obvious to detect this and other control flaws and errors - it is indeed a process that involves the use of a specific piece of software called a debugger.

FOR...NEXT[edit]

The FOR...NEXT construct (counter-controlled loop) is useful when we know how many times we want the loop body be executed. We shall now use it to print out and revise multiplication tables.

 CLEAR
 FOR I := 1 TO 8
   FOR J := 1 TO 8
    ?? I*J  NEXT
 NEXT

(Please note in this example we have a loop inside the body of another loop: this is called a nested loop). Well, this works, but its output is not very nice... Moreover, it is customary to print the multiplication tables up to 10, since we're using a decimal numeration system... let us try it again!

 CLEAR
 FOR I := 1 TO 10  
   FOR J := 1 TO 10   
     @i,j*4 SAY  I*J PICTURE "999"  
   NEXT
 NEXT

this way we can print it much prettier... by the way, when nesting loops and branching statements, it becomes important (practitioning programmers say so, and in my little I agree) to arrange the indentations in order to make the program easier to read... in The Oasis are available "source code beautifiers" such as dst314.zip. Harbour gives us the hbformat tool, https://vivaclipper.wordpress.com/tag/hbformat/.

PICTURE "999" is the instruction to specify we want the output format - as we specified three digits, the numbers in output will be printed as if they were three digits long, thus aligning them in our multiplication table.

Functions and Procedures[edit]

A function is a piece of code that returns a result every time it is called. Let us consider a function to convert Celsius into Fahrenheit:

FUNCTION cels2f( temperature )
x := (temperature*1.8 + 32)
RETURN x

FUNCTION MAIN()
? cels2f(100)
? cels2f(0)

Consider this example of use for the function HB_Random():

PROCEDURE Main
 // Random number between 0.01 and 0.99
 ? HB_Random()
 // Random number between 0.01 and 9.99
 ? HB_Random(10)
 // Random number between 8.01 and 9.99
 ? HB_Random(8,10)
 RETURN

A good function would function as a "black box", that is you can use it without worrying about how it internally works. An example usually given at this point is that of driving a car: you can use it without worrying about how the engine works (do you know anybody which looked at the pistons of their new car before buying it?). Someone else designed the engine. But there may be problems: if we change our Celsius into Fahrenheit function as follows

FUNCTION cels2f( temperature )

   x := ( temperature * 1.8 + 32 )
   number := number + 1

   RETURN x

FUNCTION MAIN()

   number := 0
   ? cels2f( 100 )
   ? cels2f( 0 )
   ? number

we'll get a side effect. This program output is

      212.0
       32.0
        2

That is, our new function did not only return a value, it also increased by 1 the variable number.

Another characteristic of variables: scope identifiers[edit]

Variables have a name, a type, and a scope, which may be explicitly declared as (list below copied verbatim from w:Harbour_(software)):

  • 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 lifetime.
  • PRIVATE: Visible within the routine which declared it, and all routines called by that routine.
  • PUBLIC: Visible by all routines in the same application.

They do not make sense before we work with functions and procedures.

/* Work on the following.
 * hbformat was run on this piece of code
 * need to provide comments, nest more functions and procedures to help figuring what goes on with scope modifiers
 */

STATIC x := 9

   ? x
   A()
   ? x
   B()
   ? x
   C()
   ? x
   D()
   ? x
   E()
   ? x

PROCEDURE A

   LOCAL x := 10

   ? "x from A=", x

   RETURN

PROCEDURE B

   PRIVATE x := 5

   ? "x from B=", x

   RETURN

PROCEDURE C

   PUBLIC x := -1

   ? "x from C=", x

   RETURN

PROCEDURE D

   ? "x from D before updating value=", x

   x := 12

   ? "x from D=", x

   RETURN

PROCEDURE E

   ? "x from E=", x

   RETURN

On running this, we get a strange output:

         9
x from A=         10
         9
x from B=          5
         9
x from C=          -1
         9
x from D before updating value=          -1
x from D=         12
         9
x from E=         12
         9

This program sets a variable x and five different procedures, A, B, C, D, E. The first three procedures define a variable x within themselves, assign it a value and print it. The fourth function assigns a new value to some variable named x without declaring it. The fifth function shows the value of some x variable, which happens to be the value of the fourth x variable. The main fact to remember here is that two variables are not the same, even if hey have the same name, provided they have different scopes.

x := 9

   ? x
   A()
   ? x
   B()
   ? x
   C()
   ? x
   D()
   ? x
   E()
   ? x

PROCEDURE A

   LOCAL x := 10

   ? "x from A=", x

   RETURN

PROCEDURE B

   PRIVATE x := 5

   ? "x from B=", x

   RETURN

PROCEDURE C

   PUBLIC x := -1

   ? "x from C=", x

   RETURN

PROCEDURE D

   ? "x from D before updating value=", x

   x := 12

   ? "x from D=", x

   RETURN

PROCEDURE E

   ? "x from E=", x

   RETURN
         9
x from A=         10
         9
x from B=          5
         9
x from C=         -1
        -1
x from D before updating value=         -1
x from D=         12
        12
x from E=         12
        12

See pascal_variable_scope in tutorialspoint.com and http://aelinik.free.fr/c/ch14.htm

Variable scope is a foretaste of object oriented programming, in the sense that it anticipates some encapsulation concepts.

The search for the Ludolphine, part 1[edit]

If you checked the list of functions you will have noticed that the xBases have no trigonometric functions. Not that in general they miss them: these languages are targeted database applications such as "accounting systems and airline reservations systems" (see w:Database_application. ) in which trigonometric functions are not really important. But we now ask ourself how to compute an approximation to the Ludolphine number, π (more informations on this "search" at http://www.mathpages.com/home/kmath457.htm), We can do it using the CT library (see http://vouch.info/harbour/index.html?hbct.htm), or importing the C standard library function atan.

 && compile with ''hbmk2 computepi.prg -lhbct''
 PROCEDURE MAIN
 SET DECIMAL TO 14
 ? 4 * ATAN (1)

The search for the Ludolphine, part 2 (Harbour only)[edit]

We get the idea from Harbour for beginners by Alexander Kresin (http://www.kresin.ru/en/hrbfaq_3.html).

  #pragma BEGINDUMP
  #include <extend.h>
  #include <math.h>
   HB_FUNC( ATAN )
   {
      double x = hb_parnd(1);
      hb_retnd( atan( x ) );
   };     
 #pragma ENDDUMP
 SET DECIMAL TO 14 
 ? 4 * ATAN (1)

It must be noted that the extend.h file (* Compatibility header file for CA-Cl*pper Extend System) contains this warning:

/* DON'T USE THIS FILE FOR NEW HARBOUR C CODE */
/* This file is provided to support some level of */
/* Harbour compatibility for old Clipper C extension code */

In fact this example is here only to consider how the open source cross-compilers (Harbour in this case) extend themselves with C library functions, which gives them a lot of flexibility. Not that computing π is useful in itself (by the way the CT library contains a function to directly compute π).

Database making[edit]

Let's return to the Wikipedia entry w:Database_application.

Different kinds of database applications exists as well. If you did store your friend's phone numbers and addresses into a word processor, you would have what is called a Free-Form Database - askSam is a specialized free-form database application. Now, a word processor lets us search the informations, but other operations, such as sorting them, cannot be done automatically by a word processor.

What about attempting to store it into a spreadsheet? We may use one column for the name, one for the surname, one for the telefone number, one for the city. This quick database, stored in a spreadsheet, may be searched and sorted: for example we can sort it by city and person's name in alphabetical order. This is a flat database, http://www2.research.att.com/~gsf/man/man1/cql.html: a flat database is a sequence of newline terminated records of delimiter separated fields, and a spreadsheet shows its limits in data entry and reporting (if you did want to use the data in your table to print out addresses on envelopes a spreadsheet is not a good tool). An example is MyDatabase (http://www.pcmag.com/article2/0,2817,760833,00.asp).

Spreadsheets are much better to do accounting: how much harder a book-keeper's work would be if his data were stored in a wordprocessing program? The purpose here is to have our data structured in a certain way: all the costs in a place, all earnings in another.

Before 1970 complex databases where managed using hierarchical databases (very little information is needed about them - see for example http://www.extropia.com/tutorials/sql/hierarchical_databases.html).

For more complex databases [put here examples], the flat approach is not recommended, and the solution is to use relational databases. They are "a database with relationships between more than one table of records based on common fields".

http://www.databasedev.co.uk/design_basics.html

http://www.filemaker.com/help/html/relational.11.2.html

http://www.lnf.infn.it/Calcolo/doc/AppuntiLinux/a2471.html

Making a first database and recording some data[edit]

A verbose way[edit]

 CREATE TMPNAMES
 USE TMPNAMES
 APPEND BLANK
 REPLACE FIELD_NAME WITH "NAME"
 REPLACE FIELD_TYPE WITH "C"
 REPLACE FIELD_LEN WITH 15
 APPEND BLANK
 REPLACE FIELD_NAME WITH "ADDRESS"
 REPLACE FIELD_TYPE WITH "C"
 REPLACE FIELD_LEN WITH 30
 CLOSE
 CREATE NAMES FROM TMPNAMES && http://www.ousob.com/ng/clguide/ng849db.php

The code above created a DBF file, names.dbf, to be used by the following code. It will add a record to the DBF file. It is equivalent to the "First Sample Program" of my old PC GUIDE, which missed a line that is necessary in modern xBase.

 CLEAR
 ? "First Sample Program"
 SELECT 1
 USE NAMES
 APPEND BLANK
 REPLACE NAME WITH "MIKE BROWN"
 REPLACE ADDRESS WITH "ROME STREET, 56"
 CLOSE && this line is missing in my PC GUIDE but is needed
 QUIT

A more concise way[edit]

The short code below does the same work of the two pieces of code of the previous section (it only produces a different file name, namesdb.dbf instead of names.dbf).

 local aStruct := { { "NAME", "C", 15, 0 }, ;
             { "ADDRESS",   "C",  30, 0 }}
 REQUEST DBFCDX
 dbCreate( "namesdb", aStruct, "DBFCDX", .t., "NAMESDB" )
 && http://www.fivetechsoft.com/harbour-docs/api.html
 USE NAMESDB
 NAMESDB->(DbAppend())
 NAMESDB->NAME := "MIKE BROWN"
 NAMESDB->ADDRESS := "ROME STREET, 56"

This example uses the alias operator, ->. http://www.ousob.com/ng/clguide/ngcf412.php


The result of this code is a file named namesdb.dbf. Informations about how DBF files are can be find at DBF File structure, http://www.dbf2002.com/dbf-file-format.html, where we find this list of Field type:

  • C – Character
  • Y – Currency
  • N – Numeric
  • F – Float
  • D – Date
  • T – DateTime
  • B – Double
  • I – Integer
  • L – Logical
  • M – Memo
  • G – General
  • C – Character (binary)
  • M – Memo (binary)
  • P – Picture
  • + – Autoincrement (dBase Level 7)
  • O – Double (dBase Level 7)
  • @ – Timestamp (dBase Level 7)

In my PC Guide the .dbf file was made with the DataBase Utility DBU. Clones of this utility are FiveDBU (with source code) at https://code.google.com/archive/p/fivewin-contributions/downloads, DBF Viewer Plus at http://www.alexnolan.net/software/dbf.htm, CLUT at http://www.scovetta.com/archives/simtelnet/msdos/clipper.

Let us see what is in our little file so far.

 USE NAMES
 LIST DATE(), TIME(), NAME, ADDRESS

Database Design Issue: the First Normal Form (1NF)[edit]

The work done in the previous section was intended to exactly reproduce the database proposed in my PC GUIDE. There are, however, inconvenients: having only one NAME field, this database cannot sort its data on the last name. Also, a careless user might insert the data of some people with the last name first, and some other data with the first name last. When designing a database precautions should be taken of these possibilities. The first normal form (http://www.1keydata.com/database-normalization/first-normal-form-1nf.php, http://www.sqa.org.uk/e-learning/SoftDevRDS02CD/page_14.htm) requires you to define fields whose information cannot be divided into smaller parts. So, instead of a NAME field, we should have a FIRST_NAME and LAST_NAME fields. Complying to the first normal form, our little database would be on the on the right track to being a normalized database.

Complicating our simple database[edit]

Here is the testdbf.prg source from \hb30\tests. It should be discussed in detail. It is a GPL piece of code poorly commented.

 /*
  * $Id: testdbf.prg 1792 1999-11-10 10:17:19Z bcantero $
  */

 function main()

   local nI, aStruct := { { "CHARACTER", "C", 25, 0 }, ;
                          { "NUMERIC",   "N",  8, 0 }, ;
                          { "DOUBLE",    "N",  8, 2 }, ;
                          { "DATE",      "D",  8, 0 }, ;
                          { "LOGICAL",   "L",  1, 0 }, ;
                          { "MEMO1",     "M", 10, 0 }, ;
                          { "MEMO2",     "M", 10, 0 } }

   REQUEST DBFCDX

   dbCreate( "testdbf", aStruct, "DBFCDX", .t., "MYALIAS" )

   ? "[" + MYALIAS->MEMO1 + "]"
   ? "[" + MYALIAS->MEMO2 + "]"
   ? "-"
   MYALIAS->( dbAppend() )
   MYALIAS->MEMO1 := "Hello world!"
   MYALIAS->MEMO2 := "Harbour power"
   ? "[" + MYALIAS->MEMO1 + "]"
   ? "[" + MYALIAS->MEMO2 + "]"
   MYALIAS->( dbAppend() )
   MYALIAS->MEMO1 := "This is a test for field MEMO1."
   MYALIAS->MEMO2 := "This is a test for field MEMO2."
   ? "[" + MYALIAS->MEMO1 + "]"
   ? "[" + MYALIAS->MEMO2 + "]"
   MYALIAS->NUMERIC := 90
   MYALIAS->DOUBLE := 120.138
   ? "[" + Str( MYALIAS->DOUBLE ) + "]"
   ? "[" + Str( MYALIAS->NUMERIC ) + "]"

   ? ""
   ? "Press any key..."
   InKey( 0 )

   ? ""
   ? "Append 50 records with memos..."
   for nI := 1 to 50
      MYALIAS->( dbAppend() )
      MYALIAS->MEMO1 := "This is a very long string. " + ;
                        "This may seem silly however strings like this are still " + ;
                        "used. Not by good programmers though, but I've seen " + ;
                        "stuff like this used for Copyright messages and other " + ;
                        "long text. What is the point to all of this you'd say. " + ;
                        "Well I am coming to the point right now, the constant " + ;
                        "string is limited to 256 characters and this string is " + ;
                        "a lot bigger. Do you get my drift ? If there is somebody " + ;
                        "who has read this line upto the very end: Esto es un " + ;
                        "sombrero grande rid¡culo." + Chr( 13 ) + Chr( 10 ) + ;
                        "/" + Chr( 13 ) + Chr( 10 ) + "[;-)" + Chr( 13 ) + Chr( 10 )+ ;
                        "\"
   next
   MYALIAS->( dbCommit() )

   ? "Records before ZAP:", MYALIAS->( LastRec() )
   ? "Size of files (data and memo):", Directory( "testdbf.dbf" )[1][2], ;
      Directory( "testdbf.fpt" )[1][2]
   MYALIAS->( __dbZap() )
   MYALIAS->( dbCommit() )
   ? "Records after ZAP:", MYALIAS->( LastRec() )
   ? "Size of files (data and memo):", Directory( "testdbf.dbf" )[1][2], ;
      Directory( "testdbf.fpt" )[1][2]
   ? "Value of fields MEMO1, MEMO2, DOUBLE and NUMERIC:"
   ? "[" + MYALIAS->MEMO1 + "]"
   ? "[" + MYALIAS->MEMO2 + "]"
   ? "[" + Str( MYALIAS->DOUBLE ) + "]"
   ? "[" + Str( MYALIAS->NUMERIC ) + "]"
   ? "Press any key..."
   InKey( 0 )
   dbCloseAll()

   dbCreate( "testdbf", aStruct,, .t., "MYALIAS" )

   for nI := 1 to 10
      MYALIAS->( dbAppend() )
      MYALIAS->NUMERIC := nI
      ? "Adding a record", nI
      if nI == 3 .or. nI == 7
         MYALIAS->( dbDelete() )
         ? "Deleting record", nI
      endif
   next
   MYALIAS->( dbCommit() )

   ? ""
   ? "With SET DELETED OFF"
   ? "Press any key..."
   InKey( 0 )

   MYALIAS->( dbGoTop() )
   do while !MYALIAS->( Eof() )
      ? MYALIAS->NUMERIC
      MYALIAS->( dbSkip() )
   enddo

   SET DELETED ON
   ? ""
   ? "With SET DELETED ON"
   ? "Press any key..."
   InKey( 0 )

   MYALIAS->( dbGoTop() )
   do while !MYALIAS->( Eof() )
      ? MYALIAS->NUMERIC
      MYALIAS->( dbSkip() )
   enddo

   ? ""
   ? "With SET DELETED ON"
   ? "and  SET FILTER TO MYALIAS->NUMERIC > 2 .AND. MYALIAS->NUMERIC < 8"
   ? "Press any key..."
   InKey( 0 )

   MYALIAS->( dbSetFilter( { || MYALIAS->NUMERIC > 2 .AND. MYALIAS->NUMERIC < 8 }, ;
                           "MYALIAS->NUMERIC > 2 .AND. MYALIAS->NUMERIC < 8" ) )
   MYALIAS->( dbGoTop() )
   do while !MYALIAS->( Eof() )
      ? MYALIAS->NUMERIC
      MYALIAS->( dbSkip() )
   enddo

   SET DELETED OFF
   ? ""
   ? "With SET DELETED OFF"
   ? "and  SET FILTER TO MYALIAS->NUMERIC > 2 .AND. MYALIAS->NUMERIC < 8"
   ? "Press any key..."
   InKey( 0 )

   MYALIAS->( dbSetFilter( { || MYALIAS->NUMERIC > 2 .AND. MYALIAS->NUMERIC < 8 }, ;
                           "MYALIAS->NUMERIC > 2 .AND. MYALIAS->NUMERIC < 8" ) )
   MYALIAS->( dbGoTop() )
   do while !MYALIAS->( Eof() )
      ? MYALIAS->NUMERIC
      MYALIAS->( dbSkip() )
   enddo

   ? "dbFilter() => " + dbFilter()
   ? ""

   ? "Testing __dbPack()"
   ? "Records before PACK:", MYALIAS->( LastRec() )
   ? "Size of files (data and memo):", Directory( "testdbf.dbf" )[1][2], ;
      Directory( "testdbf.dbt" )[1][2]
   SET FILTER TO
   MYALIAS->( __dbPack() )
   MYALIAS->( dbCommit() )
   ? "Records after PACK:", MYALIAS->( LastRec() )
   ? "Size of files (data and memo):", Directory( "testdbf.dbf" )[1][2], ;
      Directory( "testdbf.dbt" )[1][2]
   ? "Press any key..."
   InKey( 0 )
   ? "Value of fields:"
   MYALIAS->( dbGoTop() )
   do while !MYALIAS->( Eof() )
      ? MYALIAS->NUMERIC
      MYALIAS->( dbSkip() )
   enddo
   ? ""

   ? "Open test.dbf and LOCATE FOR TESTDBF->SALARY > 145000"
   ? "Press any key..."
   InKey( 0 )
   dbUseArea( ,, "test", "TESTDBF" )
   locate for TESTDBF->SALARY > 145000
   do while TESTDBF->( Found() )
      ? TESTDBF->FIRST, TESTDBF->LAST, TESTDBF->SALARY
      continue
   enddo
   ? ""
   ? "LOCATE FOR TESTDBF->MARRIED .AND. TESTDBF->FIRST > 'S'"
   ? "Press any key..."
   InKey( 0 )
   dbUseArea( ,, "test", "TESTDBF" )
   locate for TESTDBF->MARRIED .AND. TESTDBF->FIRST > 'S'
   do while TESTDBF->( Found() )
      ? TESTDBF->FIRST, TESTDBF->LAST, TESTDBF->MARRIED
      continue
   enddo

 return nil

RDDs: What Functions Are Available?[edit]

http://harbourlanguage.blogspot.de/2010/06/understanding-harbour-rdd.html

Case Study: Checkbook Balancing[edit]

An Indexed Example[edit]

Set Relation - Working with more than one table[edit]

How to create a DLL (xHarbour)[edit]

http://www.xharbour.com/xhdn/referenceguide/index.asp?page=article&article=create_dll

Object Oriented[edit]

Looking at Object-Oriented Programming from a Safety Distance[edit]

Let us suppose we're dealing with the distance function given the Cartesian coordinates of the points (http://mathinsight.org/cartesian_coordinates). The formulas we'll apply are:

D_1 = \sqrt{(x_2 - x_1)^2}

D_2 = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}

D_3 = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2 + (z_2 - z_1)^2}

for (Euclidean) distance on a real line, Euclidean plane and Euclidean space respectively.


In procedural programming our functions would look like this:

? distance1d(4,-3)
? distance2d(2,-3,-1,-2)
? distance3d(1,1,1,4,4,4)

        FUNCTION distance1d( x1, x2 )
           RETURN sqrt((x2-x1)^2)

        FUNCTION distance2d( x1,y1,x2,y2 )
           RETURN sqrt((x2-x1)^2+(y2-y1)^2)

        FUNCTION distance3d( x1,y1,z1,x2,y2,z2 )
           RETURN sqrt((x1-x2)^2+(y1-y2)^2+(z1-z2)^2)

We defined three functions, with different names, which take as arguments the coordinates. But doing so we need to pass six arguments for the distance in a three-dimensional space.

If we're doing it with object oriented programming we may get something like this:

#include "hbclass.ch"

   CREATE CLASS Point1D

   VAR Abscissa    // the abscissa of our point

METHOD New( Abscissa )    // Constructor

METHOD Distance( Point )

   ENDCLASS

   CREATE CLASS Point2D INHERIT Point1D

   VAR Ordinate    // the ordinate of our point

METHOD New( Abscissa, Ordinate )    // Constructor

METHOD Distance( Point )

   ENDCLASS

   CREATE CLASS Point3D INHERIT Point2D

   VAR Zcoord    // the Z-coordinate of our point

METHOD New( Zcoord )    // Constructor

METHOD Distance( Point )

   ENDCLASS

&& Constructors Zone
METHOD New( Abscissa ) CLASS Point1D

   ::Abscissa := Abscissa

   RETURN Self

METHOD New( Abscissa, Ordinate ) CLASS Point2D

   ::Abscissa := Abscissa
   ::Ordinate := Ordinate

   RETURN Self

METHOD New( Abscissa, Ordinate, Zcoord ) CLASS Point3D

   ::Abscissa := Abscissa
   ::Ordinate := Ordinate
   ::Zcoord := Zcoord

   RETURN Self

&&Distances Methods

METHOD Distance( Point ) CLASS Point1D

   RETURN Sqrt( ( Self:Abscissa - Point:Abscissa ) ^ 2 )

METHOD Distance( Point ) CLASS Point2D

   RETURN Sqrt( ( Self:Abscissa - Point:Abscissa ) ^ 2 + ( Self:Ordinate - Point:Ordinate ) ^ 2 )

METHOD Distance( Point ) CLASS Point3D

   RETURN Sqrt( ( Self:Abscissa - Point:Abscissa ) ^ 2 + ( Self:Ordinate - Point:Ordinate ) ^ 2 + ( Self:Zcoord - Point:Zcoord ) ^ 2 )

PROCEDURE Main()

   FirstPoint := Point1D():New( 3 )
   SecondPoint := Point1D():New( - 3 )
   ? FirstPoint:Abscissa
   ? FirstPoint:Distance( SecondPoint )
   ThirdPoint := Point2D():New( 2, - 3 )
   FourthPoint := Point2D():New( - 1, - 2 )
   ? ThirdPoint:Distance( FourthPoint )
   FifthPoint := Point3D():New( 1, 1, 1 )
   SixthPoint := Point3D():New( 4, 4, 4 )
   ? FifthPoint:Distance( SixthPoint )

   RETURN

Here we've defined three classes, their constructors, and a distance method for each of them, and showed how to use them. It is also a simple example of how inheritance works. Other concepts are encapsulation (information hiding or data hiding), abstraction, polymorphism, overloading and overriding of methods.

The first thing to note is that we start by including the clipper header file hbclass.ch, the header file for Class commands. This means that object oriented commands have been added to the xBase foundation of Harbour.

In the code above we defined three classes, each one implementing a Point. Point2D for example was defined as a class extending Point1D, that is a generalization of the concept. A method Distance was given for each of the classes.

A line such as

  ? FifthPoint:Distance( SixthPoint )

contain the output command ?, the reference to an object (FifthPoint in this case), an invocation of the Distance method :Distance, to which another point was passed ( SixthPoint ).

It is also possible to write a Distance function which takes two arguments of a Point class, that may look like this:

FUNCTION Distance ( Point1, Point2 )
   RETURN Sqrt( ( Point1:Abscissa - Point2:Abscissa ) ^ 2 + ( Point1:Ordinate - Point2:Ordinate ) ^ 2 + ( Point1:Zcoord - Point2:Zcoord ) ^ 2 )

   ? Distance( FifthPoint, SixthPoint )

This is, however, not object-oriented programming.

Another example[edit]

Copied verbatim from w:Harbour_(software)

 #include "hbclass.ch"

 PROCEDURE Main()

    LOCAL oPerson

    CLS

    oPerson := Person():New( "Dave" )

    oPerson:Eyes := "Invalid"

    oPerson:Eyes := "Blue"

    Alert( oPerson:Describe() )

    RETURN

 CREATE CLASS Person

    VAR Name INIT ""

    METHOD New( cName )
    METHOD Describe()

    ACCESS Eyes INLINE ::pvtEyes
    ASSIGN Eyes( x ) INLINE iif( HB_ISSTRING( x ) .AND. x $ "Blue,Brown,Green", ::pvtEyes := x, Alert( "Invalid value" ) )

    PROTECTED:

    VAR pvtEyes

 ENDCLASS

 // Sample of normal Method definition
 METHOD New( cName ) CLASS Person

    ::Name := cName

    RETURN Self

 METHOD Describe() CLASS Person

    LOCAL cDescription

    IF Empty( ::Name )
       cDescription := "I have no name yet."
    ELSE
       cDescription := "My name is: " + ::Name + ";"
    ENDIF

    IF ! Empty( ::Eyes )
       cDescription += "my eyes' color is: " + ::Eyes
    ENDIF

    RETURN cDescription

Making Up a User Interface[edit]