Dec 082017
Ashton Tate dBase IV Tech Notes for September 1991.
File TN9109.ZIP from The Programmer’s Corner in
Category Dbase Source Code
Ashton Tate dBase IV Tech Notes for September 1991.
File Name File Size Zip Size Zip Type
TNDB0991.TXT 83924 26155 deflated

Download File TN9109.ZIP Here

Contents of the TNDB0991.TXT file

UDF Library

You Dirty RAT()

Analyzing strings usually goes from left to right. But
there are different perspectives.

Below are some handy little modified AT() functions for
determining the starting position of text within other text. As
you already know, the AT() function will return the starting
position of the first occurence of the text. Two functions
below, RAT() and FRAT(), are similar. RAT() will return the
starting position for the last occurence of the text (first
occurence from the right - Right AT()). The other function,
FRAT (From the Right AT()), will give the starting position for
the text some number of characters from the right. The
difference is minor. Below are some examples to illustrate:

Counting from the left : 123456789
Given the String: "ABC DEFAB"
Counting from the right: 987654321

The following values will be returned, given the two
parameters "A" and "ABC DEFAB" (that is, where is "A" within
the string "ABC DEFAB").


1 8 2

You may have noticed the DO WHILE loops in RAT(). What this
does, in effect, is to reverse the text, so that an ordinary
AT() may be performed. Text entering the loop, "ABCB", becomes
"B", then "BC", then "BCB", and finally "BCBA". Then it is a
simple matter of adding and subtracting the LENgths of the
"search for" and "search in" strings.

Aesthetically Pleasing Configurations

And now for some eye-catchers. The first UDF displays a
left-scrolling message on the screen within the boundaries
specified in the UDF by the user. For example, to have the
message "Love your tie, is it new?" in white on red, scroll
within a 20 character window at row 5, column 30:

?? Banner(5,30,20,"Love your tie, is it new?","W+/R")

will continuously scroll the specified message until a key is
pressed. The syntax is:

Banner(row, column, window width, "message", "color


SeeMatch() is a UDF that can be included in your format
screen to display an instant lookup match on a particular
field. For example, say you have your Clients and Travel
databases set up as shown below:


Suppose that for each LASTNAME entered into the Clients
database via your format screen, you want to see a matching
TRAVELCODE from the Travel database somewhere on the screen.
To achieve this, you would include the following line in the
Accept Value When prompt in the screen generator...

^ ^ ^ ^ ^
LookUp LookUp Return Box Box
Database Exp Field Position Color

When you enter a new value into the LASTNAME field while
using this screen file, a shadowed box will appear with the
matching value.

Message Displaying

Last but not least, we've included a little function that
allows you to display a message (or error message) centered
like it is supposed to with SET MESSAGE TO but with some added
utility. No longer will the error message say your message and
then the annoying little afterthought message "(Press Space)".
The message and the line on which it is displayed will be the
same color. Those of you who have spent hours working out your
computer color schemes will undoubtedly love this tidbit.

This UDF can be used in a SET MESSAGE TO statement, in the
Message edit condition of a screen or in an @..GET command
line. The syntax is simple:


where CExp is a character expression in quotes.

UDF Code

* Author - Adam Menkes
PARAMETERS mText, mField
mLen1 = LEN(mText)
mLen2 = LEN(mField)
mText1 = mText
mField1 = mField
DO WHILE LEN(mText1) > 0
mSearch = mSearch + RIGHT(mText1, 1)
mText1 = SUBSTR(mText1, 1, LEN(mText1) - 1)

DO WHILE LEN(mField1) > 0
mString = mString + RIGHT(MField1, 1)
mField1 = SUBSTR(mField1, 1, LEN(mField1) - 1)
RETURN IIF(AT(mSearch, mString) = 0, 0, mLen2 - AT(mSearch, mString) + 1 -
mLen1 + 1)

Function: FRAT()
* Author - Adam Menkes
PARAMETERS mText, mField
*- Requires RAT()
RETURN IIF(RAT(mText, mField) = 0, 0, LEN(mField) - RAT(mText, mField) + 1)

Function: Banner()
* - Author: Dan Madoni
PARAMETERS b row,b col,b width,b msg,b color

*- b row, b col : Leftmost position of scroll message
*- b width : Length of displayable area from b row/b col
*- b msg : Message which will be scrolled
*- b color : Color of scrolling message

*- Record environment essentials
b cursor = SET("CURSOR")
b talk = SET("TALK")

b msg = SPACE(b width) + b msg + " "
b cntr = 0

b cntr = b cntr + 1
IF b cntr > LEN(b msg)
b cntr = 1

*- Exit if user hits any key
b pause = INKEY(.15)
IF b pause <> 0

*- Display message within scrollable area
@ b row,b col SAY SUBSTR(b msg,b cntr,b width) COLOR &b color

*- Restore environment
SET CURSOR &b cursor
SET TALK &b talk


Function: SeeMatch()
* - Author: Dan Madoni
PARAMETERS s file,s seekexp,s return,s row,s col,s row2,s col2,s color

*- s file : Database alias in which lookup will be performed.
*- The name of the database must be in quotes
*- s seekexp : The expression which will be SEEKed
*- s return : The name of the field to conataining the return
*- value. The name of the field must be in quotes
*- s row, s col, s row2, s col2 : Box coordinates
*- s color : Box color

*- Record where you were at when you started
s_startf = ALIAS()
SELECT &s file

*- Look for a matching expression
SEEK s seekexp
s ret = &s return
s ret = ""
*- Record current color and draw box
s attr = SET("ATTRIBUTES")
@ s row + 1,s col + 1 FILL TO s row2 + 1,s col2 + 1 COLOR W/N
SET COLOR TO &s color

@ s row,s col CLEAR TO s row2,s col2
@ s row,s col TO s row2,s col2

*- Display matching expression and return to intial workarea
@ s row + 1,s col + 2 SAY s ret
SET COLOR TO &s attr
SELECT &s_startf


Function: MsgExp()
* Author - Adam Menkes
* Centers message and keeps line 1 color
* Also suppresses "Press space" message
mlen = LEN(TRIM(msg))
RETURN SPACE((80 - mlen) / 2) + TRIM(msg) + SPACE((80 - mlen) / 2) + " "

Transparent VT Emulation

Transparent VT Terminal Emulation from DOS to VMS

Portia Shao

Remapping your keyboard doesn't have to be a tedious and
painful process.

Since dBASE IV became available for DECs VAX/VMS, many
PC users who use dBASE IV on VMS from a PC running a terminal
emulator have expressed the frustration of having to mentally
remap the keyboard while using the terminal emulator. The
users are already familiar with dBASE IV on DOS, and the keys
on the DOS version of dBASE IV, and want to be able to use the
same keys while running dBASE IV on VMS.
Not all terminal emulators provide the complete keyboard
re-mapping capability for users to accomplish this. Basically,
the terminal emulator must be able to map one key on the PC to
multiple keystrokes for VMS. MS-DOS Kermit v3.0 is an emulator
which allows the complete re-mapping, it also emulates VT320

How to Redefine Keys

1. Create a file called DBASE.TAK which contains the key
definitions as follows:

; filename: dbase.tak
; kermit key definitions for VMS, emulating VT320

echo MS-DOS Kermit to dBASE IV on VMS keyboard
set display 8
set terminal control 8
set terminal vt320
set terminal roll off
set terminal wrap on
set terminal cursor underline
set terminal character latin-1

; alt-number keys mapped to PF3-n, where PF3 is \27R
set key \2424 \27R1
set key \2425 \27R2
set key \2426 \27R3
set key \2427 \27R4
set key \2428 \27R5
set key \2429 \27R6
set key \2430 \27R7
set key \2431 \27R8
set key \2432 \27R9
set key \2433 \27R0

; alt-letter keys mapped to PF3-a, where PF3 is \27R
set key \2334 \27Ra
set key \2846 \27RA
set key \2352 \27Rb
set key \2864 \27RB
set key \2350 \27Rc
set key \2862 \27RC
set key \2336 \27Rd
set key \2848 \27RD
set key \2322 \27Re
set key \2834 \27RE
set key \2337 \27Rf
set key \2849 \27RF
set key \2338 \27Rg
set key \2850 \27RG
set key \2339 \27Rh
set key \2851 \27RH
set key \2327 \27Ri
set key \2839 \27RI
set key \2340 \27Rj
set key \2852 \27RJ
set key \2341 \27Rk
set key \2853 \27RK
set key \2342 \27Rl
set key \2854 \27RL
set key \2354 \27Rm
set key \2866 \27RM
set key \2353 \27Rn
set key \2865 \27RN
set key \2328 \27Ro
set key \2840 \27RO
set key \2329 \27Rp
set key \2841 \27RP
set key \2320 \27Rq
set key \2832 \27RQ
set key \2323 \27Rr
set key \2835 \27RR
set key \2335 \27Rs
set key \2847 \27RS
set key \2324 \27Rt
set key \2836 \27RT
set key \2326 \27Ru
set key \2838 \27RU
set key \2351 \27Rv
set key \2863 \27RV
set key \2321 \27Rw
set key \2833 \27RW
set key \2349 \27Rx
set key \2861 \27RX
set key \2325 \27Ry
set key \2837 \27RY
set key \2348 \27Rz
set key \2860 \27RZ
set key \27 \Kpf1 ;esc mapped to PF1


set key \315 \KdecHelp ;f1 mapped to Help
set key \316 \KdecF7 ;f2 mapped to F7
set key \317 \KdecF8 ;f3 mapped to F8
set key \318 \KdecF9 ;f4 mapped to F9
set key \319 \KdecF10 ;f5 mapped to F10
set key \320 \KdecF11 ;f6 mapped to F11
set key \321 \KdecF12 ;f7 mapped to F12
set key \322 \KdecF13 ;f8 mapped to F13
set key \323 \KdecF14 ;f9 mapped to F14
set key \324 \KdecF17 ;f10 mapped to F17

;ctrl-F1 to F10 mapped to PF2-function key
set key \1374 \27Q\KdecHelp
set key \1375 \27Q\KdecF7
set key \1376 \27Q\KdecF8
set key \1377 \27Q\KdecF9
set key \1378 \27Q\KdecF10
set key \1379 \27Q\KdecF11
set key \1380 \27Q\KdecF12
set key \1381 \27Q\KdecF13
set key \1382 \27Q\KdecF14
set key \1383 \27Q\KdecF17

;shift-f1 to f10 mapped to PF4-function key
set key \852 \27S\KdecHelp
set key \853 \27S\KdecF7
set key \854 \27S\KdecF8
set key \855 \27S\KdecF9
set key \856 \27S\KdecF10
set key \857 \27S\KdecF11
set key \858 \27S\KdecF12
set key \859 \27S\KdecF13
set key \860 \27S\KdecF14
set key \861 \27S\KdecF17

;editing keys

set key \327 \KdecFind ;home mapped to Find
set key \335 \KdecSelect ;end mapped to Select
set key \329 \KdecPrev ;pgup mapped to prevscreen
set key \337 \KdecNext ;pgdn mapped to nextscreen
set key \1399 \27Q\KdecFind ;ctrl-home mapped to kctl-find
set key \1397 \27Q\KdecSelect ;ctrl-end mapped to kctl-select
set key \1412 \27Q\KdecPrev ;ctrl-pgup mapped to kctl-prevscreen
set key \1398 \27Q\KdecNext ;ctrl-pgdn mapped to kctl-nextscreen
set key \1395 \27Q\Klfarr ;ctrl-left mapped to kctl-left
set key \1396 \27Q\Krtarr ;ctrl-right mapped to kctl-right
set key \338 \KdecInsert ;ins mapped to insert here
set key \339 \KdecRemove ;del mapped to remove
set key \783 \27S\9 ;backtab mapped to kshft-tab
set key \127 \27Q\127 ;ctrl-backspace
set key \10 \27Q\13 ;ctrl-enter
; special keys

set key \2415 \KdecF18 ;map alt-f8 to F18 refresh
set key \2416 \KdecF19 ;map alt-f9 to F19 25th-line toggle
set key \25 \27Qy ;map ctl-y to pf2-y
set key \20 \27Qt ;map ctl-t to pf2-t

This file is available from the Ashton-Tate Bulletin
Board (213)538-6196 (1200 baud) or (213) 324-2188 (2400 baud)
as file DBASE.TAK.

2. Invoke MS Kermit on DOS, and type


Log in to VMS and invoke dBASE IV, and you will have the
same familiar keys that you are accustomed to on DOS dBASE IV.

3. If you have to use different key definitions at
times, you can go back to Kermit, and enter

set key clear
take yourkeys.tak

Availability of MS-DOS Kermit

MS-DOS Kermit is widely available from many sources, it can
be freely reproduced and shared as long as is not done for
profit. No licensing or registration is required. Thus it
has many advantages over commercial terminal emulator
software. It also has many technical merits as well. For
example, if you are using DEC's PCSA(aka Pathworks) or
Lanworks, you can use the DECnet's faster CTERM or LAT
protocols via the SET PORT DECNET command.

The book Using MS-DOS Kermit written by Christine M.
Gianone, published by Digital Press, includes a diskette
for the software. You can also get Kermit from:

Kermit Distribution
Columbia University
Center for Computing Activities
612 West 115th Street
New York, NY 10025


; filename: dbase.tak
; kermit key definitions for VMS, emulating VT320

echo MS-DOS Kermit to dBASE IV on VMS keyboard
set display 8
set terminal control 8
set terminal vt320
set terminal roll off
set terminal wrap on
set terminal cursor underline
set terminal character latin-1

; alt-number keys mapped to PF3-n, where PF3 is \27R
set key \2424 \27R1
set key \2425 \27R2
set key \2426 \27R3
set key \2427 \27R4
set key \2428 \27R5
set key \2429 \27R6
set key \2430 \27R7
set key \2431 \27R8
set key \2432 \27R9
set key \2433 \27R0

; alt-letter keys mapped to PF3-a, where PF3 is \27R
set key \2334 \27Ra
set key \2846 \27RA
set key \2352 \27Rb
set key \2864 \27RB
set key \2350 \27Rc
set key \2862 \27RC
set key \2336 \27Rd
set key \2848 \27RD
set key \2322 \27Re
set key \2834 \27RE
set key \2337 \27Rf
set key \2849 \27RF
set key \2338 \27Rg
set key \2850 \27RG
set key \2339 \27Rh
set key \2851 \27RH
set key \2327 \27Ri
set key \2839 \27RI
set key \2340 \27Rj
set key \2852 \27RJ
set key \2341 \27Rk
set key \2853 \27RK
set key \2342 \27Rl
set key \2854 \27RL
set key \2354 \27Rm
set key \2866 \27RM
set key \2353 \27Rn
set key \2865 \27RN
set key \2328 \27Ro
set key \2840 \27RO
set key \2329 \27Rp
set key \2841 \27RP
set key \2320 \27Rq
set key \2832 \27RQ
set key \2323 \27Rr
set key \2835 \27RR
set key \2335 \27Rs
set key \2847 \27RS
set key \2324 \27Rt
set key \2836 \27RT
set key \2326 \27Ru
set key \2838 \27RU
set key \2351 \27Rv
set key \2863 \27RV
set key \2321 \27Rw
set key \2833 \27RW
set key \2349 \27Rx
set key \2861 \27RX
set key \2325 \27Ry
set key \2837 \27RY
set key \2348 \27Rz
set key \2860 \27RZ
set key \27 \Kpf1 ;esc mapped to


set key \315 \KdecHelp ;f1 mapped to Help
set key \316 \KdecF7 ;f2 mapped to F7
set key \317 \KdecF8 ;f3 mapped to F8
set key \318 \KdecF9 ;f4 mapped to F9
set key \319 \KdecF10 ;f5 mapped to F10
set key \320 \KdecF11 ;f6 mapped to F11
set key \321 \KdecF12 ;f7 mapped to F12
set key \322 \KdecF13 ;f8 mapped to F13
set key \323 \KdecF14 ;f9 mapped to F14
set key \324 \KdecF17 ;f10 mapped to F17

;ctrl-F1 to F10 mapped to PF2-function key
set key \1374 \27Q\KdecHelp
set key \1375 \27Q\KdecF7
set key \1376 \27Q\KdecF8
set key \1377 \27Q\KdecF9
set key \1378 \27Q\KdecF10
set key \1379 \27Q\KdecF11
set key \1380 \27Q\KdecF12
set key \1381 \27Q\KdecF13
set key \1382 \27Q\KdecF14
set key \1383 \27Q\KdecF17

;shift-f1 to f10 mapped to PF4-function key
set key \852 \27S\KdecHelp
set key \853 \27S\KdecF7
set key \854 \27S\KdecF8
set key \855 \27S\KdecF9
set key \856 \27S\KdecF10
set key \857 \27S\KdecF11
set key \858 \27S\KdecF12
set key \859 \27S\KdecF13
set key \860 \27S\KdecF14
set key \861 \27S\KdecF17

;editing keys

set key \327 \KdecFind ;home mapped to Find
set key \335 \KdecSelect ;end mapped to Select
set key \329 \KdecPrev ;pgup mapped to
set key \337 \KdecNext ;pgdn mapped to
set key \1399 \27Q\KdecFind ;ctrl-home mapped to kctl-find
set key \1397 \27Q\KdecSelect ;ctrl-end mapped to kctl-select
set key \1412 \27Q\KdecPrev ;ctrl-pgup mapped to kctl-prevscreen
set key \1398 \27Q\KdecNext ;ctrl-pgdn mapped to kctl-nextscreen
set key \1395 \27Q\Klfarr ;ctrl-left mapped to kctl-left
set key \1396 \27Q\Krtarr ;ctrl-right mapped to kctl-right
set key \338 \KdecInsert ;ins mapped to insert here
set key \339 \KdecRemove ;del mapped to remove
set key \783 \27S\9 ;backtab mapped to kshft-tab
set key \127 \27Q\127 ;ctrl-backspace
set key \10 \27Q\13 ;ctrl-enter
; special keys

set key \2415 \KdecF18 ;map alt-f8 to F18 refresh
set key \2416 \KdecF19 ;map alt-f9 to F19 25th-line
set key \25 \27Qy ;map ctl-y to pf2-y
set key \20 \27Qt ;map ctl-t to pf2-t

Installing LAN Manager

Installing the dBASE Family on LAN Manager

Jeffrey B. McCrimon

New technologies require new strategies. Here are some
helpful tips on making best use of LAN Manager with
Ashton-Tate database management software.

Ever since dBASE III PLUS and continuing with the dBASE IV
Server Edition, we have supported many network operating
systems. Over these years we've supported the likes of the
3Com 3+Share Network, IBM PC LAN Network, the Novell Advanced
Netware operating system, and some others.
These network operating systems were based on the DOS
operating system which meant that the hard-disk device of the
file server was formatted with the DOS operating system and the
only supported workstations which ran DOS as well. The
exception to this was Novell Netware which used a proprietary
operating system on the file server.
However, during the past couple of years, Microsoft teamed
with 3Com Corporation to introduce the next-generation network
operating system, LAN Manager. LAN Manager is based on the new
advanced operating system OS/2 that was developed by IBM and
Microsoft. LAN Manager requires that OS/2 is installed on the
hard-disk device of the file server, but its workstations can
run either DOS, OS/2, and some versions even include support
for the Apple Macintosh.
LAN Manager has roots from its predecessor Microsoft Network
(MS-Net), which was the basis for OEM's (Original Equipment
Manufacturers) like 3Com and IBM and their products, 3+Share
and PC Network respectively. With MS-Net, 3+Share, and PC
Network being the basis on which LAN Manager was built, their
workstations can use the shared resources (files, printers,
etc.) of LAN Manager servers.
Companies that serve as OEMs of LAN Manager include 3Com with
3+Open LAN Manager, IBM with IBM LAN Server, and Ungermann-Bass
with Net/One LAN Manager. Since its introduction, LAN Manager
has gone through several changes and enhancements. 3Com no
longer markets the 3+Open LAN Manager, because of their shift
in product focus and have turned over LAN Manager development
to Microsoft. 3Com's current version of 3+Open LAN Manager is
version 1.1F (this is probably their last).
With the release of Microsoft LAN Manager Version 2.0,
Microsoft marks their first entry into the commercial network
operating system business. IBM continues to market, sell, and
enhance IBM LAN Server. IBM LAN Server is currently at version
1.3. IBM LAN Server Version 1.3 is actually based on an early
version of Microsoft LAN Manager 2.0 code so it doesn't have
support for many of the features that are in Microsoft LAN
Manager 2.0. IBM has announced full support of the additional
Microsoft LAN Manager 2.0 features in a future release of IBM
LAN Server. Other significant features of LAN Manager-based
networks include

