home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR19
/
RLIBDOC.ZIP
/
RLIB.DOC
< prev
Wrap
Text File
|
1993-08-20
|
511KB
|
13,019 lines
RLIB
Version 3.0
Useful Functions for the Clipper Application Programmer
by Richard Low
August 1, 1991
Copyright 1991 Richard Low
All Rights Reserved
RLIB Software
Post Office Box 3232
Durham, North Carolina 27715
(919) 383-0488
For My Wife and Children
Copyright Notice
The RLIB function library is protected by United States copyright laws
and international treaty provisions. The RLIB function library,
source code, demonstration program, and documentation Copyright 1991
Richard Low. All rights reserved. No part of the RLIB function
library, source code, demonstration program, documentation or related
files may be reproduced, photocopied, or transmitted except as
provided by the license.
Software License Agreement
The RLIB function library (hereinafter referred to as "RLIB" or "the
Software") consists of the binary code which has been compiled and
assembled into a library file, together with the source code, the
demonstration programs, sample source code and software documentation.
All notices, copyright and otherwise, together with the license
agreement, restrictions and warranties apply to all of the components
of RLIB. Richard Low is the sole author of RLIB. Hereinafter, the
term "Author" refers to Richard Low.
Shareware Version
The Author is offering you a license to use the RLIB function library
for a trial period of for 21 days. If you continue to use RLIB 3.0
after the 21 day evaluation period, you are obligated to purchase it.
The shareware version of RLIB, together with the accompanying
documentation may be freely copied and shared with others provided
that the following conditions are met:
1. You may not distribute the shareware version of RLIB in any
modified form.
2. You may not charge any fee for the shareware version of RLIB or
for its distribution.
3. You must distribute all of the components of the shareware
version of RLIB as described in the section entitled Contents.
Registered Version
As a registered owner of RLIB your are granted a license to use RLIB
on a single computer for a period of 99 years. RLIB may not be
installed on a network unless each person who may access RLIB from
such a network possesses their own registered copy of RLIB.
With the registered version of RLIB the Author also grants you a
license to use the single user version of Message Reader on a single
computer, also for a period of 99 years. The single user version of
the Message Reader program may not be installed on a network unless
each person who may use Message Reader from such a network possesses
their own registered copy of RLIB or Message Reader.
iii
Programs that you write and compile which make use of one or more of
the functions in RLIB may be used, given away, or sold without any
additional license fee or royalty due to the Author. You are not
required to indicate that your programs were developed using the RLIB
function library or that they contain source code provided with RLIB.
However, the source code that is supplied with RLIB is copyrighted
material. You may use the source code to support your licensed copy
of RLIB. You may include the source code in your own development
programs, but you may only distribute copies of them in executable
form. If your program source contains RLIB function or demo program
source code, you may not distribute the parts of your source code that
contain RLIB function or demo program source code. In other words,
you may not distribute any part of the RLIB function library or demo
program source code. You may not distribute the RLIB library in
object code except as included in your executable programs as outlined
above. You are, of course, free to distribute your own source code
which may reference RLIB functions.
You may modify the RLIB source code, but the modified source code,
regardless of the extent of the modifications, shall always remain the
Authors source code. Modification or rewriting of the source code
does not give you rights of ownership. You may not remove or modify
the Authors copyright and other proprietary rights notices. You may
not distribute any part of the source code, regardless of the extent
of the modifications, and you may not transport any of the source code
to another computer or language development environment. You shall be
responsible for all claims, liability, and damages arising from your
own modifications and the products which include them.
Message Reader Program
The Message Reader program and source code are Copyright 1991 by
Richard Low and may not be reproduced in any form. You do not own the
Message Reader or RLIB source code; it is supplied for demonstration
and instructional purposes only. Just as with a book, you may
reference the source code, but you may not copy it in any form,
electronic or otherwise. Even if you modify the Message Reader source
code, it still remains the sole property of the Author. Modification
or rewriting of the source code does not give you rights of ownership.
You may not distribute the Message Reader or RLIB source code even if
you make modifications, and you may not distribute any modified
version of the Message Reader executable program.
Copyright
The RLIB function library, source code, and documentation, and the
Message Reader program, source code, and documentation are protected
by United States copyright laws and international treaty provisions.
Therefore, you must treat this software like any other copyrighted
material such as a book. You are authorized to make archival copies
for the sole purpose of backing up the software. You may also copy
RLIB to a single hard disk, and move RLIB from one hard disk to
another, provided that this copy of RLIB is not used on more than one
computer at the same time. You may not copy the written documentation
which accompanies RLIB.
iv
Limited Warranty
The RLIB function library software is provided "as is". The Author
will replace, at no charge, defective media and product materials that
are returned within 90 days of the original date of purchase. The
Author warrants that RLIB will perform in substantial compliance with
the documentation. If you report, in writing, a significant defect to
the Author, and the Author is unable to correct it within 90 days of
the date you report the defect, you may return the software and all
accompanying materials and destroy any and all copies of the software
you may have made, and the Author will refund the purchase price.
Should you encounter problems with the Software, the Author's entire
liability and your exclusive remedy shall be that the Author, at the
Author's sole option, will be to either refund you the purchase price
(upon the conditions met above) or to repair or replace the Software.
Disclaimer of Warranties
The Author makes no claims or representations as to the suitability of
the Software for any specific use. Except for the Limited Warranty
stated above, the Author disclaims any and all other warranties,
express or implied, oral or written, including any implied warranties
of merchantability or fitness for a particular purpose. In no event
will the Author be liable to you for damages, including any loss of
profits, lost savings, or other incidental or consequential damages
arising out of your use of or inability to use the software, even if
the Author or an authorized representative of the Author has been
advised of the possibility of such damages.
This limited warranty gives you specific legal rights, but you may
have other rights, which vary from state to state. Some states do not
allow excluding or limiting implied warranties or limiting liability
for incidental or consequential damages, therefore the above
limitations may not apply to you.
Trademark Acknowledgements
Blinker is a trademark of Blink, Inc.
Clipper and Nantucket are trademarks of Nantucket Corporation.
CompuServe is a trademark of CompuServe Incorporated.
dBASE, and dBASE III are trademarks of Ashton-Tate, Inc.
IBM, PC, XT, AT, PS/2, and PC-DOS are trademarks of International
Business Machines Corp.
LOTUS and 123 are trademarks of Lotus Development Corporation.
MASM, LIB, MS-DOS, Microsoft, Microsoft Object Linker and Microsoft
Library Manager are trademarks of Microsoft Corporation.
The Norton Guides, The Norton Guide Reference Database Engine are
trademarks of Peter Norton Computing, Inc.
PLINK86 and PLINK86plus are trademarks of Phoenix Technologies, Ltd.
TAPCIS is a trademark of Support Group, Inc.
TLINK, Turbo Link, TLIB, and Turbo Librarian are trademarks of Borland
International.
Any other trademarks of other companies which may appear in this
documentation are for identification purposes only.
v
TABLE OF CONTENTS
Chapter 1: Introduction
What Is RLIB? . . . . . . . . . . . . . . . . . . . . . . . . 2
What You Get! . . . . . . . . . . . . . . . . . . . . . . . . 3
The Source Code . . . . . . . . . . . . . . . . . . . . . . . 4
Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Shareware Version . . . . . . . . . . . . . . . . . . . . . 5
Registered Version . . . . . . . . . . . . . . . . . . . . 6
Changes From Version 2.0 . . . . . . . . . . . . . . . . . . . 7
Functions Enhanced from RLIB version 2.0 . . . . . . . . . 9
Chapter 2: Obtaining RLIB
Registration . . . . . . . . . . . . . . . . . . . . . . . . . 11
Technical Support . . . . . . . . . . . . . . . . . . . . . . 11
Order Information . . . . . . . . . . . . . . . . . . . . . . 12
Chapter 3: Using RLIB
System Requirements . . . . . . . . . . . . . . . . . . . . . 15
Installation . . . . . . . . . . . . . . . . . . . . . . . . . 15
Linking RLIB Into Your Applications . . . . . . . . . . . . . 16
Dynamic Overlay Linkers . . . . . . . . . . . . . . . . . . 16
Modifying The RLIB Library . . . . . . . . . . . . . . . . . . 17
Clipper Summer '87 . . . . . . . . . . . . . . . . . . . . 17
Clipper 5.0 . . . . . . . . . . . . . . . . . . . . . . . . 17
RLIB Function Overview . . . . . . . . . . . . . . . . . . . . 18
Parameter Syntax Verification . . . . . . . . . . . . . . . 18
RLIB Error Reporting . . . . . . . . . . . . . . . . . . . 18
Quick Function Listing . . . . . . . . . . . . . . . . . . . . 19
Source Code File List . . . . . . . . . . . . . . . . . . . . 21
Chapter 4: The Message Reader Demo Program
A Full Feature Application . . . . . . . . . . . . . . . . . . 24
Message Reader Source Code . . . . . . . . . . . . . . . . . . 24
Source Code Files . . . . . . . . . . . . . . . . . . . . . 24
RLIB Functions Used in Message Reader . . . . . . . . . . . . 25
The PROGNAME() Function . . . . . . . . . . . . . . . . . . 25
Compiling and Linking Message Reader . . . . . . . . . . . . . 26
Chapter 5: RLIB Function Reference
ABOXASK() . . . . . . . . . . . . . . . . . . . . . . . . . . 29
ACRONYM() . . . . . . . . . . . . . . . . . . . . . . . . . . 31
ADIM2() . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
ALIST() . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
ALPHADATE() . . . . . . . . . . . . . . . . . . . . . . . . . 35
ANYCHARSIN() . . . . . . . . . . . . . . . . . . . . . . . . . 36
ARRAYLEN() . . . . . . . . . . . . . . . . . . . . . . . . . . 37
ATINSAY() . . . . . . . . . . . . . . . . . . . . . . . . . . 38
BARMENU() . . . . . . . . . . . . . . . . . . . . . . . . . . 39
BEEP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
BIN2DEC() . . . . . . . . . . . . . . . . . . . . . . . . . . 43
BLIP() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Table of Contents vi
BORDERBOX() . . . . . . . . . . . . . . . . . . . . . . . . . 45
BOXASK() . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
BOXMENU() . . . . . . . . . . . . . . . . . . . . . . . . . . 50
BRIGHT() . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
BUZZ() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
CALENDAR() . . . . . . . . . . . . . . . . . . . . . . . . . . 56
CATF() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
CENTER() . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
CFTA() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
CHANGED() . . . . . . . . . . . . . . . . . . . . . . . . . . 65
CHECKFILE() . . . . . . . . . . . . . . . . . . . . . . . . . 67
CLOSEAREA() . . . . . . . . . . . . . . . . . . . . . . . . . 70
DBFCREATE() . . . . . . . . . . . . . . . . . . . . . . . . . 72
DEC2HEX() . . . . . . . . . . . . . . . . . . . . . . . . . . 74
DECRYPTED() . . . . . . . . . . . . . . . . . . . . . . . . . 75
DIVIDE() . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
ENCRYPTED() . . . . . . . . . . . . . . . . . . . . . . . . . 77
FEOF() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
FILEDATE() . . . . . . . . . . . . . . . . . . . . . . . . . . 79
FILES() . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
FILESIZE() . . . . . . . . . . . . . . . . . . . . . . . . . . 81
FILETIME() . . . . . . . . . . . . . . . . . . . . . . . . . . 82
FORGET() . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
FPROMPT() . . . . . . . . . . . . . . . . . . . . . . . . . . 85
FREADLINE() . . . . . . . . . . . . . . . . . . . . . . . . . 87
FRESTSCREEN() . . . . . . . . . . . . . . . . . . . . . . . . 88
FSAVESCREEN() . . . . . . . . . . . . . . . . . . . . . . . . 90
GETFILE() . . . . . . . . . . . . . . . . . . . . . . . . . . 92
GETKEY() . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
GETPARM() . . . . . . . . . . . . . . . . . . . . . . . . . . 96
HEX2DEC() . . . . . . . . . . . . . . . . . . . . . . . . . . 98
ISDBF() . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
ISFIELD() . . . . . . . . . . . . . . . . . . . . . . . . . . 100
KEYINPUT() . . . . . . . . . . . . . . . . . . . . . . . . . . 101
MAKEALIAS() . . . . . . . . . . . . . . . . . . . . . . . . . 103
MARKREC() . . . . . . . . . . . . . . . . . . . . . . . . . . 104
MEMORIZE() . . . . . . . . . . . . . . . . . . . . . . . . . . 107
MIDDLE() . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
MREPLACE() . . . . . . . . . . . . . . . . . . . . . . . . . . 110
MULTIMENU() . . . . . . . . . . . . . . . . . . . . . . . . . 111
NAMESPLIT() . . . . . . . . . . . . . . . . . . . . . . . . . 113
NO_APPEND() . . . . . . . . . . . . . . . . . . . . . . . . . 114
NO_FLOCK() . . . . . . . . . . . . . . . . . . . . . . . . . . 116
NO_RLOCK() . . . . . . . . . . . . . . . . . . . . . . . . . . 118
NOTEMPTY() . . . . . . . . . . . . . . . . . . . . . . . . . . 120
NTXKEYVAL() . . . . . . . . . . . . . . . . . . . . . . . . . 121
OLDERFILE() . . . . . . . . . . . . . . . . . . . . . . . . . 123
OPENED() . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
PARENT() . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
PATHTO() . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
PDOWNINIT() . . . . . . . . . . . . . . . . . . . . . . . . . 131
PDOWNMENU() . . . . . . . . . . . . . . . . . . . . . . . . . 136
PICKCOLOR() . . . . . . . . . . . . . . . . . . . . . . . . . 140
PICKFILE() . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Table of Contents vii
PICKREC() . . . . . . . . . . . . . . . . . . . . . . . . . . 144
POPBOX() . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
POPUPPICK() . . . . . . . . . . . . . . . . . . . . . . . . . 155
PRINTCODE() . . . . . . . . . . . . . . . . . . . . . . . . . 158
QUERY() . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
REPORTINIT() . . . . . . . . . . . . . . . . . . . . . . . . . 165
REVDATE() . . . . . . . . . . . . . . . . . . . . . . . . . . 168
RH_HEADER() . . . . . . . . . . . . . . . . . . . . . . . . . 169
RH_LINES() . . . . . . . . . . . . . . . . . . . . . . . . . . 171
RH_TEXT() . . . . . . . . . . . . . . . . . . . . . . . . . . 173
RH_WIDTH() . . . . . . . . . . . . . . . . . . . . . . . . . . 175
RJUSTIFY() . . . . . . . . . . . . . . . . . . . . . . . . . . 177
RLIBERROR() . . . . . . . . . . . . . . . . . . . . . . . . . 178
RLIBINIT() . . . . . . . . . . . . . . . . . . . . . . . . . . 179
RLIBVER() . . . . . . . . . . . . . . . . . . . . . . . . . . 180
SAYINBOX() . . . . . . . . . . . . . . . . . . . . . . . . . . 181
SETCURSOR() . . . . . . . . . . . . . . . . . . . . . . . . . 183
STARTREPORT() . . . . . . . . . . . . . . . . . . . . . . . . 184
STR2DATE() . . . . . . . . . . . . . . . . . . . . . . . . . . 189
STRETCH() . . . . . . . . . . . . . . . . . . . . . . . . . . 190
TARGET() . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
TEMPFILE() . . . . . . . . . . . . . . . . . . . . . . . . . . 194
TYPEC() . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
VALTYPEC() . . . . . . . . . . . . . . . . . . . . . . . . . . 197
VRANGE() . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Appendix A - RLIB Error Codes
Debugging Aid . . . . . . . . . . . . . . . . . . . . . . . . 201
Appendix B - The RHELP Compiler
What is RHELP? . . . . . . . . . . . . . . . . . . . . . . . . 205
RHELP Source Code . . . . . . . . . . . . . . . . . . . . . 205
Why Compile? . . . . . . . . . . . . . . . . . . . . . . . 205
Advantages . . . . . . . . . . . . . . . . . . . . . . . . 205
Help Source File Format . . . . . . . . . . . . . . . . . . . 206
Creating Help . . . . . . . . . . . . . . . . . . . . . . . . 207
Function API Quick Reference . . . . . . . . . . . . . . . . . 208
Building RHC.EXE and RHDC.EXE . . . . . . . . . . . . . . . . 208
Demonstration Version . . . . . . . . . . . . . . . . . . . 208
An Example . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Appendix C - Author's Note
Clipper Summer '87 and 5.0 . . . . . . . . . . . . . . . . . . 211
Local and Static Variables . . . . . . . . . . . . . . . . 211
Macro Differences . . . . . . . . . . . . . . . . . . . . . 211
A Macro Example . . . . . . . . . . . . . . . . . . . . . . 212
RLIB Differences . . . . . . . . . . . . . . . . . . . . . 213
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Table of Contents viii
┌───────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ Chapter 1 │
│ Introduction │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────────┘
Chapter 1: Introduction
What Is RLIB?
RLIB is a Clipper function library that furnishes the application
programmer a collection of routines to aid in rapid program
development. RLIB also contains a set of sophisticated high level
functions to help you build intuitive end user applications.
Good applications require a solid and consistent user interface.
Creating routines for menus, data entry and editing is a time
consuming process, one we all hope to avoid on a repetitive basis.
RLIB is a collection of functions that simplify a wide range of
applications oriented programming tasks such as creating and
maintaining menus, message boxes, database record selection routines,
network locking functions and much more.
The first publicly released version of RLIB, version 2.0 was very
popular because the RLIB functions let you produce applications
quickly! There are many products that help improve programmer
productivity, such as application and code generators, some of which
rely on the template concept. RLIB permits the programmer to retain
control over code creation and still crank out slick, powerful
applications at a high level. The programmer using RLIB functions
does not have to learn any applications development system, just draw
from a rich set of high level and versatile functions. RLIB will not
create applications for you, but you can significantly speed up your
application prototyping and development time.
RLIB version 3.0 continues this tradition. Several functions have
been expanded and many new ones have been added, all with the same
intent - to help the Clipper programmer develop good, consistent
applications quickly! Hey, isn't that what we all want?
There are many libraries available for Clipper programmers that
provide indispensable functions. Most of these library functions are
written in C and Assembler and provide access to features which are
not currently supported in Clipper. RLIB was not designed to provide
these types of functions, which are widely available from a number of
sources and provide excellent functionality. RLIB was designed for
the Clipper programmer that creates customized application programs
and systems and who is interested in using a collection of functions
to make this job faster and above all, consistent.
All RLIB functions are written in Clipper and all of the routines that
RLIB utilizes are in the CLIPPER and EXTEND libraries distributed in
the Clipper package. Clipper has a rich set of commands and
functions. If you are curious as to some of the capabilities of
Clipper, then check out the functions in RLIB. They are ALL WRITTEN
100% IN CLIPPER!
Introduction 2
What You Get!
Good software doesn't have to cost a lot of money! RLIB 3.0 costs
only $99.00 and with your registered copy of RLIB v3.0 you get a lot!
* The RLIB function library in both Summer '87 and Clipper 5.01
versions which includes over 90 application development functions,
crafted with over three years of real world usage.
* Over 200 pages of professionally printed documentation containing
an extensive function reference, with descriptions, information and
examples.
* Over 9,000 lines of executable source code in both Summer '87 and
5.0. This source code is extremely well formatted and legible with
extensive comments. The code is a great source for both Summer '87
and 5.0 learning. See how and what can be done in Clipper!
* The Message Reader application and printed user manual. Not only
is this included with RLIB as a sample of what RLIB can do, it is
also a full featured application which includes full source code.
There are over 3,500 lines of commented and highly instructional
source code. Message Reader is also a useful application to manage
and view CompuServe forum message bases.
* The RHELP compiler and function API which lets you create text-
based, indexed access help files. Compile the Message Reader demo
program and summon help with F1 to see fast, context sensitive help
in action.
* A Norton Guides on-line function reference database for instant
pop-up RLIB reference.
* Free technical support via CompuServe Mail.
* Just a few standout function highlights are:
- PICKREC() The premier database picklist function! Use it
once and you'll never give it up. Much easier to
use for pick lists than DBEDIT() or TBROWSE().
- PDOWNMENU() Professional pull down menus with separator lines,
dynamic graying of options and much more.
- QUERY() With one function call you have a complete query
manager. Try out the Query option in the Message
Reader demo program to see QUERY() in action.
- OPENED() Open multiple database and index files with one
call to OPENED() with complete error reporting.
Reduce coding, especially in network environments
by 90%!
See the Quick Function Listing for a complete list and descriptions
Introduction 3
The Source Code
The big bonus to RLIB is that you get the source code for all of the
functions and to the demonstration program, Message Reader. All RLIB
functions are meticulously coded with extensive comments.
The source code offers several benefits. First, you can tailor RLIB
functions if you so desire. You can expand or limit the operation of
functions to suit your needs. If a particular function behaves in a
way you would like to change, then all you have to do is change it.
Secondly, the source code is a great source of instruction for those
of you who may be starting off with Clipper or just want to see what
Clipper can do. These functions are the result of years of Clipper
programming experience, constantly exploring every Clipper feature.
Third, each RLIB function is available in both the Clipper Summer '87
and 5.0 versions. The functions for the 5.0 version have been updated
and modified specifically to take advantage of the new Clipper 5.0
storage classes (Local and Static) and code blocks to increase speed
and efficiency and reduce object code size.
By looking over this source code you can get an idea of the techniques
and methods for converting to LOCAL and STATIC variables and still
retain the functionality of PRIVATES and PUBLICS. You can see how to
employ STATICs to have them visible to called functions (like
PRIVATES), and to be visible globally just like PUBLICS.
Introduction 4
Contents
Shareware Version
The RLIB 3.0 shareware package consists of a shareware version of the
RLIB 3.0 library in Clipper 5.01 object format. The RLIB shareware
package also contains a sample demo program ready to compile and link,
and this documentation on disk.
The RLIB shareware package is distributed in a single ZIP file named
RLIB30.ZIP. PKUNZIP.EXE is needed to extract the contents of this ZIP
file. PKUNZIP.EXE (and PKZIP.EXE) are available for downloading from
most BBSs including many of the forum libraries on CompuServe. The
contents of RLIB30.ZIP are as follows:
RLIB30.ZIP - RLIB 3.0 Shareware Package
READ.ME Latest Information and Contents
RLIB.LIB RLIB 3.0 Shareware Library for Clipper 5.01
RLIB.DOC User Manual (this file)
DEMO.PRG Demo Program Source Code
DEMO.DBF Demo Program Database
DEMO.DBT Demo Program Memo File
MAKEDEMO.BAT Batch file to make the Demo Program
ORDER.DOC Order Form on Disk
Introduction 5
Registered Version
The RLIB package you purchase consists of the RLIB library, the
demonstration program Message Reader, a printed and bound manual, full
source code to all RLIB functions and demonstration programs, and a
Norton Guides on-line reference database. That's quite a bit for
$99.00!
The RLIB package is distributed on two (3) 5.25" diskettes or one (2)
3.5" diskette2. Included in the diskettes are four (4) self-
extracting ZIP files which contain the various components of RLIB in
compressed form. The following is a list of the self-extracting ZIP
files and their contents.
1. RLIB50.EXE - RLIB 3.0 Library, Source, and Make files for 5.01
RLIB.LIB RLIB Function Library for Clipper 5.01
RLIB.MAK RLIB.LIB Make file
RLIB.RSP RLIB.LIB Turbo Librarian Response File
RHC.PRG RHELP Compiler source code - Clipper 5.01
RHDC.PRG RHELP De-Compiler source code - Clipper 5.01
MAKERLIB.BAT Batch file to make RLIB.LIB
MAKERHC.BAT Batch file to make RHC.EXE and RHDC.EXE
RL_*.PRG RLIB 3.0 for 5.01 source code files (see page 21)
2. RLIB87.EXE - RLIB 3.0 Library, Source, and Make files for S'87
RLIB.LIB RLIB Function Library for Summer '87
RLIB.MAK RLIB.LIB Make file
RLIB.RSP RLIB.LIB Turbo Librarian Response File
RHC.PRG RHELP Compiler source code - Summer '87
RHDC.PRG RHELP De-Compiler source code - Summer '87
MAKERLIB.BAT Batch file to make RLIB.LIB Function Library
MAKERHC.BAT Batch file to make RHC.EXE and RHDC.EXE
RL_*.PRG RLIB 3.0 for S'87 source code files (see page 21)
3. RLIBMR.EXE - RLIB 3.0 Demo Message Reader Program
MR.CFG Message Reader Configuration File
MR.HLP Message Reader Program Help File
MR.RHC RHELP source for Message Reader help system
MAKEMR.BAT Batch file to make Message Reader - MR.EXE
MAKEMR50.BAT Batch file to make MR.EXE in Clipper 5.01
SAMPLE.MSG Sample messages file for Message Reader
FORUMS.DBF Sample forums database for Message Reader
PROGNAME.ASM Assembly function to retrieve .EXE file path
PROGNAME.OBJ Assembled and linkable PROGNAME.ASM
*.PRG Message Reader source code files (see page 24)
4. RLIBNG.EXE - RLIB 3.0 Norton Guide Reference Database
RLIB.NG RLIB 3.0 Norton Guide Reference Database
Introduction 6
Changes From Version 2.0
RLIB version 3.0 contains 91 functions, 58 that are brand new. Many
of the version 2.0 functions have been enhanced. Below is a quick
overview of the additions and enhancements. An asterisk (*) indicates
functions that are new in version 3.0, and a plus sign (+) indicates
functions that are enhanced from version 2.0.
Array Functions
---------------
* ADIM2() Formulate two dimension reference to a linear array.
* ALIST() List the elements of an array in a screen window.
* ARRAYLEN() Count the number of contiguous elements in an array.
Character Functions
-------------------
* ACRONYM() Convert a text string to its abbreviated acronym.
* ANYCHARSIN() Test if any characters in a string are in another.
BRIGHT() Convert Clipper color string to its bright equivalent.
DECRYPTED() Decrypt a character string encrypted with ENCRYPTED().
ENCRYPTED() Encrypt a character string.
* GETKEY() Replace INKEY() to allow internal customization.
GETPARM() Retrieve comma delimited token from character string.
* MIDDLE() Center string by padding with leading/trailing spaces.
NAMESPLIT() Swap from First Middle Last to Last, First Middle.
* NOTEMPTY() Validate that data was entered in a field.
PARENT() Retrieve parent directory for a specified directory.
PATHTO() Search DOS path for path leading to a given filename.
* STRETCH() Pad string with blanks or truncate to a defined width.
* TYPEC() Test if a PUBLIC/PRIVATE is character and not blank.
* VALTYPEC() Test if a LOCAL/STATIC is character and not blank.
Database Functions
------------------
* CATF() Copy array values to database fields.
* CFTA() Copy database field values to an array.
CHANGED() Test if memory copies of fields have been changed.
CLOSEAREA() Close multiple database work areas with one command.
* DBFCREATE() Dynamically create a database from a structure array.
FORGET() Release field variables created with MEMORIZE().
* ISDBF() Test if a file is a valid .DBF format database file.
* ISFIELD() Test if a field name is valid in the selected area.
* MAKEALIAS() Construct a database alias from a full filename.
+ MARKREC() Mark/select multiple records from a pick list.
MEMORIZE() Save fields from database record to memory variables.
MREPLACE() Replace fields with memvars created with MEMORIZE().
* NO_APPEND() Network append blank function with error trapping.
* NO_FLOCK() Network file lock function with error trapping.
* NO_RLOCK() Network record lock function with error trapping.
NTXKEYVAL() Get controlling index key value of the current record.
* OPENED() Open multiple databases with network error checking.
+ PICKREC() Pop up a scrollable pick list of database records.
* POPUPPICK() Generic pop-up pick list handler.
* QUERY() Create a logical query/filter string via menu prompts.
Introduction 7
Date Functions
--------------
ALPHADATE() Convert date variables to alphabetic format.
* CALENDAR() Pop up a configurable calendar on the screen.
* REVDATE() Reverse date fields for reverse index ordering.
+ STR2DATE() Convert date strings to a Clipper date type variable.
File Functions
--------------
* CHECKFILE() Verify valid filenames, optionally pop up a pick list.
* FEOF() Test for the End Of File status on a binary file.
FILEDATE() Retrieve last update date for a given file from DOS.
FILES() Test for the existence of multiple files.
* FILESIZE() Retrieve the size of a file from DOS directory.
FILETIME() Retrieve the last update time for a given file.
* FREADLINE() Read line from text file opened with FOPEN()/FCREATE()
* GETFILE() Full featured user dialogue box for GETing filenames.
* OLDERFILE() Determine the older of two disk files.
PICKFILE() Pop up directory listing from which to select a file.
* TEMPFILE() Generate a temporary filename.
Help Functions
--------------
* RH_HEADER() Retrieve the header from a RHELP compiled help file.
* RH_LINES() Get the number of text lines within a help text block.
* RH_TEXT() Extract help text for a key from compiled .HLP file.
* RH_WIDTH() Get the maximum line width within a help text block.
Menu Functions
--------------
BARMENU() Create horizontal light bar menus.
+ BOXMENU() Create boxed framed highlight bar (pop up) menus.
MULTIMENU() Create multi-column menus with 4 way cursor movement.
+ PDOWNINIT() Initialize the PDOWNMENU() function for use.
+ PDOWNMENU() Activate pull-down menu initialized with PDOWNINIT().
Miscellaneous and Internal Functions
------------------------------------
BEEP() Ring the system bell one or more times.
* BLIP() Generate a blipping sound for warnings or errors.
* BUZZ() Generate a buzzing sound for warnings or errors.
* RLIBERROR() Return and optionally set the last RLIB error number.
* RLIBINIT() Initialize internal RLIB PUBLIC/STATIC variable(s).
* RLIBVER() Retrieve the version number of the RLIB.LIB linked.
Numeric Functions
-----------------
* BIN2DEC() Convert binary number to its equivalent decimal value.
* DEC2HEX() Convert decimal numeric value to a hexadecimal string.
* DIVIDE() Divide numbers with divide by zero protection.
* HEX2DEC() Convert hex string to equivalent decimal value.
* VRANGE() Numeric range validation with error handling.
Introduction 8
Printer Functions
-----------------
* PRINTCODE() Convert text printer codes into escape sequences.
* REPORTINIT() Initialize databases used by StartReport() function.
* STARTREPORT() Report format and print control facility.
* TARGET() Provide a pop-up target printer output selection menu.
Screen Functions
----------------
* ABOXASK() Pop up a centered message box using array of messages.
ATINSAY() Display expression at in a specified color.
* BORDERBOX() Draw a box with a one line title area at the top.
+ BOXASK() Pop up a centered message box using multiple messages.
+ CENTER() Center a string and/or get the center position.
* FPROMPT() Display formatted and highlighted prompt strings.
* FRESTSCREEN() Restore screen from a file saved with FSAVESCREEN().
* FSAVESCREEN() Save screen to file to restore with FRESTSCREEN().
KEYINPUT() Get keyboard input optionally echoing dots to screen.
* PICKCOLOR() Pick a color setting from a boxed display.
* POPBOX() Restore a screen from a SAYINBOX() screen variable.
RJUSTIFY() Move trailing blanks to the front.
+ SAYINBOX() Pop up centered message box using multiple messages.
* SETCURSOR() Retrieve and optionally set the current cursor state.
Functions Enhanced from RLIB version 2.0
All RLIB 3.0 functions that were in RLIB version 2.0 maintain upward
compatibility. If new parameters have been added, parameter checking
is such that existing function usage will not be adversely affected.
Basically, you can keep using your RLIB 2.0 function syntax but take a
look at what's new... you might want to update your code.
Function Enhancements
----------- -----------------------------------------
BOXASK() New valid keys parameter
BOXMENU() Expanded colors, additional parameters
CENTER() New color parameter
MARKREC() Additional parameters for greater control
PDOWNINIT() Better use of static parameters
PDOWNMENU() Significant enhancements to parameters
PICKFILE() Now returns a fully qualified filename
PICKREC() Additional parameters for greater control
SAYINBOX() POPBOX() companion function
STR2DATE() Better date string parsing
Introduction 9
┌───────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ Chapter 2 │
│ Obtaining RLIB │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────────┘
Chapter 2: Obtaining RLIB
Registration
This shareware version of RLIB provides you with a way to see just how
useful RLIB functions are by personally trying them out in your own
applications! The shareware version of RLIB is not limited in any way
and it contains all of the features of the distribution version. The
only difference is that, like most shareware products, a product
introduction screen is displayed when you first start applications
that link in shareware RLIB functions.
The best part about this type of test drive is that it lets you
actually use RLIB functions in your own applications. When you
register all you have to do is re-link your application with the
distribution RLIB library, no code changes are necessary!
If you like RLIB and want to use it, by all means purchase your own
copy. It costs only $99.00 plus shipping and you get a lot! You will
receive the lastest version of RLIB on diskette, a 250+ page spiral
bound manual, on-line Norton Guide database, the Message Reader
program, manual and source code, and unlimited free technical support
via CompuServe Mail. Also, the big bonus is that you get the complete
source code for all of the RLIB functions and for the Message Reader
demonstration program.
A registered copy of RLIB contains a license to use the single user
version of the Message Reader program. If you want to use Message
Reader on a network, a network version is available separately.
Additional manuals are also available (for the network version only).
See the order form for information on how to order.
Technical Support
Technical support is available free of charge to paid registered users
as described below. When you order and receive you registered copy of
RLIB, you will be asked to complete and return the registration form
by mail to ensure that you are entitled to technical support.
The fastest and best way to obtain technical support is via electronic
mail on CompuServe. Send your support questions to CompuServe account
number 72007,1063. You may usually expect a reply within 24 hours.
Support is available on a limited basis by telephone for the first 30
days following registration. If no one is available, telephone calls
will be answered electronically and return calls will be placed
collect.
You can always send a letter by U.S. Mail. Letters will usually be
answered within 48 hours of receipt.
Obtaining RLIB 11
Order Information
To order your copy of RLIB, please provide the information requested
on the Order Form on the following page. If you are paying by check
or money order please enclose payment with your order. All checks or
money orders must be made in U.S. dollars. For Visa and MasterCard
orders be sure to complete the section requesting your card number,
expiration date and signature.
You may order over the telephone by completing the order form and
calling the telephone number listed, or FAXing a copy to the FAX
number listed on the order form. You may also order on-line via
CompuServe Mail by sending the completed order form on disk
(ORDER.DOC) to CompuServe Mail account 72007,1063.
Telephone, FAX, and electronic mail orders will be accepted by credit
card only. C.O.D. orders will be accepted for domestic orders only.
Please add an additional $4 for C.O.D. orders.
Regular shipping is via U.S. Priority Mail. International orders are
sent by Air Mail. Overnight shipping is by U.S. Express Mail and is
available only in the U.S. and Canada.
Obtaining RLIB 12
O R D E R F O R M
Send to: RLIB SOFTWARE Telephone: (919) 383-0488
P. O. BOX 3232 FAX: (919) 382-3028
DURHAM, NC 27715 CompuServe: 72007,1063
Quantity Item Description Unit Cost Total
_____ RLIB 3.0 Function Library in both $99.00 ________
Summer '87 and Clipper 5.01 versions,
full source code, printed manual, and
single user license for Message Reader
_____ Message Reader v2.0 Network version $199.00 ________
with single file server license
_____ Additional Message Reader printed $10.00 ________
manual. (Available only with the
Network version)
SHIPPING & HANDLING - SELECT ONE OF THE FOLLOWING:
_____ Within the U.S. and Canada $6.00 ________
_____ Outside the U.S. and Canada $18.00 ________
_____ Overnight (Only in U.S. and Canada) $20.00 ________
_____ C.O.D. Orders (add $4) $4.00 ________
TOTAL $__________
Your Name: ______________________________________________________
Company: ______________________________________________________
Address: ______________________________________________________
City: _______________________________ State: _______________
Zip Code: _________________ Country: ___________________________
Telephone: (________)____________________________
Disk Size: ______3.5" ______5.25"
Payment: ______Check/M.O. ______MasterCard _______VISA
Card #: ______________________________ Expires: _____________
Name as it appears on card: _______________________________________
Signature: ______________________________________________________
┌───────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ Chapter 3 │
│ Using RLIB │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────────┘
Chapter 3: Using RLIB
System Requirements
To make use of the RLIB function library you need either the Summer
'87 or 5.0 version of the Clipper compiler. Of course you must also
have an IBM PC, XT, AT, PS/2 or 100% compatible and PC/MS-DOS version
2.1 or above. You also need a hard disk.
Your disk space requirements will vary depending upon which versions
of Clipper you install RLIB to support. The RLIB library requires
about 150K of disk space and the source code files require another
320K. This space requirement is approximate for either the Clipper
Summer '87 or 5.0 version of RLIB. If you will install both versions,
double the figures.
Installation
The RLIB package comes on two (2) 5.25" diskettes or one (1) 3.5"
diskette. Included in the diskettes are four (4) self-extracting ZIP
files which contain the various components of RLIB in compressed form.
See the section entitled Contents for a list of the self-extracting
ZIP files and their contents.
The files within the self-extracting ZIP files are extracted or un-
compressed by simply "running" the self-extracting zip file; it is an
executable file with an .EXE file extension. To extract the files
into the proper directory, change directory to the location where you
want the files to reside and execute the self-extracting ZIP file. It
is assumed that you know how to copy and install software and that you
have your own preferred directory structure. A suggested directory
structure appears as follows:
C:\
└──CLIPPER
├──501
│ ├──BIN --> Clipper 5.01 executable
│ ├──INCLUDE --> Clipper 5.01 include files
│ └──LIB --> Clipper 5.01 libraries
│ └──RLIB --> 5.01 version of RLIB.LIB
│ ├──DEMO --> RLIB demo program files
│ └──SOURCE --> 5.01 version of RLIB source code
└──S87 --> The Clipper Summer '87 executable
└──LIB --> Third Party Libraries (like RLIB)
└──RLIB --> Summer '87 version of RLIB.LIB
├──DEMO --> RLIB demo program files
└──SOURCE --> Summer '87 version of RLIB source code
Using RLIB 15
Linking RLIB Into Your Applications
To include any RLIB functions in your application, you must include
the RLIB library name in your list of libraries when linking. The
only requirement is that you must include the Clipper EXTEND.LIB
library since RLIB makes use of functions in this library. Also you
MUST list RLIB BEFORE EXTEND.LIB so the linker will properly pick up
the routines. (Apparently, some linkers do not make a second pass
through the libraries to see if a library that follows one on the list
calls a routine in a preceding one).
The syntax for using RTLINK is:
rtlink FILE yourprog LIB clipper,rlib,extend
To use PLINK86, type:
plink86 FILE yourprog LIB clipper,rlib,extend
To use BLINKER, type:
blinker FILE yourprog LIB clipper,rlib,extend
To use MS-LINK, type:
link yourprog,,,clipper+rlib+extend
To use TLINK, type:
tlink yourprog,,,clipper+rlib+extend
<< *** REMEMBER TO LIST RLIB BEFORE EXTEND *** >>
Dynamic Overlay Linkers
The RLIB 3.0 library is written entirely in Clipper hence the RLIB
library is compatible with standard Clipper dynamic overlay linkers
such as Blinker. RLIB can be entirely overlaid using the Blinker
ALLOCATE link script command.
Using RLIB 16
Modifying The RLIB Library
You may want to custom tailor some of the functions in RLIB to meet
your own needs. Since the source code is provided for RLIB, this
capability is what makes RLIB so versatile. All you need is, of
course, a copy of Clipper and a library manager program such as LIB
from Microsoft. Included with this package is a make file named
RLIB.MAK which can be used to maintain the library. See the
discussion of how to use a library manager in the documentation that
comes with the package you use.
Clipper Summer '87
When writing a collection of functions to build into a library, the
biggest difference between Clipper compiled functions and functions
written in other languages is that Clipper uses the filename to
generate the public symbol that will be placed in the resulting object
file. If you write a program named TEST.PRG and compile it with
Clipper, the resulting object file is named TEST.OBJ and the public
symbol in that object file (the function name that you call) is named
TEST. That's ok if TEST.PRG does something useful, but if all
TEST.PRG does is to contain a function named TEST, then Clipper will
give you a SYMBOL REDEFINITION ERROR. This is because Clipper is
trying to create two symbols for the linker, both with the same name;
one named TEST for the .PRG file program itself, and the other for the
function named TEST contained in that .PRG file.
For this reason, .PRG files that contain nothing but a function must
have a name different from the function name itself. Therefore, all
the RLIB functions are contained in .PRG files starting with "RL_" and
ending with the first 5 letters of the function name. Of course you
could get around this by having one .PRG file named RLIB.PRG with all
of the functions separately listed within it, but this nullifies the
advantage of using a library. If you did it that way, all of the code
would be linked into your application whether you called all the
functions within it or not. Having the functions contained in a
library is handy because only those functions you use are extracted
and included in your .EXE file when linked.
Clipper 5.0
Clipper 5.0 has resolved this issue with the addition of the /N
compile switch. The purpose of this new switch is to suppress the
definition of a procedure with the same name as the .PRG file. This
definition of a procedure creates an entry point to the program file
on the first non-comment line of the source file. The /N switch
forces the compiler to not create this entry point and thereby not
create a public symbol with the same name as the program file. What
this all means is that in Clipper 5.0 you can have a source file named
BOXMENU.PRG with only one function in it named BOXMENU and Clipper
will not complain if you compile this with the /N compiler command
line switch.
Using RLIB 17
For consistency, the 5.0 versions of the RLIB source code have the
same source file names as the Summer '87 versions, that is, they all
are prefaced with RL_.
RLIB Function Overview
Parameter Syntax Verification
All of the RLIB functions employ parameter verification to ensure that
the correct parameters were supplied for the function to properly
execute. If one or more parameters is missing or is of the wrong data
type, the RLIB function is designed to return gracefully to the
calling routine without crashing the application. Nothing is more
annoying than to have a function bomb an application albeit due to a
coding error. However, there is another side to this coin. If an
application crashes, at least it is painfully evident that something
is wrong. By gracefully returning it is not always clear that a
function did not perform as expected.
Take for instance the Clipper Summer '87 implementation of the
SCROLL() function. If the fifth parameter, the number of lines to
scroll, is omitted, SCROLL() simply returns without doing anything.
This is good because it does not crash your application. However, it
may not be immediately clear that something is not working. If the
program crashed with even a cryptic error message such as "Proc:
SCROLL Line: 0 Parameter Error" at least you know something is wrong
within the SCROLL() function. (Note: The Clipper 5.01 version of the
SCROLL() function clears the screen if no parameters are provided.)
RLIB Error Reporting
RLIB functions give you the best of both worlds. As mentioned above,
all RLIB functions verify the correct number of and parameter types.
If a parameter is missing or of the incorrect type, the RLIB function
will not bomb but will return to the calling routine. What the RLIB
function will do is set a flag via the RLIBERROR() function.
RLIBERROR() maintains a public variable named <rliberror> which is a
numeric value that indicates the last error that may have occurred. A
normal value is zero. Through the use of RLIBERROR() the application
programmer can set break points in the Clipper debugger during testing
to trap any syntax errors in RLIB functions. To learn more about
RLIBERROR() see the function description in the function reference and
Appendix A - RLIB Error Codes.
Using RLIB 18
Quick Function Listing
ABOXASK() Pop up a centered message box using array of messages.
ACRONYM() Convert a text string to its abbreviated acronym.
ADIM2() Formulate a two dimension reference to a linear array.
ALIST() List the elements of an array in a screen window.
ALPHADATE() Convert date variables to alphabetic format.
ANYCHARSIN() Test if any characters in a string are in another.
ARRAYLEN() Count the number of contiguous elements in an array.
ATINSAY() Display expression at in a specified color.
BARMENU() Create horizontal light bar menus.
BEEP() Ring the system bell one or more times.
BIN2DEC() Convert binary number to its equivalent decimal value.
BLIP() Generate a blipping sound for warnings or errors.
BORDERBOX() Draw a box with a one line title area at the top.
BOXASK() Pop up a centered message box using multiple messages.
BOXMENU() Create boxed framed highlight bar (pop up) menus.
BRIGHT() Convert Clipper color string to its bright equivalent.
BUZZ() Generate a buzzing sound for warnings or errors.
CALENDAR() Pop up a configurable calendar on the screen.
CATF() Copy array values to database fields.
CENTER() Center a string and/or get the center position.
CFTA() Copy database field values to an array.
CHANGED() Test if memory copies of fields have been changed.
CHECKFILE() Verify valid filenames, optionally pop up a pick list.
CLOSEAREA() Close multiple database work areas with one command.
DBFCREATE() Dynamically create a database from a structure array.
DEC2HEX() Convert decimal numeric value to a hexadecimal string.
DECRYPTED() Decrypt a character string encrypted with ENCRYPTED().
DIVIDE() Divide numbers with divide by zero protection.
ENCRYPTED() Encrypt a character string.
FEOF() Test for the End Of File status on a binary file.
FILEDATE() Retrieve last update date for a given file from DOS.
FILES() Test for the existence of multiple files.
FILESIZE() Retrieve the size of a file from DOS directory.
FILETIME() Retrieve the last update time for a given file.
FORGET() Release field variables created with MEMORIZE().
FPROMPT() Display formatted and highlighted prompt strings.
FREADLINE() Read line from text file opened with FOPEN()/FCREATE()
FRESTSCREEN() Restore screen from a file saved with FSAVESCREEN().
FSAVESCREEN() Save screen to file to restore with FRESTSCREEN().
GETFILE() Full featured user dialogue box for GETing filenames.
GETKEY() Replace INKEY() to allow internal customization.
GETPARM() Retrieve comma delimited token from character string.
HEX2DEC() Convert hex string to equivalent decimal value.
ISDBF() Test if a file is a valid .DBF format database file.
ISFIELD() Test if a field name is valid in the selected area.
KEYINPUT() Get keyboard input optionally echoing dots to screen.
MAKEALIAS() Construct a database alias from a full filename.
MARKREC() Mark/select multiple records from a pick list.
MEMORIZE() Save fields from database record to memory variables.
MIDDLE() Center string by padding with leading/trailing spaces.
MREPLACE() Replace fields with memvars created with MEMORIZE().
MULTIMENU() Create multi-column menus with 4 way cursor movement.
Using RLIB 19
Quick Function Listing (Continued)
NAMESPLIT() Swap from First Middle Last to Last, First Middle.
NO_APPEND() Network append blank function with error trapping.
NO_FLOCK() Network file lock function with error trapping.
NO_RLOCK() Network record lock function with error trapping.
NOTEMPTY() Validate that data was entered in a field.
NTXKEYVAL() Get controlling index key value of the current record.
OLDERFILE() Determine the older of two disk files.
OPENED() Open multiple databases with network error checking.
PARENT() Retrieve parent directory for a specified directory.
PATHTO() Search DOS path for path leading to a given filename.
PDOWNINIT() Initialize the PDOWNMENU() function for use.
PDOWNMENU() Activate pull-down menu initialized with PDOWNINIT().
PICKCOLOR() Pick a color setting from a boxed display.
PICKFILE() Pop up directory listing from which to select a file.
PICKREC() Pop up a scrollable pick list of database records.
POPBOX() Restore a screen from a SAYINBOX() screen variable.
POPUPPICK() Generic pop-up pick list handler.
PRINTCODE() Convert text printer codes into escape sequences.
QUERY() Create a logical query/filter string via menu prompts.
REPORTINIT() Initialize StartReport() databases.
REVDATE() Reverse date fields for reverse index ordering.
RH_HEADER() Retrieve the header from a RHELP compiled help file.
RH_LINES() Get the number of text lines within a help text block.
RH_TEXT() Extract help text for a key from compiled .HLP file.
RH_WIDTH() Get the maximum line width within a help text block.
RJUSTIFY() Move trailing blanks to the front.
RLIBERROR() Return and optionally set the last RLIB error number.
RLIBINIT() Initialize internal RLIB PUBLIC/STATIC variable(s).
RLIBVER() Retrieve the version number of the RLIB.LIB linked.
SAYINBOX() Pop up centered message box using multiple messages.
SETCURSOR() Retrieve and optionally set the current cursor state.
STARTREPORT() General report format and print control function.
STR2DATE() Convert date strings to a Clipper date type variable.
STRETCH() Pad string with blanks or truncate to a defined width.
TARGET() Provide a pop-up target printer output selection menu.
TEMPFILE() Generate a temporary filename.
TYPEC() Test if a PUBLIC/PRIVATE is character and not blank.
VALTYPEC() Test if a LOCAL/STATIC is character and not blank.
VRANGE() Numeric range validation with error handling.
Using RLIB 20
Source Code File List
As mentioned earlier, the RLIB function library includes complete
source code to all functions, demo programs, and the Message Reader
program. The source code for each RLIB function is contained in a
separate disk file. All RLIB function source code file names begin
with RL_. Chapter 5, Function Reference lists the name of each source
file as part of each function description. Below is a list of each
RLIB function and the name of it's associated source code file.
NO. RLIB FUNCTION SOURCE FILE CATEGORY
--- ------------- ------------ -------------
1. ABOXASK() RL_ABOXA.PRG Screen
2. ACRONYM() RL_ACRON.PRG Character
3. ADIM2() RL_ADIM2.PRG Array
4. ALIST() RL_ALIST.PRG Debugging
5. ALPHADATE() RL_ALPHA.PRG Date
6. ANYCHARSIN() RL_ANYCH.PRG Character
7. ARRAYLEN() RL_ARRAY.PRG Array
8. ATINSAY() RL_ATINS.PRG Screen
9. BARMENU() RL_BARME.PRG Menu
10. BEEP() RL_BEEP.PRG Miscellaneous
11. BIN2DEC() RL_BIN2D.PRG Numeric
12. BLIP() RL_BLIP.PRG Miscellaneous
13. BORDERBOX() RL_BORDE.PRG Screen
14. BOXASK() RL_BOXAS.PRG Screen
15. BOXMENU() RL_BOXME.PRG Menu
16. BRIGHT() RL_BRIGH.PRG Character
17. BUZZ() RL_BUZZ.PRG Miscellaneous
18. CALENDAR() RL_CALEN.PRG Date
19. CATF() RL_CATF.PRG Database
20. CENTER() RL_CENTE.PRG Screen
21. CFTA() RL_CFTA.PRG Database
22. CHANGED() RL_CHANG.PRG Database
23. CHECKFILE() RL_CHECK.PRG File
24. CLOSEAREA() RL_CLOSE.PRG Database
25. DBFCREATE() RL_DBFCR.PRG Database
26. DEC2HEX() RL_DEC2H.PRG Numeric
27. DECRYPTED() RL_DECRY.PRG Character
28. DIVIDE() RL_DIVID.PRG Numeric
29. ENCRYPTED() RL_ENCRY.PRG Character
30. FEOF() RL_FEOF.PRG File
31. FILEDATE() RL_FILED.PRG File
32. FILES() RL_FILES.PRG File
33. FILESIZE() RL_FSIZE.PRG File
34. FILETIME() RL_FILET.PRG File
35. FORGET() RL_FORGE.PRG Database
36. FPROMPT() RL_FPROM.PRG Screen
37. FREADLINE() RL_FREAD.PRG File
38. FRESTSCREEN() RL_FREST.PRG Screen
39. FSAVESCREEN() RL_FSAVE.PRG Screen
40. GETFILE() RL_GETFI.PRG File
41. GETKEY() RL_GETKE.PRG Character
Using RLIB 21
Source Code File List (Continued)
NO. RLIB FUNCTION SOURCE FILE CATEGORY
--- ------------- ------------ -------------
42. GETPARM() RL_GETPA.PRG Character
43. HEX2DEC() RL_HEX2D.PRG Numeric
44. ISDBF() RL_ISDBF.PRG Database
45. ISFIELD() RL_ISFIE.PRG Database
46. KEYINPUT() RL_KEYIN.PRG Screen
47. MAKEALIAS() RL_MAKEA.PRG Database
48. MARKREC() RL_MARKR.PRG Database
49. MEMORIZE() RL_MEMOR.PRG Database
50. MIDDLE() RL_MIDDL.PRG Character
51. MREPLACE() RL_MREPL.PRG Database
52. MULTIMENU() RL_MULTI.PRG Menu
53. NAMESPLIT() RL_NAMES.PRG Character
54. NO_APPEND() RL_NO_AP.PRG Database
55. NO_FLOCK() RL_NO_FL.PRG Database
56. NO_RLOCK() RL_NO_RL.PRG Database
57. NOTEMPTY() RL_NOTEM.PRG Character
58. NTXKEYVAL() RL_NTXKE.PRG Database
59. OLDERFILE() RL_OLDER.PRG File
60. OPENED() RL_OPENE.PRG Database
61. PARENT() RL_PAREN.PRG Character
62. PATHTO() RL_PATHT.PRG Character
63. PDOWNINIT() RL_PDINI.PRG Menu
64. PDOWNMENU() RL_PDOWN.PRG Menu
65. PICKCOLOR() RL_PICKC.PRG Screen
66. PICKFILE() RL_PICKF.PRG File
67. PICKREC() RL_PICKR.PRG Database
68. POPBOX() RL_SAYIN.PRG Screen
69. POPUPPICK() RL_POPUP.PRG Database
70. PRINTCODE() RL_PRINT.PRG Printer
71. QUERY() RL_QUERY.PRG Database
72. REPORTINIT() RL_REPOR.PRG Printer
73. REVDATE() RL_REVDA.PRG Date
74. RH_HEADER() RL_RHELP.PRG Help
75. RH_LINES() RL_RHELP.PRG Help
76. RH_TEXT() RL_RHELP.PRG Help
77. RH_WIDTH() RL_RHELP.PRG Help
78. RJUSTIFY() RL_RJUST.PRG Screen
79. RLIBERROR() RL_RLIBE.PRG Internal
80. RLIBINIT() RL_RLIBI.PRG Internal
81. RLIBVER() RL_RLIBV.PRG Internal
82. SAYINBOX() RL_SAYIN.PRG Screen
83. SETCURSOR() RL_SETCU.PRG Screen
84. STARTREPORT() RL_START.PRG Printer
85. STR2DATE() RL_STR2D.PRG Date
86. STRETCH() RL_STRET.PRG Character
87. TARGET() RL_TARGE.PRG Printer
88. TEMPFILE() RL_TEMPF.PRG File
89. TYPEC() RL_TYPEC.PRG Character
90. VALTYPEC() RL_VALTY.PRG Character
91. VRANGE() RL_VRANG.PRG Numeric
Using RLIB 22
┌───────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ Chapter 4 │
│ The Message Reader Demo Program │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────────┘
Chapter 4: The Message Reader Demo Program
A Full Feature Application
Message Reader is a program for PC-DOS Personal Computers and 100%
compatibles which simplifies and diversifies the management of
messages captured from CompuServe forums. Refer to the Message Reader
documentation for a full description of Message Reader features.
The Message Reader program demonstrates the power and versatility of
using RLIB functions. Message Reader is written in Clipper Summer '87
and makes extensive use of a majority of the RLIB functions. The
source code to Message Reader is included as part of the registered
distribution version of RLIB 3.0. By looking through the source code
you can gain an appreciation of just how much time and effort you can
save by using RLIB functions.
Not only does Message Reader demonstrate the power of RLIB, but it is
also a full featured application program. In fact, Message Reader is
sold separately by RLIB Software as an aid to handling the voluminous
amounts of information to be gleaned from the CompuServe forum message
bases.
Take a moment to read through the Message Reader manual, and enjoy the
program!
Message Reader Source Code
The Message Reader source code is comprised of over 3,500 lines of
commented and highly instructional executable source code. This
source code line count would be much higher were it not for RLIB
functions. Given that many of the RLIB functions do so much a lot of
the coding effort has already been accomplished. For example, the
entire Message Reader query building process is handled through one
call to the RLIB QUERY() function!
Source Code Files
DEFINES.PRG Public definitions (#define's in 5.01)
MRSTART.PRG Start up and command line parser
MAIN.PRG Main program loop
MENU.PRG Menu control function
FORUM.PRG Forum options functions
IMPORT.PRG Message import functions
OPTIONS.PRG Options menu functions
PRINT.PRG Print functions
QRY.PRG Query builder
SEARCH.PRG Search functions
SEND.PRG Message compose and send functions
VIEW.PRG Viewing functions
ERRORSYS.PRG Customized Summer '87 error handler
PROGNAME.ASM Gets executing program name, aka argv[0]
The Message Reader Demo Program 24
RLIB Functions Used in Message Reader
Here is a list of some of the RLIB functions used in the Message
Reader program source code. As you can see they provide a wide
variety of uses. In particular pay close attention to PICKREC(),
which essentially drives the view screen.
ANYCHARSIN() Verifies valid characters in filenames
BORDERBOX() Draws all boxes with titled headers
BOXASK() Creates all screen centered message dialogue boxes
BOXMENU() Provides the second level from the PDOWNMENU()
CALENDAR() Shift-F1 pops up a handy calendar
CHECKFILE() Verifies filenames and provides pop-up directory
CLOSEAREA() Used to close database files
DEC2HEX() Used to generate unique MAIL message numbers
DBFCREATE() Creates Message Reader database files
FPROMPT() Provides the highlighted prompts at bottom of screen
FREADLINE() Used to read text lines during the import process
FILESIZE() Used to determine if enough disk space exists for copy
GETFILE() Used to get filenames whenever requested
MEMORIZE() Used during field edit routines
MREPLACE() Used to replace edited field data
NO_APPEND() Appends new records, testing for network errors
NO_FLOCK() Used for network file locking
NO_RLOCK() Used for network record locking
NOTEMPTY() Used in field edit VALID clause to confirm data entry
OPENED() Used whenever databases are opened
PARENT() Parses path to help generate help file path
PDOWNMENU() Provides the pull-down menu system
PICKCOLOR() Performs the color selection routine
PICKFILE() Provides the pop-up file directory listing
PICKREC() *** The view screen is controlled by PICKREC() ***
QUERY() This IS the query builder!
SAYINBOX() Provides status indicators during indexing, etc...
SETCURSOR() Cursor control is through this function
TARGET() Provides the print target output menu
The PROGNAME() Function
Message Reader makes use of one assembly language function named
PROGNAME(). PROGNAME() retrieves the name of the currently executing
program (MR.EXE) as a fully qualified filename. For instance, if the
Message Reader program is started with the command C:\DEMO\MR, then
PROGNAME() will return C:\DEMO\MR.EXE. In the C language this is
known as argv[0]. Clipper does not have a (documented) built in
function to retrieve this value.
The program name returned by PROGNAME() is stripped to a path
specification with the RLIB function PARENT(), to extract the
directory in which the MR.EXE file is located. This path is then used
to build the help file name for MR.HLP so Message Reader can find its
own help file. This assumes the help file is stored in the same
directory as the MR.EXE executable file.
The Message Reader Demo Program 25
PROGNAME() works only with DOS versions 3.0 and above. In the event
you are using DOS version 2.x, Message Reader lets you explicitly
specify the directory in which the help file can be found. The
PROGNAME() function (PROGNAME.OBJ) is compatible with both Clipper
Summer '87 and Clipper 5.0 (and 5.01).
The assembly language source code for PROGNAME() is in the file
PROGNAME.ASM and the already assembled linkable object module is in
PROGNAME.OBJ (in case you do not have an assembler program). You may
wish to add the PROGNAME.OBJ module to RLIB.LIB or even to EXTEND.LIB
for convenience. You will need a library manager such as Microsoft's
LIB or Borland's TLIB. See your library manager documentation for the
proper syntax.
Compiling and Linking Message Reader
Making the Message Reader executable program is as simple as running
the MAKEMR.BAT batch file. This batch file, which can be found in the
RLIBDEMO.EXE self-extracting ZIP file, compiles the Message Reader
source code files and links the resulting object module with the
Clipper and RLIB 3.0 libraries.
Message Reader is written in the Summer '87 version of Clipper but has
also been compiled using Clipper 5.01. If you want to compile Message
Reader with 5.01 be sure to omit any of the new Clipper 5.01 command
line switches. This will enforce compatibility with Summer '87 code.
You will also want to make sure you link the 5.01 compiled object
module with the Clipper 5.01 version of RLIB.LIB. Future versions of
Message Reader will be only in Clipper 5.01 format.
The demonstration RLIB package contains the Message Reader program in
compiled, object file format, in both Clipper Summer '87 and Clipper
5.01 versions. These object files are ready to link with the RLIB
library to produce a demonstration version of Message Reader. Two
batch files are included to simplify this process. These batch files
are named MAKEMR.BAT and MAKEMR50.BAT, and they make Clipper Summer
'87 and 5.01 executable versions of Message Reader respectively.
The MAKEMR.BAT batch file uses the PLINK86 linker included with
Clipper Summer '87, and the MAKEMR50.BAT batch file uses the RTLINK
linker included with Clipper 5.0. You may substitute your preferred
linker. Message Reader has been successfully linked with PLINK86,
BLINKER, and Borland's TLINK. The Clipper 5.01 version has been
linked with RTLINK and BLINKER 1.5.
The Message Reader Demo Program 26
┌───────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ Chapter 5 │
│ RLIB Function Reference │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────────┘
Chapter 5: RLIB Function Reference
The following section contains the detailed function descriptions.
Each function reference starts on a separate page and includes a
standardized header with the following information:
Function: The name of the function
Purpose: A one line function purpose description
Syntax: Function syntax listing parameters and sequence
Arguments: Detailed description of each parameter
Returns: The return value of the function
Description: A detailed description of the function
Notes: Notes and points about the function and behavior
Example: Code example of the function in use
Source: The name of the file containing the source code
See also: Related functions
RLIB Function Reference 28
Function: ABOXASK()
Purpose: Pop up a centered message box using an array of messages.
Syntax: ABOXASK( array [, color [, keys [, timeout ] ] ] )
Arguments: array - Array of character string messages to display
in a message box that is centered on the
screen. Each message can be up to 65
characters in length. Longer strings will be
truncated.
color - Optional Clipper color string used for the box
and message display. If omitted or a non-
character value is given, the default is the
current color setting.
keys - Optional character string of keys that cause
ABOXASK() to terminate if pressed. This string
may consist of letters or control characters.
If omitted or a non-character value is given,
the default is any keypress will cause
ABOXASK() to terminate.
timeout - Optional numeric value indicating the number of
seconds to wait before timing out and returning
a null string (""). If omitted or a non-
numeric value is given, the default wait period
is forever (INKEY(0)).
Returns: The single character pressed in response to the boxed message
displayed. If the character is lower case (a-z), it is
converted to upper case before being returned. If the
optional timeout parameter is supplied and no key is pressed
within the timeout period, a null character ("") is returned.
Description: ABOXASK() is a relative of the BOXASK() and SAYINBOX()
functions. It pops up a message box centered on the screen
and displays the message strings that are contained in the
message array argument. If the optional keys argument is
provided, these keys (expressed as a character string) will
be the only keys that, when pressed, will cause ABOXASK() to
terminate, all other keys pressed will be ignored. If the
optional timeout is given, ABOXASK() will wait the indicated
number of seconds for a keypress by issuing the GETKEY()
function with timeout as the argument. If no timeout is
given, ABOXASK() will wait forever for a keypress.
Notes: ABOXASK() performs essentially the exact same task as
BOXASK(). However, when a large number of message lines are
being passed to BOXASK() as arguments, code can get wordy.
ABOXASK() accepts a single array argument that contains the
several messages to display. If only one or two messages are
being displayed you may want to use BOXASK() since it removes
RLIB Function Reference 29
the need for declaring an extra array. ABOXASK() simplifies
box messages and allows you to maintain pre-defined arrays of
standard messages and frees you of having to clutter your
code with the message text strings.
ABOXASK() will force all letters entered in response to the
message prompt to upper case. All other keys are returned as
their CHR() values.
Example: *-- example of a SEEK or LOCATE failure notification
DECLARE msg[3]
msg[1] = "No record was found with the name you selected!"
msg[2] = "This name may have been misspelled"
msg[3] = "Press [ENTER] to try again, or [ESCAPE] to abort"
*-- present message, wait 30 seconds, default to ENTER
IF ABOXASK( msg, "W+/R", CHR(13)+CHR(27), 30 ) = CHR(27)
*-- ESCAPE key was explicitly pressed
EXIT
ENDIF
Source: RL_ABOXA.PRG
See also: BOXASK(), SAYINBOX()
RLIB Function Reference 30
Function: ACRONYM()
Purpose: Convert a text string to its abbreviated acronym.
Syntax: ACRONYM( string )
Arguments: string - The character string to parse into an Acronym
Returns: An acronym consisting of each starting alphabetic character
starting at the beginning of the string and after each space.
Description: Just what you always wanted, an acronym builder! Suppose you
are writing a report and you want a short name for each
division to appear in a column that will identify the
division but not take up a lot of real estate on the report.
Instead of printing a full name like "System Testing Under
Preliminary Investigation Division", this function will
reduce that long drawn out name to its proper acronym,
"STUPID".
Notes: Each acronym letter is retrieved from the string at each
break of one or more spaces. If no spaces are found in the
string (i.e. it is a single word), only the first letter of
the string will be returned.
If you want to ensure that the returned acronym is all upper
case, force the return value to upper case with
UPPER(ACRONYM(string)).
Example: ? ACRONYM("Three Letter Acronym")
*-- returns "TLA"
Source: RL_ACRON.PRG
See also: STR2DATE()
RLIB Function Reference 31
Function: ADIM2()
Purpose: Formulate a two dimension reference to a linear array.
Syntax: ADIM2( row, col, numcols )
Arguments: row - Numeric row of the two dimensional array
col - Numeric column of the two dimensional array
numcols - Number of columns in the two dimensional array
Returns: A linear number corresponding to the array element number
that would be located in a two dimensional array at the
positions row, column.
Description: Functions like ADIM2() have been implemented many ways, this
one allows any array to be referenced by explicitly stating
the number of columns rather that setting up a PUBLIC
variable which limits an application to only one two
dimension array.
Notes: To implement a pseudo two-dimensional array in Clipper Summer
'87, the Clipper manual suggests that you declare a PUBLIC
variable named COLS so that the function will know how many
columns are in the array. This limits access to only one
pseudo two dimensional array at a time since the example
function explicitly references the PUBLIC variable named
COLS. By using ADIM2(), and passing the number of columns as
a parameter, you can use ADIM2() to access several two
dimensional arrays simultaneously.
Example: *-- set up a matrix array for small spreadsheet with 100 rows
*-- by 20 columns
DECLARE spread[ 100 * 20 ]
*-- simulate a Data Fill down, from 1 to 2000
x = 1
FOR col = 1 TO 20
FOR row = 1 TO 100
spread[ ADIM2(row,col,20) ] = x
x = x + 1
NEXT row
NEXT col
Source: RL_ADIM2.PRG
See also: ALIST()
RLIB Function Reference 32
Function: ALIST()
Purpose: List the elements of an array in a screen window.
Syntax: ALIST( array )
Arguments: array - The array to list.
Returns: True if array listed successfully, false otherwise.
Description: This function is most likely to be used from within the
Clipper debug session. It takes an array reference as a
parameter and permits viewing of the elements in an array.
Notes: Since this function was designed as a tool for debugging, the
window is positioned on the right side of the screen so as to
overlay as little of the Clipper debug screen as possible.
An easy enhancement would be to add window coordinates and
some display positioning logic.
If ALIST() is to be called from within a Clipper debug
session, and not included in your application, you need to
make the function available by using the EXTERNAL Alist
statement. This places the function name in your
application's symbol table so the linker will bring in the
ALIST() function code so you can call it from debug.
Example: *-- the Clipper (Summer '87) debugger normally shows an array
*-- as just A from within the Clipper debugger. To show a
*-- listing of the elements of an array, in the Summer '87
*-- debug Expression window, enter the following:
ALIST(array)
*-- a screen similar to the following will appear, with
*-- the elements of your array listed
RLIB Function Reference 33
╔══════════════════════════════════════════════════════════╗
║ [#] TYPE VALUE ║
╟──────────────────────────────────────────────────────────╢
║ 1. C "This is a character array element" ║
║ 2. C "This is a very long character array elemen...║
║ 3. N 1 ║
║ 4. N 2 ║
║ 5. N 3 ║
║ 6. N 45.55555 ║
║ 7. L T ║
║ 8. L F ║
║ 9. D 04/10/91 ║
║ 10. C "The rest of the array elements are charact...║
║ 11. C "The rest of the array elements are charact...║
║ 12. C "The rest of the array elements are charact...║
║ 13. C "The rest of the array elements are charact...║
║ 14. C "The rest of the array elements are charact...║
║ 15. C "The rest of the array elements are charact...║
║ 16. C "The rest of the array elements are charact...║
║ 17. C "The rest of the array elements are charact...║
║ 18. C "The rest of the array elements are charact...║
║ 19. C "The rest of the array elements are charact...║
║ Press any key for next screen, Escape to quit ║
╚══════════════════════════════════════════════════════════╝
Source: RL_ALIST.PRG
See also: ADIM2()
RLIB Function Reference 34
Function: ALPHADATE()
Purpose: Convert date variables to alphabetic format
Syntax: ALPHADATE( [ date ] )
Arguments: date - Optional date type date variable to display.
If omitted the default DATE() is used.
Returns: The specified date as a character string in the form
January 1, 1990
Description: ALPHADATE() provides a convenient method of printing a date
in the form January 1, 1988. If you print out text date
strings often in your application, using the following code
gets old quick:
CMONTH(date) + ' ' + LTRIM(STR(DAY(date))) + ;
' ' + STR(YEAR(date),4,0)
Notes: If an invalid parameter is passed, RLIBERROR() will be set
and a null string will be returned.
Example: ? DATE() && if it is 01/01/90,
? ALPHADATE() && returns "January 1, 1990"
? ALPHADATE(DATE()+1) && and "January 2, 1990"
? ALPHADATE(CTOD("12/31/90")) && "December 31, 1990"
? ALPHADATE(12/31/90) && bad parameter, returns ""
&& and sets RLIBERROR()=1008
Source: RL_ALPHA.PRG
See also: FILEDATE()
RLIB Function Reference 35
Function: ANYCHARSIN()
Purpose: Test if any characters in one string are found in another
Syntax: ANYCHARSIN( characters, string )
Arguments: characters - Characters to test for existence in the
<string> parameter. May be any combination of
one or more characters.
string - The character string to test if any of the
characters in the <characters> parameter exist.
Returns: Zero if none of the characters in <characters> are found in
<string>, otherwise returns the position in <characters> of
the 1st character found in <string>.
Description: ANYCHARSIN() is used to test if any characters in one string
are contained in a second string. If a character is found,
its position in <characters> is returned. This is useful to
validate that only valid characters are contained in strings
such as filenames.
Notes: If an invalid parameter or an invalid number of parameters
are passed, a zero will be returned and RLIBERROR() set.
Example: fname = SPACE(66)
@ 1,0 SAY "Enter filename:" GET fname VALID GoodFname(fname)
READ
RETURN
*-----------------------------------------------------------
FUNCTION GoodFname
PARAMETER filename
PRIVATE badchars, position
badchars = ' "/[]:*<>|+=;,?'
position = AnyCharsIn( badchars, filename )
IF position > 0
BUZZ()
BOXASK( 'W+/R', 'The "' + SUBSTR(badchars,position,1) +;
'" character is not allowed in filenames!',;
'Press any key to continue', 10 )
ENDIF
RETURN (position = 0)
Source: RL_ANYCH.PRG
See also: BOXASK()
RLIB Function Reference 36
Function: ARRAYLEN()
Purpose: Count the number of contiguous elements in an array.
Syntax: ARRAYLEN( array )
Arguments: array - Array in which to count the contiguous
elements.
Returns: The number of contiguous elements in an array, starting at
the beginning array element.
Description: ARRAYLEN() is useful for determining the actual number of
elements in an array where some elements may be missing. The
LEN() function returns the length of an array as it was
declared. However, if all of the array positions are not
filled, and you try to parse each element in a FOR loop, you
will encounter a run time error on the undeclared elements.
Notes: Will return zero if an invalid array parameter or no
parameter is passed and will set RLIBERROR().
Example: DECLARE array[10]
array[1] = "Hello"
array[2] = " world."
FOR x = 1 TO LEN(array) && will be 10
?? array[x] && on #3 will produce run-time
NEXT x && error Undefined Identifier
*-- corrected version
FOR x = 1 TO ArrayLen(array) && will be 2
?? array[x]
NEXT x
Source: RL_ARRAY.PRG
See also: ALIST()
RLIB Function Reference 37
Function: ATINSAY()
Purpose: Display an expression at coordinates in a specified color.
Syntax: ATINSAY( row, column, color, string )
Arguments: row - Numeric value indicating the row on which to
display <string>. Value must be between 0 and
24, or MAXROW() in the Clipper 5.0 version.
column - Numeric value indicating the column position on
which to display <string>. Value must be
between 0 and 79.
color - Character string indicating the color setting
to use in displaying <string>. This character
string must be consistent with Clipper's color
setting requirements. See the Clipper manual
under SET COLOR for details.
string - The character string to display at screen
coordinates <row>,<column> in <color>
Returns: Nothing useful, a null string.
Description: This function takes the repetition out of displaying strings
in various color settings. You simply give this function
the row,column coordinates, the color setting, and the string
to display and it does the rest, and resets the color when
finished.
Notes: If no parameters, an invalid number, or invalid type of
parameters are passed, no action is taken and RLIBERROR()
set.
Example: *-- old way of displaying a message in White on Red, then
*-- changing back to White on Black
SET COLOR TO w/r
@ 24,30 SAY 'A sample message on line 24'
SET COLOR TO w/n
*-- new way
ATINSAY( 24, 30, 'w/r', 'A sample message on line 24' )
Source: RL_ATINS.PRG
See also: BOXASK(), CENTER(), KEYINPUT(), RJUSTIFY(), SAYINBOX()
RLIB Function Reference 38
Function: BARMENU()
Purpose: Create horizontal light bar menus.
Syntax: BARMENU( row, options [, columns [, start [, altkeys [,;
exitkeys [, messages [, msg_row [, colors ]]]]]]])
Arguments: row - Numeric value which indicates the row on which
the bar menu is to appear. Value must be
between 0 and 24, or MAXROW() in the Clipper
5.0 version.
options - Array of character strings to display as bar
menu option choices.
columns - Optional array of numeric values used as column
numbers on which to display each option.
start - Optional starting array element number for the
menu option to highlight upon start-up.
altkeys - Optional list of alternate selection keys which
when pressed, cause an option to be selected.
exitkeys - Optional list of keys to cause a zero return
value exit. Pass a null string to skip. The
default key is Escape. Pass a value of False
(.F.) to disable the zero return value exit
capability altogether.
messages - Optional array of menu option messages which
are displayed as each menu option is
highlighted.
msg_row - Optional row number on which these messages
appear. The default row for these messages in
row 24. In the Clipper 5.0 version the default
message row in MAXROW(), the bottom screen row.
colors - Optional array of character strings specifying
the color settings to use. The colors used for
the different parts of the menu are specified
as follows:
colors[1] = Menu options
colors[2] = Menu highlight bar
colors[3] = <not used>
colors[4] = Menu messages
colors[5] = Selected option on exit
Returns: A numeric value indicating the number of the array element
option selected or zero if the escape key was pressed (or one
of the <exitkeys>).
RLIB Function Reference 39
Description: BARMENU() makes creating horizontal light bar menus a snap.
Although creating this type of menu has been simplified with
Clipper's PROMPT and MENU TO commands, this function offers
additional flexibility while keeping your code to a minimum.
Notes: In the Clipper 5.0 version of BARMENU(), the <row> parameter
may be any row value between 0 and MAXROW().
Optional parameters are not required, but if you wish to skip
an optional parameter, you must pass a dummy value. The best
dummy value to use is a null string "" (set up a memvar named
dummy where dummy = "").
In addition to the right and left arrow keys, the space bar
and back space keys move the menu bar to the right and left.
The menu bar line background (color[4]) is used to clear the
menu line and place it in that color.
Example: *-- declare arrays for menu and message options
DECLARE option[5], prompt[5]
*-- menu choices
option[1] = 'File'
option[2] = 'Edit'
option[3] = 'Next'
option[4] = 'Previous'
option[5] = 'Quit'
*-- corresponding message prompts
prompt[1] = 'Load, Save, Transfer, Erase, Quit'
prompt[2] = 'New orders, Repairs, Exchanges, Quit'
prompt[3] = 'Skip to the next entry'
prompt[4] = 'Skip to the previous entry'
prompt[5] = 'Quit and return to DOS'
*-- set up column position numbers so options fill screen
*-- File Edit Next Previous Quit
*-- if omitted options will look like this:
*-- File Edit Next Previous Quit
column[1] = 0
column[2] = 18
column[3] = 36
column[4] = 54
column[5] = 76
*-- let the down and up arrows also select Next and Previous
*-- the AT() position of altkeys in the string must match the
*-- corresponding array element number.
altkeys = 'FE' + CHR(24) + CHR(5) + 'Q'
RLIB Function Reference 40
*-- set up colors to be used
DECLARE colors[5]
colors[1] = 'B/BG' && options are Blue on Cyan
colors[2] = 'B/W' && menu bar is Blue on White
colors[3] = '' && not used
colors[4] = 'B/BG' && menu line also Blue on Cyan
colors[5] = 'W+/BG' && selected option Bright White
*-- keep Escape from causing exit, force them to press Q
xitkeys = .F.
*-- initial choice = 'File' = 1
choice = 1 && initial menu choice is #1, File
toprow = 1 && put menu on top row, row #1
msgrow = 2 && show menu messages on row #2
*-- display menu on row 1 with messages on row 2
choice = BARMENU( toprow, column, option, choice, altkeys,;
xitkeys, prompts, msgrow, colors )
Source: RL_BARME.PRG
See also: BOXMENU(), MULTIMENU(), PDOWNMENU()
RLIB Function Reference 41
Function: BEEP()
Purpose: Ring the system bell one or more times.
Syntax: BEEP( [ count ] )
Arguments: count - Optional numeric variable specifying the number
of times to ring the bell. If no parameter is
specified, the bell will be sounded one time.
Returns: A null string ("").
Description: This function merely rings the system bell the specified
number of times. BEEP() is a desired replacement for the ??
CHR(7) + CHR(7) sequence. It may not be very sophisticated,
but you may find yourself using it all the time!
Notes: No known weird behavior.
Example: *-- ring the bell
BEEP()
*-- ring it 10 times
BEEP(10)
Source: RL_BEEP.PRG
See also: BLIP(), BUZZ()
RLIB Function Reference 42
Function: BIN2DEC()
Purpose: Convert a binary number to its equivalent decimal value.
Syntax: BIN2DEC( bin_str )
Arguments: bin_str - A character string representing the binary
number to convert to decimal value.
Returns: The decimal value of the binary string parameter.
Description: BIN2DEC() converts a string that represents a binary number
into its decimal equivalent.
Notes: BIN2DEC() only converts positive numbers, there is no
provision for determining the sign bit. The <bin_str>
parameter must be a valid binary string, i.e. all characters
must be either a zero or a one. If a character is not a one
("1"), then BIN2DEC() will assume it to represent a zero in
its parse calculation.
If the required parameter is omitted, a zero will be returned
and RLIBERROR() set.
Example: bin_num = "11001101"
dec_val = BIN2DEC(bin_num)
? dec_val && result = 205
Source: RL_BIN2D.PRG
See also: DEC2HEX(), HEX2DEC()
RLIB Function Reference 43
Function: BLIP()
Purpose: Generate a blipping sound for warnings or errors.
Syntax: BLIP( [ count ] )
Arguments: count - Optional numeric value specifying the number of
times to make a BLIP sound. If no parameter is
specified, one BLIP will be sounded.
Returns: Zero.
Description: BLIP() is a convenient function whenever you want to make the
PC speaker emit a short "BLIP" sound, such as when the user
encounters an error condition. The Clipper function to do
this is TONE( frequency, duration ). For a Blip sound, the
frequency would be 500Khz and the duration should be around
2/18ths of a second. Instead of having to remember
TONE(500,2) as being the function to make a BLIP sound, it is
much easier to simply use a function named BLIP().
Notes: No limitations other than one that may be imposed upon the
Clipper TONE() function.
Example: *-- user does something wrong
BLIP()
*-- user does something really wrong!
BLIP(3)
Source: RL_BLIP.PRG
See also: BEEP(), BUZZ()
RLIB Function Reference 44
Function: BORDERBOX()
Purpose: Draw a box with a one line title area at the top.
Syntax: BORDERBOX( t,l,b,r, title, [,clear [,box [,color ]]] )
Arguments: t,l,b,r - Numeric values specifying the Top, Left, Bottom
and Right screen coordinates of the display
box. The top and bottom row values must be
between 0 and 24 (MAXROW() in 5.0), and the
left and right column values must be between 0
and 79.
title - Character string or expression to display as a
title in the box header area.
clear - Optional logical flag telling BORDERBOX()
whether or not to clear the box area. If
omitted or a non-logical parameter is passed,
the default value is True.
box - Optional character string to be used as the box
characters. Specify either double, single, or
solid box characters. If omitted or a non-
character value is passed, the default is
double.
color - Optional character string to use as the color
setting for the border box and header. If
omitted or a non-character value is passed, the
default is SETCOLOR().
Returns: True if the box was painted, false if an error occurred or if
any required parameters are missing or are an invalid type.
Description: This function paints a double line box with a one line title
in it. You can optionally specify whether or not to clear
the inside area.
Notes: The first four parameters are required. If omitted, the box
will not be drawn and a false value returned. If you do not
want a title in the box, pass a null string ("") for the
title parameter.
The title string is centered in the header area of the border
box. Because of this centering feature, no provision is made
to truncate the string if it is too wide to fit in the width
of the box. Therefore, you must ensure that the title string
is not wider that the width of the inside of the box. If so,
the title string will spill over on the left and right sides.
A false value for the clear parameter is useful for not
disturbing the contents of a previously displayed box on
re-entry. If omitted, the inside of the box area is cleared.
RLIB Function Reference 45
The box parameter lets you customize the frame. However, the
concept of the border box is that the left side of the border
line must match the horizontal boxing character. This
function only uses three characters, the single side (├), the
double side (╟), and the solid side (█). If the vertical
part of your box character string is none of these, you will
need to modify this function, or use only single, double or
solid boxes. See the Clipper documentation on the @ ... BOX
.. command for more information on box strings.
Example: *-- set up a bordered box for a PICKREC() display to show a
*-- help pick list of available Account numbers
top = 1
left = 40
bottom = 10
right = 68
title = "AVAILABLE ACCOUNT NUMBERS"
BORDERBOX( top, bottom, left, right, title )
*-- now fill with PICKREC() selections, note that the
*-- PICKREC() coordinates are offset 1 row/column in
display = "' '+AcctNum+' - '+AcctName+' '"
choice = PICKREC(top+3, left+1, bottom-1, right-1, display)
*-- output will look something like this
* ╔═══════════════════════════╗
* ║ AVAILABLE ACCOUNT NUMBERS ║
* ╟───────────────────────────╢
* ║ 1000 - OFFICE SUPPLIES ║
* ║ 1001 - EQUIPMENT PURCHASE ║
* ║ 1002 - EQUIPMENT LEASE ║
* ║ 1003 - TELEPHONE EXPENSE ║
* ║ 1004 - RENT ║
* ║ 1005 - UTILITIES ║
* ╚═══════════════════════════╝
Source: RL_BORDE.PRG
See also: PICKREC(), POPUPPICK()
RLIB Function Reference 46
Function: BOXASK()
Purpose: Pop up a centered message box using multiple message strings.
Syntax: BOXASK( [color] [keys] message1 [...message9] [timeout] )
Arguments: color - If the FIRST parameter has a slash "/"
character in the 2nd, 3rd, or 4th position,
this parameter will be interpreted as the color
setting for the message box. (All color
strings look like: R/W, or R+/W, or R+*/W)
keys - If the FIRST or SECOND parameter begins with a
dollar sign character "$", the parameter will
be interpreted as a string of valid keys that
can be pressed to terminate BOXASK(). The "$"
character is easily remembered because it is
the Clipper substring "contained in" operator.
message1,9 - Any other character parameters, including the
first and or second parameters if they don't
meet the above conditions, will be displayed as
BOXASK() messages. Up to nine message lines
may be passed and displayed.
timeout - If the LAST parameter is a numeric value, it
will be used as a timeout value for the message
box. This timeout is the number of seconds
BOXASK() will wait for a keypress. If no key
is pressed before the timeout is reached,
BOXASK() will exit and return a null string.
If no timeout is supplied, BOXASK() will wait
forever for a keypress.
Returns: The single character pressed in response to the message box
displayed on the screen. If the key pressed is an alphabetic
character BOXASK will return the character normalized to
upper case. As a consequence, character comparisons need
only compare against upper case characters. See examples.
Description: BOXASK() is a function that becomes addictive! Once you
start using it you'll never stop. It's perfect for
displaying all sorts of messages in a consistent manner.
BOXASK() displays up to nine lines of text messages, centered
on the screen in a single line box, in a defined color. Each
line may be up to 68 characters long. All of the screen
centering is done automatically. After the message box is
displayed BOXASK() waits for a user keypress (in response to
the message). If no time out parameter is given, BOXASK will
wait forever for a response. If the optional keys parameter
is supplied, the characters that appear in the keys string
will be the only character accepted as valid keypresses to
terminate BOXASK().
RLIB Function Reference 47
Notes: BOXASK() accepts a variable number of parameters and will act
differently on the parameters depending on their format. All
parameters (except the timeout, which must be the last
parameter) are expected to be character type.
If the first parameter is a color setting, BOXASK() will use
that color combination instead of the default current color
SETCOLOR(). If either the first or second parameters begin
with the "$" character, the string following the dollar sign
will be used as a list of valid keypresses from which to
exit.
Ideally, all functions should be as BLACK BOX as possible.
This means that if a function alters a system state such as
the screen color, it should restore the system to the way it
was on entry. Since BOXASK() will query a user for a
keypress, ideally the cursor should be on. However, since
Clipper Summer '87 has no native way of querying the state of
the cursor, BOXASK() has no way of knowing whether or not the
cursor was on, and can not set cursor on and expect to
restore the system to the way it was. To get around this
limitation, and still allow BOXASK to turn the cursor on, an
RLIB function named SETCURSOR() is provided. (See the
documentation SETCURSOR) If you utilize the SETCURSOR()
function, BOXASK() will know and will be able to restore the
state of the cursor on exit. The Clipper 5.0 version uses
the internal SETCURSOR function instead.
If the key that is pressed in response to BOXASK() is a lower
case letter (a - z), BOXASK() will return the response as an
upper case letter. In other words, BOXASK() will uppercase
letters between a-z, so you do not have to use the UPPER()
function to test if the user pressed a "Y" for instance. All
other keys are returned as their CHR() values. BOXASK() will
wait forever for a keypress unless a timeout value is given.
In the Clipper 5.0 version of BOXASK(), the PARAMETERS have
remained as PRIVATE variables since they are referenced via
macro substitution, and this will not work with local
variables.
Example: *-- example of a SEEK or LOCATE failure notification
msg1 = "No record was found with the name you selected!"
msg2 = "This name may have been misspelled"
msg3 = "Press [ENTER] to try again, or [ESCAPE] to abort"
color = "W+/R"
keys = "$" + CHR(13) + CHR(27)
*-- present message, wait 30 seconds, default to ENTER
IF BOXASK( color, keys, msg1, msg2, msg3, 30 ) = CHR(27)
*-- ESCAPE key was explicitly pressed
EXIT
ENDIF
*-- will fall through if timed out, result = CHR(13) or NULL
RLIB Function Reference 48
Source: RL_BOXAS.PRG
See also: ABOXASK(), SAYINBOX()
RLIB Function Reference 49
Function: BOXMENU()
Purpose: Create boxed framed highlight bar (pop up) menus.
Syntax: BOXMENU( row, column, options [, choice [, altkeys;
[, exitkeys [, messages [, msg_row [, colors;
[, header [, restore ]]]]]]]]] )
Arguments: row - Numeric value indicating the row for the top
left corner of the menu box. Value must be
between 0 and 24, or MAXROW() in the Clipper
5.0 version.
column - Numeric value indicating the column for the top
left corner of the menu box. The value must be
between 0 and 79.
options - Array of character strings to use as menu
options. Each element of the array is
displayed as a menu option filling the box.
choice - Optional numeric value indicating the starting
menu option number. Value checked to be
between 1 and the number of elements in the
option array. If an out of range value is
given, the starting number will be 1.
altkeys - Optional character string indicating what keys
may be pressed to select the corresponding menu
option. The default is the first letter of
each of the menu options but, if this string is
provided, it is added to that list. The
requirement is that the AT() position of the
character in the alternate key list is the
numeric equivalent of the corresponding menu
choice.
exitkeys - Optional character string indicating which keys
if pressed will cause an exit and return zero.
If omitted or an empty (or null) string is
specified, the Escape Key will default to being
the only key to cause a return zero exit. If
this parameter is specified as a logical .F.,
no keys will cause a return 0 exit (it will be
disabled), and only the Enter Key will cause an
exit condition.
messages - Optional array of character strings to display
as messages corresponding to each of the menu
options.
msg_row - Optional numeric value indicating the row for
the optional prompt messages to appear. This
value must be between 0 and 24, or MAXROW() in
RLIB Function Reference 50
the Clipper 5.0 version. The default is row
24. In the 5.0 version the default row is
MAXROW(), the bottom screen row.
colors - Optional array of character strings specifying
the color settings to use. The colors used for
the different parts of the menu are specified
as follows:
color[1] - Menu choices (item options)
color[2] - Menu selection bar
color[3] - Active menu box (on entry)
color[4] - Inactive menu box (on exit)
color[5] - Menu choice upon selection
color[6] - Messages displayed on promptrow
header - Optional character string which, if supplied
will force BOXMENU() to extend the box around
the menu to include a header area. The string
supplied will be centered in this area as a
menu title. See BORDERBOX() for additional
details.
restore - Optional logical value indicating whether or
not to save and restore the screen region
underneath the menu on exit. The default is
false.
Returns: The number of the array element option picked, or 0 if escape
was pressed.
Description: BOXMENU() follows a popular and logical sequence for
producing box style menus. The active menu is surrounded by
a double line box. When it becomes inactive after a choice
is made, the box border changes to a single line to indicate
the menu is no longer active. If the row and/or column
positions supplied are out of bounds (not between 0 and 24
(MAXROW() in 5.0 version), and 0 and 79) a default row or
column of 1 will be used. Also, since this is mainly a menu
building tool, no provision has been made to scroll menu
items below the bottom of the menu box. Consequently, you
should consider how many options will be in the menu when
determining the top row, as the bottom of the box is
calculated by adding the number of options in the array. If
more elements exist in the array than will fit in the box,
unpredictable screen displays will occur. This exclusion was
made for the benefit of speed and compactness of code. If a
scrollable menu is needed, use ACHOICE().
Notes: If an optional parameter is skipped, you must pass a dummy in
its place.
If you use the color feature, DECLARE your colors array to
have at least 6 elements. If the colors option is not
RLIB Function Reference 51
specified or there are less than 5 elements, then the default
colors are used. These defaults are: the current Standard
color is used for the box and item displays, and the Enhanced
color is used for the menu bar. The sixth element is new to
version 3.0 (See below)
The colors array may now contain six elements. The sixth
element is used as the color for displaying the optional
messages on <promptrow>. In RLIB version 2.0, these messages
used to be displayed in the same color as the menu options
which was not always (and rarely) desirable. To maintain
upward compatibility, the color array table may remain at 5
elements. The 6th element is optional. If the 6th element
for the optional messages color is not given, then the Option
color (element #1) is used.
Example: *-- declare arrays for menu and message options
DECLARE option[5], message[5]
*-- menu choices
option[1] = " 1. Add new records (Append) "
option[2] = " 2. Edit records (Change) "
option[3] = " 3. Delete records (Remove) "
option[4] = " 4. Update records (Modify) "
option[5] = " 5. Quit and return (eXit) "
*-- corresponding messages
message[1] = "Add new records to the database"
message[2] = "Edit records already in the database"
message[3] = "Delete selected records"
message[4] = "Update dates of last appointments"
message[5] = "Leave this menu and return to previous"
*-- in addition to 1,2,3,4, or 5, (default select keys)
*-- let the following keys also select the choices
alt_keys = 'AEDUQ' + 'ACRMX'
DECLARE colors[6]
colors[1] = 'N/BG' && options are Black on Cyan
colors[2] = 'W+/GR' && menu bar is Bright White on Brown
colors[3] = 'R+/BG' && active menu is Bright Red on Cyan
colors[4] = 'R/BG' && in-active is Red on Cyan
colors[5] = 'R/BG' && selected choice is Red on Cyan
colors[6] = 'BG/N' && messages are Cyan on Black
*-- allow Escape and Left and Right arrow keys to exit
exit_keys = CHR(27) + CHR(19) + CHR(4)
*-- start with first choice
choice = 1
*-- header message
header = "AVAILABLE OPTIONS"
RLIB Function Reference 52
*-- put up menu on row 2, column 10, with messages on row 24
choice = BOXMENU( 2,10, option, choice, alt_keys, exit_keys,;
message, 24, colors, header )
Source: RL_BOXME.PRG
See also: BARMENU(), MULTIMENU(), PDOWNMENU()
RLIB Function Reference 53
Function: BRIGHT()
Purpose: Convert a Clipper color string to its bright equivalent.
Syntax: BRIGHT( [color] )
Arguments: color - Optional character string indicating the color
setting from which to extract the bright
portion. If omitted, the current color setting
returned by SETCOLOR() is used.
Returns: A character string indicating the bright color setting. This
bright color setting is created by extracting the standard
part of the color setting and adding a '+' onto the
foreground part.
Description: BRIGHT() returns the bright color attribute setting for
either the current color, or the optionally supplied color
parameter. This is useful for switching around color
combinations without having to clutter up your code with all
that SUBSTR(SUBSTR(... garbage.
Notes: If the standard color setting foreground is white, then
BRIGHT() makes the high intensity color Yellow (GR+) instead
of bright white. This was done out of preference and remains
for compatibility with RLIB version 2.0.
Example: *-- save incoming color, then get bright portion
save_color = SETCOLOR(BRIGHT())
CENTER(10,'*** TRY AGAIN ***')
SETCOLOR(save_color)
Source: RL_BRIGH.PRG
See also: GETPARM()
RLIB Function Reference 54
Function: BUZZ()
Purpose: Generate a buzzing sound for warnings or errors.
Syntax: BUZZ( [ count ] )
Arguments: count - Optional numeric variable specifying the number
of times to make a BUZZ sound. If no parameter
is specified, one BUZZ will be sounded.
Returns: A numeric zero.
Description: Whenever you want to make the PC speaker emit a short "BUZZ"
sound, such as when the user encounters an error condition,
the Clipper function to do this is TONE(frequency,duration).
For a Buzz sound, the frequency would be 100Khz and the
duration should be around 6/18ths of a second. Instead of
having to remember the command TONE(100,6) as being the
command to make a BUZZ sound, it is easier to simply use a
function named BLIP(), BUZZ(), or BEEP().
Notes: Nothing weird.
Example: *-- user does something wrong
BUZZ()
*-- user does something really wrong!
BUZZ(3)
Source: RL_BUZZ.PRG
See also: BEEP(), BLIP()
RLIB Function Reference 55
Function: CALENDAR()
Purpose: Pop up a configurable calendar on the screen
Syntax: CALENDAR( [ date [, colors [, row [, column ] ] ] ] )
Arguments: date - Optional date onto which to position the
cursor.
colors - Optional array of character strings specifying
the color settings to use. The colors used for
the different parts of the on screen calendar
are specified as follows:
color[1] - Calendar box and headers
color[2] - Current day marker, (the cursor)
color[3] - Day numbers inside the calendar
row - Optional numeric top row of the calendar.
Valid rows are from row 0 to row 10. If not
specified or an invalid row value is given, the
default row is 1.
column - Optional numeric left column of the calendar.
Valid columns are from column 0 to column 56.
If not specified or an invalid column value is
given, the default column is 56.
Returns: The date selected by pressing ENTER, or an EMPTY date if
Escape was pressed.
Description: Function to provide a pop up calendar from which to select a
date. Typical uses are to provide pop-up help for entering
dates in date fields. The example below shows how this can
be done. Other uses would include a global SET KEY procedure
to invoke a procedure that calls CALENDAR(). This provides
the end user with a handy reference calendar at any time.
The calendar display is 15 rows tall and 24 columns wide, and
appears as:
RLIB Function Reference 56
╒══════════════════════╕
│ November 1990 │
├──────────────────────┤
│ S M T W T F S │
│ 1 2 3 │
│ 4 5 6 7 8 9 10 │
│ 11 12 13 14 15 16 17 │
│ 18 19 20 21 22 23 24 │
│ 25 26 27 28 29 30 │
│ │
├──────────────────────┤
│ Day Month Year │
│ < > PgUp ^PgUp │
│ v ^ PgDn ^PgDn │
╘══════════════════════╛
^
│
└── The unprintable left, right, up, and down
arrow key characters appear here on the
screen.
CALENDAR() is fairly perpetual inasmuch as Clipper's date
routines are. The screen calendar can be moved and
CALENDAR() will remember the last screen location the next
time it is invoked (during an application session). The
default location of the calendar is in the upper right hand
corner of the screen @ 1,56.
Notes: CALENDAR() will not handle dates beyond 2999. If the color
string is not provided, the current color setting will be
used to determine the Standard and Enhanced colors, and
BRIGHT() will be used to create the color used for the
calendar numbers inside the box.
If you provide row,column parameters, CALENDAR() will
position to that location regardless of where the user may
have moved it with the control-arrow keys.
CALENDAR() handles the following keys as follows:
Date positioning keys:
----------------------------------
Up - Back one week
Down - Forward one week
Left - Back one day
Right - Forward one day
PgUp - Back one month
PgDn - Forward one month
Ctrl-PgUp - Back one year
Ctrl-PgDn - Forward one year
RLIB Function Reference 57
Calendar screen placement keys
----------------------------------
Ctrl-Up - Move up one row
Ctrl-Down - Move down one row
Ctrl-Left - Move left one column
Ctrl-Right - Move right one column
The <colors> argument may optionally be a SETCOLOR() style
color string where the 1st, 2nd, and 3rd colors correspond to
the Standard, Enhanced and Unselected color positions
respectively. This permits an in-line call to CALENDAR() to
take the form CALENDAR(DATE(),"R/W,W/R,,R+/W") which can
simplify having to declare an array just to pass color
settings.
Example: *-- set key procedure to provide F1 pop-up date help in READs
PROCEDURE MyHelp
PARAMETERS callproc, linenum, readvar
PRIVATE temp
SET KEY 28 TO && disable help while in help
IF TYPE(readvar) = "D" && if variable is a date type
temp = CALENDAR(&readvar) && pop up the calendar
IF .NOT. EMPTY(temp) && if a date was selected
&readvar = temp && assign to the readvar
ENDIF
ENDIF
SET KEY 28 TO MyHelp && turn help back on
RETURN
Source: RL_CALEN.PRG
See also: STR2DATE()
RLIB Function Reference 58
Function: CATF()
Purpose: Copy array values to database fields (Copy Array To Fields)
Syntax: CATF( array [, memcopies [, first [, last ]]] )
Arguments: array - Array of values to copy into database fields.
memcopies - Optional logical flag to copy array values to
existing public memory variables with the same
names as database fields.
first - Optional numeric value indicating the first
field in the database to be copied. If not
specified the default is field #1.
last - Optional numeric value indicating the last
field in the database to be copied. If not
specified the default is FCOUNT().
Returns: True if all elements copied successfully.
Description: CATF() is a function to copy values of each array element in
the specified array to the corresponding ordinal field in the
current record of the currently selected database, optionally
specifying to copy these array values to memory variable
copies rather than to the actual database fields.
This function is useful for stacking database record data
into and out of arrays. The companion function is CFTA() to
copy fields to arrays, and the MEMORIZE() - MREPLACE() -
FORGET() team of functions. Typically a database's record
contents are placed in PUBLIC variables with MEMORIZE(),
edited, then saved back to the database with MREPLACE(), then
released with the FORGET() function. CATF() and CFTA() let
you temporarily hold and stack these field values into arrays
which can be later retrieved, or copied (saved) into the
database, or another database with the same structure. This
forms a nice set of functions for simply manipulating data
among numbers of databases that share the same structure.
Notes: Assumes that ARRAY has at least FCOUNT() elements and that
the array element positions match up with the database field
numbers and also that the data type in each array element
MATCHES the data type of the corresponding database record.
This also assumes that if the database fields are being
REPLACEd that any necessary file or record locks are in
place.
The database whose structure defines the fields being
replaced MUST be currently selected since CATF() uses the
field definitions from the currently selected database for
its operations.
RLIB Function Reference 59
Example: *-- swap data between record #1 and record #2 in a database
DECLARE rec1[FCOUNT()], rec2[FCOUNT()]
GOTO 1 && record #1
CFTA(rec1) && copy field values to rec1 array
GOTO 2 && record #2
CFTA(rec2) && copy field values to rec2 array
CATF(rec1) && shove in record #1's field values
GOTO 1 && back to record #1
CATF(rec2) && copy rec2 array field values in
Source: RL_CATF.PRG
See also: CFTA(), FORGET(), MEMORIZE(), MREPLACE()
RLIB Function Reference 60
Function: CENTER()
Purpose: Center a string and/or get the center position.
Syntax: CENTER( [ row ,] string [, color ] )
Arguments: row - Optional numeric value which, if passed, will
cause CENTER() to print <string> centered on
row number <row>. Value checked to be between
0 and 24, or MAXROW() in the Clipper 5.0
version.
string - Target character string used to determine
center position, and optionally, to print on
row number <row> if <row> is given as a
parameter.
color - Optional character color string (in Clipper
format) used to display <string> on screen.
Returns: The column number to center <string> on an 80 column monitor.
If <row> is specified, it displays <string> centered on
<row>.
Description: Almost everyone has a function to center text on the screen.
So why should RLIB have one also? This does just what you
think; it takes the string provided, and returns the numeric
column position to center the text on an 80 column display.
Only this center can also do the displaying, and can do that
job in the color you select. All this helps cut down on the
amount of code.
Notes: The maximum string length supported, naturally, is 80 since
that is the maximum screen width.
Example: *-- this method requires two lines of code and a memvar
memvar = 'This is the string to center on row 23'
@ 23,CENTER(memvar) SAY memvar
*-- or without assigning string to memvar (very wordy)
@ 23,CENTER('This is the string to center on row 23') ;
SAY 'This is the string to center on row 23'
*-- the simpler way
CENTER(23,'This is the string to center on row 23')
*-- and if you want it in another color.. the old way
save_color = SETCOLOR("R/W")
@ 23,CENTER("Please wait...") SAY "Please wait..."
SETCOLOR(save_color)
*-- CENTER() cuts down the SLOCs (Source Lines Of Code)
CENTER( 23, "Please wait...", "R/W" )
RLIB Function Reference 61
Source: RL_CENTE.PRG
See also: MIDDLE()
RLIB Function Reference 62
Function: CFTA()
Purpose: Copy database field values to an array (Copy Fields To Array)
Syntax: CFTA( array [, memcopies [, first [, last ]]] )
Arguments: array - Existing array to receive field values from the
database fields.
memcopies - Optional logical flag to fill the array values
from existing public memory variables with the
same names as database fields.
first - Optional numeric value indicating the first
field in the database to copy. If not
specified the default is field #1.
last - Optional numeric value indicating the last
field in the database to copy. If not
specified the default is FCOUNT().
Returns: True if all field values copied successfully.
Description: Function to copy values of each field in the current record
of the currently selected database into the array specified,
optionally indicating to copy these values from existing
public memory variables with the same names as the database
fields.
This function is useful for stacking database record data
into and out of arrays. The companion function is CATF() to
copy array values to fields, and the
MEMORIZE()-MREPLACE()-FORGET() team of functions. Typically
a database's record contents are placed in PUBLIC variables
with MEMORIZE(), edited, then saved back to the database with
MREPLACE(), then released with the FORGET() function. CATF()
and CFTA() let you temporarily hold and stack these field
values into arrays which can be later retrieved, or copied
(saved) into the database, or another database with the same
structure. This forms a nice set of functions for simply
manipulating data among numbers of databases that share the
same structure.
Notes: Assumes that ARRAY has at least FCOUNT() elements.
The database whose structure defines the fields being copied
MUST be currently selected since CFTA() uses the field
definitions from the currently selected database for its
operations.
Example: *-- swap data between record #1 and record #2 in a database
DECLARE rec1[FCOUNT()], rec2[FCOUNT()]
GOTO 1 && record #1
RLIB Function Reference 63
CFTA(rec1) && copy field values to rec1 array
GOTO 2 && record #2
CFTA(rec2) && copy field values to rec2 array
CATF(rec1) && shove in record #1's field values
GOTO 1 && back to record #1
CATF(rec2) && copy rec2 array field values in
Source: RL_CFTA.PRG
See also: CATF(), FORGET(), MEMORIZE(), MREPLACE()
RLIB Function Reference 64
Function: CHANGED()
Purpose: Test if memory copies of database fields have been changed.
Syntax: CHANGED()
Arguments: None
Returns: True if any changes made to field variables since the last
REPLACE, MREPLACE(), or MEMORIZE().
Description: CHANGED() is a database function designed to serve as a
replacement for the Clipper UPDATED() function when used in
conjunction with the MEMORIZE() function. It may also be
used to compare the contents of all fields in a record to
previously MEMORIZED() copies to determine if changes have
been made to the record since it was MEMORIZED(). CHANGED()
tests to see if memory field variables have been changed from
the associated field values after an edit. This works better
than Clipper's UPDATED() function because once you test for
UPDATED(), the flag is cleared. So if you go back and READ
the data again, in a loop for instance, but do NOT change
anything this second time around, UPDATED() will return .F.,
even though something was changed previously. Ideally, when
testing for UPDATED() you want it to be .T. if any values
have changed since the last REPLACE.
Notes: CHANGED() is used in conjunction with the MEMORIZE(),
MREPLACE(), and FORGET() functions. These functions
reference all of the fields in the current database and store
the field values to memory variables of the same name,
prefaced by M->.
Example: *-- this way will not trap an update on a re-read
DO WHILE .T.
@ 1,0 GET M->name && get data
@ 2,0 GET M->city
@ 3,0 GET M->state
READ
*-- if changed this will be true, however after going back
*-- through the second time UPDATED() will only be true if
*-- another change was made. Pressing Escape the second
*-- time will not be trapped as UPDATED() will be False.
IF UPDATED()
IF LASTKEY() = 27 && escape key
IF BOXASK("W/R", "Abort edit? (y/N) ") != "Y"
LOOP
ENDIF
ENDIF
ENDIF
EXIT
ENDDO
*-- the following way will work correctly!
RLIB Function Reference 65
*-- save all database field data to field variables
MEMORIZE()
DO WHILE .T.
*-- get data (remember to preface memvars with M->)
@ 1,0 GET M->name
@ 2,0 GET M->city
@ 3,0 GET M->state
READ
*-- CHANGED() will compare all M->memvars with the twin
*-- field name to see if any values are different, and
*-- will catch it no matter how many times thru the loop
IF CHANGED()
IF LASTKEY() = 27 && escape key
IF BOXASK("W/R", "Abort edit? (y/N) ") != "Y"
LOOP
ENDIF
ENDIF
ENDIF
EXIT
ENDDO
Source: RL_CHANG.PRG
See also: MEMORIZE(), MREPLACE(), FORGET()
RLIB Function Reference 66
Function: CHECKFILE()
Purpose: Verify valid filenames, optionally popping up a pick list.
Syntax: CHECKFILE( @filename [, filelist [, mustexist [, confirm ]]])
Arguments: @filename - Character file name to check. The file name
may be fully qualified or have no directory
path, in which case the current default
directory will be used for file searches. This
parameter must be PASSED BY REFERENCE by
prefacing the variable name with the "@"
character as shown above. Passing this
variable by reference lets CHECKFILE() change
the value to a new filename selected through
the pop-up directory option.
listfiles - Optional logical value indicating whether or
not to pop-up a file listing window if
wildcards are entered. The default value is
True (.T.)
mustexist - Optional logical value indicating whether or
not to verify that the filename entered exists.
The default value is False (.F.)
confirm - Optional logical value indicating whether or
not to confirm a file overwrite if the file
exists. The default value is True (.T.)
Returns: True if a valid filename was entered and all optional flag
conditions are met. If any of these conditions fail, or if
the user presses ESCAPE, false is returned.
Description: CHECKFILE() is a high level file function usually used during
the VALID clause of an @...GET...READ, to test if the
filename entered is a valid DOS file name. The optional
flags permit control over other features provided by
CHECKFILE() which may or may not be desired, depending upon
the application.
The default parameters make CHECKFILE() an ideal VALID clause
for entering target filenames for such things as reports.
The defaults are: <mustexist> is False since the target file
must not exist in this situation, and <confirm> is True to
notify the user before overwriting a file. The RLIB function
GETFILE() makes a call to CHECKFILE() in this way.
Notes: The <listfiles> parameter is True by default. If the
filename that is to be checked contains wildcards (* or ?),
CHECKFILE() will pop-up a centered file directory window of
the directory specified in the filename. If no directory
path was entered as part of the filename, the directory
listing will be of the current directory. This feature can
RLIB Function Reference 67
be disabled by setting the <listfiles> parameter to False.
If the <filename> parameter is blank and the <listfiles>
parameter is True (the default), a directory listing will
pop-up when ENTER is pressed.
The pop-up file listing is provided by the RLIB function
PICKFILE(). See the documentation on PICKFILE() for more
information.
If a filename is selected from the pop-up directory listing,
CHECKFILE() uses Clipper's pass-by-reference feature to
assign the selected file name to the variable referenced by
the @filename parameter. In the case of the READ...VALID
example cited above, this has the effect of stuffing the
selected filename into the READ, but in a much more elegant
manner than KEYBOARDing characters. However, since the "@"
pass-by-reference operator cannot be applied to array
elements, the filename argument to CHECKFILE() may not be an
array element. Attempting to do so will result in a compile
time error - "@ error" in Summer '87 or "Illegal use of @
(pass by reference) operator" in 5.0. The bottom line is
that, fortunately, the compiler won't let you do it. For
this reason, only use memory variables as the data being
READ.
The <mustexist> parameter is False by default. Its purpose
is to optionally force CHECKFILE() to verify that the
filename entered does in fact exist. This is useful in
applications that request the user to enter a filename for a
function that requires an existing file. An example would be
a function that uses MEMOWRITE(MEMOEDIT(MEMOREAD(filename)))
to implement a rudimentary editor. The statement to query
the user for a file name must verify the file exists.
CHECKFILE() can do all that with one VALID statement.
The <confirm> parameter is True by default. Its purpose is
to optionally force CHECKFILE() to confirm that the user
wants to overwrite a file that already exists. This is
useful in report applications where the user is queried to
enter a target print file name for disk output.
If an optional parameter is to be skipped a dummy parameter
must be supplied in its place. Use a null ("") for a dummy
parameter.
If a condition is not met, CHECKFILE() will BLIP() or BUZZ()
(depending on the severity) and display a BOXASK() or
SAYINBOX() error message in color "W+/R" on color monitors or
"N/W" on monochrome monitors.
The part of CHECKFILE() that verifies valid DOS filenames
checks the filename for any of the invalid characters
( "/[]*<>|+=;,?) using the ANYCHARSIN() function, and
displays an error message indicating the offending character
RLIB Function Reference 68
if one is encountered.
Example: mfile = SPACE(120)
@ 10, 0 SAY "Enter target file for report output:";
@ 10,37 GET mfile PICTURE "@!KS40" VALID CHECKFILE(@mfile)
READ
Source: RL_CHECK.PRG
See also: ANYCHARSIN(), GETFILE(), PICKFILE()
RLIB Function Reference 69
Function: CLOSEAREA()
Purpose: Close multiple database work areas with one command.
Syntax: CLOSEAREA( [ area [, area ... ] ] )
Arguments: area - Character or numeric work area to close. If
<area> is character, it must be a valid alias
name of an open work area. If <area> is a
number, it must be a valid select area number.
If no arguments are given, the current work
area is closed.
Returns: True if the requested work areas have been closed.
Description: CLOSEAREA() allows you to close up to nine database files at
one time with one line of code without having to leave the
currently selected work area. This is useful when you have
several database files open and you want to close all but one
or two of them.
Notes: Select area numbers and work area Alias names may be
intermixed as arguments. Up to nine areas may be specified.
If no argument is given, this will be the same as issuing the
USE command, closing the current work area.
CLOSEAREA() steps through the work areas specified and issues
a USE command to close the database. After all is finished,
control is returned to the selected work area at entry. A
return value of .F. should only occur if an invalid argument
is passed (i.e. a Date, Memo, or Logical type parameter) or
if you specify an alias name that does not exist. Normally
an invalid alias name will trigger a TYPE MISMATCH runtime
error, so CLOSEAREA() tests any alias names for their proper
existence.
Example: If you had seven databases open and wanted to close all but
the databases in work areas 1 and 3 (aliases SALES and
CUSTOMERS), one of the ways to accomplish this task would be
with the following code:
SELECT 1
marker1 = RECNO()
SELECT 3
marker3 = RECNO()
CLOSE DATABASES
SELECT 1
USE Sales INDEX Sales ALIAS Sales
GOTO marker1
SELECT 3
USE Cust INDEX Cust ALIAS Customers
GOTO marker3
RLIB Function Reference 70
*-- Another way to do this would be as follows:
SELECT 2 && Invoices
USE
SELECT 4 && Payments
USE
SELECT 5 && Payables
USE
SELECT 6 && Inventory
USE
SELECT 7 && Ledger
USE
*-- With CLOSEAREA(), the following is a LOT easier and
*-- simpler!!!
CLOSEAREA(2, 4, 5, 6, 7)
*-- or, even more readable is:
CLOSEAREA("Inovices", "Payments", "Payables", 6, "Ledger")
*-- This example shows how you can mix numeric and character
*-- arguments.
Source: RL_CLOSE.PRG
See also: OPENED()
RLIB Function Reference 71
Function: DBFCREATE()
Purpose: Dynamically create a database from a structure array.
Syntax: DBFCREATE( filename, structure [, appendfile ] )
Arguments: filename - Character filename to create. This must be a
valid DOS filename and may be fully qualified
(i.e. have a full path specification). If no
path specification is provided as part of the
filename, the file is created in the current
default directory.
structure - An array containing the structure definition
for the .DBF file to be created. This is an
array of character strings with each element
defining the structure of each field. See the
tables below for examples.
appendfile - Optional character filename of the .DBF format
file to append into the newly DBFCREATED file.
This filename may be fully qualified and, if
not, the file must exist in the current default
directory.
Returns: True if the file was successfully created, false otherwise.
Description: DBFCREATE() is a database function that creates a database
file from a structure array. If an append file is specified,
it is appended into the newly created database file. The
format of the character structure array is as follows:
ELEMENT FIELD NAME TYPE LENGTH DECIMALS
---------- ---------- ---- ------ --------
array[1] = "NAME C 30 "
array[2] = "BIRTHDATE D 8 "
array[3] = "AGE N 2 0"
array[4] = "MALE L 1 "
array[5] = "NOTES M 10 "
This structure is not rigid. The number of spaces between
the field name, field type, length and decimals may vary.
The only rules are: space for field names must be at least 10
spaces; field type - 1 space, field length - 4 spaces, and 4
spaces for field decimals. If the field type is character,
no field decimal need be specified.
Notes: Although the Clipper manual does not state that the CREATE,
CREATE FROM, or APPEND FROM commands require the target file
to be FLOCK()ed or USEd EXCLUSIVEly, in a Network
environment, for safety sake, and for data integrity sake,
you may wish to SET EXCLUSIVE ON before calling this
function. Although you may not experience any problems by
not doing so, common data design sense should dictate
RLIB Function Reference 72
otherwise.
Example: *-- create a database named TEST.DBF, and append existing
*-- old data in from TEST.BAK
DECLARE struc[5]
struc[1] = "NAME C 20 0"
struc[2] = "ADDRESS C 30 0"
struc[3] = "CITY C 20 0"
struc[4] = "STATE C 2 0"
struc[5] = "ZIP C 5 0"
DBFCREATE( "TEST.DBF", struc, "TEST.BAK" )
Source: RL_DBFCR.PRG
See also: CLOSEAREA(), OPENED()
RLIB Function Reference 73
Function: DEC2HEX()
Purpose: Convert decimal numeric value to a hexadecimal string.
Syntax: DEC2HEX( dec_val )
Arguments: dec_val - The decimal numeric value to convert to a
hexadecimal character string.
Returns: The hexadecimal equivalent of <dec_val> as a character
string.
Description: This function converts numeric decimal values into their
hexadecimal equivalent. There are many libraries that
implement this feature but it's nice to know you don't need
assembly language experience to accomplish this task!
Notes: Only converts positive numbers.
Example: dec_num = 15
hex_str = DEC2HEX(dec_num)
? hex_str && result = "F"
? DEC2HEX(11281950) && returns "AC261E"
Source: RL_DEC2H.PRG
See also: BIN2DEC(), HEX2DEC()
RLIB Function Reference 74
Function: DECRYPTED()
Purpose: Decrypt a character string encrypted with ENCRYPTED()
Syntax: DECRYPTED( string )
Arguments: string - The character encrypted with ENCRYPTED() to be
decrypted.
Returns: An un-encrypted version of <string> of identical length.
Description: The is the companion to the ENCRYPTED() function. Strings
encrypted with the ENCRYPTED() function must be decrypted
with this function.
Notes: Strings decrypted with this function must have been encrypted
with the companion ENCRYPTED() function.
Example: *-- check a password stored in encrypted format
@ 5,0 SAY "Enter your password:"
*-- allow only 40 characters, upper case, and echo dots
password = KEYINPUT(40, .T., .F.) && see KEYINPUT()
USE system.dbf
IF .NOT. password == DECRYPTED(pword)
*-- assumes password stored on encrypted format.
SAYINBOX( "W/R", "*** ACCESS DENIED! ***", 6 )
USE
RETURN
ENDIF
Source: RL_DECRY.PRG
See also: ENCRYPTED(), KEYINPUT()
RLIB Function Reference 75
Function: DIVIDE()
Purpose: Divide numbers with built in divide by zero protection.
Syntax: DIVIDE( dividend, divisor )
Arguments: dividend - Number to be divided
divisor - Number to divide it by.
Returns: <dividend> / <divisor> with divide by zero protection.
Description: This is a simple function but proves to be invaluable when
doing division math. Invariably in reports you always end up
not trapping some circumstance where a number may be divided
by zero and cause a runtime error. Very bad! With
consistent use of this UDF in place of simple division, you
can rest easy.
Notes: If parameters are omitted or are non-numeric, zero is
returned and RLIBERROR() set.
Example: ? DIVIDE(10,2) && result = 5
Source: RL_DIVID.PRG
See also: BIN2DEC(), DEC2HEX(), HEX2DEC()
RLIB Function Reference 76
Function: ENCRYPTED()
Purpose: Encrypt a character string
Syntax: ENCRYPTED( string )
Arguments: string - The character to be encrypted.
Returns: An encrypted version of <string> of identical length.
Description: The are several Encrypt/Decrypt functions available, most of
which are written in assembly or C. This is a simple
encryption scheme done entirely in Clipper which is not only
functional, but the source is easily altered to provide
unique algorithms. Data encrypted with this function is
decrypted with the companion DECRYPTED() function.
Notes: Strings encrypted with this function can only be decrypted
with the companion DECRYPTED() function! However,
DECRYPTED() is not bulletproof, it uses a simple data
encryption scheme and is meant to conceal data from the
curious.
Example: *-- get a password, then store it in encrypted format
@ 5,0 SAY "Enter your password:"
*-- allow only 40 characters, upper case, and echo dots
password = KEYINPUT(40, .T., .F.) && see KEYINPUT()
USE system.dbf
REPLACE pword WITH ENCRYPTED(password)
Source: RL_ENCRY.PRG
See also: DECRYPTED(), KEYINPUT()
RLIB Function Reference 77
Function: FEOF()
Purpose: Test for the End Of File status on a binary file.
Syntax: FEOF( handle )
Arguments: handle - The numeric file handled returned by a previous
call to FOPEN() or FCREATE(). If omitted or a
non-numeric parameter is passed, FEOF() will
return True.
Returns: True if the current file pointer is at EOF, false otherwise.
Description: FEOF() is a low level file function used to test if a binary
file opened with FOPEN() or FCREATE() is at the end of file.
It is written in Clipper (as are all RLIB functions) which
further illustrates that you do not need assembler or C
experience to accomplish this task.
Notes: Assumes the file to be tested has already been opened with
the FOPEN() or FCREATE() function. If the file is not open
(an invalid handle is supplied) FEOF will return True.
If the file handle is omitted or is non-numeric, FOEF() will
return True and set RLIBERROR().
Example: *-- read in CONFIG.SYS into a single field database file
DECLARE structure[1]
structure[1] = "LINE C 80 0" && define structure
IF .NOT. DBFCREATE("test.dbf",structure) && create .DBF file
BUZZ()
SAYINBOX("W+/R", "Error creating TEST.DBF", 30)
RETURN
ENDIF
handle = FOPEN("c:\config.sys") && open CONFIG.SYS
IF FERROR() != 0
? "Error opening c:\config.sys"
RETURN
ENDIF
USE test && open database
DO WHILE .NOT. FEOF(handle) && read in lines
APPEND BLANK
REPLACE line WITH FREADLINE(handle)
ENDDO
*-- now do whatever with config.sys lines
*-- perhaps look for the PATH, etc...
FCLOSE(handle) && close up shop
USE
Source: RL_FEOF.PRG
See also: FILEDATE(), FILESIZE(), FILETIME(), FREADLINE()
RLIB Function Reference 78
Function: FILEDATE()
Purpose: Retrieve the last update date for a given file from DOS.
Syntax: FILEDATE( filename )
Arguments: filename - Character string or variable indicating the
name of the file for which to extract the date.
This filename (filespec) must and may adhere to
any fully qualified filename as required by
ADIR().
Returns: Date from the file directory entry (last update date).
Description: This function extracts the date from the given file directory
entry information. It is useful for comparing the dates of
two files, or for using the file date for a variety of
purposes. FILEDATE() may be used in conjunction with
FILETIME() to determine if an index file is current with the
associated .DBF file. FILEDATE() simplifies all the ADIR()
and associated lines of code to get the file date.
Notes: If an invalid filename is given, or if the file does not
exist, FILEDATE() will return an empty date ( / / ).
Beware that if the file being checked is currently open, the
date from the directory entry may not reflect updates until
the file is closed.
Example: *-- see if the date and time of the .DBF and .NTX files agree
ok = (FILEDATE("myfile.dbf") == FILEDATE("myfile.ntx") .AND.;
FILETIME("myfile.dbf") == FILETIME("myfile.ntx"))
USE myfile INDEX myfile
IF .NOT. ok
pbox = SAYINBOX("Please wait, updating index")
REINDEX
GO TOP
POPBOX(pbox)
ENDIF
*-- a second example, prompt user for file backup request
lastback = FILEDATE("myfile.bak")
IF BOXASK("MYFILE.DBF was last backed up on"+DTOC(lastback),;
"Do you want to back it up now? (Y/N) ") = "Y"
ERASE myfile.bak
COPY FILE myfile.dbf TO myfile.bak
ENDIF
Source: RL_FILED.PRG
See also: FILESIZE(), FILETIME()
RLIB Function Reference 79
Function: FILES()
Purpose: Test for the existence of multiple files in one function.
Syntax: FILES( filename [, filename...filename ] )
Arguments: filename - Character string or variable of the file to
test for existence.
Returns: True if all the specified files exist.
Description: FILES() is a file function that tests for the existence of
multiple files. It is useful for reducing a series of FILE()
functions .AND.ed together into a single function call. If
you have to test for more than one file often, this really
cleans things up and makes code very readable.
Notes: FILES() will accept as many file name arguments as Clipper
will allow you to pass. A practical limit of the number of
filenames which can be passed should be 10. FILES() uses the
Clipper FILE() function to successively test for each file
specified. If any test fails, FILES() returns False. Since
the FILE() function is used, it follows Clippers current SET
DEFAULT setting.
If FILES() encounters a non-character argument, it will fail,
set RLIBERROR() and return False.
Example: *-- see if all needed index files exist
USE Sales
IF FILES( "Custno.ntx", "Invoice.ntx",;
"Salesman.ntx", "Repair.ntx",;
"Saledate.ntx" )
SET INDEX TO Custno, Invoice, Salesman, Repair, Saledate
ELSE
*-- do indexing
ENDIF
*-- the old way to do it
IF FILE("Custno.ntx" ) .AND. FILE("Invoice.ntx") .AND.;
FILE("Salesman.ntx") .AND. FILE("Repair.ntx" ) .AND.;
FILE("Saledate.ntx")
Source: RL_FILES.PRG
See also: FILEDATE(), FILESIZE(), FILETIME()
RLIB Function Reference 80
Function: FILESIZE()
Purpose: Retrieve the size of a file from DOS directory information.
Syntax: FILESIZE( filename )
Arguments: filename - Character string or variable indicating the
name of the file for which to extract the size.
This filename (filespec) must and may adhere to
any fully qualified filename as required by
ADIR().
Returns: Numeric size in bytes of <filename> from the DOS directory
entry.
Description: This function extracts the size from the given file directory
entry information. It is useful for comparing the sizes of
two files, or for using the file size for a variety of
purposes.
Notes: If an invalid filename is given, or if the file does not
exist, FILESIZE() will return zero. Beware that if the file
being checked is currently open, the size from the directory
entry may not reflect updates until the file is closed.
Since FILESIZE() uses ADIR() (and presumably DOS directory's
function calls) the file does not have to be opened with
FOPEN() to get the size. This can be useful if file handles
are in short supply.
Example: *-- verify enough disk space for a faster sort operation
IF DISKSPACE(0) > FILESIZE("myfile.dbf")
USE myfile INDEX myfile
COPY TO myfile.sor
USE
ERASE myfile.dbf
RENAME myfile.sor TO myfile.dbf
ELSE
BUZZ()
SAYINBOX( "R/W", "Insufficient disk space!", 30 )
ENDIF
Source: RL_FSIZE.PRG
See also: FILEDATE(), FILETIME()
RLIB Function Reference 81
Function: FILETIME()
Purpose: Retrieve the last update time for a given file.
Syntax: FILETIME( filename )
Arguments: filename - Character string or variable indicating the
name of the file for which to extract the time.
This filename (filespec) must and may adhere to
any fully qualified filename as required by
ADIR().
Returns: Character time string of <filename> from the DOS directory
entry.
Description: This function extracts the time from the given file directory
entry information. It is useful for comparing the times of
two files, or for using the file time for a variety of
purposes. FILETIME() can be used in conjunction with
FILEDATE() to determine if an index file is current with the
associated .DBF file. FILETIME() simplifies all the ADIR()
and associated lines of code to get the file time.
Notes: If an invalid filename is given, or if the file does not
exist, FILETIME() will return a null string (""). Beware
that if the file being checked is currently open, the time
from the directory entry may not reflect updates until the
file is closed.
Example: *-- see if the date and time of the .DBF and .NTX files agree
ok = (FILETIME("myfile.dbf") == FILETIME("myfile.ntx") .AND.;
FILEDATE("myfile.dbf") == FILEDATE("myfile.ntx"))
USE myfile INDEX myfile
IF .NOT. ok
pbox = SAYINBOX("Please wait, updating index")
REINDEX
GO TOP
POPBOX(pbox)
ENDIF
Source: RL_FILET.PRG
See also: FILEDATE(), FILESIZE()
RLIB Function Reference 82
Function: FORGET()
Purpose: Release field memory variables created with MEMORIZE().
Syntax: FORGET( [ firstfield [, lastfield ] ] )
Arguments: firstfield - Optional numeric value indicating the first
field in the database whose PUBLIC M-> copy
variable is to be RELEASEd. The default is
field number 1.
lastfield - Optional numeric value indicating the last
field in the database whose PUBLIC M-> copy
variable is to be RELEASEd. The default is the
last field, FCOUNT().
Returns: True (.T.) if all fields were successively released.
Description: This function is designed to be used in conjunction with
CHANGED(), MEMORIZE(), and MREPLACE(); they are all a team.
Put together, they simplify the tedious task of making memory
variable copies of each field in a database record (some
languages call them temporary field variables). FORGET() is
used to release the PUBLIC variables created by MEMORIZE(),
when your editing and REPLACEing is finished.
Notes: Since variables created with MEMORIZE() are declared PUBLIC,
FORGET() releases them to reclaim memory and to avoid any
potential name conflicts. Some programmers save field values
to memory variables with a common prefix (like m_), and when
they are finished with them do a RELEASE ALL LIKE m_*. This
is fine if the variables are released in the same procedure
in which they were created. However, it is more efficient to
do this storing in a sub-procedure, hence the need to make
these variables PUBLIC. The problem is that in Clipper, you
cannot RELEASE ALL LIKE m_* if the m_* variables are PUBLIC
variables that were created in another procedure. FORGET()
takes care of all this by explicitly naming each variable to
be RELEASEd, which is the only way you can release a PUBLIC
variable created in another procedure.
FORGET() uses the field definitions in the currently selected
database to create the PUBLIC variable names to release. If
no database is open in the current select area, FORGET() will
return .F. and set the appropriate RLIBERROR().
Example: *-- store empty field values for a new record
MEMORIZE(.T.)
*-- get the data
@ 1,0 SAY "Enter full name" GET M->name
@ 2,0 SAY "Enter birthdate" GET M->birthdate
@ 3,0 SAY "Enter age " GET M->age PICTURE "##"
*-- remember to always PICTURE numeric memory variables!
RLIB Function Reference 83
READ
*-- now add the new record and put in the data
IF NO_APPEND()
SAYINBOX( "R/W", "Append failure, record not saved!" )
ELSE
MREPLACE()
ENDIF
*-- now release the public variables!
FORGET()
Source: RL_FORGE.PRG
See also: CHANGED(), MEMORIZE(), MREPLACE()
RLIB Function Reference 84
Function: FPROMPT()
Purpose: Display color formatted and highlighted prompt strings.
Syntax: FPROMPT( [ prompt [, color [, hilite [, row [, col ;
[, comma ] ] ] ] ] ] )
Arguments: prompt - The character string to format and print as the
prompt. See the discussion below for the
format of <prompt>.
color - Optional character string which specifies the
color to use to display the prompt text which
appears at and to the right of the equal sign.
This color string must adhere to Clipper color
setting standards. If omitted or a non-
character parameter is given, the default color
is the current SETCOLOR() setting.
hilite - Optional character string which specifies the
color to use to display the highlighted portion
of the prompt. This highlighted portion
appears to the left of the equal sign. This
color string must adhere to Clipper color
setting standards. If omitted or a non-
character parameter is given, the default is
the BRIGHT() version of the current color
SETCOLOR().
row - Optional numeric value indicating the row on
which to display the formatted prompt. If
omitted or a non-numeric value is passed, the
default row is row 24. In the Clipper 5.0
version, the default row is MAXROW().
col - Optional numeric value indicating the starting
column on which to display the formatted
prompt. If omitted or a non-numeric value is
passed, the default column is column zero.
comma - Optional single character which indicates the
character to recognize as the separator or
prompt token delimiter in the <prompt> string.
If omitted or a non-character is provided, the
default separator character is the comma.
Returns: True if the <prompt> was displayed properly, false otherwise.
Description: FPROMPT() is a screen function used to paint prompts where a
portion of the prompt is highlighted and another portion is
in a normal display color. As an example, when FPROMPT() is
given the string "F1=Help,F10=Menu", FPROMPT() will say "F1"
in a bright color with the "=Help" portion in the standard
color. FPROMPT()'s behavior is best understood through
RLIB Function Reference 85
examples.
Notes: The prompt string will be formatted to be centered on the row
specified with an even number of spaces separating the
individual elements, or tokens, in the prompt. Each separate
individual prompt element in the string must be separated
with a single comma (or other character specified by the
<comma> parameter), therefore, individual prompt elements may
not contain embedded commas. If you want an embedded comma
in a prompt element, specify and use another delimiter
character other than the comma.
If no parameters are given, or if the <prompt> parameter is
empty or non-character, FPROMPT() will clear the display line
from the column indicated to the end of the screen. If no
column is specified, column zero is assumed.
Clipper 5.0 Only!
The 5.0 library version of FPROMPT() includes a companion
function named SETFPROMPT(). This function is an example of
the benefits of the static class of variables supported by
Clipper 5.0. The SETFPROMPT() function is used to
pre-establish the values of the <color>, <hilite>, <row>,
<col>, and <comma> arguments so that they need not be
supplied in every call to FPROMPT(). This helps to reduce
"code wordiness". Because this would have to be implemented
as a series of PUBLIC variables in the Summer '87 version,
this feature is only included in the 5.0 version of the RLIB
library.
The syntax for SETFPROMPT() is the same as for FPROMPT(),
just exclude the first parameter, <prompt>.
Example: *-- this will paint a prompt with the F1, F9, F10, and Esc
*-- portions displayed in Bright Cyan on Blue with the items
*-- =Help, =Mark, =Select, and =Quit displayed in Cyan on
*-- Blue. Each option will be evenly spaced to center the
*-- entire prompt on row 24, similar to the following:
FPROMPT("F1=Help,F9=Mark,F10=Select,Esc=Quit","BG/B","BG+/B")
F1=Help F9=Mark F10=Select Esc=Quit
Source: RL_FPROM.PRG
See also: CENTER(), MIDDLE(), RJUSTIFY()
RLIB Function Reference 86
Function: FREADLINE()
Purpose: Read a line from a text file opened with FOPEN() or FCREATE()
Syntax: FREADLINE( fhandle )
Arguments: fhandle - The numeric file handled returned by a previous
call to FOPEN() or FCREATE().
Returns: The next sequential line read from the indicated file handle.
Description: FREADLINE() is a low level file I/O function (written in
Clipper) to read a single carriage return/line feed delimited
line from a text file.
Notes: Assumes the file to be read has already been opened with the
FOPEN() or FCREATE() function. If the file handle argument
is omitted or a non-numeric value is supplied, FREADLINE()
will return a null and set RLIBERROR().
FREADLINE() will read lines up to 512 characters long. This
line width is sufficient for most text files. If files with
lines longer than 512 characters are to be accessed,
FREADLINE() may be modified by increasing the value from 512
on the following lines:
rl_bufffer = SPACE(512)
rl_sizread = FREAD( p_handle, @rl_buffer, 512 )
Unlike some other FREADLINE functions, this one does not
return the carriage return/line feed pair (CR/LF) in the line
which is the desired behavior. Who needs it anyway!
Example: *-- read AUTOEXEC.BAT and look for a SET CLIPPER= statement
handle = FOPEN("c:\autoexec.bat")
DO WHILE .NOT. FEOF(handle)
line = FREADLINE(handle)
IF "SET CLIPPER=" $ UPPER(line)
*-- do whatever...
ENDIF
ENDDO
FCLOSE(handle) && remember to close the file!
Source: RL_FREAD.PRG
See also: FEOF()
RLIB Function Reference 87
Function: FRESTSCREEN()
Purpose: Restore screen from a disk file saved with FSAVESCREEN().
Syntax: FRESTSCREEN( filename )
Arguments: filename - Character filename from which to restore the
screen. This file must have been created with
the companion FSAVESCREEN() function. If the
filename is not fully qualified, FRESTSCREEN()
will search the current default directory for
the given filename.
Returns: True if screen restored. If a file I/O error occurs or if
the <filename> does not exist, FRESTSCREEN() will return
false.
Description: FRESTSCREEN() is a screen function used to restore a screen
from a disk file created with the companion FSAVESCREEN()
function. Saving many screens to memory variables can
quickly consume large amounts of free pool memory. Each
screen consumes at least 4000 bytes of memory. Saving
screens to disk files can limit this potential problem.
Notes: FRESTSCREEN() opens the disk file with the Clipper low level
file functions, reads the file contents, then restores the
screen. If a file open or read failure occurs, FRESTSCREEN()
returns false.
FRESTSCREEN() makes no checks on the contents of the file
from which to restore a screen. If the file was not saved
with FSAVESCREEN() (or another similar save screen to file
function) then results are guaranteed to be interesting. For
instance, FRESTSCREEN("c:bigfile.dbf") is guaranteed to put
something strange looking on your screen.
If the file is not at least 4000 bytes in size, or 4000 bytes
are not read from the file, FRESTSCREEN() will fail and
return False.
Clipper 5.0
FRESTSCREEN() uses the values of MAXROW() and MAXCOL() to
determine the screen size, and hence the number of bytes to
read from <filename>. To prevent strange behavior, neither
MAXROW() nor MAXCOL() must be changed with the SETMODE()
function between a FSAVESCREEN() and FRESTSCREEN() call.
Example: *-- save the current screen to file, and save some memory(0)
FSAVESCREEN("screen1.scr")
CLEAR
*-- do something
FRESTSCREEN("screen1.scr")
RLIB Function Reference 88
Source: RL_FREST.PRG
See also: FSAVESCREEN()
RLIB Function Reference 89
Function: FSAVESCREEN()
Purpose: Save screen to a disk file to be restored with FRESTSCREEN().
Syntax: FSAVESCREEN( filename )
Arguments: filename - Character filename to which to save the screen.
If the filename is not fully qualified, the
saved screen file will be placed in the current
default directory.
Returns: True if screen saved successfully. If a file I/O error
occurs while opening on writing the file, FSAVESCREEN() will
return false.
Description: FSAVESCREEN() is a screen function used to save a screen to a
disk file, to be later restored with the companion
FRESTSCREEN() function.
Notes: FSAVESCREEN() opens the disk file with the Clipper low level
file functions. If a file create or open failure occurs,
FSAVESCREEN() returns false.
Although FSAVESCREEN() uses 4k of memory during operation,
that memory is released when the function exits. Saving
screens to disk can conserve enormous amounts of memory
rather that storing multiple screens in memory variables.
FSAVESCREEN() will check for bad parameters or file I/O
errors and return false if something went wrong. The way to
check that you can successfully save a screen to memory is to
check MEMORY(0) and verify at least 4K of free pool memory is
available. Not only does this function conserve memory use
but also makes error correction a little easier.
Clipper 5.0
FSAVESCREEN() uses the values of MAXROW() and MAXCOL() to
determine the screen size, and hence the number of bytes to
write to <filename>. To prevent strange behavior, neither
MAXROW() nor MAXCOL() must be changed with the SETMODE()
function between a FSAVESCREEN() and FRESTSCREEN() call.
Example: *-- save the current screen to file, and save some memory(0)
FSAVESCREEN("screen1.scr")
CLEAR
*-- do something
FRESTSCREEN("screen1.scr")
*-- old way of saving screens to memory variables
IF MEMORY(0) < 4
*-- error message
ELSE
RLIB Function Reference 90
SAVE SCREEN TO memvar
ENDIF
*-- new way saves memory and two lines of code
IF .NOT. FSAVESCREEN("scrfile1.tmp")
*-- error message
ENDIF
Source: RL_FSAVE.PRG
See also: FRESTSCREEN()
RLIB Function Reference 91
Function: GETFILE()
Purpose: Full featured user dialog box for GETing filenames.
Syntax: GETFILE( [ filespec [, header [, mustexist [, confirm;
[, toprow [, restore ] ] ] ] ] )
Arguments: filespec - Optional character file name or file
specification. If omitted or a non-character
parameter is passed, the default is blank.
header - Optional character title to display in the
header area of the filename entry dialog box.
If omitted or a non-character argument is
given, the default header text is "Enter
Filename".
mustexist - Optional logical value indicating whether or
not to verify that the filename entered exists.
If omitted or a non-logical argument is given,
the default value is False (.F.)
confirm - Optional logical value indicating whether or
not to confirm a file overwrite if the file
exists. The default value is True (.T.)
toprow - Optional numeric top row of the filename entry
dialog box. Valid rows are from row 0 to row
20. If not specified or an invalid row value
or a non-numeric value is given, the default
row is row number 8.
restore - Optional logical value indicating whether or
not to save and restore the screen region
underneath the file entry box on exit. If not
specified or a non-logical value is given, the
default is to restore the screen on exit, or
true.
Returns: The filename entered or a null string ("") if escape pressed.
Description: GETFILE() is a file/screen function that puts up an entry
dialog box in the following format:
╔════════════════════════════════════════╗
║ Enter Filename ║
╠════════════════════════════════════════╣
║████████████████████████████████████████║
╚════════════════════════════════════════╝
The major use of this function is to query the user for a
file name. The arguments permit control over certain aspects
such as whether or not to verify that the file entered
already exists.
RLIB Function Reference 92
Notes: All arguments are optional. However a dummy must be passed
to get at a trailing argument.
The file entry box is drawn in double lines as show above,
and is centered on the screen beginning at the top row
specified.
The filename is retrieved using the @ x,y GET...READ
commands. Therefore, in Clipper Summer '87 this function
must not be embedded within a pending READ, such as in a
VALID statement. This is because nested READ's are not
supported directly in the Summer '87 version of Clipper.
In the Clipper 5.0 version of RLIB, GETFILE() declares
GETLIST as a LOCAL which allows a call to GETFILE() to be
nested within other READS.
The width of the file entry dialog box is 42 characters.
Since fully qualified filenames may be longer the @GET
display scrolls horizontally by virtue of the @S40 function
in the PICTURE template.
GETFILE() uses the CHECKFILE() function to perform the edit
checks specified by the various arguments.
Example: *-- get a target file for a set printer command
target = GETFILE("", "Enter target output file", .F., .T.)
IF EMPTY(target)
RETURN
ENDIF
SET PRINTER TO (target)
*-- in this example, the default target file is OUTPUT.PRN
*-- accepting all other GETFILE() defaults
target = GETFILE("OUTPUT.PRN")
SET PRINTER TO (target)
Source: RL_GETFI.PRG
See also: CHECKFILE(), BORDERBOX(), PATHTO(), PARENT(), TARGET()
RLIB Function Reference 93
Function: GETKEY()
Purpose: Function to replace INKEY() to allow internal customization
Syntax: GETKEY( timeout )
Arguments: timeout - REQUIRED numeric value which is the number of
seconds to wait for a keypress, as in INKEY().
Returns: The INKEY() value of the key pressed.
Description: GETKEY() is a character function which is used as a
replacement for INKEY() in all RLIB functions that accept
INKEY() input. It can otherwise be referred to as a "stub"
function which lets the programmer create their own
customized GETKEY() to replace the keyboard wait routines in
RLIB functions. One such use is to trap the F1 key (INKEY()
= 28) within GETKEY() in order to extend the calling of HELP
routines from within RLIB functions. This is because INKEY()
is not considered a "wait" state and help is not called when
F1 is pressed at an INKEY() state. By installing the example
function below, you can have both help and INKEY().
Notes: All of the RLIB functions that solicit keyboard input use the
RLIB GETKEY() function instead of INKEY(). This enables you
to provide your own "hook" into the internals of RLIB
functions. By creating your own customized GETKEY() function
and including it in your application, you can trap keystrokes
and act on them before they even get to the RLIB function.
Take a look at the GETKEY() function in the Message Reader
demo program source code to see how GETKEY() expands the
capabilities of the RLIB PICKREC() function.
A sample program KEYBOARD.PRG is provided with the 5.01
version of Clipper that illustrates the same concept of
"stubbing out" the INKEY() function.
WARNING: NO ARGUMENT CHECKING IS PERFORMED IN GETKEY()!!!.
You MUST pass the <timeout> parameter. This was done in the
interest of speed since a parameter will always be used. If
someone is stomping on the down arrow key in PICKREC(),
parameter checking on every call to this function would slow
it down needlessly. To add parameter checking, include the
sample GETKEY() function below.
Usually, the internal HELP routine receives three parameters;
the calling procedure name, line number, and input variable.
Any help called from this function will have GETKEY as the
calling procedure.
Example: *-- sample customized GETKEY() that traps the F1 Help key
FUNCTION GetKey
PARAMETER timeout
PRIVATE ikey
RLIB Function Reference 94
*-- add this if you want parameter checking for safety.
timeout = IF( TYPE("timeout") = "N", timeout, 0 )
DO WHILE .T.
ikey = INKEY(timeout)
IF ikey != 28
EXIT
ENDIF
DO Help WITH PROCNAME(), PROCLINE(), READVAR()
ENDDO
RETURN (ikey)
Source: RL_GETKE.PRG
See also: KEYINPUT(), PICKREC()
RLIB Function Reference 95
Function: GETPARM()
Purpose: Retrieve a comma delimited token from a character string
Syntax: GETPARM( position, string )
Arguments: position - Numeric value indicating the ordinal position
in the comma delimited token list.
string - The comma delimited string from which to
extract the token following the <position>-1
comma.
Returns: The extracted portion of <string> starting at the
(<position>-1)th comma up to the next comma or the end of the
string. If no characters exist at the ordinal position
indicated, or if any arguments are missing or an invalid
type, GETPARM() will return a null string.
Description: This function is used to retrieve a comma delimited parameter
from a character string. The ways in which this can be used
are unlimited, but as an example, several RLIB functions use
GETPARM() to retrieve color settings from SETCOLOR().
Notes: GETPARM() is used in many RLIB functions to parse SETCOLOR()
to retrieve default colors when no color arrays are specified
in functions that offer color as an option. Therefore, you
must not remove GETPARM() from RLIB!
Example: *-- get the current Enhanced color setting from the
*-- second part of SETCOLOR()
mreverse = GETPARM(2, SETCOLOR())
*-- this will return "W/R" if SETCOLOR()="R/W,W/R,,,R/BG"
*-- 2nd token parameter is -------------------^
Example #2:
*-- write a function that accepts several parameters, all
*-- contained in one character string.
*-- Here is a sample parameter
files = "TEST1.DBF, TEST2.DBF, TEST3.DBF, TEST4.DBF"
*-- here is the call to the function
*-- open all the files in the string in separate work areas
OPENFILES(files)
*----------------------------------------------------------
*-- now here's your UDF to open many files in one swoop
*----------------------------------------------------------
RLIB Function Reference 96
FUNCTION OpenFiles
PARAMETER filenames
PRIVATE file2open, x
x = 1
DO WHILE .T.
file2open = GETPARM(x, filenames)
IF EMPTY(file2open)
EXIT
ENDIF
SELECT 0
USE (file2open)
x = x + 1
ENDDO
RETURN .T.
Source: RL_GETPA.PRG
See also: BRIGHT()
RLIB Function Reference 97
Function: HEX2DEC()
Purpose: Convert a hexadecimal string to its equivalent decimal value.
Syntax: HEX2DEC( hex_str )
Arguments: hex_str - The hexadecimal value to convert to a decimal
value, expressed as a character string.
Returns: The decimal value of the hexadecimal string <hex_str>
Description: This function converts hexadecimal values expressed as
character strings to their decimal value equivalents. There
are many libraries that implement this function but it's nice
to know you don't need assembly language experience to
accomplish this task!
Notes: The string must be a valid hexadecimal number (i.e. contains
only digits and letters A-F). If a letter is encountered
that is not in the range A-F, HEX2DEC() will calculate that
letter as zero, and that letter will be ignored. However,
this may cause erroneous results. Ensure that hex strings
contain only valid hexadecimal characters.
HEX2DEC() ignores case so it does not matter if the hex
string contains lower, upper, or mixed case letters.
Example: ? HEX2DEC("FFFF") && result = 65535
? HEX2DEC("010") && result = 16
? HEX2DEC("Fr0") && result = 3840
Source: RL_HEX2D.PRG
See also: BIN2DEC(), DEC2HEX()
RLIB Function Reference 98
Function: ISDBF()
Purpose: Test if a file is a valid .DBF format database file.
Syntax: ISDBF( filename [, showerror ] )
Arguments: filename - Character string or variable indicating the
name of the file to check if is a valid .DBF
format database file.
showerror - Optional logical value indicating whether or
not to display an error message if the file is
not a valid .DBF format file. If omitted or a
non-logical value is given, the default is
False, do not display any error message.
Returns: True if the file is a valid .DBF format file, false if not.
Description: ISDBF() is a file function used to test if a given file is a
valid .DBF format file. This is useful in situations where
the format of a file cannot be assumed to be .DBF.
Notes: If the required filename parameter is omitted, or is not a
character type parameter, ISDBF() will return False and set
RLIBERROR().
The .DBF file format dictates that the first byte of the file
be either 0x03 or 0x83 hexadecimal values (3 or 131 decimal),
0x03 for regular .DBF files, 0x83 for .DBF files with one or
more memo fields.
Example: *-- verify a file is .DBF before trying to USE it
IF ISDBF("myfile.dbf")
USE myfile.dbf
ELSE
? "Not a valid .DBF file."
ENDIF
Source: RL_ISDBF.PRG
See also: DBFCREATE(), ISFIELD()
RLIB Function Reference 99
Function: ISFIELD()
Purpose: Test if a field name is valid in the selected database.
Syntax: ISFIELD( fieldname )
Arguments: fieldname - Character name to test if is a field in the
currently selected database.
Returns: True if <fieldname> is a field in the currently selected
database.
Description: ISFIELD() is a database function used mainly to verify a
fieldname in the current database file. This can be helpful
in verifying that fields explicitly named in your application
have not been altered, removed, or renamed in the database
file outside the control of your application.
Notes: If no fieldname is provided, ISFIELD() will return false and
set the appropriate RLIBERROR()
Example: *-- verify Name field before replacing
IF ISFIELD("name")
REPLACE name WITH "Richard Low"
ELSE
BUZZ()
SAYINBOX( "W+/R", "Internal database error!",;
"Field NAME does not exist", 10 )
ENDIF
Source: RL_ISFIE.PRG
See also: ISDBF()
RLIB Function Reference 100
Function: KEYINPUT()
Purpose: Get keyboard input, optionally echoing dots to the screen
Syntax: KEYINPUT( length, upper_case, echo_chars, string )
Arguments: length - Optional numeric value specifying the maximum
length of the string that may be entered (and
returned by KEYINPUT). If omitted or an
invalid parameter is passed, the default length
will be 80 characters.
upper_case - Optional logical value indicating if all
characters that are typed will be forced to
upper case. If omitted or an invalid parameter
is passed, the default is false, characters
will be returned as entered.
echo_chars - Optional logical value indicating if typed
characters will appear on the screen. If this
value is false, dots will echo on screen. If
omitted or an invalid parameter is passed, the
default is true, characters will echo on screen
as entered.
string - Optional starting character string for key
input. If omitted or an invalid parameter is
passed, KEYINPUT() starts with a null (empty)
string.
Returns: The character string typed in, or a null string ("") if the
Escape key was pressed.
Description: KEYINPUT() is a screen function used for accepting direct
keyboard input from the user while giving the programmer
control over each key press. One such use is for direct dots
onto the screen instead of the characters typed. This is
most often used during password entry.
Notes: There is no built in way of allowing key input while echoing
dots on the screen to prevent on-lookers from seeing what is
being entered. SETting COLOR TO X will blank out the screen
but then you cannot see how many characters have been
entered. We may want to see dots echo (as most BBS' do) so
we can tell how many characters we have entered. With
KEYINPUT() you can easily do this, while also determining the
maximum length of the input string, whether or not it is to
be all upper case, and whether or not to echo the actual
characters on the screen, or just dots.
KEYINPUT() starts accepting character input at the current
cursor location on the screen and terminates when either the
maximum character count has been reached or ENTER or ESCAPE
is pressed.
RLIB Function Reference 101
If <length> is greater than the remaining width of the
screen, KEYINPUT() will wrap to the next line.
Example: *-- get the user's password, keep it less than or equal to 30
*-- characters, make upper case, and echo dots on screen
@ 5,0 SAY "Enter your password: "
password = KEYINPUT( 30, .T., .F. )
Source: RL_KEYIN.PRG
See also: BOXASK(), GETFILE()
RLIB Function Reference 102
Function: MAKEALIAS()
Purpose: Construct a database work area alias from a full filename.
Syntax: MAKEALIAS( filename )
Arguments: filename - Character string or variable name of the file
from which to construct a default work area
alias name. If omitted or a non-character
parameter is provided, a null string is
returned and RLIBERROR() set.
Returns: A default work alias for a supplied DBF file name.
Description: This function will strip off a trailing .DBF extension and
any leading drive/path name qualifiers to create a default
alias. This is useful in a runtime environment where it is
necessary to supply a valid alias name where otherwise one
would not be available.
Notes: This can be most useful for creating generic file open
functions where a standard default work area alias name must
be generated when a file is opened. MAKEALIAS() is used
internally by OPENED() to construct an alias name from the
database file name.
Example: ? MAKEALIAS("c:\data\myfile.dbf") && returns "MYFILE"
Source: RL_MAKEA.PRG
See also: OPENED()
RLIB Function Reference 103
Function: MARKREC()
Purpose: Mark and select multiple records from a database pick list.
Syntax: MARKREC( t, l, b, r, fieldlist, markkey, markfield, colors )
Arguments: t,l,b,r - Numeric values specifying the Top, Left, Bottom
and Right screen coordinates of the display
box. The top and bottom row values must be
between 0 and 24 (MAXROW() in 5.0), and the
left and right column values must be between 0
and 79.
fieldlist - Character expression which evaluates to a field
list to be displayed at runtime. This value is
macro substituted, so it must evaluate
correctly to a character string. Any valid
expression may be used.
markkey - Optional mark/unmark key ASCII value which,
when pressed, toggles the current record being
included in a "marked" list. If omitted or a
non-numeric value is passed the default ASCII
key value is -8, for the F9 key.
markfield - Optional field name or expression evaluated and
used to add an item to the marked list. If
omitted or <markfield> is non-character in type
or empty, then the default expression used to
add items to the marked list is
"STR(RECNO(),8,0)"
colors - Optional array of color settings used to govern
the colors of various parts of the MARKREC()
display. See the table listed below for
options and default values if the array is not
provided.
Returns: A character string of selected record numbers, each eight
digits long, delimited with a comma ",", or a null string if
Escape was pressed. If the optional <markfield> parameter is
provided, the character string returned consists of elements
added during the marking process.
Description: MARKREC() is a function for cursoring through a pick list
selection of records from the currently selected database,
and marking the records to work with by pressing a designated
key (default = F9). When the MARKREC() session is completed,
MARKREC() returns a single character string which contains
comma delimited tokens. This string can then be parsed to
extract each token in succession to process the records that
were marked.
MARKREC() lets a user select multiple records from a database
RLIB Function Reference 104
to be included in some subsequent operation. One such use is
for prompting the user for records to include in a report.
The user cursors up and down through a database pick list and
presses a designated mark key to select each record. When
the user terminates by pressing the Enter key, MARKREC()
returns a list of record numbers or field contents of the
records selected.
Notes: MARKREC() behaves very similar to PICKREC() except that
instead if picking one record, you mark several records for
processing. MARKREC() skips forward and backward through the
database records as the up and down arrow keys are pressed.
The PgUp and PgDn scroll one window full of records. When
the Enter key is pressed, MARKREC() exits and returns a list
of selected records in the form of a string of record
numbers, each 8 digits with a comma delimiter. For example,
if the marked records were record numbers 5, 12 and 123, the
string would be: " 5, 12, 123,". Notice the
trailing comma; a comma is added to the end of each selected
record number. To process the selected records you may use
either FOR <data> $ string logic, or a loop to extract each
record number to process. See the example. If the markfield
parameter is supplied, this field (or expression) is
extracted, and a trailing comma added to the end. You can
create your parsing loop based on the length of this field or
expression.
MARKREC() merely packages the parameters and makes a call to
PICKREC() specifying the proper marking arguments. See the
PICKREC() function documentation for more details. PICKREC()
can be called directly.
The elements of the color array are:
Element# Description Default
-------- -------------------------- ---------------------
color[1] Normal text display Standard - SETCOLOR()
color[2] Selected or Marked BRIGHT() Standard
color[3] Hi-lited (scroll bar) Enhanced
color[4] Hi-lited & Selected/Marked Enhanced/Bright/Blink
color[5] Color on exit from XITKEYS BRIGHT() Standard
color[6] Normal text IF (color[8]) Standard - SETCOLOR()
color[7] Hi-lited IF (color[8]) Enhanced
color[8] Character condition "(.T.)"
Example: *-- database of customer orders, select orders to print
*-- Orderno and Customer are fields in your database
output = "Orderno + ' ' + Customer"
*-- draw a double line box with a title header
BORDERBOX( 1, 0, 22, 36, "CUSTOMER ORDERS" )
*-- make the F5 key (INKEY() = -4) be the marking key
marked = MARKREC( 4, 2, 21, 35, output, -4 )
RLIB Function Reference 105
*-- now you can print information in one of two ways
*-- Method #1
REPORT FORM custrepo FOR STR(RECNO(),8,0)+"," $ marked
*-- the comma on the end solves the problem of a mistaken
*-- match from two record numbers concatenated together
*-- " 110000000" = record 1 and 10000000, but would
*-- match on record number 11 or 110 or 1100 etc...
*-- Method #2 is a little more code but much quicker
DO WHILE LEN(marked) > 0
*-- get a record number from list (1st 8 digits in list)
mrecord = VAL(SUBSTR(marked,1,8))
*-- or you could do this another way
*-- mrecord = VAL(GETPARM(1,marked))
GOTO (mrecord)
DO <your_report_printing_routine>
*-- strip off first 9 characters (8 digits plus a comma)
marked = SUBSTR(marked,10)
ENDDO
Source: RL_MARKR.PRG
See also: GETPARM(), PICKREC()
RLIB Function Reference 106
Function: MEMORIZE()
Purpose: Save field values from a database record to memory variables.
Syntax: MEMORIZE( [ blank ] )
Arguments: blank - Optional logical value which if specified as
True tells MEMORIZE() to create an empty
M->memvar of the associated field type for each
database field.
Returns: True if all fields successively stored to memory variables.
Description: This function is designed to be used in conjunction with the
CHANGED(), MREPLACE(), and FORGET() functions; they are all a
team. Put together, they simplify the scattering and
gathering of database field contents into and from associated
memory variables (some languages call them temporary field
variables). What MEMORIZE() does is to create a PUBLIC
memory variable with the same name as each of the fields in
the current record of the currently selected database file,
and assign to that memory variable the value of its
associated field. You then GET the contents of the memory
variable rather than GETting the field directly. After your
READ is finished, you check to see if any of the memory
variable values have CHANGED() from their database field
counterparts and, if so, issue a MREPLACE() then FORGET()
them. The process may seem a little complicated at first,
but it's a lot easier than cluttering up code with STORE TO's
and REPLACE WITH's.
Notes: Used to store a working copy of all the database record field
contents to memory variables for editing. This is good
programming practice in that you should never GET a field
directly, but only work with a copy which can later be
REPLACEd. The <blank> option is useful for creating a set of
field variables when appending a new record. Remember,
memory variables created with MEMORIZE() have the same name
as their database field counterparts. Whenever there are
fields and memory variables with the same names, fields take
precedence. So to access these variables you must preface
the variable name with the memory variable identifier alias
M->.
Each memory variable created is the same data type as its
associated field. If the optional blank parameter is
supplied, each of these variables are empty (Memo field
variables are initialized as a character string of zero
length). The following table of samples gives the data types
created:
RLIB Function Reference 107
FIELD NAME FIELD TYPE LEN VARIABLE NAME BLANK VALUE
---------- ---------- --- ------------- ------------
Name Character 32 M->name SPACE(32)
BirthDate Date 8 M->birthdate CTOD(" ")
Age Numeric 2 M->age 0
Male Logical 1 M->male .F.
Comments Memo 10 M->comments ""
Example: *-- store empty field values for a new record
MEMORIZE(.T.)
*-- get the data
@ 1,0 SAY "Enter full name" GET M->name
@ 2,0 SAY "Enter birthdate" GET M->birthdate
@ 3,0 SAY "Enter age " GET M->age PICTURE "##"
*-- remember to always PICTURE numeric memory variables
READ
*-- now add the new record and put in the data
IF NO_APPEND()
*-- error message
RETURN
ENDIF
MREPLACE()
*-- now release the public variables
FORGET()
Source: RL_MEMOR.PRG
See also: CHANGED(), MREPLACE(), FORGET()
RLIB Function Reference 108
Function: MIDDLE()
Purpose: Center a string by padding with leading and trailing spaces.
Syntax: MIDDLE( string, width )
Arguments: string - Character string or variable which is to be
padded with leading and trailing spaces
sufficient to center in <width>.
width - Optional numeric value representing the desired
width of the returned string. If omitted or an
invalid parameter is passed, the default width
is 80 characters.
Returns: <string> padded with leading and trailing spaces to center
<string> in a line of length <width>.
Description: MIDDLE() is a character/screen function used to pad strings
with leading and trailing spaces sufficient to center the
string in <width>. It can most commonly be used in menuing
and field edit schemes where a centered prompt message is
needed at the bottom of the screen. This can also be
accomplished with the CENTER() function. However, since
middle returns strings with leading and trailing blanks, the
line does not need to be erased first.
Notes: The default width is 80 characters, ideal for screen oriented
displays. MIDDLE() works fine with wider widths for printed
reports.
The difference between MIDDLE() and CENTER() is that MIDDLE()
can effectively erase any previous screen data.
Example: *-- use MIDDLE() to display centered prompts
@ 24,0 SAY MIDDLE("Press any key to continue")
Source: RL_MIDDL.PRG
See also: CENTER()
RLIB Function Reference 109
Function: MREPLACE()
Purpose: Replace fields with memory variables created with MEMORIZE()
Syntax: MREPLACE()
Arguments: None
Returns: True if all fields successively replaced.
Description: This function is designed to be used in conjunction with the
MEMORIZE(), CHANGED(), and FORGET() functions; they are all a
team. Put together, they simplify the scattering and
gathering of database field contents into and from associated
memory variables (some languages call them temporary field
variables). What MREPLACE() does is to replace each field in
the current database record with the associated field memory
variable that was created with MEMORIZE() and usually,
recently edited.
Notes: Memory variables created with MEMORIZE() have the same name
as their database field counterparts. Whenever there exist
fields and memory variables with the same name, fields take
precedence. To access these variables you must preface the
variable name with the memory variable identifier alias M->.
MREPLACE() does a REPLACE <field> WITH <fieldvar> for each
field of the database record.
Example: *-- store field values to memvar copies
MEMORIZE()
*-- get the data
@ 1,0 SAY "Enter full name" GET M->name
@ 2,0 SAY "Enter birthdate" GET M->birthdate
@ 3,0 SAY "Enter age " GET M->age PICTURE "##"
*-- remember to always PICTURE numeric memory variables
READ
*-- don't bother replacing if no change
IF CHANGED()
IF .NOT. MREPLACE()
SAYINBOX("Error writing fields! Replace failed.")
ENDIF
ENDIF
*-- now release the public variables
FORGET()
Source: RL_MREPL.PRG
See also: CHANGED(), FORGET(), MEMORIZE()
RLIB Function Reference 110
Function: MULTIMENU()
Purpose: Create multi-column menus with four way cursor movement.
Syntax: MULTIMENU( t, l, b, r, options [, columns [, messages ;
[, msg_row [, colors ] ] ] ] )
Arguments: t,l,b,r - Numeric values specifying the Top, Left, Bottom
and Right screen coordinates of the display
box. The top and bottom row values must be
between 0 and 24 (MAXROW() in 5.0), and the
left and right column values must be between 0
and 79.
options - Array of character strings to use as menu
options. Each element of the array is
displayed as a menu option filling the box.
columns - Optional numeric value indicating the number of
columns to use for displaying the options. If
omitted or a non numeric parameter is passed,
or if it is zero, the columns will be
calculated to fit the most options across the
left and right window boundaries.
messages - Optional array of character strings to display
as messages corresponding to each of the menu
options.
msg_row - Optional numeric value indicating the row for
the optional messages to appear. This value
must be between 0 and 24 (MAXROW() in 5.0).
The default is row 24, or MAXROW() in the
Clipper 5.0 version.
colors - Optional array of character strings specifying
the color settings to use. See the color table
below for the colors used for the different
components of the menu.
Returns: The number of the array element chosen, or zero if the escape
key was pressed.
Description: MULTIMENU is a multi-column menu selection function. Many
programs offer a list of options to choose from displayed
across the screen allowing you to cursor up, down, left and
right to navigate around the options. This function takes an
array of character strings and displays them in this format.
Notes: If any of the first four parameters specifying the window
coordinates are out of bounds, or the <right> is less than or
equal to <left>, or <bottom> is less than or equal to <top>,
MULTIMENU() will fail and return zero. Also, if the options
array is empty, a zero will be returned. If the number of
RLIB Function Reference 111
columns option is omitted (or zero to make the number of
columns automatic), MULTIMENU() will position columns so that
columns are separated by at least one space. If more
elements exist in the array than will fit in the display
window given the number of columns being used, the PgDn and
PgUp keys will skip forward and back between windows.
The following color table shows which features of the menu
each element of the color array controls:
colors[1] = Menu choices.
colors[2] = Menu selection bar.
colors[3] = <not used>
colors[4] = <not used>
colors[5] = Selected choice on exit.
If you use this color feature, DECLARE your colors array to
have at least 5 elements. If the colors option is not
specified or there are less than 5 elements, then the default
colors are used. These defaults are: the current Standard
color is used for the item displays, and the Enhanced color
is used for the menu selection bar.
Example: *-- display fields in box with structure for each shown below
USE manyflds.dbf
*-- declare arrays for field names
num = FCOUNT()
DECLARE fields[num], types[num], widths[num], dec[num]
DECLARE struct[num]
AFIELDS( fields, types, widths, dec ) && fill with .DBF info
FOR x = 1 TO num
*-- now make each field name 12 spaces wide
fields[x] = STRETCH(fields[x],12)
*-- and build field description message for each
struct[x] = IF( types[x] = "C", "Character",;
IF( types[x] = "N", "Numeric",;
IF( types[x] = "L", "Logical",;
IF( types[x] = "D", "Date", "Memo")))) +;
" Length: " + STR(widths[x],3,0) +;
" Decimals: " + STR(dec[x],3,0)
NEXT x
*-- now present these fields in a single line box
@ 1,0,10,79 BOX "╔═╗║╝═╚║"
*-- present fields with structure for each on line 11
*-- the zero makes UDF calc column number dynamically
fieldnum = MULTIMENU( 2,1,9,78, fields, 0, struct, 11 )
Source: RL_MULTI.PRG
See also: BARMENU(), BOXMENU()
RLIB Function Reference 112
Function: NAMESPLIT()
Purpose: Convert names from First Middle Last to Last, First Middle.
Syntax: NAMESPLIT( name )
Arguments: name - Character string indicating the name string in
the form First Middle Last to parse into Last,
First Middle.
Returns: A character string equal to <name> flipped to lastname first,
with a comma space inserted.
Description: NAMESPLIT() is a character function used to parse names to
split into the last name, middle name, and first name
components. What NAMESPLIT() does is let you type in a name
in the form RICHARD C. LOW, and it returns LOW, RICHARD C.
This is particularly useful for SEEKing names from an index
that was indexed on PAD(TRIM(Lastname)+', '+Firstname,32).
Such an index will insure the correct ordering of names.
This is especially helpful in front end applications as a
user interface tool...NAMESPLIT() can allow a user to perform
a name search without regard to internal name storage format.
Notes: NAMESPLIT() is aware of the standard name suffixes, i.e.
JR., SR., II, 2ND, III, 3RD, 4TH, M.D., PHD, and will
recognize these as not being lastnames. Without this, a name
entered as RICHARD C. LOW, JR. may incorrectly be split
into JR., RICHARD C. However, there will be occasions where
a name/ suffix combination may not work. The good news is
that NAMESPLIT() makes name entering easier 99% of the time.
Example: ? NAMESPLIT("John Smith")
*-- returns "Smith, John"
? NAMESPLIT("John M. Smith, MD")
*-- returns "Smith MD, John M."
*-- consider a file indexed on the following key:
*-- (note that the above index expression is built to, then
*-- limited to 32 characters in order to keep the index key
*-- a constant length)
INDEX ON UPPER(PAD(TRIM(Lastname)+", "+Firstname,32)) TO x
? "Enter name to locate:"
mname = KEYINPUT(40,.T.) && they enter "RICHARD LOW"
SEEK NAMESPLIT(mname) && it finds "LOW, RICHARD"
Source: RL_NAMES.PRG
See also: GETPARM(), KEYINPUT()
RLIB Function Reference 113
Function: NO_APPEND()
Purpose: Network append blank function with specific error trapping
Syntax: NO_APPEND( [ color [, msg1 [, msg2 [, msg3 ] ] ] ] )
Arguments: color - Optional character string color setting in
which to display error messages. If omitted or
an invalid value is passed, the default color
is IF( ISCOLOR(), "W+/R", "N/W" )
msg1 - Optional character string first line message to
appear in the error box if an error occurs. If
omitted or an invalid parameter is passed, the
default messages shown below are used.
msg2 - Optional character string second line message
to appear in the error box if an error occurs.
If omitted or an invalid parameter is passed,
the default messages shown below are used.
msg3 - Optional character string third line message to
appear in the error box if an error occurs. If
omitted or an invalid parameter is passed, the
default messages shown below are used.
Returns: True if an APPEND BLANK operation is NOT successful. A
return value of False indicates a record was successfully
appended.
Description: This function, if successful, will append a blank record to
the currently selected database file. NO_APPEND() is most
commonly used in a network environment to provide run time
recovery options from append failures because of file/record
locking conflicts, or from disk failures. It is simpler to
use because it packages the APPEND BLANK command into a loop
which will test for NETERR() and allow retry or abort.
Notes: In a network environment NO_APPEND() abides by the same
record and file lock logistics as APPEND BLANK. If
successful, a record lock is left in place on the newly
appended record unless a file lock was previously in place,
in which case the file lock is left intact.
The NO_APPEND() return value is the reverse of True
indicating success. True indicates failure, False success.
The advantage of this approach is apparent during coding
because most often, specific branch action is taken if an
append fails. See the example for details.
The default first, second, and third line messages that
appear in the BOXASK() message box are as follows:
RLIB Function Reference 114
┌────────────────────────────────────────────────┐
│ │
│ Append record failed! │
│ Another user must have this file locked │
│ Do you want to re-try? (Y/n) │
│ │
└────────────────────────────────────────────────┘
You should use the default messages unless you ensure that
the message you give will let the user know they have the
option to re-try the append operation.
The default answer to the third line prompt is YES, retry.
This will keep the append attempt in a loop. The function
used to get this response is BOXASK() and is set with a
timeout value of 30 seconds. If the user does not respond
within this time, the function will timeout and attempt to do
the append. This allows an append error condition to
automatically recover without user intervention (like in the
middle of the night!) If you program batch mode operations
and must ensure that the program does not enter a loop, use
the APPEND BLANK, command directly then test for NETERR().
See the Clipper manual section on networking operations.
If you want to skip the first color parameter and get at the
following message parameters, as in all cases, pass a dummy
parameter for the color. Although the color parameter is
character in type, a null dummy ("") will work fine since the
parameter is tested with the TYPEC() function which not only
verifies that it is a character type, but that it is not
blank (as is a null).
Example: *-- store empty field values for a new record
MEMORIZE(.T.)
*-- get the data
@ 1,0 SAY "Enter full name" GET M->name
@ 2,0 SAY "Enter birthdate" GET M->birthdate
@ 3,0 SAY "Enter age " GET M->age PICTURE "##"
*-- remember to always PICTURE numeric memory variables!
READ
*-- now add the new record and put in the data
IF NO_APPEND()
SAYINBOX( "R/W", "Record not saved!" )
ELSE
MREPLACE()
ENDIF
*-- now release the public variables!
FORGET()
Source: RL_NO_AP.PRG
See also: OPENED(), NO_FLOCK(), NO_RLOCK(), TYPEC()
RLIB Function Reference 115
Function: NO_FLOCK()
Purpose: Network file lock function with specific error trapping
Syntax: NO_FLOCK( [ alias [, color [, msg1 [, msg2 [, msg3 ]]]]] )
Arguments: alias - Optional character string work area alias name
to lock. If omitted or an invalid parameter is
passed the default is the current work area.
color - Optional character string color setting in
which to display error messages. If omitted or
an invalid value is passed, the default color
is IF( ISCOLOR(), "W+/R", "N/W" )
msg1 - Optional character string first line message to
appear in the error box if an error occurs. If
omitted or an invalid parameter is passed, the
default messages shown below are used.
msg2 - Optional character string second line message
to appear in the error box if an error occurs.
If omitted or an invalid parameter is passed,
the default messages shown below are used.
msg3 - Optional character string third line message to
appear in the error box if an error occurs. If
omitted or an invalid parameter is passed, the
default messages shown below are used.
Returns: True if a lock on the database file in the currently selected
work area failed. A return value of false indicates the file
lock was placed successfully.
Description: NO_FLOCK() is a network database function that simplifies the
tedious task of network database locking mechanics. This
function, if successful, will place a Clipper FLOCK() on the
database file in the current work area, or upon the file in
the work area designated by the parameter ALIAS. NO_FLOCK()
will return to the current select area if an alias is given.
The benefit of using NO_FLOCK() over a simple FLOCK() call is
the automatic re-try built into NO_FLOCK(). If the file lock
fails the user is presented with a BOXASK() message
indicating that they may re-try or cancel the attempt. This
BOXASK() message will timeout after 30 seconds and re-try the
FLOCK().
Notes: The default first, second and third line messages that appear
in the BOXASK() message box are as follows:
RLIB Function Reference 116
┌────────────────────────────────────────────────┐
│ │
│ File lock failed! │
│ Another user must have this file locked │
│ Do you want to re-try? (Y/n) │
│ │
└────────────────────────────────────────────────┘
If you want to supply your own message(s) but do not want to
designate a different alias other that the current work area,
you may either supply the current work area alias as the
first parameter (ALIAS()), or pass an invalid argument such
as a null string or a logical.
You should use the default messages unless you make sure the
message you give will let the user know they have the option
to re-try.
If an invalid alias name is supplied as the first parameter,
i.e. the work area alias name is not in use, NO_FLOCK() will
return .T. and set the appropriate RLIBERROR() value.
The default answer to the third line prompt is YES, retry.
This will keep the lock attempt in a loop. The function used
to get this response is BOXASK() and is set with a timeout
value of 30 seconds. If the user does not respond within
this time, the function will timeout and attempt to do the
file lock. This allows a lock error condition to
automatically recover without user intervention (like in the
middle of the night!)
Example: *-- place a file lock to perform a REPLACE ALL
IF NO_FLOCK()
BOXASK( "File unavailable for update at this time",;
"Press any key to continue" )
ELSE
REPLACE ALL flag_field WITH "*"
UNLOCK && !!!!!!!
ENDIF
*-- another example: lock two database files at one time
IF NO_FLOCK("Customer") .OR. NO_FLOCK("Orders")
BOXASK( "File unavailable for update at this time",;
"Press any key to continue" )
ELSE
*-- do multiple updates here
UNLOCK ALL
ENDIF
Source: RL_NO_FL.PRG
See also: OPENED(), NO_APPEND(), NO_RLOCK()
RLIB Function Reference 117
Function: NO_RLOCK()
Purpose: Network record lock function with specific error trapping
Syntax: NO_RLOCK( [ alias [, color [, msg1 [, msg2 [, msg3 ]]]]] )
Arguments: alias - Optional character string work area alias name
to lock. If omitted or an invalid parameter is
passed the default is the current work area.
color - Optional character string color setting in
which to display error messages. If omitted or
an invalid value is passed, the default color
is IF( ISCOLOR(), "W+/R", "N/W" )
msg1 - Optional character string first line message to
appear in the error box if an error occurs. If
omitted or an invalid parameter is passed, the
default messages shown below are used.
msg2 - Optional character string second line message
to appear in the error box if an error occurs.
If omitted or an invalid parameter is passed,
the default messages shown below are used.
msg3 - Optional character string third line message to
appear in the error box if an error occurs. If
omitted or an invalid parameter is passed, the
default messages shown below are used.
Returns: True if a lock on the database record in the currently
selected work area failed. A return value of False indicates
that the lock was placed successfully.
Description: NO_RLOCK() is a network database function that simplifies the
tedious task of network database locking mechanics. This
function, if successful, will place a Clipper RLOCK() on the
database record in the current work area, or upon the file in
the work area designated by the parameter ALIAS. NO_RLOCK()
will return to the current select area if an alias is given.
The benefit of using NO_RLOCK() over a simple RLOCK() call is
the automatic re-try built into NO_RLOCK(). If the record
lock fails the user is presented with a BOXASK() message
indicating that they may re-try or cancel the attempt. This
BOXASK() message will timeout after 30 seconds and re-try the
RLOCK().
Notes: The default first, second, and third line messages that
appear in the BOXASK() message box are as follows:
RLIB Function Reference 118
┌─────────────────────────────────────────────────────────┐
│ │
│ Lock failed! │
│ Another user must have this file or record locked │
│ Do you want to re-try? (Y/n) │
│ │
└─────────────────────────────────────────────────────────┘
If you want to supply your own message(s) but do not want to
designate a different alias other that the current work area,
you may either supply the current work area alias as the
first parameter (ALIAS()), or pass an invalid argument such
as a null string or a logical.
You should use the default messages unless you make sure the
message you give will let the user know they have the option
to re-try.
If an invalid alias name is supplied as the first parameter,
i.e. the work area alias name is not in use, NO_RLOCK() will
return .T. and set the appropriate RLIBERROR() value.
The default answer to the third line prompt is YES, retry.
This will keep the lock attempt in a loop. The function used
to get this response is BOXASK() and is set with a timeout
value of 30 seconds. If the user does not respond within
this time, the function will timeout and attempt to do the
file lock. This allows a lock error condition to
automatically recover without user intervention (like in the
middle of the night!)
Example: *-- place a record lock to perform a REPLACE
IF NO_RLOCK()
BOXASK( "Record unavailable for update at this time",;
"Press any key to continue" )
ELSE
REPLACE flag_field WITH "U"
UNLOCK && !!!!!!!
ENDIF
*-- Example #2: lock two database file records at one time
IF NO_RLOCK("Customer") .OR. NO_RLOCK("Orders")
BOXASK( "Record unavailable for update at this time",;
"Press any key to continue" )
ELSE
REPLACE CUSTOMER->lastorder WITH DATE(),;
ORDERS->count WITH ORDERS->count + 1
UNLOCK ALL
ENDIF
Source: RL_NO_RL.PRG
See also: OPENED(), NO_APPEND(), NO_FLOCK()
RLIB Function Reference 119
Function: NOTEMPTY()
Purpose: Generic function to validate that data was entered in a field
Syntax: NOTEMPTY( expression )
Arguments: expression - An expression of any type to test if is EMPTY()
Returns: True if <expression> is NOT an empty value.
Description: NOTEMPTY() is usually used in the VALID clause of an @
READ... GET... VALID statement to force data entry in the
GET field. NOTEMPTY() simplifies this chore and provides a
consistent generic error message when all that is needed is a
prompt that the field may not be blank.
Notes: All NOTEMPTY() does is call the EMPTY() function to test if
<expression> is empty. However, NOTEMPTY() goes one step
further by packaging a BOXASK() error message if EMPTY()
returns True. The error message is as follows:
┌──────────────────────────────────────┐
│ │
│ This field may not be blank! │
│ Press any key to continue │
│ │
└──────────────────────────────────────┘
NOTEMPTY() will also BUZZ(), then the BOXASK() message will
timeout after three (3) seconds.
The message is displayed in color IF(ISCOLOR(),"W+/R","N/W")
Example: *-- set up a READ requiring all fields to be entered
@ 1,0 SAY "Full name:" GET name VALID NotEmpty(name)
@ 2,0 SAY "Address: " GET address VALID NotEmpty(address)
READ
Source: RL_NOTEM.PRG
See also: ANYCHARSIN(), BUZZ(), ISFIELD()
RLIB Function Reference 120
Function: NTXKEYVAL()
Purpose: Get the controlling index key value of the current record
Syntax: NTXKEYVAL()
Arguments: None
Returns: The value of the current database record index key, of a type
determined by the type of field in the index key expression.
Description: This function allows you to easily get the value of an index
key field from the currently selected database. It is handy
in place of using the INDEXKEY() function and subsequent
macro substitution.
Notes: If no database file is open, or no index file is open,
NTXKEYVAL() returns a null string ("").
NTXKEYVAL() returns the value of the index key expression,
not the index expression string. It is used to evaluate the
index key for the current record of the currently selected
database. Retrieving the value of the index key field is
useful if you have applications that list records on the
screen.
For instance, while using PICKREC(), you may want to instruct
PICKREC() to refresh the screen if, after a record was
edited, the value of a field used as part of the controlling
index expression was changed. This is because changing such
a record causes the order of the database to appear
different. NTXKEYVAL() can be used to retrieve the value of
the key field before and after the edit. If changed,
PICKREC() can be instructed to repaint the screen with a
<row> value of -1.
Example: *-- index a database with a 12 character long Name field
*-- and a 6 character serial number field
INDEX ON Name+Serialnum TO myindex
SEEK "Low"
? INDEXKEY() && returns "Name+Serialnum"
? INDEXKEYVAL() && returns "Low 12345 "
*------------------------------------------------------------
*-- test if and index key field was changed during an edit
*-- save the index key value for comparison
savekey = NTXKEYVAL()
@ x,y GET keyfield
READ
*-- see if an index key field was changed in the process
IF savekey != NTXKEYVAL()
*-- do corrective things
ENDIF
RLIB Function Reference 121
*------------------------------------------------------------
mrow = 0
DO WHILE .T.
FPROMPT(" ─┘=Edit,Ins=Insert,Del=Delete,Esc=Exit")
mrow =PICKREC(1,0,20,79,"CUSTOMER->Name","","",mrow,.F.,1)
DO CASE
CASE LASTKEY() = 27 && Escape
EXIT
CASE LASTKEY() = 22 && Insert
newrec = .T.
CASE ( BOF() .OR. EOF() ) && a record must exist
LOOP
CASE LASTKEY() = 13 && Enter
savekey = NTXKEYVAL() && save current key value
DO EditRoutine
IF savekey != NTXKEYVAL() && did it change
mrow = -1 && refill box from top
ENDIF
CASE LASTKEY() = 7 && Delete key
BLIP()
IF BOXASK("Delete record? (Y/N) ")="Y"
IF .NOT. NO_RLOCK()
DELETE
UNLOCK
mrow = 0 && force PICKREC() refresh
ENDIF
ENDIF
LOOP
OTHERWISE && trap other exits
LOOP
ENDCASE
ENDDO
Source: RL_NTXKE.PRG
See also: PICKREC()
RLIB Function Reference 122
Function: OLDERFILE()
Purpose: Determine the older of two disk files.
Syntax: OLDERFILE( file1, file2 [, timedigits ] )
Arguments: file1 - Character string or variable indicating the
name of the file to compare with <file2> to
determine which is older.
file2 - Character string or variable indicating the
name of the file to compare with <file1> to
determine which is older.
timedigits - Numeric value indicating the number of
significant digits in the file time character
string to use. If not specified or an invalid
parameter is passed the default of 5
significant digits is used which yields time
comparison to the minutes ("10:01")
Returns: A numeric value indicating one of the following:
0 = file dates and times are equal
1 = file 1 is older than file 2
2 = file 2 is older than file 1
-1 = file 1 does not exist
-2 = file 2 does not exist
-3 = Other (syntax error)
Description: OLDERFILE() is a file function useful for easily comparing
two files to determine which file is older. Alternately, it
can be used to quickly test if two files share the same file
date and time stamp.
Notes: Time precision is only accurate to seconds, not hundredths of
seconds. It is VERY unlikely that two files will have the
exact same creation time to the second much less the
hundredths of a second, hence the default time string
precision is to 5 digits. To get accuracy to the second make
the precision 8 (10:00:00), to hundredths of seconds make the
precision 11 (10:00:00.00)
OLDERFILE() uses the RLIB functions FILEDATE() and FILETIME()
to extract file dates/times from the DOS directory
information. File date and time stamps are subject to the
limitations posed by DOS's maintenance schedule. In other
words, if a file is already open, the date and/or time stamp
from the directory information may not be updated until the
file is closed.
Example: *-- check if database file was updated since last indexed
IF OlderFile("myfile.dbf", "myfile.ntx") = 1
*-- reindex here
RLIB Function Reference 123
*-- or do something else
ENDIF
Source: RL_OLDER.PRG
See also: FILEDATE(), FILES(), FILETIME()
RLIB Function Reference 124
Function: OPENED()
Purpose: Open one or more databases with network error checking.
Syntax: OPENED( [ errorFlag ] database [ ... database10 ] )
Arguments: errorFlag - Optional LOGICAL value which if true will cause
automatic error messages to be displayed. The
default value is True.
database - Character string similar in form to that
supplied to the USE command. This string may
contain one or more INDEX files, and ALIAS name
specifier and an EXCLUSIVE or SHAREABLE keyword
qualifier. Up to 10 database parameter strings
may be passed allowing up to 10 files to be
opened at once.
Returns: True if all files were opened successfully, false otherwise.
If a false is returned an errorlevel is also passed via the
RlibError() function. See below for specific error values.
Description: OPENED() is a database function which lets you open several
database files and indexes with one call! It also checks to
make sure everything opened ok before returning. If any one
of the file opens fails, all files opened thus far in the
call to OPENED() are closed, and a false (and RlibError())
are returned. This is primarily intended to aid the
developer in dealing with opening multiple databases in a
network environment where error trapping is critical.
OPENED() eliminates the messy and cumbersome nested IF
statements necessary to ensure proper error trapping.
OPENED() can also benefit the single user developer by
greatly reducing the amount of code needed to open files and
indexes. See the example below for sample syntax and the
amount of coding it can save!
Notes: OPENED() works by parsing each of up to ten parameters, one
at a time. Each parameter is first verified to be character
then left and right trimmed and converted to upper case.
Next, each parameter is checked for the following keyword
strings:
" ALIAS " -- An alias name was specified.
" INDEX " -- Index file(s) are to be opened.
" EXCLUSIVE" -- File is to be opened in exclusive mode.
" SHAREABLE" -- File is to be opened in shareable mode.
The exclusive and shareable keywords are EXPLICIT
instructions. This means that OPENED() will use the current
default state of SET EXCLUSIVE unless either of these flags
is specified. Since there is no way in native Summer '87
Clipper to query the status of SET EXCLUSIVE, OPENED() cannot
change the setting and return it to its incoming state. This
RLIB Function Reference 125
is one area where OPENED() is not black boxed. (For
compatibility reasons, the Clipper 5.0 version of OPENED()
will NOT save and restore the setting of SET EXCLUSIVE. Some
applications may come to expect the state of SET EXCLUSIVE to
be as the last call to OPENED() left it).
Work area selection:
Upon successful completion, OPENED() leaves the last database
specified as the currently selected work area. If OPENED()
fails, the work area selected upon entry is re-selected, and
all files OPENED() may have successfully opened are closed.
Important points:
1. Index file names MUST be separated by commas, not spaces.
2. Four letter abbreviations such as INDE are NOT allowed.
Parameter sequence:
The order in which the keyword string ALIAS, INDEX,
EXCLUSIVE, and SHAREABLE is arbitrary. The only requirement
is that, naturally, the name of the database file to open is
the first part of the string.
Any of the parameters may be a logical value. If a logical
parameter is encountered, its value is used to set the flag
whether or not automatic error messages are displayed. The
default state is true which means that if a file is not
found, or and index file is not present, or a file open
fails, then an error message will be displayed before
OPENED() stops and returns .F. (plus setting RLIBERROR()).
If this flag is set to false, then error messages will not be
generated, only a return value will signal your application
which may then generate its own error messages.
These logical values may be listed multiple times, the status
takes effect on all files opened after the logical value is
encountered.
One interesting side effect of turning automatic error
messages off is that the user will not have the option of
re-trying to open a file in a network environment, if the
open failed due to an exclusive use conflict; OPENED() will
simply fail and return .F. plus RlibError() = 1101.
RLIBERROR() return values:
The possible RlibError() return values from OPENED() are:
RLIB Function Reference 126
0 = Success
1101 = File sharing violation
1102 = Database .DBF file not found
1103 = Associated .NTX file not found
1104 = Associated .DBT file not found (future)
1105 = Invalid alias name syntax or other syntax error
These error values are established to be in an increasing
order of severity. Normally an error level of 1101 means
that the file was not available in a network environment.
Error levels of 1102, 1103, or 1104 indicate that a run-time
file is not present. This is usually recoverable by
correcting the situation outside of the program. An
errorlevel of 1105 or above is intended to indicate a calling
program syntax problem.
Example: *-- Open three dbf's and indexes in various modes with error
*-- reports in a network environment. See how simple it is!
d1= "cust ALIAS Customers INDEX custName, custNumb SHAREABLE"
d2= "invt ALIAS Inventory INDEX invtNumb, invtDesc SHAREABLE"
d3= "tempdbf.001 INDEX tempntx.001 ALIAS Tempfile EXCLUSIVE"
IF .NOT. OPENED( d1, d2, d3 )
RETURN
ENDIF
*-- ALL DONE!!!!!!!!!!!!!
*-- ============= T H E O L D W A Y =============
*-- Look at all this monstrous code! Yecch! Use OPENED()!
SET EXCLUSIVE OFF
IF ! (FILE("cust.dbf") .AND. FILE("invt.dbf") .AND.;
FILE("tempdbf.001") .AND. FILE("custname.ntx") .AND.;
FILE("custnumb.ntx") .AND. FILE("invtnumb.ntx") .AND.;
FILE("invtdesc.ntx") .AND. FILE("tempntx.001"))
*-- You think this is overkill? What happens if one file
*-- gets deleted from under your nose on a network?
BUZZ(2)
BOXASK( "W+/R", "Required file(s) are missing" )
RETURN
ENDIF
*-- we've only just begun, lots of code still must follow!
SET EXCLUSIVE OFF
SELECT 0
DO WHILE .T.
USE cust ALIAS Customers
IF .NOT. NETERR()
EXIT
ENDIF
IF BOXASK( "File in use by another. Re-try?", 30 ) = "N"
RETURN
ENDIF
ENDDO
RLIB Function Reference 127
SET INDEX TO custname, custnumb
SELECT 0
DO WHILE .T.
USE invt ALIAS Inventory
IF .NOT. NETERR()
EXIT
ENDIF
IF BOXASK( "File in use by another. Re-try?", 30 ) = "N"
CLOSEAREA("Customers")
RETURN
ENDIF
ENDDO
SET INDEX TO invtNumb, invtDesc
SELECT 0
SET EXCLUSIVE ON
DO WHILE .T.
USE tempdbf.001 ALIAS Tempfile
IF .NOT. NETERR()
EXIT
ENDIF
IF BOXASK( "File in use by another. Re-try?", 30 ) = "N"
CLOSEAREA("Customers", "Inventory")
RETURN
ENDIF
ENDDO
SET INDEX TO tempntx.001
*-- FINALLY, we're done! Yech, what a pile of code!
Source: RL_OPENE.PRG
See also: BOXASK(), CLOSEAREA(), RLIBERROR()
RLIB Function Reference 128
Function: PARENT()
Purpose: Retrieve the parent directory for a specified directory.
Syntax: PARENT( [ directory ] )
Arguments: directory - Optional character string indicating the name
of the directory whose parent directory you
wish to find. If not specified or an invalid
parameter is passed, the current directory is
assumed.
Returns: A character string indicating the name of the parent
directory (i.e. the directory above) the specified
directory.
Description: PARENT() is an environment/character function used to parse a
directory name and return the name of the parent directory.
Notes: This can be useful in directory/file management routines when
you want to let a user navigate through the directory
structure. Although you can get the names of sub-directories
with ADIR(), if you want to take them 'back up' a directory,
you have to get the current directory name, and strip it down
to find the parent directory part. PARENT() makes this task
easy.
If the current or supplied directory is at the top level
(i.e. the root directory), PARENT() will return '\'.
PARENT() will return the directory portion of a fully
qualified filename. (See the third example)
Example: *-- if the current directory is \APPS\CLIPPER\TEST
? PARENT() && "\APPS\CLIPPER"
*-- PARENT() with parameters
? PARENT("C:\DOS\UTILITY") && "C:\DOS"
? PARENT("C:\CLIPPER\CLIPPER.EXE") && "C:\CLIPPER"
Source: RL_PAREN.PRG
See also: PATHTO()
RLIB Function Reference 129
Function: PATHTO()
Purpose: Search the DOS path for the path leading to a given filename.
Syntax: PATHTO( filename )
Arguments: filename - Character string indicating the name of the
file to locate through the DOS path.
Returns: A character string indicating the path pointing to <filename>
plus a trailing backslash '\'. If the file is not found
along the DOS path, a null string ("") is returned.
Description: PATHTO() is an environment/character function used to search
the current DOS path to find the path pointing to <filename>.
This can be used to build a fully qualified filename (such as
d:[path]filename) as a character string to be used to open a
file. In the example below, a help file is kept in the same
drive and directory as the program (.EXE) file. The path to
the .EXE file is found and used to point to the help file.
This way, the help file can be located at runtime, provided
the .EXE file is in a directory that is in the DOS path.
Notes: PATHTO() only searches the DOS environment variable PATH so
it will only find files that are located in a drive or
directory that is listed in the path.
Example: *-- Example program name is DEMO.EXE, and help file is named
*-- DEMO.HLP and both are located in C:\MYAPPS.
*-- path=C:\;C:\DOS;C:\CLIPPER;C:\UTILITY;C:\MYAPPS
PROCEDURE Help
PARAMETERS a,b,c
helppath = PATHTO("demo.exe") && returns "C:\MYAPPS\"
helpfile = helppath + "DEMO.HLP" && "C:\MYAPPS\DEMO.HLP"
IF FILE(helpfile)
USE (helpfile)
*-- <help code goes here>
ENDIF
RETURN
Source: RL_PATHT.PRG
See also: PARENT()
RLIB Function Reference 130
Function: PDOWNINIT()
Purpose: Initialize the PDOWNMENU() function for use.
Syntax: PDOWNINIT( row, columns, menus, items, starts ;
[, menu_msgs [, msg_row [, colors ;
[, altkeys [, canexit [, restscrn ]]]]]] )
Arguments: row - Numeric value indicating the row on which the
top of the Pull Down Menu is to appear. Value
may be between 0 and 24 (MAXROW() in the 5.0
version). However, in practice the value will
usually be row number 0 or 1.
columns - Array of numeric values indicating the column
number on which each top level menu option will
be displayed. These column numbers control how
the options and their pull down menus are
spaced across the screen.
menus - Array of character strings which will be used
as the top menu options displayed across the
top of the pull down menu. Each <menu> element
will display at its corresponding <columns>
element number. For example, Menu #2 will
display at coordinate position row,columns[2].
items - Array of character strings which will be used
as the elements, or items, of each of the
pulled down menus. This is a linear array with
each group of pull down menu items being
defined by a starting element number in the
<starts> array.
starts - Array of starting element numbers. Each
element in this array is a number which
indicates the starting position in the <items>
array at which each group of menu items begin.
There should be one element for each
corresponding menu in the <menus> array.
menu_msgs - Optional array of messages which correspond to
each of the menu choices in the <menus> array.
There should be one element for each menu. If
a menu message is to be blank (omitted), insert
a null string ("") as the element value. If
omitted then no messages will display.
msg_row - Optional numeric value which indicates the row
on which the messages contained in the
<menu_msgs> array are to appear. If omitted or
a non-numeric value is supplied, the default
row is row 24. (In the Clipper 5.0 version,
the default row is MAXROW()).
RLIB Function Reference 131
colors - Optional array of character strings indicating
the colors to use for the top bar and pull down
box menus. Each element in the color array
table represents and controls the color for a
separate part of the pull down menu system.
color[1] - Menu choices (item options)
color[2] - Menu selection bar
color[3] - Pull-down ACTIVE menu box
color[4] - Pull-down IN_ACTIVE menu box
color[5] - Menu choice item upon selection
color[6] - Messages displayed on <msg_row>
color[7] - Un-selectable option
color[8] - Top menu bar option upon selection
altkeys - Optional array of character strings which
indicate the set of characters to use as
alternate select keys for each of the pull-down
menu choices. There should be one element for
each corresponding menu. If omitted, the
default direct select keys are the first letter
of each menu item.
canexit - Optional logical value which indicates if
pressing the escape key will cause an exit of
the top level menu. If omitted the default
value is false.
restscrn - Optional logical value which indicates if the
screen area displaced by PDOWNMENU() is to be
used as the screen to restore on each "pull
down" side step. The default is false. See
the notes below for a more in-depth explanation
of this option.
Returns: True if initialization successful, false if parameters error.
Description: PDOWNINIT() initializes PDOWNMENU() for operation and is
required to set up the variables used to control PDOWNMENU().
Since PDOWNMENU() has a lot of work to do, it is inefficient
to repeat many of the processes and parameter passing every
time the function is called. Therefore, the pull down menu
function is split into an initialization routine and the main
menu routine.
A call to PDOWNINIT() establishes the working environment for
PDOWNMENU(). This working environment consists of such items
as the menu column coordinates, the underlying screen, menu
colors, and alternate select keys. If this information had
to be passed to PDOWNMENU() on each call, which is many times
in a menu control loop, then the parameter passing and
parameter parsing overhead would slow PDOWNMENU() down
unnecessarily.
RLIB Function Reference 132
Notes: Upon initialization, a PUBLIC array is established to hold
various environment information. This array is named
RL_PD[], so check that this name does not conflict with any
others in your program. To release this public array, and
clear the PDOWNMENU environment, issue the PDOWNINIT()
function with no parameters. Although not absolutely
necessary, it is probably a good idea to release variables
and arrays that are not being used.
Optional parameters are not required but if you wish to skip
an optional parameter you must pass a dummy value. The best
dummy value to use is a null string "".
The example that follows shows a basic menu and how simple it
is to construct a full featured pull down menu system. For
an extensive example of the ultimate in menu options and
control, see the menu initialization routine in the Message
Reader demo program source code.
Changes from Version 2.0
All changes from version 2.0 are upward compatible. You will
not need to modify any existing code. However, you may want
to modify existing code to take advantage of the new
features. The following sections list the changes that are
specific to some of the parameters, listing the parameter
name, an indicator of the change, and a description of the
change.
<starts> - Expanded from v2.0
If a zero is provided as the starting element number in the
<items> array for the associated menu number, then no pull
down menu will show for that top menu option. This is useful
when you want a top menu option to be a single command all by
itself.
<menu_msgs> - Ignored in v2.0
Although specified in the documentation as the array of menu
ITEM messages, it was not used by PDOWNINIT(). This array
is now used by PDOWNMENU() as the list of messages for each
top (bar) menu option (not the pull-down menu items). This
now gives you the capability of attaching a single line
message to each of the top menu choices as well as the
individual menu items in the sub-menus.
<menu_msgs> - Ignored in v2.0
The <msg_row> parameter was being ignored in version 2.0.
This has now been corrected and is being used as the row on
which messages are display. In version 2.0 messages were
always displayed on row 24.
RLIB Function Reference 133
<colors> - Expanded
The colors array may now contain eight elements. The sixth
element is now used as the color for displaying the optional
messages on <msg_row>. These messages used to be displayed
in the same color as the menu options which was not always,
and rarely, desirable. To maintain upward compatibility, the
color array table may remain at 6 elements however the 6th
element has changed from the top menu bar color on exit.
(See my apology note below). The 7th and 8th elements are
optional. If the 7th element for un-selectable options color
is not given, then the Option color (element #1) is used. If
the 8th element for the top menu bar on selection is not
provided, BRIGHT() is used. The defaults for the menu colors
are as follows:
colors[1] - Current color
colors[2] - Enhanced color
colors[3] - BRIGHT() of current color
colors[4] - Current color
colors[5] - BRIGHT() of current color
colors[6] - Current color
colors[7] - Current color
colors[8] - BRIGHT() of current color
<restscrn> - New parameter
RLIB version 2.0 PDOWNINIT() saved the area of the screen
that was displaced by the menu boxes upon initialization and
restored this original screen upon each entry and side
movement in PDOWNMENU(). This is fine if you don't care if
your screen underneath the PDOWNMENU() is disrupted. In the
case of a pull-down menu that is to overlay an area of the
screen, this is un-desirable. The <restscrn> parameter lets
you control this action. Althought the default value is True
to maintain upward compatibility with RLIB version 2.0, the
better desired default value is False. See the demo.
Separator Lines
If an menu item in a pull-down menu consists of a separator
line composed of ASCII CHR(196) characters, then such lines
will be treated as separator lines and skipped as menu item
selections. The requirements are that a separator line must
not be a pull down menu's first or last option (that doesn't
make any sense anyway) and the line must begin at position #1
in the option string.
Apology Note
At a slight cost of upward compatibility, the <colors> array
has been ordered to be the same as the colors used by
RLIB Function Reference 134
BOXMENU(). Many times you may want to have a BOXMENU() that
cascades below a PDOWNMENU(). By making the color array
tables consistent, you can now pass the same color array to
both PDOWNINIT() and BOXMENU(). Sorry for possibly changing
your menu colors, but it's worth it!
Example: *-- arrays to hold top menu, columns, and starting elements
DECLARE menus[5], columns[5], starts[5]
*-- array to hold each pull down menu items
DECLARE items[12]
menus[1] = "File"
menus[2] = "Edit"
menus[3] = "View"
menus[4] = "Utility"
menus[5] = "Quit"
columns[1] = 0
columns[2] = 24
columns[3] = 41
columns[4] = 58
columns[5] = 76
starts[1] = 1
items[ 1] = "Retrieve "
items[ 2] = "Save "
items[ 3] = "Erase "
starts[2] = 4
items[ 4] = "Record "
items[ 5] = "File "
items[ 6] = "Memo "
starts[3] = 7
items[ 7] = "Record "
items[ 8] = "File "
items[ 9] = "Memo "
starts[4] = 10
items[10] = "Directory "
items[11] = "Reccount "
items[12] = "Index "
starts[5] = 0
*-- initialize menu on row 1 using default colors & keys
CLEAR
PDOWNINIT( 1, columns, menus, items, starts )
Source: RL_PDINI.PRG (RL_PDOWN.PRG in 5.0 Library)
See also: BARMENU(), BOXMENU(), MULTIMENU(), PDOWNMENU()
RLIB Function Reference 135
Function: PDOWNMENU()
Purpose: Activate the pull-down menu initialized with PDOWNINIT().
Syntax: PDOWNMENU( @menu, @item, menus, items, columns, starts;
[, item_msgs [, canexit [, itemflags ]]] )
Arguments: @menu - Numeric variable which indicates the starting
top menu option. This variable must be PASSED
BY REFERENCE by preceding the variable name
with the @ operator. Passing this variable by
reference allows PDOWNMENU() to change its
value.
@item - Numeric variable which indicates the starting
menu item for the starting menu option
indicated by <@menu>. This variable must be
PASSED BY REFERENCE by preceding the variable
name with the @ operator. Passing this
variable by reference allows PDOWNMENU() to
change its value. A value of zero indicates
that the pull-down menu should not be "dropped"
and the menu bar should remain on the top menu
option. The <item> number is relative to the
menu.
menus - Array of character strings which will be used
as the top menu options displayed across the
top of the pull down menu. Each <menu> element
will display at its corresponding <columns>
element number. For example, Menu #2 will
display at coordinate position row,columns[2].
items - Array of character strings which will be used
as the elements, or items, of each of the
pulled down menus. This is a linear array with
each group of pull down menu items being
defined by a starting element number in the
<starts> array.
columns - Array of numeric values indicating the column
number on which each top level menu option will
be displayed. These column numbers control how
the options and their pull down menus are
spaced across the screen.
starts - Array of starting element numbers. Each
element in this array is a number which
indicates the starting position in the <items>
array at which each group of menu items begin.
There should be one element for each
corresponding menu in the <menus> array.
item_msgs - Optional array of messages which correspond to
RLIB Function Reference 136
each of the pull-down menu items in the <items>
array. There should be one element for each
menu item. If a pull-down menu item message is
to be blank (omitted), insert a null string
("") as the element value. If omitted then no
messages will display.
canexit - Optional logical value which indicates if
pressing the escape key will cause an exit of
the top level menu. If omitted the default
value is false.
itemflags - Optional array of logical flags which parallel
each menu item in the <items> array. Each
element value is a logical True or False which
indicates whether or not the corresponding
pull-down menu item is selectable. Un-
selectable menu items are displayed in the un-
selectable color initialized in the color array
in PDOWNINIT(). If this parameter is omitted
or a non-array value is passed, the default is
that all menu items are selectable.
Returns: Since the <menu> and <item> parameters are passed by
reference with the @ operator, the menu and item number
selected is changed for the calling procedure. However,
PDOWNMENU() also returns a single value which is the element
number of the item array element chosen. If only a top menu
option is selected, then the menu array element number is
returned as a negative value. If escape was pressed, and no
selection was made, zero is returned.
Description: The pull down menu consists of two parts: the "top" level
menu which looks and acts like BARMENU(), and the "pulled
down" menus, which look and act like BOXMENU()s. When the
menu starts, the left and right arrow keys move the highlight
bar across the top menu options. When either the ENTER key
or the first letter of one of the menu options is pressed,
the menu drops down to the pull down menu. At this point the
up and down arrow keys highlight the different menu item
options and the ENTER key or first letter will selects each
one. The left and right arrow keys at this point cause
PDOWNMENU() to skip left and right from pull down menu to
pull down menu.
Notes: Make sure that the numeric values referenced by <menu> and
<item> are integer in nature, that is, do not have any
decimal parts. Since Clipper stores numeric values in
internal binary format and not ASCII, numeric comparisons can
sometimes lead to un-predictable and undesired results.
Consider this situation:
x = (1.10 - 1.00) * 10 && will = 1.00
? x = 1 && Clipper will return .F.
RLIB Function Reference 137
Since PDOWNMENU() makes only integer comparisons, make sure
the MENU and ITEM numeric values have no decimal parts.
PDOWNMENU(), like all RLIB functions, uses the RLIB GETKEY()
function to retrieve keystrokes during the menu process. If
you create your own customized version of GETKEY() (see the
function notes for GETKEY()), you can perform various actions
while the pull down menu is in action. Since the <menu> and
<item> parameters are passed by reference, you can examine
their values, as they change, while the menu is active. This
opens up enormous capabilities of things you can do while a
menu is in progress! Consider a demo program that, while the
user is cursoring through a pull-down menu, a box on the
bottom right side of the screen is changing with descriptions
of each menu option.
See the notes for the preceding PDOWNINIT() function.
Example: *-- after having been initialized (see above), do the menu
menu = 1 && start on menu number 1
choice = 0 && do not "pull down" on entry
DO WHILE menu < 5 && menu #5 = Quit
PDOWNMENU( @menu, @choice, menus, items, columns, starts )
DO CASE
CASE menu == 1 && File
FileOp(choice)
CASE menu == 2 && Edit
EditOp(choice)
CASE menu == 3 && View
ViewOp(choice)
CASE menu == 4 && Utility
UtilOp(choice)
ENDCASE
ENDDO
RETURN
*------------------------------------------------------
* Function: FileOp()
* Purpose: Specific file operations based on the value
* of the <choice> parameter.
* Notes: You would have a similar function for
* EditOp(), ViewOp(), and UtilOp()
*------------------------------------------------------
FUNCTION fileop
PARAMETER choice
DO CASE
CASE choice = 1
DO retrieve
CASE choice = 2
DO save
CASE choice = 3
RLIB Function Reference 138
DO erase
ENDCASE
RETURN
Source: RL_PDOWN.PRG
See also: BARMENU(), BOXMENU(), MULTIMENU(), PDOWNINIT()
RLIB Function Reference 139
Function: PICKCOLOR()
Purpose: Pick a color setting from a boxed display.
Syntax: PICKCOLOR( [ pick_color [, box_color [, x_string [, toprow;
[, leftcolumn [, show_names ] ] ] ] ] ] )
Arguments: pick_color - Character string indicating the initial color
to position the highlight bar on as the
selected color. The default is the current
color setting.
box_color - Character string indicating the color to use
for the display box border and color names
text. The default is the current color
setting.
x_string - String to use instead of the X's as the fill
characters in the color boxes. The default
string is a five character string " XXX ".
toprow - Numeric value indicating the top row on which
to position the color grid box. Valid range is
from 0 to 5. If omitted or an invalid number
is given, the default row of 4 will be used.
leftcolumn - Numeric value indicating the left column of the
box display. The default is calculated so as
to center the box on the screen.
show_names - Logical true or false indicating whether or not
to display the color names along the right side
of the selection box. The default is True
(.T.)
Returns: The selected color as a Clipper character color string, or a
null string ("") if terminated by pressing the Escape key.
Description: PICKCOLOR() is very useful as a function to allow the user to
interactively select a color setting from within an
application. PICKCOLOR() draws a box on the screen either
centered or at the column you specify, and fills it with a
grid of 16 rows by 8 columns of " XXX ", or the string you
specify, displaying each of the 128 possible color
combinations. Optionally, the descriptive names of each of
these colors is displayed to the right of the display box.
At the bottom of the screen two sample lines are shown in the
highlighted color setting.
Notes: PICKCOLOR() occupies most of the screen area when displaying
the color grid. Initially PICKCOLOR() was designed to clear
the screen. This was later removed so that an application
could leave instructions somewhere on the screen, perhaps the
menu choice showing the user which color option they were
RLIB Function Reference 140
selecting.
PICKCOLOR() does save and restore the screen area underneath
when it terminates. The initial <pick_color> parameter
determines where the highlight bar is initially positioned in
the grid.
The default x_string is " XXX " with automatic centering. If
you specify a longer (or shorter) string, and you also
specify the left column, PICKCOLOR() will determine if the
column you provided would cause the grid to fall off the
screen. If this happens, the grid will be shifted left the
necessary number of columns. All of these positioning
considerations vary depending whether or not the color names
are displayed, since they take up room on the right side of
the grid.
Example: *-- set up default screen color settings
SETCOLOR("R/W,W/R,,,BG/R")
*-- retrieve current Enhanced & Unselected color settings
m_getcolor = GETPARM( 2, SETCOLOR() )
m_unselect = GETPARM( 5, SETCOLOR() )
*-- present routine to let user select GET color scheme
@ 1,0 SAY "Select color for highlighted variables:"
*-- pop up grid in White on Blue, showing blocks of " ## "
*-- in the top right corner of the screen, no color names
*-- Hint: the column of 79 forces right side alignment
m_getcolor = PICKCOLOR(m_getcolor, "W/B", " ## ", 0, 79, .F.)
@ 1,0 SAY "Select color for unselected variables:"
m_unselect = PICKCOLOR(m_unselect, "W/B", " ## ", 0, 79, .F.)
Source: RL_PICKC.PRG
See also: BRIGHT(), GETPARM()
RLIB Function Reference 141
Function: PICKFILE()
Purpose: Pop up a directory listing from which to select a file.
Syntax: PICKFILE( [ filespec [, top [, left [, bottom [, colors;
[, expanded [, showpath ]]]]]]] )
Arguments: filespec - Optional character string indicating the
filespec to use for the directory search. This
filespec must follow the conventions required
by ADIR(). If omitted, PICKFILE() defaults to
all files (*.*).
top - Optional numeric value indicating the top row
for the directory box. If omitted or an
invalid type parameter is specified, the
default row is row 6 to center the box on the
screen.
left - Optional numeric value indicating the left
column for the directory box. If omitted or an
invalid parameter is specified, the default is
the column position necessary to center the
directory box on the screen.
bottom - Optional numeric value indicating the bottom
row for the directory box. If omitted or an
invalid type parameter is specified, the
default row is row 19, to center the box on the
screen.
colors - Optional character string specifying the color
settings to use. This color setting is passed
to ACHOICE() so the format is that required by
ACHOICE().
expanded - Optional logical value indicating if the file
listing display is to be expanded to include
the file size, date, and time. If omitted or
an invalid parameter is passed, the default
value is true, display expanded listing.
showpath - Optional logical value indicating whether or
not to display the filepath specified on the
top of the box. If omitted or an invalid
parameter is passed, the default value is
false.
Returns: The selected filename as a character string, or a null string
("") if the Escape key was pressed.
Description: PICKFILE() is a full featured file function which provides
easy access to a pop-up boxed file directory listing from
which to choose a file. PICKFILE() is very useful for
RLIB Function Reference 142
popping up file selection menus when a user is required to
enter a filename for a file that already exists on disk.
Notes: After the file selection is made, the menu box disappears and
the screen below it is restored.
The previous version of PICKFILE() in RLIB v 2.0 would not
return a fully qualified filename. If you selected a file
that was not in the current directory, only the filename was
returned, not the full path preceding it. This has been
fixed in version 3.0
Example: *-- ask user for name of .DBF file to USE
*-- make the F10 key the pop-up controller
SET KEY -9 TO FileLister
*-- allocate plenty of space for fully qualified filename
dbf_file = SPACE(60)
@ 10,0 SAY "Enter filename or press F10 for a list";
GET dbf_file PICTURE "@!S40"
READ
USE (dbf_file)
*--<now do whatever>
*-----------------------------------------------------------
* Procedure: FileLister
* Notes: Procedure to pop-up list of .DBF files. This
* example uses the macro operator to assign the
* picked filename to the READVAR. In Clipper
* 5.0 if the READVAR() is not a PUBLIC or PRIVATE
* variable, this will not work.
*-----------------------------------------------------------
PROCEDURE FileLister
PARAMETERS callproc, callline, inputvar
&inputvar = STRETCH( PICKFILE("*.DBF"), LEN(&inputvar) )
RETURN
Source: RL_PICKF.PRG
See also: FILEDATE(), FILESIZE(), FILETIME(), PICKREC()
RLIB Function Reference 143
Function: PICKREC()
Purpose: Pop up a scrollable pick list of database records.
Syntax: PICKREC( t, l, b, r, fieldlist [, procname [, condition ;
[, pickrow [, exitkeys [, pickmode ;
[, markkey [, markfield [, colors [, boxchars ;
[, boxheader [, restore ]]]]]]]]]]] )
Arguments: t,l,b,r - Numeric values specifying the Top, Left, Bottom
and Right screen coordinates of the display
box. The top and bottom row values must be
between 0 and 24 (MAXROW() in 5.0), and the
left and right column values must be between 0
and 79.
fieldlist - Character string that evaluates to a valid
character expression. This character
expression is evaluated via macro expansion to
produce the text that is displayed in the
PICKREC() display box and the scrolling
highlight bar. Since it is macro expanded, it
must evaluate correctly to a character string.
Any valid expression may be used. Normally the
expression contains a database field list such
as "Lastname + ' ' + Firstname", hence the name
<fieldlist>.
procname - Optional character string indicating the name
of the procedure to call after each keypress.
Since the call to this procedure is named at
runtime via macro substitution, the procedure
name must be identified to the compiler/linker
by using the EXTERNAL declaration unless it is
included in or is a module that will be linked.
If omitted or an invalid or empty character
parameter is provided, the default is no
procedure will be called.
condition - Optional character string indicating the
condition that records must meet to be included
in the list. This character string is
evaluated at runtime via macro substitution,
therefore it MUST evaluate to a logical
expression! If omitted or an invalid or empty
character parameter is provided, the default
condition is ".T.", i.e. all records in the
database will be included.
pickrow - Numeric value indicating the current row number
of the 'selection bar'. This parameter is
required to allow PICKREC() to 'remember' where
the bar was upon return from a previous
selection. Additionally, this parameter allows
RLIB Function Reference 144
display refresh control by optionally passing
the following values:
0 - Clear display box, GO to the TOP of the
selected database or to the first record
meeting the <condition> if specified, and
display records until box filled, End Of
File, or <condition> is false. Zero is
the value passed at startup.
-1 - Clear display box, display records
starting at the current record until box
filled, EOF() .OR. (.NOT. &condition).
exitkeys - Optional character string which consists of a
set of characters which, when pressed, will
cause PICKREC() to exit. If omitted or an
invalid parameter is passed, the default is
CHR(22) + CHR(7) which are the character values
of the Insert and Delete keys.
pickmode - Optional numeric value indicating the action
mode for PICKREC(). If omitted or an invalid
parameter is passed, the default mode is zero.
See the detailed notes section for more
information. The allowed values are:
0 - No refresh, pick up at current
record/row.
1 - Refresh record display at current
record/row.
2 - Same as mode 1 above but tell PICKREC()
to not wait for or process any keys but
to immediately exit.
markkey - Optional mark/unmark key ASCII value which,
when pressed, toggles the current record being
included in a "marked" list. If omitted or a
non-numeric value is passed then mark toggling
will not be activated. If numeric with a value
of zero, the default ASCII key value is -8, for
the F9 key.
markfield - Optional field name or expression evaluated and
used to add an item to the marked list. If the
mark option is not activated (<markkey> not
defined), then <markfield> is ignored. If
marking is on and <markfield> is either omitted
or is non-character in type or empty, then the
default expression used to add items to the
marked list is "STR(RECNO(),8,0)"
RLIB Function Reference 145
colors - Optional array of color settings used to govern
the colors of various parts of the PICKREC()
display. See the table listed below for
options and default values if the array is not
provided.
boxchars - Optional character string to use in drawing a
box around the PICKREC() border using the
@..BOX command. The boxing character string
must be in a form acceptable to BORDERBOX()
since BORDERBOX() is used to draw the box and
header (if specified). If omitted, empty, or a
non-character type parameter is passed, no box
will be drawn.
boxheader - Optional character string to use as a header to
display in a header area of a BORDERBOX() style
box. The string must be in a form acceptable
to BORDERBOX(). If omitted or a non-character
type parameter is passed (or boxchars) was not
specified, no box header will be drawn.
restore - Optional logical value indicating whether or
not to restore the screen area displaced with
the PICKREC() to its contents prior to
PICKREC() being called. If omitted or a
non-logical value is passed, the default is
False.
Returns: The row number of the selected record, or zero if the Escape
Key was pressed to exit. If either the insert or delete keys
are pressed, the routine exits to the calling procedure which
can test for Insert or Delete with the LASTKEY() function.
Description: PICKREC() is a database interface function which permits
scrolling through a picklist of records from the currently
selected database. It provides an easy method to PICK a
RECord from a database. Pressing the ENTER key selects a
record for further processing. Views are also supported in
that the fieldlist data which is displayed can be any valid
expression including field data from related databases.
Some of the most functional uses are to produce pop-up
listings in windows for on line help, or for supplying a menu
of database records from which to select for editing,
appending or deleting. You simply give the function the four
screen coordinates defining the display box, and the field
list or expression to display, and it lists these expressions
in a box for you to cursor up and down through to find the
one you want and select it by pressing ENTER. Other
parameters allow you to call a procedure to perform display
duties each time the arrow keys are pressed, and facilities
for controlling the display refresh.
RLIB Function Reference 146
This description is only the tip of the iceberg. PICKREC()
is a powerful tool! The various parameters extend the finest
level of control while not forcing you to write your own
customized DBEDIT() style picklist routine; most of the grunt
work has been done for you.
Notes: PICKREC() skips forward and backward through the database
records as the up and down arrow keys are pressed. The PgUp
and PgDn scroll one window full of records. When the Enter
key is pressed, PICKREC() exits with the record pointer
positioned at the selected record. If the Escape Key is
pressed, the record pointer is at the last displayed record,
but PICKREC() returns zero.
As always, if any parameter is to be skipped, pass a dummy
parameter such as a null string in place of the actual
parameter.
Key handling:
The following default key actions are defined for PICKREC():
Key Action
--------- -------------------------------------------------
Up Skip back one record, scroll screen if at top
Down Skip forward 1 record, scroll screen if at bottom
PgUp Skip back <n> records (n = winBottom - winTop)
PgDn Skip forward <n> records
Home Goto logical top (GO TOP if no condition)
End Goto logical bottom (GO BOTTOM if no condition)
Escape Abort, return zero
Enter Highlight current record, return current pickrow
Alt-R Refresh screen
Character Start/continue indexed search
Screen refresh: (Alt-R)
If you use your own replacement GETKEY() function you can
send PICKREC() certain messages in the form of keystroke
requests such as inkey value 275 which equals Alt-R to
refresh the screen.
Indexed search:
PICKREC() has built in an indexed search capability.
However, this feature is only available if the database
underlying the PICKREC() session is indexed and that index is
active. The index must be character in nature.
The index feature works as follows. When PICKREC() is
active, if the user presses a character key, such as a
letter, PICKREC() performs a SEEK on that letter. If a
RLIB Function Reference 147
record is found, the PICKREC() display is refreshed with the
found record appearing at the top of the display box. At
this point the index search is still "active" and the user
can "home in" on the correct record by pressing another
letter key. PICKREC() will then SEEK the first letter
pressed plus this next letter. This process will continue
until the SEEK fails or a standard PICKREC() control key,
such as the up or down arrow, is pressed.
For example, if PICKREC() were listing a database of customer
names, lastname first, and the user pressed "L", PICKREC()
would jump to the first record with a lastname beginning with
"L". If the user next pressed "O", PICKREC() would jump to
the first name beginning with "LO", and so on.
Additional parameter information:
<fieldlist>
If the <fieldlist> is wider than the width of the display box
area (right - left - 1) PICKREC() will truncate the
expression text to fit in the display box. If <fieldlist> is
narrower than the display box width, PICKREC() will pad the
<fieldlist> text with spaces sufficient to extend the
highlight bar the width of the display box.
<procname>
This feature is useful for creating applications that refresh
an area of the screen as the user scrolls through the
PICKREC() display. As PICKREC() cycles through the loop that
retrieves keystrokes it displays the <fieldlist> expression
for the current record then calls <procname> before
retrieving the next keystroke. <procname> is called as a
procedure via macro substitution with the code "DO &procname"
therefore the <procname> procedure must be known at runtime.
This means that the linker will not find and resolve
<procname> on its own. The best way to ensure that
<procname> is linked in is to declare it as EXTERNAL in the
module which contains the PICKREC() call.
<condition>
The <condition> parameter does not perform the function of a
FILTER. Instead <condition> is intended to be used with an
indexed database. PICKREC() abides by <condition> on a WHILE
basis. This means that the database should be indexed such
that all of the records that meet the <condition> are
logically grouped together. Furthermore, if <condition> is
specified, the programmer must position the database record
pointer to a record that meets the <condition> before the
call to PICKREC().
RLIB Function Reference 148
The <condition> character string MUST evaluate to a logical
expression. For example, to list all sales orders for
customer code RCL100, the condition would be "ALIAS->CUSTNO =
'RCL100'". Notice that strings enclosed in quotes are
bounded by quotes within quotes. If this condition does not
evaluate to a logical expression, a runtime TYPE MISMATCH
error may occur. RLIB will make an attempt to verify that
the string is logical in nature.
<exitkeys>
To maintain upward compatibility with previous versions of
PICKREC(), the default exit keys are INSERT and DELETE. In
addition, the default keys which cause an exit condition are
ENTER and ESCAPE. Escape will force a return of zero while
ENTER will cause the current record to be highlighted. Do
not supply CHR(27)+CHR(13) (ENTER and ESCAPE) as exit keys
unless you purposefully want to bypass the default actions
that are performed when ENTER or ESCAPE is pressed. If you
do pass these keys, or any other keys (such as up, down etc.)
the internal actions that PICKREC() performs on these keys
will be circumvented. This usually is not desired, however
this does allow you the option to bypass the standard
function of one of these keys and substitute your own routine
instead. To bypass this parameter, you must pass some
parameter so pass a non-character such as a logical. If you
pass a null this will disable the default exit keys of Insert
and Delete.
Most keys can safely be represented in this string in their
CHR() forms. Certain function keys, notably F2-F10 return
negative inkey() values. Their CHR() return values wrap to
the very high ASCII characters. For instance the inkey value
for F2 is -1. To express this with the CHR() function,
CHR(F2) is the same as CHR(-1), which is the CHR(254)
character. Likewise, F3 is -2 and CHR(-2) = CHR(253) and so
on. The end result is that placing function key values on
the <exitkey> string reveals a string with high ascii
characters. This works fine. The only potential, albeit
very slight, problem is if a user were to hold down the alt
key and press 253 on the numeric keypad, they would get the
same action if they had pressed F2.
<pickmode>
This is a numeric "action" indicator which tells PICKREC()
how to display records. It is usually used on re-entry to
PICKREC() since an initial call to PICKREC() uses a <pickrow>
parameter value of 0, or -1. (See the <pickrow> parameter
details above.) This mode parameter can be used in
conjunction with <pickrow> so that PICKREC() can use the
saved value of <pickrow> to help refresh the record display
in a more natural way. Usually, you will save the screen
after a PICKREC() selection, do some processing, then loop
RLIB Function Reference 149
back to the next call to PICKREC() after restoring the
screen. If the <pickrow> parameter is intact, (not 0 or -1)
PICKREC() does not do any record displaying, it just picks up
and displays the current record on the row indicated.
However, after a record INSERT or DELETE, a value of -1 is
best passed which forces a record re-fresh, but from the top
row. This doesn't always look very clean.
The following action modes are defined:
0 - No refresh, pick up at current
record/row. This is the default mode.
The <pickrow> parameter is used to tell
PICKREC() whether or not to fill the box
with records.
1 - Refresh record display at current
record/row. PICKREC() will fill the box
with records from the current record. It
will SKIP backwards to fill from the
current row back up to the top, then will
go back to the starting record, fill
forward the remaining box, then return to
the starting record. If you've ever
watched the DBEDIT() function refresh the
screen when you page down, you'll notice
how this behaves.
2 - Same as mode 1 above but tell PICKREC()
to not wait for or process any keys but
to immediately exit. This is useful for
using PICKREC() to perform screen
refreshes for you without having to code
a bunch of DO WHILE.. SKIPs etc.... If
the <pickrow> parameter is zero, then the
box will fill from the GO TOP (see
<pickrow> parameter), but this mode will
instruct PICKREC() to exit.
<markkey>
An enhancement to PICKREC() was to give it MARKREC()
capabilities. The "mark" parameters are optional, if they
are supplied, PICKREC() will adopt MARKREC() characteristics,
but in all other ways will continue to behave just like
PICKREC(). The main reason for doing this was to exercise
practical memory usage. Since the two functions share almost
identical code, it was sensible to merge the two. For upward
compatibility reasons, the existing function names still
exist, except that MARKREC() now simply calls PICKREC() with
the extended parameters.
One interesting note is that you can use PICKREC() as
MARKREC() directly. However, PICKREC() returns a numeric
RLIB Function Reference 150
value and MARKREC() returns a character string (the string of
marks). If you want to use PICKREC() directly, you must
establish a memory variable named <rl_marked> before calling
PICKREC(). This is precisely what MARKREC() does; it
initializes <rl_marked>, then calls PICKREC() with the
appropriate parameter values, then returns <rl_marked>. If
you want to preserve the value of this marker variable
<rl_marked> when PICKREC() exits (for instance you need to
exit PICKREC() temporarily to process a F1 Help request),
then you would establish <rl_marked> by setting it to a null
("") before the very first call to PICKREC(). Remember
however to make sure you release <rl_marked> or re-initialize
it back to a null ("") before your next fresh call to
PICKREC() for marking. For this reason, <rl_marked> is not
declared PRIVATE in this code.
<colors>
Another side benefit to all this is that you can now
explicitly define color settings for PICKREC(). If you do
not want to use marking but want to get at the color
parameter, pass as the markkey parameter a non-numeric
parameter ("") to get at the colors array. This allows you
more control over the highlight color rather that accepting
the BRIGHT() version of the default color.
The elements of the color array are:
Element# Description Default
-------- ------------------------- ----------------------
color[1] Normal text display Standard - SETCOLOR()
color[2] Selected or Marked BRIGHT() Standard
color[3] Hi-lited (scroll bar) Enhanced
color[4] Hi-lited & Selected/Marked Enhanced/Bright/Blinking
color[5] Color on exit from XITKEYS BRIGHT() Standard
Advanced Color Features:
The color array elements #6, 7 and 8 can be used to display
records in a different color if a specified condition exists.
The condition is a logical expression which is represented by
the color array element #8. If this condition expression
evaluates to True (via macro substitution) then the
<fieldlist> text will be displayed in color[6] for normal
display, and color[7] when highlighted.
Element# Description Default
-------- ------------------------- -----------------------
color[6] Normal text IF (color[8]) Standard - SETCOLOR()
color[7] Hi-lited IF (color[8]) Enhanced
color[8] Character condition (.T.)
Example: See several examples in the Message Reader demo program.
RLIB Function Reference 151
*-- Example #1, fairly basic pick and edit routine
fieldlist = "Lastname+', '+Firstname+' - '+Fonenumber"
pickrow = 0
pickmode = 1
boxchars = "╔═╗║╝═╚║"
boxheader = "AVAILABLE PHONE LISTINGS"
restore = .F.
SELECT Fonebook
DO WHILE .T.
*-- now present records from database to choose from
pickrow = PICKREC( 4, 40, 23, 79, fieldlist, "", "",;
pickrow, xitkeys, pickmode, "", "",;
"", boxchars, boxheader, restore )
DO CASE
CASE pickrow = 0 && Escape returns 0
EXIT
CASE LASTKEY() = 22 && Insert Key - add a record
MEMORIZE(.T.) && Initialize empty structure
DO edit_proc && perform edits on new entry
pickrow = -1 && force screen refresh with -1
CASE LASTKEY() = 7 && Delete Key
IF BOXASK("W/R","Are you sure? (Y/N)") = "Y"
DELETE
pickrow = 0 && start over at top of file
ENDIF
CASE LASTKEY() = 13 && Enter Key - edit record
*-- get controlling index key expression if any
ntx_key = NTXKEYVAL()
DO edit_proc
*-- now see if edits changed an index key value
IF .NOT. ntx_key == NTXKEYVAL()
*-- field contents changed from before edits
*-- must refresh screen so order is in sync
pickrow = -1
ENDIF
ENDCASE
ENDDO
*-- Example #2:
*-- use PICKREC() to provide pop-up help in field edits
SET KEY -1 TO PopUpHelp && F2 key is pop-up help
mzip = SPACE(5)
@ 10,0 SAY "Enter zip code (press F2 for listing)";
GET mzip PICTURE '#####'
READ
RLIB Function Reference 152
.
.
.
.
PROCEDURE PopUpHelp
PARAMETERS callproc, linenum, inputvar
PRIVATE inarea
inarea = SELECT()
SELECT ZipCodes
BORDERBOX( 1, 50, 20, 79, "ZIP CODE LISTING" )
IF PICKREC( 4, 51, 19, 78, "Zip + ' - ' + City" ) > 0
mzip = ZIPCODES->ZipCode
ENDIF
SELECT (inarea)
RETURN
Source: RL_PICKR.PRG
See also: MARKREC()
RLIB Function Reference 153
Function: POPBOX()
Purpose: Restore a screen from a SAYINBOX() screen variable.
Syntax: POPBOX( sayinbox_return_string )
Arguments: The specialized character string that was returned by the
last call to the SAYINBOX() function.
Returns: True.
Description: POPBOX() is a companion function to the SAYINBOX() function.
SAYINBOX() returns a character string which contains not only
the contents of the displaced screen image, but also the
coordinates of this screen region displaced by SAYINBOX().
This character string can be used as a parameter to this
companion function to restore the screen to the way it was
before SAYINBOX() was called. This feature is ideal for
situations where you want to put up a message box, do some
processing, then remove the message box while restoring the
screen to its previous state.
Notes: The string parameter must be the one returned by SAYINBOX(),
otherwise unpredictable results may occur. This is due to
the fact that SAYINBOX() stores the four screen coordinates
(top, left, bottom, right) as the first four characters in
the return string, and POPBOX() uses these coordinates as the
screen coordinates to issue a RESTSCREEN() function.
Example: *-- example of an INDEX message
pbox = SAYINBOX( "BG+/B", "Indexing, please wait" )
*-- Do the indexing, message will remain
INDEX ON keyfield TO indexfile
*-- Remove the message
POPBOX(pbox)
Source: RL_SAYIN.PRG
See also: ABOXASK(), BOXASK(), SAYINBOX()
RLIB Function Reference 154
Function: POPUPPICK()
Purpose: Generic pop-up pick list handler
Syntax: POPUPPICK( t, l, b, r, disp_field [, message, [, box_title,;
[, rtrn_field [, alias [, color ] ] ] ] ] )
Arguments: t,l,b,r - Top, Left, Bottom, Right window coordinates
bound checked to be within 0,0 to 24,79. Also,
if the left + width of disp_field would cause
the display to overflow the right side of the
window, the display is truncated as per
PICKREC()
disp_field - Character string which is the name of the
database field or expression to display in a
PICKREC() box. This may be any expression that
evaluates to a character string.
message - Optional message to display on line 24. If
omitted or an invalid or empty character
parameter is given, then default message will
be: "Choose with ^X^Y, select with ^Q─┘, or
press ESCAPE to quit" it will be centered on
row 24. In the Clipper 5.0 version the message
is displayed on MAXROW().
box_title - Optional character string indicating the title
to appear in the pop-up box header area. If no
title is specified, the box will have no header
area.
rtrn_field - Optional character string indicating the field
or expression to return as the selected value.
This may be any expression. If omitted or a
non-character parameter is supplied, the
default field is [disp_field].
alias - Optional character string indicating the name
of the database work area to select for the
pop-up. If omitted or a non-character
parameter is given, the default is the current
work area, ALIAS().
color - Optional array of color settings used to govern
the colors of various parts of the display.
This color array has the same structure as the
color array required by PICKREC(). See the
table below.
Returns: Selected <rtrn_field> contents, or a null string if escape
pressed.
Description: POPUPPICK() is a database function to provide a pop-up
RLIB Function Reference 155
listing for a database. It is particularly helpful in
applications where you need a consistent convention for
calling help pick lists. POPUPPICK() is also very useful for
creating pick lists in data entry validation functions.
Notes: The first five parameters are required. If any of the
remaining parameters are to be skipped, you must pass a dummy
parameter such as a null in its place. The message is
displayed on line 24 (or MAXROW() in the 5.0 version) in the
current color setting before the color is changed.
POPUPPICK() assumes the required database(s) is/are already
opened. The database need not be SELECTed if the alias name
parameter is specified.
<colors>
Element# Description Default
-------- ------------------------- ----------------------
color[1] Normal text display Standard - SETCOLOR()
color[2] Selected or Marked BRIGHT() Standard
color[3] Hi-lited (scroll bar) Enhanced
color[4] Hi-lited & Selected/Marked Enhanced/Bright/Blinking
color[5] Color on exit from XITKEYS BRIGHT() Standard
color[6] Normal text IF (color[8]) Standard - SETCOLOR()
color[7] Hi-lited IF (color[8]) Enhanced
color[8] Character condition (.T.)
Example: *------------------------------------------------------------
* Procedure: Help
* Purpose: Help facility, called with SET KEY 28 TO Help
*------------------------------------------------------------
PROCEDURE Help
PARAMETERS callproc, linenum, readvar
PRIVATE htop, hleft, hbottom, hright, houtput, hmessage
PRIVATE htitle, hfield, halias, hpick
*-- By default, Clipper starts every application with the F1
*-- key set to call Help. This is equivilent to issuing the
*-- command: SET KEY 28 TO Help. Since we don't want Help to
*-- be called recursively while in Help, we need to disable
*-- the F1 help key with the following command:
SET KEY 28 TO
IF readvar == "VENDOR"
htop = 1
hleft = 78 && will force right alignment
hbottom = 22
hright = 79
houtput = "' '+VENDOR->name"
hmessage = "Select a vendor from the following list"
htitle = "VENDOR LISTING"
RLIB Function Reference 156
hfield = "VENDOR->name"
halias = "Vendors"
hpick = PopUpPick( htop, hleft, hbottom, hright,;
houtput, hmessage, htitle,;
hfield, halias )
IF LASTKEY() != 27
M->vendor = STRETCH( hpick, LEN(M->vendor) )
ENDIF
ENDIF
*-- ok, now turn Help back on
SET KEY 28 TO help
RETURN
Source: RL_POPUP.PRG
See also: PICKREC(), RH_HEADER(), RH_LINES(), RH_TEXT(), RH_WIDTH()
RLIB Function Reference 157
Function: PRINTCODE()
Purpose: Convert text printer codes into actual escape sequence codes.
Syntax: PRINTCODE( textcodes )
Arguments: textcodes - The character text printer codes to parse and
convert into actual printer control codes.
Returns: The parsed printer control codes.
Description: PRINTCODE() is a printer function that helps application
programmers easily store and retrieve printer control codes
as character strings that can be edited.
The format of the <textcodes> string is industry familiar.
ASCII codes are entered as a series of comma delimited
numbers, each one representing one control character. Actual
characters may be entered instead of or in conjunction with
ASCII codes, the only requirement being that literal codes
are enclosed in double or single quote delimiters.
Notes: Printer control strings that are parsed by PRINTCODE() have
either the form: "27,'(s3B'", or "27,40,115,51,66". The
first format combines an ASCII character designation for the
escape character (ASCII value = 27 decimal) followed by the
actual literal character sequence "(s3B". The second example
specifies the escape sequence as a list of decimal ASCII
values.
The PRINTCODE() function is used by the REPORTINIT() function
to initialize printer control codes.
Example: *-- store some LaserJet control codes in a database
USE printers
REPLACE reset WITH "27,'E'"
REPLACE bold_on WITH "27,'(s3B'"
REPLACE bold_off WITH "27,'(s0B'"
*-- or it could be entered as
REPLACE bold_off WITH "27,40,115,51,66"
*-- use PRINTCODE() to translate codes stored in a database
*-- and place printer in Bold mode
? PRINTCODE(reset) + PRINTCODE(bold_on)
?? "RLIB users program quicker and better!"
?? PRINTCODE(bold_off)
*-- or, create character enhancement functions
? BOLD("Hello RLIB world")
*-- where the following function is defined
*-------------------------------------------------------
FUNCTION Bold
RLIB Function Reference 158
PARAMETER string
RETURN PRINTCODE(bold_on) + string + PRINTCODE(bold_off)
Source: RL_PRINT.PRG
See also: REPORTINIT(), STARTREPORT()
RLIB Function Reference 159
Function: QUERY()
Purpose: Create a logical query/filter string via menu prompts.
Syntax: QUERY( [ names [, fields [, types ] ] ] )
Arguments: names - Optional character array containing the field
names or expression names to pop up as
selections to the query builder. If omitted or
an invalid parameter is passed, the default
will be all field names in the currently
selected database.
fields - Optional character array containing the field
or expressions to be evaluated corresponding to
the fields or expression names in the <names>
array. If omitted or an invalid parameter is
passed, the default will be all field names in
the currently selected database.
types - Optional array of single character elements in
which each element identifies the type to use
in the query process for each corresponding
expression in the <fields> array. If a given
type element is not character in type, or is
not one of the characters C,N,D,L,M then the
query type will be determined by the actual
type of the <fields> element.
Returns: A character string containing the selected <fields>
expressions which must evaluate to a logical true or false
when expanded via macro expansion.
Description: QUERY() is a high level full screen function that provides
menu driven access to a powerful query builder. A list of
fields or expressions from the current database is presented
from which the user selects. After a field is selected, a
menu of operators for the particular data type of the field
is presented. Once an operator is selected, the query data
is requested. An optional array of expressions may be given
in place of default field names. QUERY() provides a very
sophisticated and powerful tool to give end-user applications
full report query control.
To learn more about the power of QUERY() see the RLIB Message
Reader demo program, and select the Query option!
Notes: The <names> array contains the names you want shown in the
pop up selection box. The <fields> array contains the actual
field or expression names to be evaluated. For instance if
one of the fields is named MSG_CNT, specify "Message Count"
in the <names> array whereas in the <fields> array specify
"MSG_CNT". This lets the user pick a descriptive field from
the list and be shielded from the actual cryptic field names.
RLIB Function Reference 160
If the <names> array is omitted (or skipped by passing a
dummy parameter) then the <fields> array will default to the
same names in the <names> array EVEN IF YOU SPECIFY A
<fields> ARRAY. This is because the names must match the
fields.
The <fields> array may contain any valid expressions,
including references to user-defined functions. The only
criteria is that the expression must evaluate correctly at
run-time. The query builder will check all expressions and
if an invalid expression is encountered will set RLIBERROR()
and return a null.
The <types> array allows you to force QUERY to pop up a
specific selection scheme regardless of the actual type of
the <fields> array element selected. A specific example of
this is when you supply a <fields> element that uses
QUERY()'s built in macro substitution, or replaceable
parameter. Suppose for instance that the <fields> element is
"CONTAINS('%v')" and the CONTAINS() UDF returns a logical
type result. By default QUERY() would evaluate CONTAINS() as
logical and present the selection window for a True or False
selection. But suppose the purpose of your CONTAINS()
function was to take a character parameter, and return true
if that parameter was contained in multiple records (hence
why you could not simply use the $ operator.) By giving a
<types> element of "C", QUERY would present the character
selection choices, then insert your selection into CONTAINS()
by virtue of the macro %v option. See the example for a more
detailed and specific example.
The three macros are:
%v - Replace %v with the data value entered,
as a character string.
%o - Replace %o with the operator (i.e. =, <,
> ) as a character string.
%c - Replace %c with ".T." if case is to be
honored, or ".F." if case is to be
ignored.
<types> is an advanced feature which you do not have to use.
It is there to provide total control over the query building
process. USE IT WITH CARE! Query() normally verifies that
all field expressions are valid. However, because of the
macro substitution feature these fields would not otherwise
evaluate. So if you plan on using the %% feature you will
HAVE to supply a TYPE for each field that uses %% AND Query
will bypass the expression validation for each of those
fields.
RLIBQUERY:
RLIB Function Reference 161
In addition to returning a logical expression value, QUERY()
declares a public variable named RLIBQUERY. Query() stores
the resulting query text, that shows in the query window, in
this public variable for your reference. It is a character
string with hard carriage returns between each statement and
can easily be displayed with MEMOEDIT().
The Example
In the example below there are two databases. The first is
named INVOICES and contains records of all invoices created.
The second database, DETAIL contains the detail for each line
item associated with an invoice. Each DETAIL record
represents one line item entry into an invoice and each
record contains the invoice number which is the key to the
parent invoice.
Most of the field names, descriptions and types are self-
explanatory and the defaults will suffice. However, scanning
the line item DETAIL file can be tricky. This is a perfect
example of how to use the macros built into QUERY(). The
third <fields> element is "DetailDesc('%v',%c). This is a
user-defined function that accepts two parameters. The first
parameter is a text string for which to scan the DETAIL line
item description records and the second is a logical value
indicating whether case should be respected. DetailDesc()
returns a logical True if a detail record is found which
contains the indicated text. For this reason the <types>
array element must be forced to "C" to tell QUERY() to ask
the user for character type data rather than logical, the
default for the DetailDesc() function. (Also, QUERY() cannot
properly evaluate DetailDesc() at runtime to determine its
type because of the embedded macro references.
Once the query is built a temporary index is created. The
index evaluates the query and if a record meets the query
condition, it is placed at the front of the index. This is
accomplished through the use of the IF() function. Once
indexed, the "subset" or "view" of records meeting the query
is presented for view with PICKREC() with the condition being
that all records must meet the query condition.
Example: DECLARE names[5], fields[5], types[5]
names[1] = "Invoice Number"
names[2] = "PO Number"
names[3] = "Item Description"
names[4] = "Amount Paid"
names[5] = "Date Paid"
fields[1] = "INVOICE"
fields[2] = "PONUMBER"
fields[3] = "DetailDesc('%v',%c)"
fields[4] = "AMTPAID"
RLIB Function Reference 162
fields[5] = "DATEPAID"
types[1] = ""
types[2] = ""
types[3] = "C"
types[4] = ""
types[5] = ""
*-- open the necessary databases, return if not successful
IF .NOT. OPENED( "invoices", "detail INDEX detail" )
RETURN
ENDIF
*-- clear screen for the query, if selected, proceed
CLEAR
SELECT Invoices
tempntx = TEMPFILE()
myquery = QUERY( names, fields, types )
IF .NOT. EMPTY(myquery)
pbox = SAYINBOX("Indexing query, one moment")
INDEX ON IF(&myquery,"A","Z")+Invoice TO (tempntx)
POPBOX(pbox)
fieldlist = "Invoice+' '+PoNumber+' '+STR(AmtPaid,8,2)"
BORDERBOX( 1, 0, 23, 79, "INVOICE QUERY RESULTS" )
PICKREC( 4, 1, 22, 78, fieldlist, "", myquery )
ENDIF
CLOSE DATABASES
ERASE (tempntx)
RETURN
*----------------------------------------------------------
* Function: DetailDesc()
* Syntax: DetailDesc( string, honorcase )
* Notes: The <honorcase> flag is really shown here for
* example, QUERY() would force the target string
* to upper case for us if the user selected the
* Case Insensitive option in QUERY().
*----------------------------------------------------------
FUNCTION DetailDesc
PARAMETERS string, honorcase
PRIVATE inrecno, found
*-- first uppercase the string if not honoring case
IF .NOT. honorcase
string = UPPER(string)
ENDIF
*-- save the record number where we are in the detail file
SELECT Detail
inrecno = RECNO()
*-- now scan through the detail file for this invoice
LOCATE FOR string $ DETAIL->ItemDesc WHILE ;
RLIB Function Reference 163
DETAIL->invoice == INVOICES->invoice
*-- fix up things and return true if string was found
found = FOUND()
GOTO (inrecno)
SELECT Invoices
RETURN found
Source: RL_QUERY.PRG
See also: STARTREPORT()
RLIB Function Reference 164
Function: REPORTINIT()
Purpose: Initialize the PRINTERS and REPORTS StartReport() databases.
Syntax: REPORTINIT( [ create ] )
Arguments: create - Optional logical value which if supplied, and
is True, the databases will be created even if
they already exist. The default value is
false, which means the databases will be
created and filled with data only if they do
not already exist.
Returns: Logical true if databases created successfully and/or if they
currently exist, or False if they do not exist and an error
occurred when attempting to create and/or append records.
Description: REPORTINIT() is a printer/database function that is used to
generically set up two database files that are used by the
StartReport() RLIB function. These two files, a description,
their structures, and field contents follow.
PRINTERS.DBF - This database contains printer names and
control codes. ReportInit() will initially create this
database with printer drivers for ASCII Text, HP LaserJet+,
and Epson FX printers. Since it is a database file you as
the application programmer may design an interface to allow
users to add, edit, or delete records. This can give the end
user complete printer control.
Structure of PRINTERS.DBF
RLIB Function Reference 165
Field Name Type Len Dec Description
---------- ---- --- --- ----------------------------
NAME C 24 Descriptive name for printer
PGHEIGHT N 4 1 Printable page height inches
PGWIDTH N 4 1 Printable page width in inches
RESET C 60 Printer reset initialize code
SIX_LPI C 60 Six lines per inch
EIGHT_LPI C 60 Eight lines per inch
PORTRAIT C 60 Portrait mode on (Laser only)
LANDSCAPE C 60 Landscape mode on (Laser only)
BOLD_ON C 60 Bold print on
BOLD_OFF C 60 Bold print off
COND_ON C 60 Condensed mode on
COND_OFF C 60 Condensed mode off
WIDE_ON C 60 Wide print on
WIDE_OFF C 60 Wide print off
ITAL_ON C 60 Italics font on
ITAL_OFF C 60 Italics font off
UNDR_ON C 60 Underline on
UNDR_OFF C 60 Underline off
SUPER_ON C 60 Superscript on
SUPER_OFF C 60 Superscript off
SUB_ON C 60 Subscript on
SUB_OFF C 60 Subscript off
REPORTS.DBF - This database contains report definitions. It
can be used as a user definable report scheme.
Structure of REPORTS.DBF
Field Name Type Len Dec Description
---------- ---- --- --- ----------------------------
NAME C 40 Descriptive name for report
TITLE C 40 Definable title for report
DESCRIP C 254 Description of report
PRNAME C 24 Selected printer driver name
WIDTH N 3 0 Report width in columns
PITCH C 1 N=Normal, C=Condensed
ORIENT C 1 P=Portrait, L=Landscape
SPACING N 1 0 6=Six LPI, 8=Eight LPI
LEFTMARGIN N 2 0 Left margin (in columns)
TOPMARGIN N 2 0 Top margin (in lines)
BOTMARGIN N 2 0 Bottom margin (in lines)
SETUPSTR C 60 0 Additional setup string
Notes: Passing a <create> argument value of True is useful to ensure
that any existing PRINTERS.DBF and REPORTS.DBF have the
proper database structure. The default is false. If create
is specified and the file already exists, the old data will
be appended into the newly created files. If you want the
files to be empty when created, OPENED() them then ZAP before
RLIB Function Reference 166
calling REPORTINIT().
The printer control codes are stored in the PRINTERS database
in a text form that can be both read and edited. These codes
are converted to actual printer control codes (escape
sequences) using the RLIB PRINTCODE() function. See the
documentation for PRINTCODE() for details.
Example: *-- preparation startup code in order to use StartReport()
ReportInit()
.
.
.
IF StartReport()
*... do report stuff here
ENDIF
Source: RL_REPOR.PRG
See also: PRINTCODE(), STARTREPORT()
RLIB Function Reference 167
Function: REVDATE()
Purpose: Reverse date fields to index in reverse chronological order.
Syntax: REVDATE( date )
Arguments: date - Date type field or variable to be reversed.
Returns: A character string which, when used as an index key, will
order a database in reverse chronological order with the most
recent dates first.
Description: REVDATE() is a date function which REVerses a DATE to allow
indexing and/or searching on dates in descending order. The
function converts the year, month, and day into a reverse
string format to formulate a descending date order. As an
example:
date = CTOD("01/31/87")
STR(3000-YEAR(date),4,0) = STR(3000 - 1987) = "1013" +;
STR(13-MONTH(date),2,0) = STR(13 - 1 ) = "12" +;
STR(32-DAY(date),2,0) = STR(32 - 1 ) = "31"
REVDATE(date) = "10131231"
Example dates: (note that dates must be converted from char)
REVDATE(CTOD("01/01/88")) = "10111231"
REVDATE(CTOD("02/01/88")) = "10111131" *-- note that this
places the date 02/01/88 before 01/01/88
Notes: Since REVDATE() has parameter error checking built in, there
is some overhead associated with each function call. If you
plan on using REVDATE() in an indexing key you may want to
remove the RlibInit() and TYPE() error checking lines to
decrease overhead and increase indexing speed. However, if
REVDATE() is to be used dynamically, as in ad hoc user
querying or reporting, you as the application programmer must
ensure that the proper date type is passed as a parameter
since REVDATE() will no longer check.
Example: *-- order customer sales database with most recent sale first
IF .NOT. OPENED("Sales")
RETURN
ENDIF
INDEX ON Customer + REVDATE(SaleDate) TO sales.ntx
Source: RL_REVDA.PRG
See also: ALPHADATE(), STR2DATE()
RLIB Function Reference 168
Function: RH_HEADER()
Purpose: Retrieve the header from a RHELP compiled help file
Syntax: RH_HEADER( rhelpFile )
Arguments: rhelpFile - This parameter may be either the rhelp compiled
filename, or the numeric file handle returned
from a previous call to FOPEN() to open the
help file.
Returns: The header from the specified help file.
Description: This function reads and returns the header from a help file
that was compiled with the Rhelp compiler. This header has a
specific structure, but you need not concern yourself with
the details of this structure unless you want to access the
header record elements directly. All header and header
record information is available through calls to the various
Rhelp functions (API).
See Appendix C entitled The RHELP Compiler for more detailed
information and examples.
Notes: If the helpfile parameter is supplied as a character string,
it is deemed to be the name of the Rhelp file. In this case
the help file is opened (using FOPEN()), the header is then
extracted, the help file closed, and the header returned. If
the FOPEN() fails, a null is returned, and RLIBERROR() set.
If the helpfile parameter is supplied as a numeric value, it
is deemed to be the numeric file handle returned by
previously FOPEN()ing the help file. In this case, the
header is read and returned, but the file is not closed.
This feature allows you the flexibility of leaving the help
file open during the course of your application, therefore
speeding up access by not having to constantly open and close
the help file. This method of access is not recommended if
you are short on file handles or you are not comfortable with
low level file operations. If you use this method, always
remember to FCLOSE() your files.
You should not need to explicitly extract the header since
all help functions are available. However, the header may be
manipulated directly for speed considerations. Also, the
other help functions use this function to extract the header.
Example: helpHeader = RH_HEADER("myapp.hlp")
*-- or
helpHandle = FOPEN("myapp.hlp")
helpHeader = RH_HEADER( helpHandle )
RLIB Function Reference 169
Source: RL_RHELP.PRG
See also: RH_TEXT(), RH_WIDTH(), RH_LINES()
RLIB Function Reference 170
Function: RH_LINES()
Purpose: Get the number of text lines within a help text block
Syntax: RH_LINES( rhelpfile, help_key )
Arguments: rhelpfile - This parameter may be either the rhelp compiled
filename, or the numeric file handle returned
from a previous call to FOPEN() to open the
help file.
help_key - Character value indicating the text associated
as the key for the desired help. This text can
any length but only the first 16 characters are
significant. Case is insensitive.
Returns: Numeric line count in the associated help text block. If the
specified help key is not found, or an error occurs, zero is
returned.
Description: This function reads and returns the number of lines within a
block of help text associated with the help key, from a help
file that was compiled with the Rhelp compiler. Knowing this
line count allows you to tailor the help display window size
to the size of the text.
The help key is a unique character string which is
significant to the first 16 characters, that identifies an
entry in the Rhelp compiled help file. This allows help
systems to be queried by supplying a descriptive character
string.
See Appendix C entitled The RHELP Compiler for more detailed
information and examples.
Notes: If the helpfile parameter is supplied as a character string,
it is deemed to be the name of the Rhelp file. In this case
the help file is opened (using FOPEN()), the header is then
extracted, the help file closed, and the header returned. If
the FOPEN() fails, a null is returned, and RLIBERROR() set.
If the helpfile parameter is supplied as a numeric value, it
is deemed to be the numeric file handle returned by
previously FOPEN()ing the help file. In this case, the text
is read and returned, but the file is not closed. This
feature allows you the flexibility of leaving the help file
open during the course of your application, therefore
speeding up access by not having to constantly open and close
the help file. This method of access is not recommended if
you are short on file handles or you are not comfortable with
low level file operations. If you use this method, always
remember to FCLOSE() your files.
The help file pointer position is left unchanged.
RLIB Function Reference 171
Example: helpLines = RH_LINES("myapp.hlp", "MENU HELP" )
*-- or
helpHandle = FOPEN("myapp.hlp")
helpLines = RH_LINES( helpHandle, "MENU HELP" )
Source: RL_RHELP.PRG
See also: RH_HEADER(), RH_TEXT(), RH_WIDTH()
RLIB Function Reference 172
Function: RH_TEXT()
Purpose: Get help text for specified help key from compiled .HLP file
Syntax: RH_TEXT( rhelpfile, help_key )
Arguments: rhelpfile - This parameter may be either the rhelp compiled
filename, or the numeric file handle returned
from a previous call to FOPEN() to open the
help file.
help_key - Character value indicating the text associated
as the key for the desired help. This text can
any length but only the first 16 characters are
significant. Case is insensitive.
Returns: The associated help text block as a character string. If the
specified help key is not found, or an error occurs, a null
string ("") is returned.
Description: This function reads and returns a block of help text
associated with the specified help key from a help file that
was compiled with the Rhelp compiler. The help key is a
unique character string that identifies an entry in the Rhelp
compiled help file. This allows help systems to be queried
by supplying a descriptive character string. RH-TEXT()
function does all the work.
See Appendix C entitled The RHELP Compiler for more detailed
information and examples.
Notes: If the helpfile parameter is supplied as a character string,
it is deemed to be the name of the Rhelp file. In this case
the help file is opened (using FOPEN()), the header is then
extracted, the help file closed, and the header returned. If
the FOPEN() fails, a null is returned, and RLIBERROR() set.
If the helpfile parameter is supplied as a numeric value, it
is deemed to be the numeric file handle returned by
previously FOPEN()ing the help file. In this case, the text
is read and returned, but the file is not closed. This
feature allows you the flexibility of leaving the help file
open during the course of your application, therefore
speeding up access by not having to constantly open and close
the help file. This method of access is not recommended if
you are short on file handles or you are not comfortable with
low level file operations. If you use this method, always
remember to FCLOSE() your files.
After reading the help text, the file pointer position is
left after the text (perhaps at the next text location.)
Example: helpText = RH_TEXT("myapp.hlp", "MENU HELP" )
RLIB Function Reference 173
*-- or
helpHandle = FOPEN("myapp.hlp")
helpText = RH_TEXT( helpHandle, "MENU HELP" )
Source: RL_RHELP.PRG
See also: RH_HEADER(), RH_WIDTH(), RH_LINES()
RLIB Function Reference 174
Function: RH_WIDTH()
Purpose: Get the maximum line width within a help text block
Syntax: RH_WIDTH( rhelpfile, help_key )
Arguments: rhelpfile - This parameter may be either the rhelp compiled
filename, or the numeric file handle returned
from a previous call to FOPEN() to open the
help file.
help_key - Character value indicating the text associated
as the key for the desired help. This text can
any length but only the first 16 characters are
significant. Case is insensitive.
Returns: Numeric maximum line width with the associated help text
block. If the specified help key is not found, or an error
occurs, zero is returned.
Description: This function reads and returns a block of the maximum line
width of all the text lines within a help text associated
with the specified help key, from a help file that was
compiled with the Rhelp compiler. Knowing this maximum width
allows you to tailor the help display window width to the
size of the text.
The help key is a unique character string which is
significant to the first 16 characters, that identifies an
entry in the Rhelp compiled help file. This allows help
systems to be queried by supplying a descriptive character
string.
See Appendix C entitled The RHELP Compiler for more detailed
information and examples.
Notes: If the helpfile parameter is supplied as a character string,
it is deemed to be the name of the Rhelp file. In this case
the help file is opened (using FOPEN()), the header is then
extracted, the help file closed, and the header returned. If
the FOPEN() fails, a null is returned, and RLIBERROR() set.
If the helpfile parameter is supplied as a numeric value, it
is deemed to be the numeric file handle returned by
previously FOPEN()ing the help file. In this case, the text
is read and returned, but the file is not closed. This
feature allows you the flexibility of leaving the help file
open during the course of your application, therefore
speeding up access by not having to constantly open and close
the help file. This method of access is not recommended if
you are short on file handles or you are not comfortable with
low level file operations. If you use this method, always
remember to FCLOSE() your files.
RLIB Function Reference 175
The help file pointer position is left unchanged.
Example: helpMaxWidth = RH_WIDTH("myapp.hlp", "MENU HELP" )
*-- or
helpHandle = FOPEN("myapp.hlp")
helpMaxWidth = RH_WIDTH( helpHandle, "MENU HELP" )
Source: RL_RHELP.PRG
See also: RH_HEADER(), RH_TEXT(), RH_LINES()
RLIB Function Reference 176
Function: RJUSTIFY()
Purpose: Right justify string by moving trailing blanks to the front.
Syntax: RJUSTIFY( string )
Arguments: string - Character string or variable to be right
justified.
Returns: String with trailing blanks moved to the front of the string.
Description: Takes a character string and moves any trailing blanks to the
front of the string, to allow for right justification in
display or printing.
Notes: Useful for displaying or printing character data that may
have trailing blanks flush right in reports.
The string returned is the same length as the one provided.
Example: acct_num = SPACE(20)
@ 1,0 SAY "Enter account number:" GET acct_num
READ
*-- they entered 12-34-567890 which has 8 trailing spaces
*-- you want it printed flush right under the page number
*-- on an 80 column display
@ 1,67 SAY "Page No.: " + STR(pageno,3,0)
@ 1,60 SAY RJUSTIFY(acct_num)
*-- replaces: @ 1,60+20-LEN(TRIM(acct_num)) SAY ...
Source: RL_RJUST.PRG
See also: CENTER(), MIDDLE(), SAYINBOX()
RLIB Function Reference 177
Function: RLIBERROR()
Purpose: Return and, optionally set, the last RLIB error number.
Syntax: RLIBERROR( [newerror] )
Arguments: newerror - Optional numeric value to set RLIBERROR.
Returns: The last RLIB error number.
Description: This is an error function used to query for the last error
that occurred in an RLIB function. Optionally this error
value may be set to a new value. This capability is used
primarily by all RLIB functions internally to set the error
value initially to zero, and to set the error value if and
when an error occurs.
For a complete list of RLIB error values and their meanings,
see Appendix A - RLIB Error Codes.
Notes: Every RLIB function sets this error value to zero on entry.
Example: IF .NOT. OPENED("dbf1 INDEX ntx1", "dbf2 INDEX ntx2")
*-- OPENED() returned False, but why.....
DO CASE
CASE RLIBERROR() = 1101
message = "File sharing violation"
CASE RLIBERROR() = 1102
message = "Database file not found"
CASE RLIBERROR() = 1103
message = "Associated index file not found"
CASE RLIBERROR() = 1104
message = "Associated memo file not found"
CASE RLIBERROR() = 1105
message = "Invalid alias name or other syntax error"
ENDCASE
BOXASK( "W+/R", "Error opening required database files:",;
message, "Press any key to continue" )
ENDIF
Source: RL_RLIBE.PRG
See also: RLIBINIT(), RLIBVER()
RLIB Function Reference 178
Function: RLIBINIT()
Purpose: Initialize internal RLIB PUBLIC/STATIC variable(s).
Syntax: RLIBINIT()
Arguments: None
Returns: Zero
Description: This is an internal function which is called at the beginning
of every RLIB function. Its purpose is to initialize the
PUBLIC variable <rliberror> to zero. This variable is used
throughout as a debugging aid to return information about the
state and/or failure code of an RLIB function. See Appendix
A - RLIB Error Codes for more information.
Notes: The additional benefit of this central function comes in its
central nature. Global modifiers can easily be added to all
Rlib functions in this module.
Example: Used internally. See individual function code.
Source: RL_RLIBI.PRG
See also: RLIBVER()
RLIB Function Reference 179
Function: RLIBVER()
Purpose: Retrieve the version number of the RLIB.LIB linked.
Syntax: RLIBVER()
Arguments: None
Returns: The version of RLIB linked as a character string such as
"3.00"
Description: Use this to test for a proper version. Useful when debugging
so you don't end up chasing what you think was a bug for
three hours only to find you had linked in an older version
of RLIB.
Notes: Returns the version as a character string NOT a number!
Example: IF RLIBVER() < "3.0"
? "Update now!"
ENDIF
Source: RL_RLIBV.PRG
See also: RLIBERROR(), RLIBINIT()
RLIB Function Reference 180
Function: SAYINBOX()
Purpose: Pop up a centered message box using multiple message strings.
Syntax: SAYINBOX( [color] message1 [...message9] [timeout] )
Arguments: color - If the FIRST parameter has a slash "/"
character in the 2nd, 3rd, or 4th position,
this parameter will be interpreted as the color
setting for the message box. (All color
strings look like: R/W, or R+/W, or R+*/W)
message1,9 - Any other character parameters, including the
first and or second parameters if they don't
meet the above conditions, will be displayed as
BOXASK() messages. Up to nine message lines
may be passed and displayed.
timeout - If the LAST parameter is a numeric value, it
will be used as a timeout value for the message
box. This timeout is the number of seconds
BOXASK() will wait for a keypress. If no key
is pressed before the timeout is reached,
BOXASK() will exit and return a null string.
If no timeout is supplied, BOXASK() will wait
forever for a keypress.
Returns: A formatted character string where the first four bytes are
the screen coordinates of the screen area underneath the
SAYINBOX() box and message, plus the SAVESCREEN() string
itself. This is used as a parameter to the POPBOX() function
to restore a screen to its state before a SAYINBOX() message
was displayed.
Description: SAYINBOX() is a screen function very similar to BOXASK().
However, it is different in two very distinct ways. First,
BOXASK() is intended to query the user for a keypress
response to a message, and to return the key pressed.
SAYINBOX() does not wait for key input from the user.
Secondly, SAYINBOX() returns a character string which
contains the coordinates of the screen region displaced by
the SAYINBOX() image. This character string can be used as a
parameter to the companion function POPBOX() to restore the
screen to the way it was before SAYINBOX() was called. This
feature is ideal for situations where you want to put up a
message box, do some processing, then remove the message box
and restore the screen to its previous state.
This is a function that becomes addictive! Once you start
using it you'll never stop. It's perfect for displaying all
types of messages in a consistent manner. SAYINBOX()
displays up to nine lines of text messages, centered on the
screen in a single line box, in a user definable color. Each
line may be up to 68 characters long. All of the screen
RLIB Function Reference 181
centering is done for you.
Notes: SAYINBOX() accepts a variable number of parameters and will
act differently on the parameters depending on their format.
All parameters except the timeout are expected to be of
character type.
If the first parameter is a color setting, SAYINBOX() will
use that color combination instead of the default current
color.
If the optional <timeout> argument is supplied, SAYINBOX()
will wait the specified number of seconds, then restore the
screen and terminate.
Example: *-- example of an INDEX message
pbox = SAYINBOX( "BG+/B", "Indexing, please wait" )
INDEX ON keyfield TO indexfile
POPBOX(pbox)
Source: RL_SAYIN.PRG
See also: ABOXASK(), BOXASK(), POPBOX()
RLIB Function Reference 182
Function: SETCURSOR()
Purpose: Retrieve and optionally set the current cursor state.
Syntax: SETCURSOR( value )
Arguments: value - Optional numeric argument to cause the cursor
state to be changed. <value> may be either a
numeric value where 1 indicates the cursor
should be turned ON and a value of 0 indicates
the cursor should be turned OFF. <value> may
optionally be a logical type value where a
value of True (.T.) causes the cursor to be
turned ON and a value of False (.F.) causes the
cursor to be turned OFF.
Returns: The current SETCURSOR() state as a numeric value where a
value of one (1) means the cursor is currently ON, and a
value of zero (0) means the cursor is currently OFF.
Description: SETCURSOR() is an environment function used to be able to
make functions "black boxed" such that they may return the
system state to the way it was after having made a change.
If used consistently throughout an application, SETCURSOR()
provides a facility to retrieve the current state of the
cursor, optionally setting it on or off.
Notes: SETCURSOR() maintains the current state of the cursor via a
PUBLIC memvar named RLIBCURSOR. If this variable does not
exist as a Numeric type variable, it is created and
initialized to True (assuming the cursor is ON by default).
Several RLIB functions such as BOXASK() will detect if the
SETCURSOR() function is being used to control the cursor
state by testing if the public variable RLIBCURSOR exists as
a numeric type variable. If it does exist, BOXASK() will
turn the cursor ON (to query the user for a keypress) then
restore the cursor to its incoming state on exit.
The SETCURSOR() only exists in the Summer'87 version of RLIB
since Clipper 5.0 has a built in SETCURSOR() function.
Example: *-- save the current cursor state and turn it on
incursor = SETCURSOR(1) && or SETCURSOR(.T.)
WAIT "Press 'Y' for Yes or 'N' for No:" TO answer
SETCURSOR(incursor)
IF answer = "Y"
*-- do whatever for a yes answer
ENDIF
Source: RL_SETCU.PRG
See also: BOXASK()
RLIB Function Reference 183
Function: STARTREPORT()
Purpose: General purpose report format and print control function.
Syntax: STARTREPORT( [ reportname [, say_colors [, msg_color ]]] )
Arguments: reportname - Optional character string name of the report.
This name can be a name identified in a .PRG
module or dynamically retrieved from a pick
list of reports in the database REPORTS.DBF.
If specified, this name is LOCATEd in the
reports definition database REPORTS.DBF. If
not specified or the given name is not found in
REPORTS.DBF then the default report
configuration is used. See below for this
default configuration.
say_colors - Optional character color string in the same
format as other Clipper color strings which is
used for the report definition window. Normal
text is displayed in the Standard color, and
GETs are displayed in the Enhanced color. If
not specified or an invalid parameter is passed
the default color settings will be the current
SETCOLOR().
msg_color - Optional character color string used to display
the SAYINBOX() message that the report is being
printed. If not specified or an invalid
parameter is passed, the default color is the
current Enhanced color setting (that used for
GETs).
Returns: True if all is a go, false otherwise (escaped or canceled)
Description: STARTREPORT() is a high level printer function which
simplifies the process of formatting printed reports. Its
main use is in automating all the steps necessary to set up a
printer for a report. It is used in conjunction with the
REPORTINIT() and STOPREPORT() RLIB functions. REPORTINIT()
initializes the printer and reports databases for use by
STARTREPORT() while STOPREPORT() cleans up printer settings
when the report is finished.
In addition to performing the necessary settings to send
output to a printer, STARTREPORT() pops up a generic report
configuration window which lets the end user customize the
appearance of any report. The STARTREPORT() screen appears
as follows:
RLIB Function Reference 184
╔════════════════════════════════════════════╗
║ REPORT PRINT CONFIGURATION ║
║ Destination: PRN ║
╟────────────────────────────────────────────╢
║ Report Title: Purchase Requisition ║
║ ║
║ Printer Driver: Epson FX Printer ║
║ ║
║ Print size (width): Normal ║
║ Page orientation: Portrait ║
║ Line spacing (lines per inch): 6 LPI ║
║ Top margin (in lines): 0 ║
║ Bottom margin (in lines): 0 ║
║ Left margin (in columns): 0 ║
║ Report width (in columns): 80 ║
║ Report setup string: ║
╚════════════════════════════════════════════╝
Press S to start, F to format, ESC to quit
The basic control functions extended to the user are:
* Report title and width
* Printer driver selection
* Page orientation and line spacing
* Top, left, and bottom margins
* Customized printer control codes
All of these settings are saved in the REPORTS.DBF database
so they may be easily retrieved repeatedly.
For the programmer, STARTREPORT() initializes a set of PUBLIC
variables which can be used programmatically to control the
appearance of printed output. There are two basic sets of
PUBLIC variables; those that begin with "PRN_" are printer
control codes and printer information, those that begin with
"RPT_" are report definition settings. The complete list is:
Printer setup information
-------------------------
prn_name Descriptive name of the selected printer
prn_pgheight Printable page height in inches
prn_pgwidth Printable page width in inches
prn_setup Printer setup string for the report which is
the combination of codes necessary to
implement the report format configuration
selected.
RLIB Function Reference 185
Printer control codes (escape sequences)
----------------------------------------
prn_reset Printer reset (initialize) code
prn_6lpi Six lines per inch line spacing
prn_8lpi Eight lines per inch line spacing
prn_boldon Bold print on
prn_boldoff Bold print off
prn_condon Condensed mode on
prn_condoff Condensed mode off
prn_wideon Wide print on
prn_wideoff Wide print off
prn_italon Italics font on
prn_italoff Italics font off
prn_undron Underline on
prn_undroff Underline off
prn_supron Superscript on
prn_suproff Superscript off
prn_subson Subscript on
prn_subsoff Subscript off
prn_portrait Portrait mode on (Laser only)
prn_landscape Landscape mode on (Laser only)
Report definitions
------------------
rpt_title Char User definable title for report
rpt_width Num Report width in columns
rpt_pitch Char "N"=Normal, "C"=Condensed
rpt_orient Char "P"=Portrait, "L"=Landscape
rpt_space Num 6=Six LPI, 8=Eight LPI
rpt_lmarg Num Left margin (in columns)
rpt_tmarg Num Top margin (in lines)
rpt_bmarg Num Bottom margin (in lines)
rpt_setup Char User defined additional report setup
string which is sent to the printer
after PRN_SETUP.
Other
-----
rpt_popbox This is the SAYINBOX() saved screen from the
prompt that is displayed after the user selects
the Startreport() option. This public variable
is used in STOPREPORT() to restore the screen
area under the SAYINBOX() message when the
report has finished printing.
Notes: STARTREPORT() performs the following sequence of events:
1. Initializes report "rpt_" PUBLIC variables
2. Initializes printer "prn_" PUBLIC variables
3. Queries the user for target destination with
TARGET()
4. Opens the PRINTERS and REPORTS databases,
retrieves any existing formats for the named
RLIB Function Reference 186
report.
5. Pops up a report format description window and
asks the user to press "S" to start report or "F"
to format.
6. If they respond with Start, the printer is set to
the specified target with the following sequence:
IF .NOT. target == "CON"
SET PRINTER TO (M->rpt_target)
SET DEVICE TO PRINT
SET CONSOLE OFF
SET PRINT ON
SET MARGIN TO rpt_lmarg
?? M->prn_reset+M->prn_setup+M->rpt_setup
ENDIF
* * * W A R N I N G * * *
Always remember to make a call to the STOPREPORT() function
when you are finished. When you do all the SET PRINTER stuff
by hand, you usually remember to end with a corresponding SET
PRINTER TO to close the print output from a printer or file
or whatever. With STARTREPORT() this is done for you, and if
you do not finish with a call to STOPREPORT(), your
application will remain directed to wherever you selected
with TARGET(). If this was to a printer or a file, SET
CONSOLE will remain off and all screen writes will go to that
device. Furthermore, to make it appear everything is screwed
up, some screen writes will go to the screen; things like
@... BOX, RESTORE SCREEN etc, things that write to the
screen.
The STOPREPORT() function is included in the STARTREPORT()
module rather than being contained in a separate library
module. Since STOPREPORT() will ALWAYS be called when
STARTREPORT() is being used it makes sense to include it in
the same code.
The STOPREPORT() function issues a form feed and printer
reset then returns print and device control back to the
screen.
Example: *-- instead of lines and lines of code necessary to
*-- prepare a report, use one function
IF StartReport()
DO MyReort
StopReport()
ENDIF
RETURN
*-- This procedure assumes target output was selected by a
*-- call to STARTREPORT() which also initializes the printer
*-- control codes beginning with PRN_
RLIB Function Reference 187
PROCEDURE MyReport
? prn_undron + "C U S T O M E R S T A T U S" + prn_undroff
?
?
? "Customer: " + BOLD(CUST->name)
? "Account#: " + BOLD(CUST->acctno)
? "Last Chg: " + BOLD(DTOC(CUST->lastchg))
? "Balance: " + BOLD(TRANSFORM(CUST->balance,"###,###.##"))
? "Avail Cr: " + BOLD(TRANSFORM(CUST->availcr,"###,###.##"))
RETURN
*-----------------------------------------------------------
* Function: BOLD()
* Syntax: BOLD( string )
* Assumes: StartReport() printer control code variables are
* visible
*-----------------------------------------------------------
FUNCTION Bold
PARAMETER string
RETURN prn_boldon + string + prn_boldoff
Source: RL_START.PRG
See also: REPORTINIT()
RLIB Function Reference 188
Function: STR2DATE()
Purpose: Convert date strings to a Clipper date type variable.
Syntax: STR2DATE( datestring )
Arguments: datestring - Character date string to be converted. The
string may be in either the long or short month
spelling format but in either case must be in
the general format of "January 31, 1990".
Returns: A date variable corresponding to the date supplied in the
string. If the string is in an invalid format, an empty date
(" / / ") is returned.
Description: STR2DATE() is a character/date function used to translate
dates which are expressed in spelled out form to Clipper date
type variables. A date that is expressed as Feb 28, 1990 is
converted into a date type of 02/28/90. This is useful when
the need arises to convert dates which are stored in
character format to date type fields. Some software packages
export date data in this character format.
Notes: STR2DATE() is fairly robust and it can handle dates that omit
the comma after the month. If an invalid date string
argument is given, STR2DATE() will set RLIBERROR() and return
an empty date.
Example: ? STR2DATE("Feb 1, 1990") && Date value = 02/01/90
? STR2DATE("feb 01 90") && Date value = 02/01/90
*-- Example #2
*-- Get data from an import text file from other software
APPEND FROM textfile DELIMITED
*-- date string is in field named StringDate
*-- convert date in form Sep 10, 1988 to date variable
REPLACE Startdate WITH STR2DATE(Stringdate)
Source: RL_STR2D.PRG
See also: ALPHADATE(), CALENDAR(), REVDATE()
RLIB Function Reference 189
Function: STRETCH()
Purpose: Pad a string with blanks or truncate to a defined width.
Syntax: STRETCH( string, length )
Arguments: string - Character string to pad with spaces (or to
truncate) to make length <length>.
length - Numeric desired length of the resulting string.
Returns: <string> padded with spaces or truncated to <length>.
Description: STRETCH() is a character function used to normalized strings
to a certain length. This is most often used to guarantee
that a character string will be a certain length, either by
added spaces onto the end of the string, or by truncating
characters off of the string.
Notes: STRETCH() is also very useful is reports to aid in lining up
columns. If a variable may be an undetermined length, or if
you fear a field may be lengthened or shortened, STRETCH()
can be used to guarantee a defined output width.
STRETCH() performs the same function as many PAD() functions
but lacks other options which make it leaner. STRETCH() may
be customized to fit your particular needs.
If a <length> of zero is specified, or if invalid arguments
are supplied, STRETCH() will return a null string ("").
Example: *-- expand a variable for edit length
help_path = STRETCH(help_path,60)
@ 10,20 SAY "Enter path for help files:"
@ 11,20 GET help_path PICTURE "@!S40"
READ
*-- now trim it back down
help_path = TRIM(help_path)
Source: RL_STRET.PRG
See also: CENTER(), MIDDLE()
RLIB Function Reference 190
Function: TARGET()
Purpose: Provide a pop-up target printer output selection menu.
Syntax: TARGET( [ row [, column [, colors [, confirm ;
[, header [, fileext ] ] ] ] ] ] )
Arguments: row - Optional numeric value indicating the top row
on which to place the TARGET() selection menu.
If not specified or an invalid parameter is
passed, the default row is 10. Valid rows are
from 0 to 10.
column - Optional numeric value indicating the left
column on which to place the TARGET() selection
menu. If not specified or an invalid parameter
is passed, the default column is 21. Valid
columns are from 0 to 41.
colors - Optional array of character strings specifying
the color settings to use. This color array is
identical to the array required by BOXMENU().
The colors used for the different parts of the
menu are specified as follows:
colors[1] - Menu choices (item options)
colors[2] - Menu selection bar
colors[3] - Active menu box (on entry)
colors[4] - Inactive menu box (on exit)
colors[5] - Menu choice upon selection
colors[6] - Messages displayed on promptrow
confirm - Optional logical value indicating whether or
not to warn if a selected filename already
exists and to confirm an overwrite. The
default value is True.
header - Optional character string to display as the
header in the BOXMENU() style print target
menu. If this parameter is omitted or a
non-character type parameter is passed, the
default header text will be: "PRINT SELECTION
MENU".
fileext - Optional character string indicating the
default file extension to append to the end of
a target file name if one is entered. Specify
only the three character file extension, do not
include the leading dot. If omitted or a
non-character argument is supplied the default
extension is ".PRN". If the character string
is longer than three characters, only the first
three characters will be used for the file
extension. To disable the automatic extension
RLIB Function Reference 191
append feature, pass a null ("") for the
<fileext>.
Returns: The selected target output device as a character string of
either "CON", "PRN", "LPT1", "LPT2", "LPT3", "COM1", "COM2",
<filename>, or a null ("") if escape was pressed or Abort
selected.
Description: TARGET() is a high level printer control function that takes
the hassle out of prompting the user for directed printer or
file output. TARGET() pops up a centered BOXMENU() style
menu which lets the user select a desired target for further
output. Selections include standard printer (PRN), other
device (LPT 1,2,3, COM 1,2), screen, or to a file, the name
of which the user is prompted to enter.
Notes: All arguments are optional. As with all Clipper functions,
an argument may be skipped, but a "dummy" argument must be
supplied in its place.
The colors array is identical in structure to the array used
in BOXMENU() and the same array may be used interchangeably.
TARGET() maintains a PUBLIC memvar named RL_TARGET which
saves the last target filename entered, if any. This lets
TARGET() display the last entered target filename on
subsequent calls.
The TARGET() menu appears as follows:
╔═════════════════════════════════════╗
║ PRINT SELECTION MENU ║
╟─────────────────────────────────────╢
║ Printer - print to the standard PRN ║
║ Device - select a different port ║
║ Screen - send output to screen ║
║ File - send output to a file ║
║ Abort - cancel this request ║
╚═════════════════════════════════════╝
If the Device option is selected, a sub-menu appears with the
following options:
RLIB Function Reference 192
┌─────────────────────────────────────┐
│ PRINT SELECTION MENU │
├─────────────────────────────────────┤
│ Printer - print to the standard PRN │
│ Device - select a different port │
│ Screen - ╔═════════════╗screen │
│ File - ║PRINT DEVICES║a file │
│ Abort - ╟─────────────╢uest │
└───────────║ 1. LPT1 ║───────────┘
║ 2. LPT2 ║
║ 3. LPT3 ║
║ 4. COM1 ║
║ 5. COM2 ║
╚═════════════╝
If the File option is selected a data entry box appears as
follows:
┌─────────────────────────────────────┐
│ PRINT SELECTION MENU │
├─────────────────────────────────────┤
│ Printer - print to the standard PRN │
│ Device - select a different port │
│ Screen - send output to screen │
│ File - send output to a file │
╔════════════════════════════════════════╗
║ Enter Filename ║
╟────────────────────────────────────────╢
║ ║
╚════════════════════════════════════════╝
Example: *-- query user for desired output
mtarget = TARGET()
IF .NOT. mtarget == "CON" && not to the screen
SET PRINTER TO (mtarget)
SET PRINT ON
SET CONSOLE OFF
DO MyReport
SET PRINT OFF
SET PRINTER TO
SET CONSOLE ON
ENDIF
Source: RL_TARGE.PRG
See also: GETFILE(), REPORTINIT(), STARTREPORT()
RLIB Function Reference 193
Function: TEMPFILE()
Purpose: Generate a temporary filename.
Syntax: TEMPFILE( [ extension ] )
Arguments: extension - Optional character string indicating the file
extension to assign to the temporary filename.
Specify only the 1 to 3 character extension, do
not include the dot leader. If more than three
characters are specified, only the first three
will be used. If omitted or an invalid
argument is given, the default file extension
is ".TMP".
Returns: A unique temporary filename or a null ("") if an error
occurred.
Description: TEMPFILE() is a file function used to create a unique
temporary file name. This is most often used to create
temporary index files, or other temporary storage files.
Notes: This function is not 100% foolproof! In a Network
environment two workstations could conceivably acquire the
same filename although it is HIGHLY UNLIKELY. This function
can be made very safe in a network if the optional extension
is supplied and is unique to each workstation making the
call. For instance, if the network assigns workstation
numbers, and the current workstation is assigned station
number 1, then a temporary file extension could be passed to
TEMPFILE() as "S1". In this manner each workstation would be
guaranteed a unique extension.
Example: *-- build a temporary index file for a Query condition
USE mydbf
tempindex = TEMPFILE()
condition = QUERY()
pbox = SAYINBOX( "Building query index, please wait" )
INDEX ON IF(&condition, "A", "Z") TO (tempindex)
POPBOX(pbox)
SEEK "A"
DBEDIT()
SET INDEX TO
ERASE (tempindex)
USE
Source: RL_TEMPF.PRG
See also: CHECKFILE(), FILEDATE(), FILESIZE(), FILETIME(), PICKFILE()
RLIB Function Reference 194
Function: TYPEC()
Purpose: Test if a PUBLIC/PRIVATE is character type and not blank.
Syntax: TYPEC( "memvar" )
Arguments: memvar - The name of the PUBLIC or PRIVATE variable to
test. The variable name must be passed to
TYPEC() as a string and therefore must be
enclosed in single or double quotes.
Returns: True if the indicated variable is of character type and is
not empty (blank or a null string).
Description: This function is very useful if you need to not only verify
that a variable or argument is of character type but also
that it is not empty or a null string. TYPEC() is especially
useful in user-defined functions where parameter verification
is important.
Notes: TYPEC() follows the same convention as the Clipper TYPE()
function.
Example: PRIVATE blank_var, null_var, char_var, num_var
blank_var = " "
null_var = ""
char_var = "Y"
num_var = 1
? TYPEC("blank_var") && .F.
? TYPEC("null_var") && .F.
? TYPEC("char_var") && .T.
? TYPEC("num_var") && .F.
? MyOpen() && .F.
? MyOpen(" ") && .F.
? MyOpen("my.dbf") && .T.
*------------------------------------------------------------
* Function: MyOpen()
* Purpose: Open a database named with the character filename
* parameter after verifying the correct parameter
* usage, and that the file exists.
*------------------------------------------------------------
FUNCTION MyOpen
PARAMETER filename
IF .NOT. TYPEC("filename")
*-- not only will this verify that the required parameter
*-- is Character in type, but also that it is not blank.
BOXASK("No filename given.", 10)
RETURN .F.
ENDIF
USE (filename)
RETURN .T.
RLIB Function Reference 195
Source: RL_TYPEC.PRG
See also: VALTYPEC()
RLIB Function Reference 196
Function: VALTYPEC()
Purpose: Test if a LOCAL/STATIC is character type and not blank.
Syntax: VALTYPEC( memvar )
Arguments: memvar - The STATIC or LOCAL memory variable to test.
As with all Clipper 5.0 Static and Local
variables, do not enclose the variable name in
quotes as with the TYPEC() function.
Returns: True if the indicated variable is of character type and is
not empty (blank or a null string).
Description: This function is very useful if you need to not only verify
that a variable or argument is of character type but also
that it is not empty or a null string. VALTYPEC() is
especially useful in user-defined functions where parameter
verification is important.
Notes: Pass the LOCAL or STATIC variable directly to VALTYPEC() just
as you would to VALTYPE(). Do not enclose the variable name
in quotes, as in the syntax for TYPEC(). Doing so will
allays yield a false return value since STATIC and LOCAL
variables are not known by name at run time.
VALTYPEC() is specific to the Clipper 5.0 version of RLIB and
does not exist in the Summer '87 version of RLIB.LIB.
Example: LOCAL blank_var, null_var, char_var, num_var
blank_var := " "
null_var := ""
char_var := "Y"
num_var := 1
? VALTYPEC(blank_var) // .F.
? VALTYPEC(null_var) // .F.
? VALTYPEC(char_var) // .T.
? VALTYPEC(num_var) // .F.
? MyOpen() // .F.
? MyOpen(" ") // .F.
? MyOpen("my.dbf") // .T.
*------------------------------------------------------------
* Function: MyOpen()
* Purpose: Open a database named with the character filename
* parameter after verifying the correct parameter
* usage and that file exists.
*------------------------------------------------------------
FUNCTION MyOpen ( filename )
IF .NOT. VALTYPEC(filename)
*-- not only will this verify that the required parameter
RLIB Function Reference 197
*-- is Character in type, but also that it is not blank.
BOXASK( "No filename given.", 10 )
RETURN .F.
ENDIF
USE (filename)
RETURN .T.
Source: RL_VALTY.PRG
See also: TYPEC()
RLIB Function Reference 198
Function: VRANGE()
Purpose: Numeric range validation with error handling.
Syntax: VRANGE( value, lower, upper [, color ] )
Arguments: value - Numeric value to validate as being between the
<lower> and <upper> limits, inclusive.
lower - Numeric lower limit that <value> must be equal
to or greater for VRANGE() to return True.
upper - Numeric upper limit that <value> must be equal
to or less than for VRANGE() to return True.
color - Optional character color string to use when
displaying error messages. If omitted or an
invalid parameter is passed, the default color
is Bright White on Red (W+/R) for color
monitors and High intensity for monochrome.
Returns: True if <value> is between <lower> and <upper> inclusive.
Description: VRANGE() is a numeric function most often used within VALID
clauses of GET statements. Its best use is as a replacement
for the limited RANGE clause.
VRANGE() checks that <value> is greater than or equal to
<lower> and that <value> is less than or equal to <upper>.
If this is false, VRANGE() displays a SAYINBOX() error
message (in the optional <color> specified) and waits for a
confirming keypress for 10 seconds. After 10 seconds,
VRANGE() times out and returns False.
Notes: If any of the first three arguments are either missing or
non- numeric in type, VRANGE() will set the appropriate
RLIBERROR() value and return False.
Example: *-- prevent a negative age with a nice looking error message
age = 0
@ 10, 0 SAY "Enter your age:"
@ 10,16 GET M->age PICTURE "##" ;
VALID Vrange( M->age, 1, 99, "GR+/R" )
READ
Source: RL_VRANG.PRG
See also: BOXASK(), NOTEMPTY(), SAYINBOX()
RLIB Function Reference 199
┌───────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ Appendix A │
│ RLIB Error Codes │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────────┘
Appendix A - RLIB Error Codes
All RLIB functions are designed to handle runtime errors with as much
grace as possible. When a runtime error occurs, the programmer has a
choice of trapping these errors or letting the error crash your
program. RLIB functions use the former method.
The most frequent errors that occur when calling Clipper functions are
parameter omission and/or type mismatches. Most of the RLIB functions
test for the proper number of parameters and for the proper parameter
types. If a required parameter is omitted or if a parameter type is
mismatched, and the function cannot rely on a default value, the
function will simply return. If the function returns a value that is
indicative of success, the return value in such a case will be the
failure value.
As do all Clipper functions, every RLIB function must return some
value. Additionally, as with functions in Clipper and C, RLIB
functions may return ONLY ONE VALUE.
Debugging Aid
To make program debugging a little easier, all RLIB functions maintain
an error value which can be retrieved by a call to the RLIBERROR()
function. Normal function completion will always set this value to
zero. Any non-zero value is an indication of some level of failure in
the last RLIB function called.
This error value is also used by some RLIB functions to return more
specific error information to the calling routine. In such a case the
error was not fatal (or an invalid syntax error) but merely an
additional bit of information on the result of the function operation.
A good example is the OPENED() function where the RLIBERROR() value
returns details on why the files were not opened successfully.
If you find that during your application development testing phase, a
particular routine is not operating correctly, and the routine calls
one or more RLIB functions, fire up the Clipper debugger and, at the
point in question, evaluate RLIBERROR() to get the last error value.
This can be a tremendous time saver in tracking down missing or
invalid RLIB parameters.
One additional technical note, RLIBERROR() simply maintains a PUBLIC
variable named rliberror, and this variable is always visible. Rather
than making explicit calls to RLIBERROR(), you may set a breakpoint
(in Clipper Summer '87) or to a tracepoint (in Clipper 5.0) to the
expression RLIBERROR != 0. In this manner your debugging execution
will stop at the point of failure, when RLIBERROR becomes non-zero.
Below is a table of all of the RLIBERROR error codes and their
meanings. These numbers were assigned sequentially as the RLIB
functions were coded and modified, so they are not in any logical
order and are not necessarily grouped by function.
Appendix A - RLIB Error Codes 201
CODE INDICATION
---- ----------
0 Normal completion, no error occurred.
1002 Non-character type or no parameter passed to ISFIELD()
1003 Non-array type or no parameter passed to ARRAYLEN()
1004 Non-array type or no parameter passed to ABOXASK()
1005 Non-character type, empty, or no parameter passed to ACRONYM()
1006 Non-numeric type, none, or partial parameters passed to ADIM2()
1007 Non-array type or no parameter passed to ALIST()
1008 Non-date type parameter passed to ALPHADATE()
1009 Non-character or insufficient parameters passed to ANYCHARSIN()
1010 Invalid or insufficient parameters passed to ATINSAY()
1011 Non-array type or no parameter passed to BARMENU()
1012 Non-character type or no parameter passed to BIN2DEC()
1013 Invalid or insufficient parameters passed to BORDERBOX()
1014 Non-character type or no parameter passed to BOXASK()
1015 Invalid or insufficient parameters passed to BOXMENU()
1016 Invalid or insufficient parameters (1-5) passed to PDOWNINIT()
1017 Mismatched array element count in parameter 2 & 3 to PDOWNINIT()
1018 No field array provided and no database selected in QUERY()
1019 Non character value in names/fields array in QUERY()
1020 Invalid expression in fields array in QUERY()
1021 Invalid or insufficient parameters passed to DBFCREATE()
1022 Non-numeric type or no parameter passed to FREADLINE()
1023 Non-character type or no parameter passed to MAKEALIAS()
1024 Non-array type or no parameter passed to CATF() or CFTA()
1025 No database selected in CATF() or CFTA()
1026 Array or first/last out of bounds in CATF() or CFTA()
1027 No database selected in CHANGED()
1028 No database selected or no fields in MEMORIZE()
1029 First or last out of bounds in MEMORIZE()
1030 PUBLIC variable undeclared or wrong type in CHANGED()
1031 No database selected or no fields in MREPLACE()
1032 First or last out of bounds in MREPLACE()
1033 PUBLIC variable undeclared or wrong type in MREPLACE()
1034 Non-character type or no parameter passed to CHECKFILE()
1035 Non-numeric type or no parameter passed to DEC2HEX()
1036 Non-character type or no parameter passed to DECRYPTED()
1037 Non-character type or no parameter passed to ENCRYPTED()
1038 Non-numeric type, none, or partial parameters passed to DIVIDE()
1039 Non-numeric type or no parameter passed to FEOF()
1040 Non-character type or no parameter passed to FILEDATE()
1041 Non-character type or no parameter passed to FILETIME()
1042 Non-character type or no parameter passed to FILESIZE()
1043 Non-character type or no parameter passed to FILES()
1044 No database selected or no fields in FORGET()
1045 First or last out of bounds in FORGET()
1046 Non-character type or no parameter passed to SAYINBOX()
1047 Invalid or insufficient parameters passed to GETPARM()
1048 Non-character type or no parameter passed to HEX2DEC()
1049 Non-character type or no parameter passed to ISDBF()
1050 Invalid or insufficient parameters passed to PICKREC()
1051 Non-character type or no parameter passed to MIDDLE()
1052 Invalid or insufficient parameters passed to MULTIMENU()
Appendix A - RLIB Error Codes 202
CODE INDICATION
---- ----------
1053 Invalid window coordinates or array length in MULTIMENU()
1054 Non-character type or no parameter passed to NAMESPLIT()
1055 Invalid or non-existent alias passed to NO_FLOCK()
1056 Invalid or non-existent alias passed to NO_RLOCK()
1057 No parameter passed to NOTEMPTY()
1058 Non-character or insufficient parameters passed to OLDERFILE()
1059 Non-character type or no parameter passed to PATHTO()
1060 Invalid or insufficient parameters passed to POPUPPICK()
1061 Non-character type or no parameter passed to PRINTCODE()
1062 Invalid type or no parameter passed to RH_HEADER()
1063 Error opening file in RH_HEADER()
1064 Invalid format in file given to RH_HEADER() (missing signature)
1065 Invalid type or no parameter passed to RH_HEADER()
1066 Error opening file in RH_TEXT()
1067 Error reading file in RH_TEXT()
1068 Non-character type or no help key parameter passed to RH_TEXT()
1069 Error opening file in RH_WIDTH()
1070 Invalid type or no parameter passed to RH_WIDTH()
1071 Non-character type or no help key parameter passed to RH_WIDTH()
1072 Error opening file in RH_LINES()
1073 Invalid type or no parameter passed to RH_LINES()
1074 Non-character type or no help key parameter passed to RH_LINES()
1075 Invalid or insufficient parameters passed to MARKREC()
1076 Non-date type parameter passed to REVDATE()
1077 Invalid or insufficient parameters passed to STRETCH()
1078 Non-character type or no parameter passed to RJUSTIFY()
1079 Invalid or insufficient parameters passed to PDOWNMENU()
1080 Non-character type or no parameter passed to STR2DATE()
1081 Invalid date string parameter passed to STR2DATE()
1082 Error opening REPORTS.DBF or PRINTERS.DBF in STARTREPORT()
1083 Error locking REPORTS.DBF or PRINTERS.DBF in STARTREPORT()
1084 Invalid or insufficient parameters passed to VRANGE()
1085 Append file not found in DBFCREATE()
1086 Error opening file in ISDBF()
1101 Function OPENED() - File sharing violation
1102 Function OPENED() - Database .DBF file not found
1103 Function OPENED() - Associated .NTX file not found
1104 Function OPENED() - Associated .DBT file not found (future use)
1105 Function OPENED() - Invalid alias name or other syntax error
1106 Function OPENED() - More than seven index files specified
1107 Function OPENED() - More than 10 parameters specified
Appendix A - RLIB Error Codes 203
┌───────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ Appendix B │
│ The RHELP Compiler │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────────┘
Appendix B - The RHELP Compiler
What is RHELP?
RHELP is a text-based help system that lets you easily build and
maintain context-sensitive help files. RHELP includes an Application
Programming Interface (API) that lets you build help systems from the
simple to the complex. It provides all the necessary pieces so you
don't have to do the nitty gritty work.
The RHELP system consists of the RHELP compiler program (RHC.EXE)
which builds the indexed help file from a text based source file.
Also included is the RHELP de-compiler program RHDC.EXE which de-
compiles a RHELP.HLP file into a source text file. Finally a set of
API functions are included that extract help information from an
indexed help file based on a unique key value. The RHELP compiler RHC
compiles (indexes) a help source file into a single file which
contains the help text along with a header containing an index.
RHELP Source Code
As with all RLIB components, the RHELP system comes with full source
code included. This includes the source code for RHC.EXE, RHDC.EXE
and the API functions, which are included in the RLIB function
library.
Why Compile?
Compiling a help source file with RHC results in a single runtime help
file that contains both the index and the help text. It is accessed
with the Clipper low level file I/O functions. However, you do not
need to concern yourself with the low level file functions because all
help information is retrieved via simple to use RLIB functions. For
example, to retrieve a block of help text associated with the key
"EDIT SCREEN" from a help file named MYAPP.HLP, you only need to issue
one function call; helpText = RH_TEXT("myapp.hlp", "EDIT SCREEN").
Once the help text is retrieved you display it in your preferred way.
An example of a help display function follows in the section entitled
"An Example".
Advantages
The advantage of the RHELP approach becomes apparent when you try to
create a help system for a product to be distributed, especially when
it will run on a network. Many Clipper developed help systems use a
database file with memo fields to store help keys and text. Using a
.DBF file to contain help information has limitations. First, the
help text is usually contained in a memo file and the help database
file is usually indexed into an index file. This means that your help
system now consists of three files; HELP.DBF, HELP.DBT, and HELP.NTX.
Appendix B - The RHELP Compiler 205
Furthermore, you may wish to set the file attributes of help files to
ReadOnly to protect from accidental overwrite or erasure. Clipper and
dBASE will not open a database file that is marked ReadOnly. Clipper
5.0 has just overcome this limitation with the READONLY clause to the
USE command but Clipper Summer '87 still will not open a database file
that is marked ReadOnly. Because RHELP help files are accessed with
the Clipper low level file functions, a ReadOnly attribute will not
affect the ability to open these files.
Another advantage of the RHELP approach over a .DBF file based help
system is the fact that the source help text is maintained in a plain
ASCII text file. This file can be edited and maintained with your
favorite editor or word processor which may include a spell checker
and thesaurus. With a .DBF file based help system you must either use
dBASE or write a custom application just to enter or edit help text,
not to mention that the editor in such a system may not be as
desirable as some word processors.
Help Source File Format
A RHELP help file is compiled (or indexed) from a text-based source
file with the RHELP compiler RHC.EXE. Help text is delimited by help
keyword Id markers. When RHC finds a help Id marker, it records file
location information which is stored in the resulting help file header
for fast text retrieval. RHC is not really a compiler but rather an
indexer - it creates an index to help text which is stored at the
beginning of the resulting help file. RHC compiled help files have an
extension of .HLP by default.
RHC compiles help text files which have keyword and Id markers.
Keywords are text strings which uniquely identify a block of help
text. Id markers are special characters that delimit keywords. These
keywords are stored in the help file header, and are the strings that
are used to look up help text blocks via the RHELP API functions.
Id markers are denoted by the special colon and vertical bar character
sequence ":|" left justified in the first two line column positions.
They may not be indented, if they are, the text will be treated as
normal help text. Immediately following the Id marker is the help
keyword. Keyword text may be any length but only the first 16
characters are significant. Case is not significant, keywords may be
upper, lower, or mixed case. All keywords are normalized to upper
case at lookup time. Id markers and keywords must appear on a single
line together by themselves. The actual help text begins on the next
line. The following is a sample excerpt from a RHELP help source
file.
Appendix B - The RHELP Compiler 206
┌────────────────────────────────────────────────────────────────┐
1│My applications help source file. (this line will be ignored!) │
2│:|MAIN MENU This is an Id marker │
3│ │
4│ This is help text associated with a main menu option │
5│ │
6│Press the directional arrow keys to navigate through the menu │
7│items, press ENTER to select a menu item, or ESCAPE to leave. │
8│ │
9│:|CUSTOMER EDIT SCREEN │
10│ │
11│Press the up and down arrow keys to move between edit fields. │
12│Enter data in all of the fields highlighted. The fields are: │
13│ │
14│Name - Enter the customer's full name, last name first. │
15│ │
16│Address - Enter the street address for the customer │
17└────────────────────────────────────────────────────────────────┘
In the above example, line number one is ignored by RHC because it is
not associated (comes after or under) an Id marker. Line number two
is an Id marker line because the two character sequence ":|" appears
in the left column. Only the first 16 characters of this Id marker
(not including the Id marker ":|" itself) are saved as the help key.
In this example the keyword is "MAIN MENU". Any characters appearing
on this line after the 16th character are ignored by RHC. In this
example the comment "This is an Id Marker" is ignored. The next six
lines are the help text associated with the help key MAIN MENU. The
next line (line #9) is another Id marker line. The help key is saved
as "CUSTOMER EDIT SC" since these are the first 16 characters. The
following seven lines are its associated help text.
RHC will compile help files with a limit of 500 Id markers (keywords).
Since RHC stores pointer information in arrays during the compile,
making this limit larger consumes more memory. To increase (or
decrease) the number of keys allowed, just change the MAXKEYS variable
(or #define in the 5.01 version) in the RHC.PRG source code and re-
compile and re-link RHC.EXE. You should note that the practical limit
is about 1000 keys. With MAXKEYS set to 1000 the runtime executable
program requires about 512K of RAM to run.
Creating Help
You can create RHELP-based help systems a number of ways. One way is
to mark sections of your source code with unique help keys. For
instance, in your customer data entry screen, just before the READ
command, set a global (PUBLIC or STATIC) variable named rh_HelpKey to
"CUSTOMER ENTRY" (rh_HelpKey = "CUSTOMER ENTRY"). Do this throughout
your code building a list of help keys as you go along. Then collect
this list of help keys and write your help text source file with
specific help text for each unique help key. A handy way to collect
the list of help keys is with a text search or grep program, by
scanning all .PRG files for the text "rh_HelpKey = ".
Appendix B - The RHELP Compiler 207
The next step is to compile your help source file into a .HLP file
with RHC. The default filename extension assumed by RHC is .RHC so if
your source file is named MYAPP.RHC, you would compile this help
source file with the command: RHC myapp The .RHC file extension is
optional. If your help source file has an extension other than .RHC,
use the full filename on the command line such as RHC myapp.src. This
will compile and create a file named MYAPP.HLP. This is the runtime
help file which is ready to be queried with the RLIB RHELP API
functions. See the example that follows for a sample help display
function.
Function API Quick Reference
RH_HEADER() Retrieve the header from a RHELP compiled help file.
RH_LINES() Get the number of text lines within a help text block.
RH_TEXT() Extract help text from a compiled .HLP file.
RH_WIDTH() Get the maximum line width within a help text block.
Building RHC.EXE and RHDC.EXE
To create the RHELP compiler RHC.EXE and de-compiler RHDC.EXE, simply
run the MAKERHC.BAT batch file supplied. RHC.PRG and RHDC.PRG are
both written in Clipper Summer '87 but may also be compiled with
Clipper 5.0. Both RHC.EXE and RHDC.EXE use the RLIB function library.
Demonstration Version
The demonstration RLIB package contains the RHELP compiler program RHC
in linkable object file format which has already been compiled with
Clipper Summer '87. The registered distribution version of the RLIB
package contains the RHELP compiler and RHELP de-compiler program
source code files RHC.PRG and RHDC.PRG.
An Example
The following is an example of a help system which utilizes the RHELP
API functions contained in the RLIB function library. This help
system reads help text from a designated help file and displays the
text centered on the screen.
Appendix B - The RHELP Compiler 208
*====================================================================
* Procedure: Help
* Purpose: Generic help module.
* Syntax: DO help WITH (helpkey), (helpfile)
* Parameters: helpkey - The text of the "Help keyword" to lookup
* helpfile - Name of the RHELP compiled help (.HLP) file.
*====================================================================
PROCEDURE Help
PARAMETERS sv_helpkey, sv_hlpfile
PRIVATE inrow, incol, incolor, inscreen, incursor
PRIVATE help_text, help_width, help_lines, HelpColor
PRIVATE win_width, win_lines, win_top, win_left, win_bottom, win_right
IF TYPE("sv_helpkey") + TYPE("sv_hlpfile") != "CC"
RETURN
ENDIF
IF .NOT. FILE(sv_hlpfile)
BLIP()
BOXASK( "Help file " + sv_hlpfile + " does not exist",;
"Help is not available", "Press any key to return", 30 )
SETCURSOR(incursor)
RETURN
ENDIF
helpColor = "B/W" && set your color here
incursor = SETCURSOR(.F.) && save and turn off cursor
inrow = ROW()
incol = COL()
help_lines = RH_LINES( sv_hlpfile, sv_helpkey )
help_width = RH_WIDTH( sv_hlpfile, sv_helpkey )
help_text = RH_TEXT( sv_hlpfile, sv_helpkey )
IF help_lines = 0 .OR. help_width = 0 .OR. EMPTY(help_text)
BOXASK(HelpColor,"No help available","Press any key to return",30)
ELSE
win_width = MIN( help_width, 76 )
win_lines = MIN( help_lines, 20 )
win_top = 11 - ROUND(win_lines / 2, 0) && middle of screen
win_bottom = win_top + win_lines + 1 && calc bottom row
win_left = 2 + INT( (76 - win_width) / 2 )
win_right = 79 - win_left
incolor = SETCOLOR(HelpColor)
inscreen = SAVESCREEN(win_top,win_left-2,win_bottom,win_right+2)
@ win_top, win_left-2, win_bottom, win_right+2 BOX "┌─┐│┘─└│ "
@ win_top, 37 SAY " Help "
@ win_bottom,26 SAY " Press ESCAPE to exit help "
MEMOEDIT(help_text,win_top+1,win_left,win_bottom-1,win_right,;
.F., "", help_width)
RESTSCREEN(win_top,win_left-2,win_bottom,win_right+2,inscreen)
SETCOLOR(incolor)
@ inrow,incol SAY ""
ENDIF
SETCURSOR(incursor)
RETURN
Appendix B - The RHELP Compiler 209
┌───────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ Appendix C │
│ Author's Note │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────────────┘
Appendix C - Author's Note
Clipper Summer '87 and 5.0
RLIB contains libraries for both Clipper Summer '87 and Clipper 5.0.
The 5.0 version of RLIB was specifically written to take advantage of
the new Clipper LOCAL and STATIC storage classes. This results in
optimized function performance, object code size reduction, and symbol
and address resolution at compile time rather than at run time.
Local and Static Variables
Probably the most important change to Clipper was the addition of true
Local and Static storage classes. I will not attempt to go into an
explanation of these storage classes, the Clipper manual does a good
job of that. I do want to add my two cents worth. Local and Static
variables finally let you truly hide information within a function.
Not only are local variables not visible below the function (in
routines which the function calls, unlike PRIVATE variables), but
their name is resolved at compile time. This means simply that if you
have a local variable in your function named HOURLYRATE that this is
only meaningful in your source code. Once it is compiled the need for
the name is gone, it is resolved to an offset address in your code.
In Clipper Summer '87, your executable ended up with a symbol (some
text), HOURLYRATE, contained in the .EXE file. Aside from the 16 to
22 or so bytes of space that consumed for each variable, it was there
for the poking at run time.
Static variables are exciting for the same, yet an additional reason.
Values you assign to static variables aren't released when the
function exits. This means you can write functions that can remember
details about the state they were in, and have that information
available the next time the function is invoked. Again, the Clipper
manual does a very good job of explaining these concepts as do a
number of third party publications.
The Clipper 5.0 version of the RLIB library makes extensive use of
LOCAL and STATIC variables, not only for more efficient and faster
functions, but also as a matter of good code form. I just want to
stress my feeling of satisfaction over the inclusion of Locals and
Statics into Clipper 5.0.
Macro Differences
Unfortunately, this is not a perfect world. One of the things I
stressed as a benefit of RLIB version 2.0 was that it came (as does
version 3.0) will full source code included. When Nantucket upgraded
Clipper to a new version, the RLIB owner would only have to re-compile
the RLIB functions to create an upgraded RLIB. Libraries that were
written in C and Assembler, and particularly those that poked into the
internals of Clipper, would have to be upgraded by their authors
Appendix C - Author's Notes 211
before you could get your upgrade. Well, my upgrade plan was fine as
long as Clipper itself maintained 100% upgrade compatibility with
itself. Unfortunately, this was not the case. There are a few areas
where Summer '87 and 5.0 code behave differently, most importantly in
the handling of macros.
This macro handling incompatibility affected two of the RLIB 2.0
functions, CHANGED() and MREPLACE(). They didn't act the same when
compiled under Clipper 5.0. Specifically, the aliasing in the REPLACE
statement does not work under Clipper 5.0 the way it did in Summer
'87. If you have a memory variable with the same name as a database
field, you normally override the default field by prefacing the memvar
with the M->. This works fine if you do it explicitly, but not if it
is done through a macro reference. So the code: REPLACE
&malias.->&mfield WITH M->&mfield works fine under Summer '87 but does
not under 5.0. Clipper 5.0 still retrieves the database field
contents in the code M->&mfield so the REPLACE does nothing but
replace the field with itself! The fix is to embed the M-> memvar
qualifier within the macro variable. In the example above, the
expression REPLACE &malias.->&mfield ... is replaced with REPLACE
&mfldvar ...where MFLDVAR is the string "M->FIELDNAME".
A Macro Example
To illustrate the problem, compile the sample program below under
Summer '87 and 5.0 and observe the results.
*-- Create a simple database named "TEST"
*-- with a single character field named "DATA" of length 12
USE test
APPEND BLANK
REPLACE data WITH "FIELD DATA"
M->data = "MEMVAR DATA"
? data && prints "FIELD DATA" as expected
? M->data && prints "MEMVAR DATA" as expected
memvar = "data" && assign the memvar name for macro reference
? M->&memvar && 5.0 prints "FIELD DATA" S'87, "MEMVAR DATA"
memvar = "M->data" && embed the M-> reference in the memvar
? &memvar && 5.0 now prints "MEMVAR DATA"
USE
RETURN
These differences have been fixed in RLIB by altering the expression
of macros and, in the 5.0 library, by replacing macro references with
code blocks and new Clipper functions for getting and putting field
values. The new Clipper functions for accomplishing these tasks are
far superior to using macros so the rule of thumb is that you can
probably do without macros in Clipper 5.0.
Appendix C - Author's Notes 212
RLIB Differences
There are a few differences between the Summer '87 and 5.0 versions of
the RLIB library. These differences are limited to functions that are
not appropriate in one or the other library.
SETCURSOR() Clipper now has its own internal SETCURSOR() function.
The Summer '87 version of RLIB has a SETCURSOR()
function that takes a single numeric value as an
argument, and is compatible with the 5.0 version.
Since Clipper 5.0 now has a SETCURSOR() function, it
is not present in the 5.0 version of RLIB.
VALTYPEC() This RLIB function is specific to, and only exists in,
the 5.0 version of RLIB.
Appendix C - Author's Notes 213
Index
A Shareware Version . . . . . . . 11
Directory Structure . . . . . . 15
ABOXASK() . . . . . . . . . . . 29 Disk Space . . . . . . . . . . 15
ACRONYM() . . . . . . . . . . . 31 Diskettes . . . . . . . . . . . 6
ADIM() . . . . . . . . . . . . 32 DIVIDE() . . . . . . . . . . . 76
ALIST() . . . . . . . . . . . . 33 Dynamic Overlays . . . . . . . 16
ALPHADATE() . . . . . . . . . . 35
ANYCHARSIN() . . . . . . . . . 36
ARRAYLEN() . . . . . . . . . . 37 E
ATINSAY() . . . . . . . . . . . 38
Author's Note . . . . . . . . 211 ENCRYPTED() . . . . . . . . . . 77
B F
BARMENU() . . . . . . . . . . . 39 FEOF() . . . . . . . . . . . . 78
BEEP() . . . . . . . . . . . . 42 FILEDATE() . . . . . . . . . . 79
BIN2DEC() . . . . . . . . . . . 43 FILES() . . . . . . . . . . . . 80
Blinker . . . . . . . . . . . . 16 FILESIZE() . . . . . . . . . . 81
BLIP() . . . . . . . . . . . . 44 FILETIME() . . . . . . . . . . 82
BORDERBOX() . . . . . . . . . . 45 FORGET() . . . . . . . . . . . 83
BOXASK() . . . . . . . . . . . 47 FPROMPT() . . . . . . . . . . . 85
BOXMENU() . . . . . . . . . . . 50 FREADLINE() . . . . . . . . . . 87
BRIGHT() . . . . . . . . . . . 54 FRESTSCREEN() . . . . . . . . . 88
BUZZ() . . . . . . . . . . . . 55 FSAVESCREEN() . . . . . . . . . 90
C G
CALENDAR() . . . . . . . . . . 56 GETFILE() . . . . . . . . . . . 92
CATF() . . . . . . . . . . . . 59 GETKEY() . . . . . . . . . . . 94
CENTER() . . . . . . . . . . . 61 GETPARM() . . . . . . . . . . . 96
CFTA() . . . . . . . . . . . . 63
CHANGED() . . . . . . . . . . . 65
Changes H
From RLIB 2.0 . . . . . . . 7
Upward Compatibility . . . 9 Help
CHECKFILE() . . . . . . . . . . 67 Sample Program . . . . . 209
CLOSEAREA() . . . . . . . . . . 70 HEX2DEC() . . . . . . . . . . . 98
Code Generators . . . . . . . . 2
CompuServe . . . . . . . . . . 24
Contents . . . . . . . . . . . 5 I
Copyright . . . . . . . . . . iii
Installation
Diskettes . . . . . . . . . 15
D Introduction . . . . . . . . . 2
ISDBF() . . . . . . . . . . . . 99
DBFCREATE() . . . . . . . . . . 72 ISFIELD() . . . . . . . . . . 100
DEC2HEX() . . . . . . . . . . . 74
DECRYPTED() . . . . . . . . . . 75
Index 214
K P
KEYINPUT() . . . . . . . . . 101 Parameter Verification . . . . 18
PARENT() . . . . . . . . . . 129
PATHTO() . . . . . . . . . . 130
L PDOWNINIT() . . . . . . . . . 131
PDOWNMENU() . . . . . . . . . 136
Libraries PICKCOLOR() . . . . . . . . . 140
CLIPPER . . . . . . . . . . 2 PICKFILE() . . . . . . . . . 142
EXTEND . . . . . . . . . . 2 PICKREC() . . . . . . . . . . 144
Linking RLIB . . . . . . . . . 16 PLINK86 . . . . . . . . . . . . 16
Local Variables . . . . . . . 211 POPBOX() . . . . . . . . . . 154
POPUPPICK() . . . . . . . . . 155
PRINTCODE() . . . . . . . . . 158
M PROGNAME() . . . . . . . . . . 25
Macros
Differences . . . . . . . 211 Q
MAKEALIAS() . . . . . . . . . 103
MARKREC() . . . . . . . . . . 104 QUERY() . . . . . . . . . . . 160
MEMORIZE() . . . . . . . . . 107
Message Reader . . . . . . . . 24
Functions Used In . . . . . 25 R
MIDDLE() . . . . . . . . . . 109
MREPLACE() . . . . . . . . . 110 Registration . . . . . . . . . 11
MS-LINK . . . . . . . . . . . . 16 REPORTINIT() . . . . . . . . 165
MULTIMENU() . . . . . . . . . 111 REVDATE() . . . . . . . . . . 168
RH_HEADER() . . . . . . . . . 169
RH_LINES() . . . . . . . . . 171
N RH_TEXT() . . . . . . . . . . 173
RH_WIDTH() . . . . . . . . . 175
NAMESPLIT() . . . . . . . . . 113 RHELP . . . . . . . . . . . . . 3
NO_APPEND() . . . . . . . . . 114 RHELP Compiler . . . . . . . 205
NO_FLOCK() . . . . . . . . . 116 Creating Help . . . . . . 207
NO_RLOCK() . . . . . . . . . 118 File Format . . . . . . . 206
Norton Guides . . . . . . . . 3, 6 Function Reference . . . 208
NOTEMPTY() . . . . . . . . . 120 RJUSTIFY() . . . . . . . . . 177
NTXKEYVAL() . . . . . . . . . 121 RLIB
Changes From Version 2.0 . 7
Enhanced Functions . . . . 9
O New Functions . . . . . . . 7
Registered Version . . . . 6
OLDERFILE() . . . . . . . . . 123 RLIB Error Codes . . . . . . 201
On-line Reference Database . . 6 RLIBERROR() . . . . . 18, 178, 201
OPENED() . . . . . . . . . . 125 RLIBINIT() . . . . . . . . . 179
Order Information . . . . . . . 12 RLIBVER() . . . . . . . . . . 180
Order Form . . . . . . . . 13 RTLink . . . . . . . . . . . . 16
ORDER.DOC . . . . . . . . . 12
Shipping . . . . . . . . . 13
Index 215
S
SAYINBOX() . . . . . . . . . 181
Self-Extracting ZIP Files . . . 15
Contents . . . . . . . . . 6
Shareware Version . . . . . 5
Registered Version . . . . 6
SETCURSOR() . . . . . . . . . 183
Source Code . . . . . . . . 4, 11
Clipper 5.0 . . . . . . . . 4
Space Required . . . . . . 15
Summer '87 . . . . . . . . 4
STARTREPORT() . . . . . . . . 184
Static Variables . . . . . . 211
Storage Classes
Local . . . . . . . . . . . 4
Static . . . . . . . . . . 4
STR2DATE() . . . . . . . . . 189
STRETCH() . . . . . . . . . . 190
System Requirements . . . . . . 15
T
TARGET() . . . . . . . . . . 191
Technical Support . . . . . . . 11
CompuServe Mail . . . . . . 11
Telephone . . . . . . . . . 11
TEMPFILE() . . . . . . . . . 194
TLINK . . . . . . . . . . . . . 16
TYPEC() . . . . . . . . . . . 195
V
VALTYPEC() . . . . . . . . . 197
VRANGE() . . . . . . . . . . 199
W
Warranty . . . . . . . . . . . v
What Is RLIB? . . . . . . . . . 2
What You Get . . . . . . . . . 3
Index 216