The magazine of the Melbourne PC User Group
Xbase Programming - Part 3
Gary Taig
garyt@melbpc.org.au
|
 |
[ Continued
from last month's article.]
It's back to basics this month. If you found last month's lesson easy to carry
out but hard to comprehend, then you should enjoy this one.
Did everyone finish up with a screen that looks like Figure 1? I hope so because
Figure 1 was captured from dBASE III PLUS as I tested the code. That screen is
exactly as you should have it. This month we will thoroughly dissect the program
code behind Figure 1.
If we have space we will write a few lines to enable data entry to the MEMO
fields, enabling you to enter some notes for each person. Then we can learn how
to MODIFY the data held in the MEMO fields.
Later, in a future lesson, we will work together to develop a more acceptable
data entry screen layout 'Me screen in Figure 1 has quite a lot squashed into a
small space and, given some time, we can devise far better layouts. I'll show
you how to arrange it so that some of your data can be entered onto a second and
perhaps even a third screen.
Before We Go Any Further
This month we will write small snippets of code. Check out the built-in text editor your
Xbase software provides. In dBASE and Foxbase this is opened by typing MODIFY
COMMAND at the DOT prompt. As with all Xbase commands, you need only type the first four characters; thus to create a small program named
BIGTEST.PRG you need only type MODI COM
BIGTEST. Play around with it, learn how it works. Using the built-in editor is much easier and faster for small jobs than jumping out to start another word processor just for small changes.
Are you excited? This is where we move into forward gear. This is where we actually learn how to accomplish something with our Xbase software.
Select Low Gear
If you found the program code in Lesson 2 just a little bit too complex and
hard to understand as you read through it, then you should probably slow down.
You might read things a wee bit too
fast. You could be a bit like me, I do it all the time because I'm always in too
much of a hurry.
You must think about every line. Stop after every line and ask
yourself "what does that mean?" or "what does that do?" Sometimes
the question might be "what on earth is he saying?!"
Make notes,
that's an important part of this learning exercise. If you really cannot work
out what is happening, write down a question. Later it might be answered in the
text but at least you won't forget it.
A Tip!
You might never think of this but it's extremely important. Every now and
then you should go back and read the previous lessons. After you have gone
through this month's lesson would be an ideal time to revise Lesson 1. You
should also look in your manual and check for additional information on the
various topics we cover. The reasons are fairly obvious aren't they!
Memory Variables
This is a good time for a brief discussion, just for those who are not familiar
with programming.
Memory Variable (a name indicating change), is an expression used to refer to
part of the computer's memory that is set aside by your software for the purpose
of temporarily storing data.
This memory area gets a special name (we select the name) and it has an address
so that it can be accessed. The actual address in memory does not concern us,
our ?base software takes care of that. We simply nominate the amount of memory
space we require and from time to time. enter some data into it.
|
|
What is an Xbase Program?
Some beginners are a little confused by one of the most fundamental aspects of all this. The question of "what is an Xbase program?"
If you're entirely happy with the definition that its like any other computer program, "a series of instructions written in an Xbase language, to be executed by the computer, one at a time, in sequential order", then go back to the text. If that doesn't satisfy you, try carrying out the following exercise at the DOT PROMPT.
Type in each of the following commands and press the [enter] key after each one. Remember to start dBASE or FoxBase or whichever Xbase System you are using before you do this. Typing Xbase instructions at the DOS C:\ prompt will give a variety of unwanted results including "Syntax Error" and "Bad Command or File Name" messages... and it's not recommended because with enough bad luck you could also do some damage.
SET ALTERNATE TO STATUS.DOC
SET ALTERNATE ON
DIR
LIST MEMO
LIST STATUS
SET ALTERNATE OFF
CLOSE ALTERNATE
CLEAR |
You have just carried out manually, eight (8) separate steps, from the keyboard. You have issued eight separate instructions to your software but you did them
interactively, remember that from Lesson 1?
QUIT from Xbase and use your favourite file viewer to examine the file named STATUS.DOC that we just created. You will see a variety of information dependent upon how many .DBF files were present in your current directory, how many memory variables were existing in memory at the time and so forth.
Now use your TEXT EDITOR to create a file named TEST.PRG which contains all those instructions, exactly as they are above, on separate lines. Save the file, start your abase System, type DO TEST at the DOT PROMPT and press
[enter].
You should also go back to Lesson 1 and find how to avoid data scrolling up the screen. Add the required two (2) lines of code and repeat the exercise.
You have just created a computer program, and ran it. The beauty of a program is that you can run it over and over without the need to type the same old instructions every single time.
We can also go a level higher than that. Can you imagine what the following program code might do...?
FOR i = 1 to 30
DO TEST
ENDFOR |
Yes... you would have just saved yourself typing DO TEST 30 times! Think of the total saving in keystrokes in just that little exercise. The benefit of writing a program for repeated tasks becomes pretty obvious, doesn't it.
Note that the FOR ... ENDFOR structure is NOT available in dBASE or Foxhase. However, if you use Foxpro then those commands would be available to you.
As a final exercise, start Xbase, type the command STORE "many digits" TO MVAR and press (enter). Now DO TEST again. Examine the file and you will see a different result. What have you learnt from that?
Another quick one, before we go back to the text. If you leave the filename STATUS.DOC unchanged, that file will be overwritten each time you nun TEST.PRG. I'll show you shortly in another lesson how to create NEW FILENAMES on the run, automatically. |
In our sample program you found things like
STORE space(10) to mvar. We
were telling Xbase to set aside sufficient memory to hold 10 characters, to
store initially some ASCII 32 characters (blank spaces), and to use only that
memory location whenever we refer to the variable named mvar in our program.
|

Figure 1.
|
The exact opposite of a memory reservation such as store, is
RELEASE. When we are done with our variables we can free up that
memory space by issuing the command
RELEASE mvar.
We are not talking about disk space, that's something entirely different. We are
talking about electronic memory - temporary storage! I lave you studied "Eight
bits of Impact"? If not, go back to Lesson 1.
There should be several questions on our sample code so let's begin at the top
and work down.
Setting Up The Environment
We skipped over thus and agreed to cover it this month. Let's take each line as
it comes.
SET TALK OFF
This thing known as TALK, is something is something like ECHO. If you look at the screen in
Figure 7 you will notice that I had typed the command
line
STORE "many digits" TO mvar,
then immediately under that, ran the next line,
appears the character string "many digits". That line was
echoed to
the screen when I hit the ENTER key because TALK was SET ON.
Try it yourself. SET TALK ON and then OFF, type an identical command each time.
You will see immediately why we have it SET OFF. Most Xbase activities are
echoed to the screen if we leave TALK set on, and that has a tendency to make a
real mess of our screens. Try running your program with the SET TALK OFF program
line commented out.
Did you understand that? Did you follow exactly what I meant by the words
"commented out"? You cannot afford to let one sentence pass by without
understanding its meaning or noting a question. When I suggest you try something
there is a good reason for it and I'll harp on that until I'm positive you
understand the importance of it. You must get into the right habits because in a
few months time when we reach some of the complex bits you will need all those
good habits to be well and truly SET ON! They must be very much a part of your
learning process. Breeze over nothing!
A comment line in an Xbase program is one which begins with an asterisk. You
recall that from Lesson 1 didn't you! Remember we put comments in our programs to
make them more readable? Well, we temporarily change a program line into a
comment line, just by putting an asterisk in front of it. That stops our Xbase
software from acting on it. The line is ignored Saves re-typing when we might
want to re-use it later!
So, back to where we left off. Comment out the SET TALK OFF and run your program
again. See what a mess it makes. Then do the same with SET BELL OFF. The sound
effects will teach you more than I could explain in three pages. SET BELL ON can
be used quite deliberately when you want to draw the operators attention to what
they are doing - like waking them up just in case they are nodding off' after a
heavy lunch. Where would you deliberately use SET BELL ON? Think about it.
Listen for the BELLS in other programs you use. Try to work out when and why the
bell is utilised.
On the other hand, if you just want the bell to ring once at a certain spot,
simply add the following line into your program: ?? CHR(7)
ASCII Character 7 is the BELL character and if you output that to your console
(screen) with the single or double question mark "output" command, the
bell will ring. Your screen will not display the bullet symbol though, as you
might imagine it would.
As a further demonstration of this, key in the following program and run it,
just to see what happens. Remember, each line on a new line and don't forget to
save it with a .PRG file extension. The first line starts with a single question
mark and all others start with two question marks. This will teach you more than
a thousand words could ever explain. Watch the screen carefully as your program
runs.
? CHR(66)
?? CHR(101)
?? CHR(108)
?? CHR(108)
?? CHR(7)
?? CHR(32)
?? CHR(104)
?? CHR(97)
?? CHR(115)
?? CHR(32)
?? CHR(114)
?? CHR(117)
?? CHR(110)
?? CHR(103)
|
Now that you have seen the results, try writing that little example in just one
line. If you can, and it works, you are doing well. I'll show you later what it
should have been.
SET SAFETY OFF
If you have safety SET OFF, that allows you to issue some very dangerous
commands without your Xbase Software interrupting and asking "are you sure
you want to do that?"
SAFETY always defaults to being SET ON. We must deliberately and consciously SET
it OFF when required - Why? Because the software designers knew for certain that
some people would cause very serious damage, quite inadvertently, if they were
not asked to confirm their intentions in dangerous situations. The designers
decided it was better to be safe than sorry because we all lose concentration at
times.
For instance, if you type the command ZAP and then {enter) when you have a .DBF
file open, the file contents can be lost for ever. ZAP is the command that
permanently DELETES or if you like REMOVES, all records in a file. Setting
SAFETY OFF allows you to do that and get away with it, without any warning. So
use it carefully, only after you have tested your programs absolutely
thoroughly.
When I began using dBASE, I used to have SAFETY set ON at all times, and I
should have left it on too because now I drink too much coffee. dBASE used to
display the message "are you sure
you need that..?" and ring the bell, every time I went to move away from
the keyboard and head for the kitchen! Come on - lighten up a bit - life is too
short! That was just one of my versions of SET ALERT ON.
SET DATE is self explanatory. The choices are in your manual. Check them out.
SET STATUS shows or hides the status bar. One lesson you will learn by using it,
is that when you SET STATUS OFF or ON in the middle of a program, the screen is
cleared and you must repaint the entire screen immediately. Sometimes it's
handy, other times it's a nuisance. Later I'll show you the best way to get
around that one.
Inexplicable Events
That reminds me of another small problem. We had better diverge here for a
moment and cover a very important aspect of these Xbase Systems. They all have
their peculiarities. Such as SET STATUS clearing the screen for us, without
invitation.
I have seen these referred to as bugs. Some people think if a System behaves in
a certain way not to their liking, or in a way they perceive is incorrect, then
that constitutes a bug in the Software.
I have seen them referred to as features. Usually though it's the Software
Developers who call them features, with big tongue in cheek.
They are also known as quirks, aberrations, irregularities and many other names
but really they fall into either one of two categories. Either it is something
the designers missed entirely, and found when it was far too late for them to
make the change. Or, it was something they couldn't change, because it would
have meant changing something else as well, and they didn't quite want to do
that.
If you use FoxBase 2.1 you will find that the screen clears every time you SET
SCOREBOARD OFF. There are some undocumented things like that you will discover
from time to time. Finding a way around them helps you to learn by forcing you
to do some lateral , so stay with it
Back to our Program
CLEAR simply clears the screen, like the CLS command in DOS or Basic. It's a
good habit and more often than not you'll find it necessary. By that I mean,
"experience will teach you" it's a wise habit to clear the screen at
the beginning of every program.
SET PROCEDURE TO <program-name>
We've already briefly covered SET PROCEDURE TO, in Lesson 2. I'll tell you a lot
more about it later when we get to the point where you will be better equipped
to understand and follow a more detailed discussion.
For now, just remember the following two important items and the explanation
that comes after it:
(1) When you issue a command
DO (program-name) your Xbase Software runs around looking for a program of that
name, which it can execute. A program usually has the .PRG file extension.
(2) Any Xbase program, that is, a program code file with the .PRG file
extension, can also be a Procedure File. The simple distinction is that it
contains Procedures.
If you have provided a procedure file name to your current session, by issuing
the command
SET PROCEDURE TO <program-name>
either manually at the DOT prompt, or from
within a program, this causes your Xbase Software to look through that file for
every program it is required to execute.
Yes, that's right. From then on, every time you issue the command
DO <some-other-program-name>
in the current session, Xbase will search
entirely through the Procedure File first. It will be looking for a line
starting with
PROCEDURE <some-other-program-name>.
Only if the required line is not present, will Xbase go off hunting around on
your disk trying to find a separate program to execute.
Make sure you understand what this also means. If a file contains a procedure
with the same name as another, separate program, and you have already SET
PROCEDURE TO that file, the procedure will be found and executed, not the other
separate program.
In Lesson 2 our program file was named MBINPUT.PRG and it contained procedures
- MAIN, BLNKVARS, and PITITIN. To really see this principle demonstrated, split
a copy of MB INPUT.PRG into four separate programs named MBINPUT.PRG, MAIN.PRG,
BLNKVARS.PRG and PUTITIN.PRG. Comment out the line that
says SET PROCEDURE TO MBINPUT. comment out each of the PROCEDURE lines if you
still have them, then try running MBINPUT.PRG again.
Everything will work perfectly, the only difference now is that your system is
not so efficient, not that it makes much difference here of course, but Xbase
now must search on your disk to find the other programs each time they are
called. (Refer to Figure 2 for a brief discussion on the speed of a hard disk vs
the speed of memory.)
|
|
Nanoseconds, Milliseconds and Disk Access
The subject of "Disk Access" time prompts me to make the following comparison. This will be somewhat simplistic but it will serve to
highlight the huge difference between the speed of your computer's memory and the time it takes your machine to "find" the start of a file
on a hard disk.
Memory Chips
The average XT uses memory chips with a rated speed of somewhere between 100 and 150 nanoseconds. In contrast, if you have a late model
286 or 386, running at 16 or 20 MHz, your memory is more likely to be rated in the 70 to 80 nanosecond category.
Disk Access
Obviously disk speed varies with the type of disk. If you use an older disk with an average rated seek time of 50 to 70 milliseconds, that's
fairly slow by present day standards. If you have a new disk with an average seek time of (say) 12 to 14 milliseconds, your disk is
comparatively fast.
One millisecond is 1/1000th of a second. That's a short period of time, isn't
it!
A slow old disk can perform an average seek in just 70/1000ths of a second - or in other words, in terms of rated speed, complete about 14
such activities, every second.
Some Big Numbers
One second is equal to 1,000 milliseconds One millisecond equals 1,000 microseconds One microsecond equals 1,000 nanoseconds
If we reach for the calculator, or exercise some grey matter, we find there are 1,000 million nanoseconds in every second.
Oranges and Apples
One disk access, which takes 70 million nanoseconds, is competing with your memory which has a rated speed, for a vaguely similar exercise, of
as low as 70 nanoseconds. Now that does not make your memory one million times faster than your disk because we are comparing apples
with oranges but it does mean that your memory can perform approximately one million address operations in the time it takes your
disk to perform one average seek.
If you machine is running at 20 MHz, then it is capable of doing almost 20 million single program instructions per second. Compare that
massive amount of work, with the 14 miserable "seek" activities your slow disk might undertake in the same period of time.
If you must make a programming decision in favour of either extra memory activity or extra disk activity, choose memory. You will get a lot
of work done while that disk finds the required file and retrieves the data you need. Data that in some cases you might have had, and
thrown away quite needlessly, a few millionths of a second earlier.
Figure 2 |
PROCEDURE MAIN
You'll remember that I ran out of room last month and was forced to cut some
code from the sample so it would fit? Well, just to make sure you managed to get
it right I've included those few lines for you in full this month. Compare
Figure 3
with the code you wrote on your own. Mark yourself very strictly though, because
it must be exactly correct.
|

Figure 3
|
Memory Variables - Public vs Private
I'm sure many of you would like an explanation of this. I wrote Lesson 2 in a
bit of a hurry and couldn't possibly handle it there so here we go. Variables
can be either PUBLIC or PRIVATE.
Some of what you learn here changes in later
versions of some Xbase Systems but the fundamentals are still important and
we'll start our coverage of PUBLIC vs PRIVATE from the way they were in the
beginning - that is, back in the days of dBASE III and FoxBase.
To understand this properly we must firstly examine how our program code is
executed. We must look closely at the order of processing of the instructions in
our program file.
Take a look at Figure 4. Each PROCEDURE is represented by a separate box.
(Remember, these are known in some circles as SUB-ROUTINES). The first Box is
not a procedure though, it is simply the start of the program. In fact, it would
represent the entire content of MBINPUT.PRG if you split the three procedures
out into separate programs as we discussed earlier.
MBINPUT.PRG calls the procedure; named MAIN. This in turn calls BLNKVARS and
PUTITIN.
We could not allow the memory variables that we create in MAIN.PRG to be
created at the lower level in BLNKVARS instead, because when processing returned
from BLNKVARS to MAIN, any variables created in BLNKVARS would be released. [There is another twist on this but we'll cover it
last!]
Last month I told you that a program called by MAIN could not release memory
variables that existed at the
time it was called. That is not correct if you are working with some of the
earlier versions because dBASE III PLUS for instance, is quite happy to do that.
The best way to find the limits of your software is to create a small program to
test the situation. Follow the exercise below.
(1) Create some variables from the DOT prompt. Do this by typing the commands as
they would appear in a program e.g.
STORE "1213" TO char_var
STORE 15 TO num_var
STORE "abcdefgh"
TO next_var
|
We created three different variables. The first and third now contain character
strings; the second, a numeric value.
(2) Type
DISPLAY MEMORY and
[enter]. You will see that your memory contains at
least those three variables. They will be PUBLIC by default.)
Now, to test our particular Xbase software we need to run some programs. If your
software cannot release variables created by another program, you will soon find
out. Key in the following program and run it, without leaving Xbase.
STORE "zzzzz" to new_var
RELEASE char_var,num_var,next_var
DISP MEMO
SUSPEND
|
|