* Full integration with the OS/2 operating system.
* Advanced security system with auditing capabilities.
* Peer service allows workstations to share resources across
a network.
* Workstations can access UNIX, Netware servers, and IBM
minicomputers and mainframe systems.
With its capabilities, LAN Manager has gained a respectable
place in the industry. This broad usage and acceptance of LAN
Manager has incurred many calls into the Ashton-Tate Software
Support Center, because users want to use our products under
this network operating system.
Currently, the only dBASE products that are officially
supported by Ashton-Tate using LAN Manager-based network are:
dBASE IV version 1.1 under the 3Com 3+Open LAN Manager Version
1.1F and the dBASE IV Server Edition under the Microsoft LAN
Manager Version 2.0. Although we don't officially support all
of the other environments, we do have reports from our users
that they have successfully installed and use dBASE III PLUS
(dBASE Administrator), dBASE IV version 1.1, and dBASE IV
Server Edition under 3Com 3+Open, Microsoft LAN Manager, and
IBM LAN Server.
Through some limited testing in Software Support, we have
found that these reports from our users to be true. However,
we must clarify that, although some informal testing has been
done, Ashton-Tate does not officially support the
aforementioned products on all LAN Manager-based networks other
than those previously mentioned. In this article, we provide
instructions for installing the dBASE family of products under
LAN Manager. The dBASE products that we cover are dBASE III
PLUS version 1.1 (dBASE Administrator), dBASE IV version 1.1,
and the dBASE IV Server Edition. We will make references to
the specific dBASE products and specific LAN Manager network
brands where necessary.
Preparing Your LAN Manager Network

The procedures and instructions in this article assume the
* You are familiar with the LAN Manager NET SHARE and NET
USE commands.
* If your LAN Manager file-server is using user-level
security, to be familiar with the NET USER, NET GROUP,
and NET ACCESS commands.
* Your workstations can access the file-server and you
are performing the installation from a workstation.
* You are logged into the network as the Administrator or
an account with Administrator privileges.

Installing dBASE IV

Turn-Off The OS/2 DOS Compatibility Mode

One of the features of OS/2, including and prior to version
1.3, is the support of a DOS Compatibility Mode. This DOS
Compatibility Mode allows most DOS applications to run, but
once the DOS Mode is not active it is suspended. The OS/2 DOS
Mode is only active when it has the focus. When the OS/2 DOS
Mode is active other OS/2 sessions are still active. Since a
LAN Manager file server runs the OS/2 operating system, it is
possible for the OS/2 DOS Mode to be present on the file
server. Microsoft recommends to turn-off the OS/2 DOS Mode on
a machine that will act as a LAN Manager file-server, because
running the wrong application can potentially hang the server.
The OS/2 DOS Mode also impairs performance because switching to
the OS/2 DOS Mode causes the microprocessor to switch to Real
If you run an application in the OS/2 DOS Mode which writes
to an invalid memory location, the machine will hang. This
doesn't happen with an OS/2 application because it runs in the
microprocessor's protected mode which provides protection for
its multiple running session by only terminating the failing
OS/2 application while not affecting the other running OS/2
applications. With IBM's pending release of OS/2 Version 2.0,
this should no longer be a concern as this same protection will
be extended to the DOS Mode because it will use the virtual
8086 mode of the 80386 microprocessor, thereby allowing
multiple DOS Mode (sessions) to run simultaneously.

The OS/2 DOS Mode is on by default during OS/2 installation.
None of the LAN Manager-based network operating systems gives
you an option to turn off the OS/2 DOS Mode during its
installation process. Microsoft LAN Manager 2.0 indirectly
does this. However, if your file server is a 386-based
machine and is formatted with the HPFS file system, using the
386 version of the HPFS driver, better known as HPFS386,
automatically turns off the OS/2 DOS Mode. Otherwise, turning
off the OS/2 DOS Mode requires that the PROTECTONLY command in
the OS/2 CONFIG.SYS file is set to YES. For example,


Creating A Shared Directory

