home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 17
/
CD_ASCQ_17_101194.iso
/
vrac
/
chkarg.zip
/
CHECKARG.DOC
< prev
next >
Wrap
Text File
|
1994-09-10
|
16KB
|
411 lines
CheckArg v1.0
Function-Argument Type Checking
9/10/94
Copyright (C) 1994 All rights reserved. Paul Long
CompuServe: 72607,1506
Internet: Paul_Long@ortel.org
pci!plong@ormail.intel.com
At A Glance
-----------
// test.prg
#include "checkarg.ch"
// Generates the following run-time error
// because function expects numeric.
DoIt("Now")
function DoIt(nHowMuch)
return nil
┌──────────────────────────────────────────────┐
│ C is an invalid type for parameter nHowMuch │
│ of module DOIT, called from TEST/5. │
│ │
│ Quit Skip Skip Module Skip All │
└──────────────────────────────────────────────┘
Introduction
------------
CheckArg performs type checking on function and procedure arguments
based on Hungarian notation without source-code changes. To use
CheckArg, your parameter names must use the notation that has become
somewhat of a standard in the Clipper programming community. For
example, an array parameter must start with a lower-case "a", as in
aCons, and a numeric must start with a lower-case "n", as in nRequested.
CheckArg is capable of performing the following checks:
1. Argument types.
2. Parameter names to assure that they conform to Hungarian notation.
This is especially useful in larger shops in order to enforce naming
conventions.
3. Missing required arguments. This relies on a non-standard naming
convention, e.g., nuEnd for an optional numeric and nEnd for a
required numeric, and is therefore initially turned off.
4. Extra arguments that the called function could not possibly be
expecting because no parameters are defined for them. This may not
be considered a transgression by some programmers so it is initially
turned off.
LIMITED WARRANTY AND REMEDIES
-----------------------------
CHECKARG IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO WARRANTIES OF
PERFORMANCE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
FUNCTIONALITY, OR COMPLETENESS. IN NO EVENT WILL PAUL LONG BE LIABLE TO
YOU FOR ANY DAMAGES, INCLUDING INCIDENTAL OR CONSEQUENTIAL DAMAGES,
ARISING OUT OF THE USE OF THE PROGRAM, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
Integration
-----------
The following steps are required to integrate CheckArg into your code:
1. Compile the source files in which you want to perform type checking with
checkarg.ch included at the top of the file.
2. Compile (with the options, /a/w/n) and link checkarg.obj into the
executable.
Compile-time Control
--------------------
Normally checking is not enabled. Identifiers defined on the
compilation command line control this. Checking is enabled by defining
the DEBUG identifier. To always enable type checking regardless of
whether DEBUG is defined, define CHECKARG on the command line. Likewise,
to disable type checking, define NOCHECKARG. If both are specified,
CHECKARG takes precedence over NOCHECKARG. Run-time control is affected
by the functions that are described in the section, Modifying Default
Behavior.
Requirements
------------
1. Hungarian notation used for function and procedure parameter names.
2. Short or long names used for the FUNCTION and PROCEDURE keywords, not
anything in between, such as FUNCTI or PROCED.
3. Clipper 5.2.
Type checking in OOP
--------------------
In a typeless, pure object-oriented programming language such as
Smalltalk, arguments have no type. Therefore, argument type checking
such as that performed by CheckArg would be useless. With OOP
extensions such as Class(y), Clipper becomes a hybrid OOPL like C++.
As a result, Clipper OO programs tend to use objects for some
medium-to-large-grained entities, such as windows, and conventional
types for low-level entitites, such as record count and list of field
names. Therefore, it still makes sense to use CheckArg in an
object-oriented program.
Possible Enhancements
----------------------
Support other versions of Clipper.
Allow to be used with other products that have a function UDC, such as
Class(y).
Ignore "self" parameter for use with Class(y)? General solution would
be to let user provide an array of parameter names to ignore.
Allow user to define type indicators to ignore. For example, "h" if
they use that for file handles, as in hSource. Eventually, let the user
define how these types are to be type checked by CheckArg.
Optionally check all elements of an array argument instead of just the
first one?
Allow user to provide a code block for error logging.
Allow user to provide a code block to replace CheckArg's error reporting
mechanism.
For bad-type error, try to display actual value, not just type.
Allow user to define their own non-standard naming convention.
Detect and optionally ignore non-Hungarian parameter names. For
example, if "custno" is encountered, assume that no type checking is
to be performed.
Allow typing prefix to be used without a base, as in just "n" for a
numeric. Presently an uppercase character must be present after the
typing prefix.
Allow user to indicate that no type checking is to be performed on a
particular function, such as NOCHECK FUNCTION DoIt(nThisMuch). For
the time being, using an otherwise illegal keyword variation, such as
FUNCT fakes out CheckArg. Yucko.
Other type checking, such as on return values and initializers.
Parameter-name Syntax
---------------------
In general, a parameter name consists of a type prefix and a base. The
base must begin with an uppercase letter to distinguish it from the
all-lower-case prefix. The prefix is either one or two characters long.
The first character is the type indicator; the second, the modifier.
The type indicator is either a scalar (b, c, d, l, m, n, o, or x) or an
array (a). "Any type" is indicated by x and may be redefined to another
character with the CAAnyChars() function. The other type indicators are
standard Clipper types, such as those returned by VALTYPE().
The array type can be used with a type indicator as its modifier. This
indicates that the parameter is an array of the specified type. For
example, anSelected is an array of numerics. Noteable array parameter
names include, for example, axList, aList, and aaList. The first two
are arrays of any type; the third is an array of arrays. An array of
arrays of a particular type cannot be expressed using this naming
convention. For example, it is illegal to express an array of arrays of
character strings as aacGrid.
When CheckArg checks whether a passed value is of the proper type for an
array parameter with a type-indicator modifier, it only checks the first
element in the array. This is to save time. All elements are assumed
to be of the same type.
The u modifier indicates that the parameter may be undefined, or, in
other words, is optional. Examples include luSoftSeek and auText. This
is the only modifier that may be used with scalars. When used to modify
the array type, it indicates an optional array argument, not an array of
undefined's. The CAOptChars() function redefines the character that
CheckArg recognizes for this modifier. The CACheckReq() function
determines whether CheckArg assures that required parameters--those
without the u modifier--are actually passed a value.
Backus-Naur Form:
The following is the Backus-Naur Form, or BNF, of parameter names that
CheckArg expects. This means of syntax specification is very exacting
but a bit hard to read, especially if you are not used to reading BNF.
::= means "is the same as," | means "or," <> identifies an intermediate
grammar by name, [] means "is optional."
scalar ::= b | c | d | l | m | n | o | <any>
any ::= x
array ::= a
undefined ::= u
scalar prefix ::= <scalar> [ <undefined> ]
array prefix ::= <array> [ <array modifier> ]
array modifier ::= <scalar> | <undefined>
prefix ::= <scalar prefix> | <array prefix>
upper ::= A | B | ... | Y | Z
digit ::= 0 | 1 | ... | 8 | 9
lower ::= a | b | ... | y | z
id char ::= <upper> | <lower> | <digit>
id chars ::= <id chars> | <id char>
base ::= <upper> <id chars>
name ::= <prefix> <base>
Syntax Diagram:
If you found BNF hard to understand, rest your eyes and take a look at
the following syntax diagram. It is kind of loose, but it gets the
point across a little easier. | mean "is optional."
b| |
c| |
d| |
l|u|
m| |
n| |
o| |
x| |
t m N a m e
|a|
|b|
|c|
|d|
a|l|
|m|
|n|
|o|
|x|
|u|
Examples:
ndStart Clipper meta-syntax, such as this, is not
supported--you cannot specify a list of possible
types, only one.
xStart Any type (no type checking)
luFull Optional logical
nLedgers
oWExam
aRecords
axRecords Equivalent to aRecords.
auRecords An optional array, not an array of optional values.
Error Messages
--------------
When CheckArg detects an error, it displays an error box containing a
description of the error and gives the user the following options:
Quit - Terminate the program, close all open files, and return to the
operating system.
Skip - Skip only this transgression.
Skip Function - Discontinue type checking for this function for this
and all subsequent calls.
Skip All - Discontinue all type checking. Can be turned back on from
within the program by executing CASkipAll(.t.).
The possible error messages are:
<cType> is an invalid type for parameter <cArg> of module <cModule>,
called from <cModule>/<nLine>
<cArg> is an invalid parameter name in module <cModule>,
called from <cModule>/<nLine>
<nExtra> extra argument(s) passed to module <cModule>,
called from <cModule>/<nLine>
Modifying Default Behavior
--------------------------
The following functions can be called to modify the default behavior of
CheckArg. They are all accessor functions in that if the argument is
present, CheckArg uses the value. The value of the previous setting is
returned regardless of whether the argument is present. Their effect is
program-wide, not just in the function or source file from which they
are called. They can be called any number of times and at any time.
CASkipAll(luSkipAll)
Example: CASkipAll(.t.)
Whether to skip type checking. This overrides whatever was specified
when a source file was compiled.
CACheckReq(luStrict)
Example: CACheckReq(.t.)
Whether to distinguish between optional and required arguments.
Initially false--all arguments are assumed to be optional. This has to
do with the character that indicates whether an argument is optional.
This character is initially "u" but can be set to any other character
with the CAOptChars() function.
Consider the following code segment:
CACheckReq(.f.) // Do not check whether arguments are required.
DoIt1() // No error detected because checking turned off.
DoIt2() // Ditto.
CACheckReq(.t.) // Check whether args are required.
DoIt1() // No prob--argument is defined to be optional
// as indicated by the "u" in the name.
DoIt2() // Prob--CheckArg would detect that a required
// argument is missing. Required is
// indicated by the absence of a "u" in the
// name.
function DoIt1(nuHowFar)
...
return nil
function DoIt2(nHowFar)
...
return nil
CACheckExtra(luExtra)
Example: CACheckExtra(.t.)
Whether to check for extra arguments in a call to this function.
Initially false. This could uncover a situation where the caller passes
more arguments than are expected.
Consider the following code segment:
CACheckExtra(.f.) // Do not check for extra arguments.
DoIt(1, "Hello") // None detected, although present.
CACheckExtra(.t.) // Check for extra arguments.
DoIt(1, "Hello") // CheckArg would detect that an extra argument,
// "Hello", is present.
function DoIt(nHowFar)
...
return nil
CAOptChars(cuOpt)
Example: CAOptChars("e")
Determines what character or characters to use to indicate that an
argument is optional. Initially "u". The actual check is turned on and
off with the CACheckReq() function. If more than one character is
specified, each character can be used individually to indicate an
optional argument--they are synonyms. For example, "ue" means that
either "u" or "e" indicates an optional argument, not "ue" together.
CAAnyChars(cuAny)
Example: CAAnyChars("v")
Determines what character or characters to use to indicate "any
type"--no type checking. Initially "x". Like the CAOptChars()
function, if more than one character is specified, each character can be
used individually to indicate "any type."
CAModName(buModName)
Example: CAModName({|nAct| methodname(nAct)})
Specifies a block that accepts an activation level and returns the
corresponding module name. Initially {|nAct| procname(nAct)}. This is
provided so that the Class(y) methodname() function can be used in place
of procname(), as in {|nAct| methodname(nAct)}.
Trademarks
----------
Trademarks are the property of their respective owners.
Licensing agreement
-------------------
The CheckArg source, header, and included accessory files ("the
software") are the copyrighted work of their author, Paul Long. All
descendant manifestations of the software are also the copyright of Paul
Long. All rights under US and international copyright law are reserved.
You are hereby granted a limited license at no charge to use the
software and to make copies of and distribute said copies of the
software, as long as:
1. Such use is not primarily for profit. "For profit" use is defined as
primary use of the program whereby the user accrues financial benefit or
gain directly from use of the software; for example, integrating the
software with a commercial quality-assurance product would be a use
primarily for profit. "Primary use" is defined as the major use of the
program, or the primary reason for acquiring and using the program.
2. Such copies maintain the complete set of files as provided in the
original distribution set, with no changes, deletions or additions. The
archive storage format may be changed as long as the rest of this
condition is met.
3. Copies are not distributed by any person, group or business that has
as its primary purpose the distribution of free and "shareware" software
by any means magnetic, electronic or in print, for profit. BBS
distribution is allowed as long as no fee is charged specifically for
this software. Bona fide non-profit user's groups, clubs and other
organizations may copy and distribute the software as long as no charge
is made for such service beyond a nominal disk/duplication fee not to
exceed $5.00. For-profit organizations or businesses wishing to
distribute the software must contact the author for licensing
agreements.