Figure 4
|
What do you see? If your memory contents displayed on screen include the three
variables we just now tried to release, then you have discovered that your
software will not allow a program to release PUBLIC variables created at the DOT
prompt. So far so good. Now we had better test that same thing in a program
environment.
Write a small program to duplicate the first lot of commands we typed above at
the DOT prompt. This will become the calling program, we'll refer to it as the
"higher level" program
From within that program you must run the small program that tries to release
the variables and see what happens. If the variables are still in memory when
the higher level program displays the current memory, then you will know your
software does not allow a lower level program to release memory previously
reserved by another.
Are you having trouble working out where to call the other program? If yes, this
is what your higher level program should do:
(a) Store some information, any data type is OK, into some memory variables,
like we did in Step (1) above, at the DOT prompt.
(b) Call your other program, whatever you named it, with the command
DO
<YOUR-PROGRAM>. This will try to release the memory reserved.
(c) Next, include the command
DISPLAY MEMORY. This will show you what remains in
memory after the lower level program has tried to release the variables created
at the higher level.
Are you making notes at the top of these programs? Are you noting what each
program does? Are you noting the changes you make? Are you getting the idea that
writing programs involves creating an awful lot of documentation? Either you
are, or you're not doing the job properly! There is no other way to learn.
Public Variables
The original intention behind declaring a variable PUBLIC, was that any program
could use the variable, modify its content etc, but not release it. The
variable was PUBLIC property.
As it is, dBASE III allowed a lower level program
to release memory reserved by another. Common opinion is that dBASE should not
have allowed this to happen. Later, more sophisticated Xbase Systems don't
allow it.
Private
If a lower level program wants to use an existing variable, perhaps change its
content or manipulate it in some other way, but not affect the existing content,
that can be done. But, the variable must be declared PRIVATE, within that lower
level program, before any messing around takes place.
In some respects PRIVATE is rather like allowing a lower level program to re-use
the name already used by another variable. When the existing variable contains
some data, the lower level program can also get hold of that data, manipulate
it, discard whatever values it finished up with and so on, without affecting the
actual value stored in the original variable.
In our sample system, BLNKVARS certainly does alter the contents of all
variables. It stores spaces and other blank data to them but in that particular
case we wanted the change to be retained. so in that case we would have no need
whatsoever to make the variables PRIVATE within BLNKVARS, would we!
Test this by trying to run your program with the variables declared PRIVATE in
BLNKVARS, before any blanks are stored in them, and see what happens. You will
learn a lot from that exercise. Examine the results by displaying memory before,
during and after the execution of BLNKVARS.
Why not Make Variables Public In BLNKVARS
Wouldn't they be available and still existing when we returned? Yes they would!
We could actually create all of our variables and store blank spaces in them,
from within PROCEDURE BLNKVARS, make them PUBLIC, and as a result, find them
still available when we returned. However, there is a catch.
We would not be able to call PROCEDURE BLNKVARS again during that session,
because you cannot declare a variable PUBLIC once it has already been declared
PUBLIC.
We would be forced to find a way around that problem. See if you can work it
out, there is at least one way around it. I'll show you next lesson.
By now you
should be getting the impression that there is more than one way of achieving
each end result. There is - often we could write the same program in many
different ways. I hope you practice a lot and play around with ideas as we are
doing this because as the inimitable Tom Coleman once put it - "computer
knowledge is absorbed through the tips of the fingers".
|