IBM LAN Server Considerations
With most of the LAN Manager-based networks, with the
exception of IBM LAN Server, you can perform the entire dBASE
installation from an Enhanced DOS workstation. This is because
a user with administrator privileges can perform administrative
functions from an Enhanced DOS workstation. IBM LAN Server
doesn't provide administrative capabilities from a DOS
If you are installing to IBM LAN Server, go to the file
server and get to an OS/2 prompt. From the OS/2 prompt, logon
to the server with the ADMIN account or an account with
administrator privilege, and create a directory off the
physical root directory of the server that will be shared to
hold the dBASE software. To share the directory, use the NET
SHARE command. For example,


Then you can go to a DOS workstation, logon with the ADMIN
account or an account with administrator privilege. Continue
with the section titled Installing Multi-User dBASE.
LAN Manager Considerations
The first step to installing a dBASE software package is to
first logon to the network at a DOS workstation with the ADMIN
account or an account with administrator privilege. Also make
sure that you are using a DOS Enhanced workstation as this
gives remote administrative access (NET ADMIN, NET ACCESS) to
the server. Please note that the remaining steps assume that
you are using an Enhanced DOS workstation. If the server is
running share-level security, to gain administrator rights to
the server, issue the command,


To create the directory that will be shared, issue the


This creates the directory \DBASE off the root directory of
the server's drive C:. To share the \DBASE directory, type


This example shares the directory C:\DBASE as the sharename
D4SRVED with unlimited user access and a description. If the
server is running share-level security, append the /PERMISSIONS
clause to the NET SHARE command to assign the privileges to the
directory. Share-level security servers may optionally assign
a password to the shared directory for additional security.
Using The Shared Directory
Then use the NET USE command to connect to the shared
directory as a logical drive:


This example connects to the sharename D4SRVED and will be
known to the workstation as drive F:.
Installing Multi-user dBASE

dBASE Administrator (dBASE III PLUS LAN)
For dBASE Administrator, place the System Disk #1 in a floppy
drive, log or change to the drive, then issue the command


This example installs dBASE Administrator to drive F:,
placing the dBASE system files in the root directory of drive
F: and the /DBNETCTL.300 directory and its files off the root
directory of drive F:.
After dBASE Administrator installation, change to drive F:
and use the DOS ATTRIB utility to mark the dBASE Administrator
system files read-only. For example:


You then may run the ADDUSER utility to add more users to
simultaneously access dBASE Administrator.
This step isn't necessary with dBASE IV and dBASE IV Server
Edition as they automatically mark the appropriate system files
as read-only during installation.
dBASE IV & dBASE IV Server Edition
For dBASE IV and the dBASE IV Server Edition, place the
Installation Disk in a floppy drive, log or change to the
drive, then issue the command


Select Multi-user Install, and enter the destination
drive/directory that will hold the dBASE system files. For our
example the destination drive and directory is F:\. Then
follow the prompts.
The last step of installation gives you the opportunity to
run the ADDUSER4 utility to allow additional users access to
dBASE on the network.
Assigning Access Rights

Share-level Security Server Considerations
Assigning access rights to servers with share-level security
is handled with the /PERMISSIONS clause of the NET SHARE
command. The permissions applied with the NET SHARE command on
a share-level security server holds for any other files and
directories that are created under the shared directory. Any
user that can access the shared directory are granted the same
privilege for access.
For dBASE Administrator on a share-level security server, the
required rights for users that access it are Read, Write,
Create. If database (.DBF) files planned to be maintained
under the dBASE Administrator shared directory, you should also
assign the Delete privilege. For example:

/REMARK:"dBASE Administrator" /UNLIMITED

The Create and Write privileges are necessary for users that
will start dBASE Administrator from any directory under the
shared directory, because the file that is created and written
to is the LOGIN.DB file which contains the list of the users
that are currently running dBASE Administrator. This also
holds true for users that will use the PROTECT utility because
it creates and modifies the DBSYSTEM.DB file.
dBASE Administrator users should be aware that the LOGIN.DB
is created in the current directory from wherever you start

dBASE which is a problem because in order for the LOGIN.DB to
be updated and maintained properly, every user of dBASE
Administrator must start it from the same directory on the
network. The LIST/DISPLAY USERS command of dBASE Administrator
reads the LOGIN.DB to display the users that are currently
using dBASE on the network. dBASE IV and the dBASE IV Server
Edition also uses LOGIN.DB for the same purpose. This problem
was corrected in dBASE IV by placing the LOGIN.DB in the
\DBNETCTL.300 directory. dBASE IV Server Edition places the
LOGIN.DB file in the \DBASE directory.
Regarding Rights

For dBASE IV on a share-level security server, the required
rights are Read, Write, Create, and Delete. The Write, Create,
and Delete privileges are necessary because dBASE IV maintains
the temporary files (if TMP or DBTMP are not set to a different
drive/directory), LOGIN.DB, and DBSYSTEM.DB (PROTECT), in the
\DBNETCTL.300 directory.
For dBASE IV Server Edition on a share-level security server,

