Next Previous Contents

6. A Clipper Tutorial

In this section I explain you what I know about Clipper/xBase programming, concentrating on how to produce source code compatible with all the Open Source compilers.

6.1 An analysis of the helloworld application

Let's try to highlight the parts of helloworld:

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

(you can obtain this by using 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 compulsory with (x)Harbour, as if it is missed errors would occur during compilation.

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.

You can write comments in many different styles: using the 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 program clear, but instead to clean the screen. You could also use clear screen or cls, although these two commands are not exactly the same of the simple clear (the difference will be clear later, when we can GET the point - then, you could also appreciate the joke in this paragraph).

?"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, especially when dealing with flow control, 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.

6.2 A small application with two files and two functions

When one creates a program, he will probably write several files and call a function defined in a file from another function in another file. This feature is so easy to apply that it was the first thing I learned how to do with Harbour, just after I learned how to define a function and created my first program, and so I present it just after your first program :-).

ifexample.prg


Function MAIN()
LOCAL number
INPUT "Key in a number: " TO number
IF number % 2 = 0
   ? "You keyed in an even number"
ELSE
   ? "You keyed in an odd number"
ENDIF
RETURN
ifexample2.prg


Function MAIN()
LOCAL number
INPUT "Key in a number: " TO number
IF number % 2 = 0
   ? "You keyed in an even number"
   ? "I can prove it:"
   ? "the result of ",number," % 2 = 0 is ", number % 2 = 0
ELSE
   ? "You keyed in an odd number"
   ? "I can prove it:"
   ? "the result of ",number," % 2 = 0 is ", number % 2 = 0
ENDIF
RETURN
local.prg


function MAIN
LOCAL nNumber := 0
//
INPUT "Key in a number: " TO nNumber
//
IF nNumber < 50
? "Less than 50"
ELSEIF nNumber = 50
? "Is equal to 50"
ELSE
? "Greater than 50"
ENDIF
menu.prg


Function MAIN

* Display menu choices.

@ 3, 25 PROMPT "First choice"
@ 4, 25 PROMPT "Second choice"

* Get menu key.
MENU TO choice

* Perform an action based on your menu choice.
DO CASE
CASE choice = 0
RETURN
CASE choice = 1
DO One
CASE choice = 2
DO Two
ENDCASE
RETURN

nihilist.prg


Function MAIN()
LOCAL number
INPUT "Key in a number: " TO number
IF number = 0
? "Congratulations, you keyed the fabolous number "
ENDIF
? number
RETURN
One.prg


function One
? "One"
return
sumup.prg


Function MAIN
LOCAL num, somma, n
CLS
? "Let's sum up the first n odd numbers."
INPUT "How many numbers: " TO n
somma=0
num=1
DO WHILE num <= 2*n
   somma=somma+num
   num=num+2
ENDDO
? "The sum is ",somma
Two.prg


function Two
? "Two"
return

6.3 Flow control

Flow control is the single point in which xBase syntax shows its similarities with BASIC.

In this section I will presume that you know already how to program in another programming language, and I will answer to the same question I had to ask myself when I began working with xBase: How do I call the basic flow-control commands (if, for, while...) ?

The place in which I found the answers has already been cited, http://www.clipx.net/norton.php, yet here I collect all the structures in a single page so that you don't have to surf an hypertext to read what you need. Remember anyway that there you will find more informations. Here you will find instead enjoyable examples.

IF, ELSE, ELSEIF, ENDIF

IF forks a program: it evaluates a condition and executes one of several alternative blocks of statements.

We will now see an example of how the if function works. This example is very easy: inputs a number from the keyboard and uses the if to decide whether the number is even or odd.

               Function MAIN()  
               LOCAL number  
               INPUT "Key in a number: " TO number  
               IF number % 2 = 0  
                  ? "You keyed in an even number"  
               ELSE  
                  ? "You keyed in an odd number"  
               ENDIF  
               RETURN

By LOCAL number we tell the program that we are about to use a variable named 'number'.

The syntax of the input instruction is also very easy: Key in a number is what the program will show on the screen, TO number is where the program will put the variable read from the keyboard.

The IF instruction is more complex: it is five lines long (it ends surprisingly with the keyword ENDIF). It contains two instructions, ? "You keyed in an even number" and ? "You keyed in an odd number", and executes the first or the second instruction according to the result of the expression number % 2 = 0. In this statement we recall the variable number, that stores the number we entered, and make the computation with the operator %, whose name is modulus and that returns a number representing the remainder of the first number divided by the second.

Then, it makes the comparison with 0 using the = operator. This operator returns the two values accepted by the IF: true or false, whose names in Clipper/xBase are respectively .T. and .F..

If the result is .T. the program executes the first instruction or block of instructions it encounters, if the result is .F. it executes the first instruction or block of instructions after the ELSE keyword. In the following example we show what block of instructions means.

          Function MAIN()  
          LOCAL number  
          INPUT "Key in a number: " TO number  
          IF number % 2 = 0  
             ? "You keyed in an even number"  
             ? "I can prove it:"  
             ? "the result of ",number," % 2 = 0 is ", number % 2 = 0  
          ELSE  
             ? "You keyed in an odd number"  
             ? "I can prove it:"  
             ? "the result of ",number," % 2 = 0 is ", number % 2 = 0  
          ENDIF  
          RETURN