Figure 5
|

Figure 6
|
Data Entry Take a good look at Figures 5 and 6. These explain a little about how
our software locates information on the screen. Figure 6 actually explains how you
can enter data into memory variables at the DOT prompt. Type the following
commands and test it yourself, you will learn much by doing this.
STORE space(10) to mvar
@ 10, 10 GET mvar
READ
|
You will find in this instance that the cursor jumps to the location of the
variable and allows you to enter data. Type something! After you press [enter]
you will be put back at the DOT prompt. Display your memory at that point and you
will see that mvar contains whatever you typed into it.
Do the same again but next time STORE 0 (zero) to a variable. Then GET it,
somewhere in the middle of the screen, and issue a READ. You'll find the
variable contains numeric data instead of character data. Everything is spelled
out for you when you DISP MEMO.
Look in your manual for PICTURE clauses, try adding some PICTURE clauses to the
GET and READ for numeric variables.
There is enough in that little exercise to keep you going for a month or more.
You will learn heaps by doing these things. Remember, make notes all the time!!
The case structure in our code, at the bottom of PROCEDURE MAIN, simply reads
each of the key presses and branches control accordingly. The Readkey() values
are all contained in your manual, study them carefully. After a while, with
constant use, they become like the "three times tables", you will know
them by heart
Reprinted from the December 1991 issue of PC Update, the magazine of Melbourne PC User Group, Australia
|