the required rights are Read, Write, Create, and Delete. The
Write, Create, and Delete privileges are necessary because
Server Edition maintains the temporary files (if TMP or DBTMP
are not set to a different drive/directory), LOGIN.DB, and
DBSYSTEM.DB (if PROTECT is invoked), in the same directory
where the dBASE IV Server Edition system files are located.
dBASE IV Server Edition users should remember that there is no
more \DBNETCTL.300 directory with the removal of the SuperLok
encryption scheme.
For dBASE Administrator and dBASE IV, you can implement even
greater security for the dBASE system files by placing the
\DBNETCTL.300 directory under an additional sharename. Doing
this requires the user to link (NET USE) to one more additional
sharename and to start a dBASE session with an additional
parameter (#DF=). The #DF= parameter informs the software as
to where to find the \DBNETCTL.300 directory. You then make
the permissions for the shared directory that holds the dBASE
system files Read-Only and keep the privileges for the
\DBNETCTL.300 directory Read, Write, and Create. dBASE IV and
dBASE IV Server Edition users also need the Delete privilege if
the temporary files are not redirected to a different
drive/directory with DBTMP or TMP.
Note that dBASE Administrator users shouldn't try to start
from the shared directory where the system files are located
because dBASE Administrator tries to unsuccessfully create or
write to the LOGIN.DB file and returns the error message "File
is not accessible." This also prevents dBASE Administrator
users from using the PROTECT utility to create and maintain the
DBSYSTEM.DB file. To share a directory for the \DBNETCTL.300
directory, make a directory on the server, share it, and copy
the entire \DBNETCTL.300 directory and its contents to the
shared directory. Note that you should use the DOS XCOPY
utility to perform this because there is a directory within the
\DBNETCTL.300 directory which contains a file with a 0-byte
length. The standard DOS COPY command cannot handle this
0-byte length file. The following example shows how to perform
this operation.

/REMARK:"dBASE Administrator Control files"

User-level Security Server Considerations
Assigning access rights to the servers with user-level
security is handled with the NET ACCESS command. Thereby
giving great control to the access of files in a shared
For dBASE Administrator, the series of privilege assignments
are as follows:


For dBASE IV, the series of privilege assignments are as


For dBASE IV Server Edition, the series of privilege
assignments are as follows:


Starting a dBASE Session
Make sure the shared directory to the dBASE system files is
reflected in the DOS PATH, and if you have the \DBNETCTL.300
directory on a different shared directory make sure it's
reflected on the #DF= parameter. The following example assumes
that the dBASE system files and the \DBNETCTL.300 directory are
under different shared directories. t



Getting to Know the Report Generator

Getting to Know the dBASE IV Report Generator

Naoma Stow

dBASE III PLUS developers sometimes dismiss the reporting
capabilities of dBASE IV because it looks too different.

A while back, in talking to a veteran dBASE III PLUS
developer, I learned that he had owned dBASE IV for some time
but had not used the new Report Generator. He explained that
the new Report Design screen looked too different and
confusing. He confessed he was still writing custom programs
to output his report data. I was a bit surprised and strongly
encouraged him to explore the new Report Generator, emphasizing
how many new features had been incorporated; features that made
the task of writing programs a less efficient use of time.
Later, it occurred to me that this may not be an isolated
case. After all, people can get very set in their ways and in
general, are not apt to change something that they have not
been asking for themselves. So, I thought an article on
designing reports in dBASE IV was in order for all of you
dyed-in-the-wool skeptics out there.
The Report Generator in dBASE IV represents a vast
improvement over the dBASE III PLUS generator. It offers so
many more possibilities than its predecessor, that it's really
hard to make a qualitative comparison between the two. When I
talk to users on the phone about why they should update to
dBASE IV, one of the most exciting changes I like to tell them
about is the new design work surfaces that allow the creation
of custom screens, reports and labels.

Multiple Layouts

The new Report Generator offers many options which were not
available in dBASE III PLUS, which now provides menu options
for three quick report types:
* A COLUMN report which is most similar to the type of
report you could create in dBASE III PLUS.
* A FORM report which can display or print your data in
the style of a custom screen to a pre-printed form
(such as a payroll check or invoice).
* A MAILMERGE report accesses the dBASE text editor and
allows you to create a letter to be merged with your
data to give you word processing capability.
(Remember how often you've had to export your dBASE
data to a word processor to do the same job?)
After these quick layout report types are created, they can
be modified and customized to meet individual needs. Any item,
whether it be a field template or a piece of text may be
deleted, enhanced with printer attributes such as boldface,
italics and underlining or repositioned. As you build the look
of the report on your screen, you'll have an accurate display
of what it will look like when you print it out.

These QUICK LAYOUTS are optional items, of course. They
represent a great starting point to get to know the Report
Generator. Now, if you like being completely original (or even
if you don't) you may layout the entire report from scratch.

Strike Up the Bands

The work surface for the new report is referred to as a
WYSIWYG interface. The WYSIWYG is an acronym for
"what-you-see-is-what-you-get." Using this approach, you are
allowed much more flexibility as to where text and field
information can be positioned in the report. The new Report
Generator design surface allows you to place specific
information in bands or sections of the report. These bands
REPORT SUMMARY, and may also optionally include GROUP INTRO and
The REPORT INTRO and PAGE HEADER bands allow much more output
than the report title permitted in dBASE III PLUS as do the
GROUP INTRO and GROUP SUMMARY bands. You decide how many lines
and what text or field information is contained therein.

Hidden Calculated Fields

One of the most exciting new features of the new Report
Generator is the feature of hidden fields. These hidden fields
can be used for calculations, the results of which can be used
in other display-able fields.
There are various functions which are referred to as
"aggregate functions". These functions include: AVERAGE,
COUNT, MAX, MIN, SUM, STD, and VAR. These functions can be
defined to calculate a function for groups of records or in
some situations, for all records included in the report.
Unfamiliar Territory

When dBASE III PLUS users first access the new Report
Generator in dBASE IV, they find little which is familiar.
This can be a bit uncomfortable for someone who has become very
comfortable with the dBASE III PLUS Report Generator, which was
very concise and menu-oriented. Virtually no action was
undertaken without the user accessing a menu option and being
strictly guided through a series of steps. On one hand, this
had the effect of keeping you on the right track but,
ultimately shows severe limitations in design.

With dBASE IV you can be in either a menu or on the work
surface. The work surface bears more resemblance to dBASE III
PLUS Screen Design with the exception that the concept of bands
being added. Just the term "bands" may be discouraging and
ominous in its non-familiarity. If the word is a new concept
for you, just think of a band as a section. The concept of
bands allows a section orientation for the report. It is not
necessary to use all the bands; sometimes you may only use one
or two. The bands are provided to better help you create and
organize the elements of your report. If you do not need a
band, it is possible to close it by placing the cursor on the
highlighted band title and pressing the Enter key. Reopen the
band using the same process. If you do not close a band and
have not used it for output, you will end up with one or more
blank lines on each report page.

How You Use Bands

An explanation of the function of each band may be helpful in
understanding their implementation.
The Page Header Band can be used to present items (such as

column names, titles, date, page numbers, and so on) which you
would like to see at the top of each page of the report. If
you use a Quick Layout for a form or column type report, the
page number and the date will automatically be included in the
Page Header Band.
The Report Intro Band can be used to "paint" or define output
which the user would like to see on the first page and
beginning of the report.
The Group Intro Band is only available if the user has
selected the option to add a band from the Bands menu. It can
be used to define the elements you would like to see before
information is displayed or printed for groupings of records.
The option to add a group band is dimmed and unavailable when
the cursor is positioned on the Detail Band or one below.
The Detail Band is used to output and/or compute information
for each record. This is the most frequently used report
section because it contains the template information that will
output each record in a database. If the user selects to
output a database field in this band, it will output that field
in this section for all selected records.
The Group Summary Band is included only if the user has
elected to add a band. This band is used primarily to output
summary information for a group.
The Report Summary Band is used to output summary information
for all records. The results of aggregate information such as
sums, averages and record counts are typically placed in the
Report or Group Summary Bands.
The Page Footer Band can be used to define output which the
user would like to see at the bottom of each page of the
report. It could be text such as "Copyright 1991, Ashton-Tate
Corporation" or possibly calculated data, although calculated
data is more likely to be found in Group or Report summary

Group Bands

The report is not limited to a single group. Groups may be
nested within groups for very detailed and complex reporting.
The maximum number of nested group bands is 44. It's hard to
imagine any report needing to be more detailed than that.
As mentioned before, the work surface for designing reports
is WYSIWYG (what-you-see is-what-you-get). So if you wish to
output text in a particular section of the report, you move the
cursor to the section and column position where you wish to see
the output and type in the text or place the field marker. If
you desire the output to be field information from the
corresponding database, you access the Fields menu using either
the F5 key, Alt-F, or F10, and choose the Add field option. A
picklist of available fields appears from which you can
choose. After the field is selected, another menu appears
which allows you to assign formatting and editing options.
These options are there for possible further customizing of a
field and need not be selected. If the default options are
satisfactory (often, you will find they are), press Ctrl-End
twice to place the field marker on the work surface.
The PICTURE, TEMPLATE, and EDIT options are provided for your
convenience and provide many options which were not available
in dBASE III PLUS (as well as some which were). Many of these
options were on the wish lists of many power dBASE users. For
instance, it is now a simple menu option in the Picture
sub-menu while defining a field, to suppress zeros in numeric
columns, while still maintaining the ability to TOTAL on that
column. In dBASE III PLUS this was at best, a jerry-rigged
operation. But that option is just one of the many
automatically provided for when building your report. The
PICTURE function also permits the following formats for numeric
data output:

Credits displayed with CR
Debits displayed with DB
Negatives displayed with ()
Blanks for 0's
Financial formatting (example: $123,456.78)
Exponential display

and the following for character data output:

Trim (removes trailing blanks)
Left align
Center align
Vertical stretch (permitting you to wrap the same field to
the next line and beyond)
Horizontal stretch (permitting the same as above but in a
word wrap band)

The Template feature allows you to define the formatting of
the data output in a different way. Here you can enter an
example of what the output should look like including:

9's, commas and periods to define a numeric template
A for alphabetic characters only
! for outputting in upper case

As was previously mentioned it is also possible to create
calculated fields in the Report Generator. If you create a
calculated field that is not part of the final printed report,
you can hide the field by setting the Hidden menu toggle to
YES. Notice on this menu there is also the feature to Suppress
Repeated Values. If this feature is selected for a field, only
the first occurrence will print.
Navigating Through the Work Surface

When working on the work surface you will always find cursor
navigation information on the bottom of the screen:


One of the convenient, time-saving features of the new Report
Generator is the ability to move text or output field from one
location to another. Here's how:

1. Move the cursor to the first character you wish to move
and press F6 to activate the SELECT mode.

2. Extend the SELECT with a cursor key and complete by
pressing the Enter key.

3. Move the cursor to the destination position and press
the F7 MOVE key.

4. Complete the move by pressing the Enter key.

These steps are slightly different than those presented in
the documentation; however, by using the above technique you
will be able to move text and field output not only within a
specific band but also from one band to another. The move, as
presented in the documentation, will allow movement only within
a band. This can sometimes elicit confusion on the part of the
user who decides he needs to have his headings in the Group
Summary Band rather than the Page Header Band.

Copying Field Expressions

If you wish to use variations of the same expression for more
than one calculated field, here is a great time saving tip.
Follow steps 1 and 2. At step 3, rather than pressing the F7
MOVE, press the F8 COPY key. Then press the Alt-F key
combination to access the Fields menu and modify the newly
copied field, editing the expression and anything else you wish
to change.

Order Of Precedence

It is not unusual in the technical support department to get
a call from someone whose report calculations are not returning
appropriate values. Generally, these inappropriate values are
calculated fields; fields which are derived from expressions as
opposed to directly from the selected database. Generally
these problems can be resolved with a review of the order in
which fields are calculated for a report:

1. Hidden calculated fields
2. Calculated fields
3. Aggregate/Summary function fields
4. Un-named calculated fields

I think the most important thing to notice here is that
un-named fields are last to be calculated. When two or more
fields fit into the same category the following applies:

* The order the fields were created

Left to right
Top to bottom

Un-naming a Calculated Field

One of the more common problems in report calculations is a
field which appears to be behind in the calculation (in other
words, a calculation that would have been appropriate for the
previous group), or it is blank. The most common solution is
simply to modify the field by removing its name. It is then
last to be calculated and it is correct.
A common question we hear is: In my group summary or report
summary band I have summed several fields so how do I add those
sums together? There are at least two different ways this
could be accomplished. Taking advantage of the order of
precedence we could create an un-named, calculated field in the
summary band: the calculation for this field would be the name
of the first sum field plus the name of the second sum field,
and so on. Another way to do this is to create a hidden
calculated field in the Detail Band incorporating an expression
such as

Field1 + Field2 + Field3

Next, in the Group or Report Summary Band, position the
cursor where you would like to see the summary information,
then select the Fields: Add a field option. Use the cursor key
to select the aggregate function SUM in the last column of the
pick-list that appears.

Frequently we get asked how to set up conditional responses
based upon varying data in a report. For example, if a field
named Balance shows 0, you could output "NO PAYMENT IS DUE",
otherwise an amount is displayed. This can be done with a
calculated field. Using the IIF() function in our expression
is the key here. The syntax for the IIF() function is:


Basically what this means is if the condition is true, the
output is expression 1. If false, the output is expression 2.
In our example above, a user unfamiliar with dBASE syntactical
rules may be inclined to express this type of conditional

IIF(Balance = 0, "NO PAYMENT IS DUE", Balance)

The above statement assumes that BALANCE is a numeric field.
The resulting expressions are of different data types. The "NO
PAYMENT IS DUE" is obviously a character string. This will
generate an error when you try to enter the expression. The
Report Generator will not let you insert invalid expressions.
Instead, you would have to do something like:

IIF(Balance = 0, "NO PAYMENT IS DUE",

Non-Zero Averaging

You may find that the AVERAGE aggregate function does not
give the figure that you expect. The AVERAGE function averages
for all records but frequently it is desirable to average only
records where the field being averaged is not equal to zero.
The IIF() function comes into play here again. A calculated
field can be created using an expression like:

IIF(numfield > 0, 1, 0)

Then, a hidden calculated field is created in the Group or
Report Summary Band using the SUM aggregate operator and
identifying the field to be averaged. For this example, let's
refer to this field as Scount. The field containing the IIF()
expression above can be either hidden or un-hidden. We'll
identify this field with the name TBeAvg. Last, an un-named
calculated field would be created, the expression for this
field would be: SCount/TBeAvg. This field is un-named so that
it would be calculated after the aggregate function calculates.

Running Balances

The aggregate functions are not limited to Summary Bands. On
occasion, customers find the need for maintaining a running
total or numbering each record or line item. The aggregate
functions are helpful in these situations. Let's first look at
the Running Balance situation.
Assume first that the amounts to be credited are in one field

and the amounts to be debited in another. In the Detail Band,
you would create two hidden SUM fields: one for the credits and
another for the debits. While still in the Detail Band, create
an un-named calculated field, the expression being: the sum of
the credits minus the sum of the debits. The precise
expression could vary depending upon the accounting model or
protocol being used.
If the debits and the credits were all contained in the same
field, the debits being saved as negative values, then a single
aggregate SUM of this one field would display the running total
for this field.

Record Numbering

To number each record or line item, position the cursor in
the Detail band where you want the number to appear. Then
choose the COUNT function from the aggregate functions menu
(Add a field: Create Calculated field). After selecting this
function, another menu opens and from this menu the count may
be reset every group, page or report.

Column Widths

You may be curious as to how to control the width of a column
or how to make a long field or expression wrap as was done in
dBASE III PLUS. The dBASE IV default is the original field
width of a field or variable being placed on the report work
surface. After selecting a field, move to the PICTURE option
and press Enter. When the sub-menu opens, set the Vertical
stretch option ON (remember this option permits a field or
expression to wrap to the next line and beyond within the
boundaries of the length you've specified). Press Ctrl-End
till you return to the work surface. The cursor should be
positioned on the field you've just added. Make certain all
the V's (indicating a Vertical stretch assignment) are
highlighted. If not, press the F6 Select key and then the
right-arrow key to extend the highlight. Finish by pressing
Enter. The last step is to use the Shift-F7 to size this
field. Use the cursor keys to diminish the size of the field
to the number of columns and complete with the Enter key.
Calculating Percentages

Now, we're getting a little more technical. You've read this
far and it's too late to turn back. There are times when you
may need to calculate what percentage each line item represents
relative to its group or to an entire report. The procedure to
achieve this goal is less straight-forward than those we have
previously discussed. Prior to creating or modifying the
report, the database is ordered (indexed) on the field by which
it will later be grouped. Then, in your program or at the dot
prompt, you must issue the command


In the command line above, the marker is replaced
by the field on which the percentages will be based. The
filename Newfile is arbitrary to the example and could be any
filename that doesn't already exist (or, if it does exist,
doesn't concern you if it is completely overwritten). The
result of this command is the creation of a new database where
there will exist a single summary record for each group by
which you've ordered the database. Link the databases with a
query (or appropriate sequence of SET RELATION commands); be
sure to include all applicable fields needed for the report in
the View skeleton of your query (or SET FIELDS command). At
this point, can you create (or modify) a report which will
include a calculated field in the Detail Band where the
original numeric field is divided by the totalled field from
the summary database, thus giving the percentage information

Strike Up the Bands

Contrasting dBASE IV and dBASE III PLUS, the automated
reporting capabilities have been improved significantly. The
new WYSIWYG interface allows you to layout your report more
precisely. The flexibility of aggregate functions, calculated
fields and dynamically sizeable report sections were previously
only available by writing your own programs. The new report
generator provides quick layouts which, in many cases, provide
acceptable layouts in an instant. But alas, since the new
report work surface looks like such foreign terrain, some
pre-suppose that it must be too complicated and are reluctant
to try it. But you don?t have to be that brave. Give yourself
a break and do some exploring. You can experiment all you want
without any adverse effect to your databases. So get going.
You can?t fly before you walk. s


Basing a Calculation
on a Calculation

How do I use a calculated field in a query that bases its calculation
on another calculated field?

My scenario involves a field called Hrly_Wage which shows how much
someone makes per hour. I have created a calculated field called Ann
Sal (which takes Hrly_Wage * 2080). I want to figure my expected
Federal Tax (Fed_Tax) as Ann_Sal * .28 but when I try to configure this
in the Query Design Screen, it gives me errors. What can I do besides
repeating the formula for Fed_Tax in the next calculated field?

This is actually quite simple. Under the formula for Ann_Sal, place a
variable name (xxx in this example). The formula for Fed_Tax is now xxx
* .28.

Written Off with a Blank Check

I have a problem using an optical drive and dBASE IV. I'm consistently
getting "Drive not ready" messages and the error code 9901. Is dBASE IV
not compatible with this type of hardware?

It most likely has to do with where your temp files are being written
and is a matter of how the drive is formatted. You can choose to direct
your temp files to be written to other than the optical drive, which is
the simplest route. (This is done by setting the TMP environmental
variable in your AUTOEXEC.BAT).
If writing temp files to your optical drive, make sure a low level
format writes 0 to all sectors on the disk/cartridge. The error is
encountered because of a blank check. The blank check means there was a
request to read a sector, but if the sector is blank and has never been
written to, an error will be returned.

Sizing a Numeric Field

When using BROWSE, I wish to limit my fields to a particular width but
I am having problems with numeric fields. I can use the command

BROWSE FIELDS Charfld/15, Datefld/8, Logicfld/3, Numfld/10

but my results for my number field divide by 10 instead of limiting the

Convert it to a character field using the STR() Function.

BROWSE FIELDS Charfld/15, Datefld/8, Logicfld/3, STR(Number, 10)

This would limit your numeric field to a width of 10.
Calculated Results

I want several calculated fields that use the results of other
calculated fields. What can I do?

Assume you had a field called Mnthly_Sal (Monthly Salary) and you
wanted to calculate the Annual Salary and Hourly Rate, and limit these
fields to 8, 10 and 6 characters respectively. You would use the syntax

BROWSE FIELDS STR(Mnthly_Sal, 8), Annual_Sal = STR(Mnthly_Sal * 12, 10),
Hourly_Rate = STR(VAL(Annual_Sal) / 2080, 6).

Basically, numeric fields act the same as in an Index Expression. If
you INDEX ON a NUMERIC field + another NUMERIC field, the database will
be indexed on the SUM of the 2 fields, NOT by the fields individually.

Pausing a RUN

When I RUN (!) a DOS command outside of a defined WINDOW, the screen
does not pause. If I am in a window, it does pause, even when I try to
bypass it using the command KEYBOARD CHR(13). How do I override these
defaults and what other tips do you have with using DOS and the RUN

KEYBOARD CHR(13) will work to override the pause provided the command
is issued before the RUN command. This will store it in the keyboard
buffer and execute when control is passed back from DOS. To get pause
to work for the full screen, simply define a window from 0,0 to 24,79.
In answer to your other question, RUN COMMAND is useful for getting you
out of dBASE IV into DOS (without quitting and losing all your settings)
to allow you to perform multiple DOS operations. When you are done,
simply type EXIT at one of your DOS prompts (such as C\> ). An example
of a useful DOS-from-dBASE IV command could be

RUN TREE [DRIVE][PATH] > filename

which can be useful for storing a graphical representation of your
directory structure (much like the type you can see from with the
Control Center Tools Change Drive/Directory option when you press
Shift-F1). This will only work with DOS 3.3 and above. If you create a
database with one character field and width of 80 then issue the command


you can either BROWSE this database or DEFINE POPUP and PROMPT for the
FIELD. An example to get the TREE structure of all of Drive D into a
file called Tree.TXT would look like


What Is an Expression?

I am attempting to use the VALID clause in a @GET command in a program
but I keep getting the command "Data type mismatch" when I run the
program. What could be causing this.

It may be that the expression you've provided in the VALID clause isn't
a logical expression, just a character expression. Consider the two
expressions below.


The first will give you the error you receive, the second will operate

.BIN Indexin' Too Long

.BIN Indexin? Too Long

Charlie Prankel and Roland Appel

Indexes can be real time savers when locating data but there
are times when their presence slows down the show.

The whole raison d'tre of index files is their ability to
speed up your applications by reducing the time it takes to
search information contained in your .DBF files. But, as
always, you have to pay a price for improvements. First of
all, index files tend to consume big chunks of disk space.
Secondly, apart from the time needed for its creation, an index
file has to be updated whenever there are modifications to the
accompanying .DBF file, which concern the index key values.
This itself costs a certain amount of time although in most
cases you won't notice a time lag. But there are .DBF file
operations which are considerably delayed by updating
associated index files. For example, it takes much longer to
APPEND records to a .DBF file if it is indexed rather than in
natural order. The more index tags you have created, the
longer the operation takes.

To Index or not to Index

There are at least two cases in which it would be convenient
to make a minimal use of an .MDX file:
* To conserve disk space: An index for a given .DBF file
is always easy to reconstruct. So if you back up your
data or send data by modem, you will spare time and/or
money if you save or send only .DBF files and not
associated .MDX files.
* To save time: Let us take the example of the APPEND
FROM command again. Depending on the complexity of the
index key expressions and on the number of records to
append, it could even take much longer to add records
to an indexed .DBF file rather than to delete the index
file then append the records to the unindexed .DBF file
and finally to rebuild an index file. With regard to a
production .MDX file, it won't do just to deactivate
index tags (SET ORDER TO) instead of deleting the .MDX
file because the index file will be updated.

So why not just delete the .MDX files in these cases?

Unfortunately, there is a problem with deleting .MDX files
under dBASE IV. If you create a production index, dBASE IV
sets a flag byte in the header of the corresponding .DBF file.
This byte is checked by the program when the .DBF file is
opened. If the flag is set, the production .MDX file is
searched for. If it is found, it will be opened together with
the .DBF file. This in turn guarantees that the index file can
be automatically updated if necessary.

On the other hand, deleting a production .MDX file by the
ERASE or DELETE FILE command or the DOS command DEL does not
affect the flag byte in the header of the corresponding .DBF
file. So an unsuccessful search for an index file ensues when
you open a .DBF file after having deleted its production .MDX
file. This accounts for the error message:

"Production MDX not found."

and for the corresponding prompt window which asks if you want
to continue. Unless you respond with "Proceed", the .DBF file
will not be opened. Unfortunately, this error cannot be
trapped in an ON ERROR routine. So if you merely delete a
production .MDX file by one of the above mentioned commands,
your applications will always be suspended and have to wait for
the user, when a corresponding .DBF file is to be opened. But
of course we want our applications to cope automatically with
situations like this.
There is an easy solution to this problem, which will be
sufficient in many cases, and a more complex one for the other

Tag Elimination

With this solution, you can delete a production .MDX file and
at the same time, take care of the index flag byte in the
header of the associated .DBF file.
Take a look at the following simple loop:

USE test && opens TEST.DBF and TEST.MDX
DO WHILE "" <> TAG(1)

The TAG(n) function returns the name of the n-th index tag in
the production .MDX file. Therefore the loop condition is true
(the tag name does not equal an empty string), if the .mdx file
(still) contains a first index tag, which will be deleted by
the command "DELETE TAG TAG(1)". If you have a production index
file with multiple tags, what has been tag 2 before will now
become tag 1 and accordingly this tag will be deleted by the
next run of the loop. This goes on, until the production index
is empty, which in turn results in the deletion of the .mdx
file and - most important - in resetting the index flag byte in
the header of the .DBF file!
This method to avoid the above mentioned error message has
two disadvantages.
* If a production index file already has been deleted or
has otherwise been lost, this method will not work.
(You won't be able even to run the first line of the
routine without receiving an error message.)
* If you use the method to temporarily eliminate a .MDX
file, you will have to rebuild the .MDX file from
scratch afterwards. Depending on the number of index
tags and the complexity of the index keys, you might
need to insert a whole chain of INDEX ON commands into
your application.

A .BIN File Solution

The second solution consists of a short binary program file,
MDXBYTE.BIN, which allows you to set the production index flag
byte in the header of .DBF files either to 0 (or OFF) or to 1
(ON). So you can easily delete production index files and
reset the index flag byte with help of the .BIN routine. In
addition, you can take care of missing .MDX files (see Figure
1). Finally Figure 2 will show a way to temporarily deactivate
an index file to speed up some time consuming .DBF file
operations. This method has the additional advantage over the
first solution in that you can finally update the index file by
a single REINDEX command instead of, perhaps many INDEX ON...
To run the MDXBYTE.BIN in dBASE IV, you have to use the two

LOAD mdxbyte
CALL mdxbyte WITH "<.dbf filename with extension>", "0/1"

The parameter, <.dbf filename.ext> is the .DBF file in which
you want to change the index flag. The second character
expression (which also has to be enclosed in quotes) is passed
either "0" to reset the index flag byte or "1" to set the
flag. Of course, alternatively you can pass the values by
In a network environment, the .DBF file will be locked while
the flag byte is changed. If the .DBF file has already been
opened, MDXBYTE cannot change the byte and will return an error
message. Hence you should check if the .DBF file has already
been opened before you run MDXBYTE.
Important Considerations

* Never try MDXBYTE on other than .DBF files!

* MDXBYTE should open a .DBF file for modification
exclusively. This applies to network and to single-user
environments. The reason for this is: if a .DBF file which is
to be modified by MDXBYTE, had already been opened by dBASE IV,
MDXBYTE would change the flag byte of the file. This file
would then be saved to disk, while dBASE IV will still use its
own unchanged copy of the file in RAM. Therefore it is very
important to make sure that the .DBF file to be modified is not
in use by dBASE IV when you run MDXBYTE.

You should always close an open .DBF file, before modifying
it by MDXBYTE. In a network environment the attempt to run
MDXBYTE to modify a .DBF file which is already open will result
in an error message. On the other hand, in a single-user
environment an error message will be displayed if the resident
DOS program SHARE is active.
Error Handling

MDXBYTE will display the error message "CALL mdxbyte: Wrong
number of parameters." and wait for a key to be pressed, if you
do not pass exactly two parameters.
If other errors occur, the message "Error while running
MDXBYTE.BIN." will be displayed. If you pass the second
parameter by a variable, this variable will additionally
contain the value "E" (Error) after MDXBYTE passes control back
to dBASE IV.

Errors can occur for two different reasons:
* Too many (or not enough) parameters have been passed
and/or are not valid. This in turn can have different
* file does not exist
* drive not valid
* path not valid
* filename not valid
* file has already been opened
* user has no right to write to the file in a network

Below, are two scenarios where the use of MDXBYTE would be
useful. Hopefully, you aren?t totally jaded about production
.MDX files (that wasn?t our intention), just informed about

alternative ways to get maximum efficiency out of dBASE IV. t

Scenario 1: Deleting production index flag byte if the
production .MDX file does not exist

If you suspect that a .MDX production file could be missing,
you could run the following routine to avoid an error

mbyte = '0'
mdx ok = FILE("test.mdx")
IF .NOT. mdx ok
* check if .mdx file is missing.
LOAD mdxbyte
CALL mdxbyte WITH "test.dbf", mbyte
* delete flag byte.
mdx ok = (mbyte = '0')
* steps to rebuild an index
* could follow here.
IF mdx ok
USE test.dbf

Scenario 2: Speeding up an APPEND operation

Whether this routine is faster than a routine which just
appends records to an indexed .DBF file depends on the number
of records to be appended and on the number and complexity of
index tags in the production .MDX file. By this method you
might reduce the time needed to append records to less than
half of the time needed to append records to an indexed .DBF

mbyte = "0" && Set flag byte to 0.
LOAD mdxbyte
CALL mdxbyte WITH "test.dbf", mbyte
IF mbyte = "0"
USE test
* Close the file before you run MDXBYTE!
mbyte = "1" && Set flag byte back to 1.
CALL mdxbyte WITH "test.dbf", mbyte
IF mbyte = "1"
USE test

A Pressing Issue

A Pressing Issue

Dan Madoni

Overuse and abuse of a stellar feature in dBASE IV.

Tight control over your application is a key to how well it
will do its job. Although dBASE IV handles a wide variety of
key interrupts and trapping, you've probably needed to do a
little bit of your own. I would like to point out a few things
that might help you in designing efficient and functional
key-trapping with and without the use of ON KEY.
Before we begin, we need a database which we will be using in
the examples that will ensue. Either locate the CLIENTS.DBF
file in your SAMPLES sub-directory, or create a file called
CLIENTS.DBF with the following structure and fill the database
with at least 5 records:

Field Name Type Width

FIRSTNAME Character 20
LASTNAME Character 20
ADDRESS Character 25
CITY Character 20
STATE Character 2
ZIPCODE Character 5
PHONE Character 13

As a simple example of how dBASE IV traps keys in ways that
you might have taken for granted, type in the following two
lines at the dot prompt:


Of course, you see an edit screen full of data. Now, what is
it that you have to do to get to the next record? Ah-ha! You
have to press a key, (PgDn in this case.) What do you have to
do to display a help screen? You have to press the F1 key.
This all sounds very simple because you probably don't think
much about what is going on internally whenever you use EDIT or
BROWSE or any of the other full-screen commands.
Key Trapping Methods

dBASE IV offers several different methods of key-trapping --
mainly ON KEY, READKEY(), LASTKEY(), INKEY(), and WAIT. You
may already be familiar with these commands, but I notice that
a lot of users have a "one-track method of key-trapping. The
programmer who uses one of these for the first time gets hooked
on that method of key-trapping. Consequently the programmer
finds himself using ON KEY, (for example,) in an awkward way.
I personally have some rules of thumb about when to use which
method for key-trapping. Below is a list of these "rules of
thumb" and accompanying explanantions.
Don't use ON KEY in a READ when the key that is to be trapped
is a key that exits a READ, (ESCape, PgDn, PgUp, Ctrl-End, and
so on.)
In these cases, LASTKEY() or READKEY() is preferable since
they give you greater control over your program. In addition,
you don't lose the functionality of the key in question. To
illustrate, type in and run the program below:

@ 5,5 GET firstname
@ 6,5 GET lastname
IF LASTKEY() = 18 && PageDown
? "Watch this message!"

Notice that the message appears below the second GET where
you would expect it to appear. Now try this program:

ON KEY LABEL PgDn ? "Watch this message!"
@ 5,5 GET firstname
@ 6,5 GET lastname
ON KEY && To release ON KEY definition

Notice this time that the message appears on the same line as
the cursor and you are no longer able to leave the READ. This
brings us to our next rule:

Use ON KEY in a READ when you want to disable an exit key or
when the action to be performed is not to cancel the READ.
As shown above, an ON KEY trap will not exit the READ. A
common example of when you might want to do this is presenting
a help screen or pick list.
Some programmers like to limit the users ability to exit a
READ. You may prefer that the user is allowed to leave a READ
only when the Enter key is pressed on the last field or if
ESCape is pressed. The program below illustrates how to use ON
KEY to disable the other exit keys:

ON KEY LABEL Ctrl-End ??
@ 5,5 GET firstname
@ 6,5 GET lastname
ON KEY && To release ON KEY definitions

Use ON KEY in a programming loop only if it is impractical or
impossible to use INKEY().
Type in the following program:

IF INKEY() = 3
ON KEY && To release ON KEY definition

Running this program will cause dBASE IV to loop continuously
until PgUp or PgDn is pressed. Both key-trap methods seem to
work fine here - why choose one over the other? Again, the
reason is control. If you have a programming loop that has
loops within it, or that calls sub-routine after sub-routine,
it may become a programming hazard to allow the given activity
to occur anywhere within the loop. If it is possible, use
INKEY() in place of ON KEY and test for INKEY() in places where
you are sure an interfering program will not cause a problem.

Try not to use WAIT if you are concerned about Program
WAIT is a simple little command for simple programs, but
there's one particularly annoying thing about it that keeps me
from including it in important applications. The problem with
WAIT is that it always left-justifies the input prompt giving
me no horizontal control of where to place the prompt. Use
INKEY() with a 0 parameter instead as shown in the two
comparitive examples below:

WAIT "" TO userkey
* is the same as...
userkey = CHR(INKEY(0))

As discussed in the above ON KEY section, use INKEY() with no
parameter for key-trapping during a program loop. As discussed
in the above WAIT section, use INKEY(0) instead of WAIT to trap
a key.
Not only does this get around the problem of program control
(cancelling a program by pressing Escape), it also allows you
to trap keys which are not alphanumeric, (such as the arrow
keys). For a list of the values returned by non-alphanumeric
keys, see page 4-57 through 4-59 of dBASE IV Language
Reference. The example below illustrates how to use INKEY(0):

? "Browse the Clients file? Y/N"

Remember that you can use the INKEY() parameter to time-out
if the user does not press a key.
The program below illustrates this feature of INKEY(). By
testing for a key value after prompting the user, we can
determine whether or not to continue with the action:

? "Press any key to browse the Clients file..."
userkey = INKEY(5) && Wait 5 seconds
IF userkey <> 0
? "I guess you don?t want to browse the file!"

As discussed in the ON KEY section, use LASTKEY() to
determine what key was pressed to exit a READ. Use LASTKEY()
to determine what key was pressed to exit a full-screen
operation such as EDIT or BROWSE.

Try the following program to illustrate this:


Running this program will display a BROWSE screen, followed
by the ASCII value of the key you pressed to exit the BROWSE,
(see page 4-57 through 4-59 of dBASE IV Language Reference for
an ASCII value chart.)

Use LASTKEY() when you need to determine what key was pressed
several commands after the user actually pressed the key.
Did I confuse you? What I mean by this is that you should
use LASTKEY() if the program doesn't need to know what key was
pressed until a few commands after the key was actually
pressed. This is illustrated in the program below:

? "Gee, that was a fun BROWSE"

After all the messages fly across the screen, the LASTKEY()
command at the bottom of the program will display the key you
pressed to exit the BROWSE way back at line 2.
Use READKEY() ONLY to determine if a record was updated.
Page 4-108 and 4-109 of dBASE IV Language Reference show a
list of what numbers are returned based on whether or not the
current record was updated. Since the READKEY() return values
are so obscure and since the range of keys that READKEY() can
identify are limited to exit keys, I see no practical purpose
for using it outside of checking for an updated record.
The program below uses some concepts outlined in the article
and simulates EDIT.


 December 8, 2017  Add comments

Leave a Reply