Try compiling this program and see what it does. In this example, you see also that to print more strings, or strings and variables with the same ? instruction, you only need to put a comma to separate the various items passed to the command.

We will specify a last thing: the ELSE statement is not compulsory. You can omit it, as the following example does:

               Function MAIN() 
               LOCAL number 
               INPUT "Key in a number: " TO number 
               IF number = 0 
                  ? "Congratulations, you keyed the fabolous number " 
               ENDIF 
               ? number 
               RETURN

As you see, this program always prints the number entered by the user, but seems to get happy when the user enters the number 0 (this is an example of nichilist programming).

LOCAL nNumber := 0
//
IF nNumber < 50
? "Less than 50"
ELSEIF nNumber = 50
? "Is equal to 50"
ELSE
? "Greater than 50"
ENDIF

DO CASE, CASE, OTHERWISE, ENDCASE

To execute one of several sets of statements depending on which of a set of associated conditions is true.

If none of the preceding CASE conditions are true, the statements following the OTHERWISE statement are executed up to the next ENDCASE statement.

* Display menu choices.

@ 3, 25 PROMPT "First choice"
@ 4, 25 PROMPT "Second choice"

* Get menu key.
MENU TO choice

* Perform an action based on your menu choice.
DO CASE
CASE choice = 0
RETURN
CASE choice = 1
DO One
CASE choice = 2
DO Two
ENDCASE
RETURN

To repeatedly execute a series of statements while a condition is true (.T.).

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 num, somma, n 
               CLS 
               ? "Let's sum up the first n odd numbers." 
               INPUT "How many numbers: " TO n 
               somma=0 
               num=1 
               DO WHILE num <= 2*n 
                  somma=somma+num 
                  num=num+2 
               ENDDO 
               ? "The sum is ",somma

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 somma=somma+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 WHILE has the control of the expression in its head, as opposed to the REPEAT-UNTIL looping statement which has the control of the condition in its tail (these are Italian expressions, I do not know how English express the same concept). How do the xBase/Clipper say REPEAT-UNTIL? It doesn't. Here is how to emulate it:

FOR...NEXT

The FOR...NEXT construct is most useful for traversing arrays.

6.4 Data types in general (and operators...)

alfanum.prg


function MAIN
a := "12"
b := "3"
? a+b
return
data.prg


function MAIN
a:=date() && system date
? a+1

b:=ctod("12-12-91")
c:=ctod("12-12-06")
? a-b
return

dbcreate.prg


FUNCTION MAIN
CREATE clientes
USE clientes
APPEND BLANK
REPLACE FIELD_NAME WITH "CODIGO"
REPLACE FIELD_TYPE WITH "C"
REPLACE FIELD_LEN WITH 5
APPEND BLANK
REPLACE FIELD_NAME WITH "NOMBRE"
REPLACE FIELD_TYPE WITH "C"
REPLACE FIELD_LEN WITH 30
CLOSE
RETURN

mismatch.prg


function MAIN
a := "1"
b := 2
? a + b
return

num.prg


function MAIN
a := 1
b := 2
? a+b

6.5 The tables

6.6 Arrays

6.7 Subroutines, i.e. Functions and Procedures

6.8 I/O and the production of a TUI

6.9 Managing databases

If this was a tutorial about a normal programming language, it would already have been finished. Now it is time to move on its most interesting features.

dbcreate.prg


FUNCTION MAIN
CREATE names
USE names
APPEND BLANK
REPLACE FIELD_NAME WITH "name"
REPLACE FIELD_TYPE WITH "C"
REPLACE FIELD_LEN WITH 30
APPEND BLANK
REPLACE FIELD_NAME WITH "address"
REPLACE FIELD_TYPE WITH "C"
REPLACE FIELD_LEN WITH 30
CLOSE
CREATE NAMES FROM NAMES
RETURN

and this is the next piece of code:

db1.prg


function MAIN
clear
? "First database example program"
select 1
use names
append blank
replace name with "Mario Rossi"
replace address with "Development Road, 1"
quit

From the Guide To CA-Clipper 5.3 comes this useful example:

function MAIN
//  This example is a procedure that simulates an interactive CREATE utility:

   CreateDatabase("NewFile")
   RETURN

   FUNCTION CreateDatabase( cNewDbf )
 CREATE TmpExt// Create empty structure extended
 USE TmpExt
 lMore := .T.
 DO WHILE lMore    // Input new field definitions
    APPEND BLANK
    CLEAR
    @ 5, 0 SAY "Name.....: " GET Field_name
    @ 6, 0 SAY "Type.....: " GET Field_type
    @ 7, 0 SAY "Length...: " GET Field_len
    @ 8, 0 SAY "Decimals.: " GET Field_dec
    READ
    lMore := (!EMPTY(Field_name))
 ENDDO

 // Remove all blank records
 DELETE ALL FOR EMPTY(Field_name)
 PACK
 CLOSE

 // Create new database file
 CREATE (cNewDbf) FROM TmpExt
 ERASE TmpExt.dbf
 RETURN NIL

//  This example creates a new definition in a structure extended
//  file for a character field with a length of 4000 characters:

   APPEND BLANK
   REPLACE Field_name WITH "Notes",;
 Field_type WITH "C",;
 Field_len  WITH 4000 % 256,;
 Field_dec  WITH INT(4000 / 256)

Next Previous Contents
Hosted by www.Geocities.ws

1