                                dUFLP/dHUNG
                     Coding Standards and Conventions
                                Version 1.6
                               November, 2004


dUFLP -- dBASE Users Function Library Project -- Coding Standards and
Conventions -- Based upon the HUNGARIAN / xBase Conventions by Robert A.
DiFalco. These Standards and Conventions have been defined and generally
agreed upon by several of the 'regulars' on the Borland (once Ashton-
Tate) Bulletin Board System (BORBBS (now defunct)), but are by no means 
a rigid definition. As dBASE has evolved, some of these standards
are probably obsolete, and could use an update. Attempts have been made
to do so here, but the product is constantly changing. With the advent
of the Object-Oriented DML (Database Manipulation Language) there
are a lot more object types to worry about. If what you are looking
for is not covered here, use something that makes sense (i.e., 
dMyDatabase for a database object, or rMyRowset for a rowset object 
reference,
etc.).

This file contains modifications to Robert DiFalco's (CIS: 71610,1705)
HUNG standard for X-Base languages; it was developed by members of the
Ashton-Tate/Borland Bulletin Board System to be used in a user-developed
library.  Several aspects of this document have been changed, as the 
dUFLP standards are more aimed at dBase than other programming 
languages, but have been only slightly modified where needed, and some 
duplicate definitions were removed in the variable naming practices. The
original document (HUNG14.ZIP) may be found on the CompuServe dBASE 
Forum. (If it's still there ... CompuServe has been changing ...)

NOTE: There are references throughout to Visual dBASE 7.x -- these
can be applied to all versions of dBASE 32-bit releases.

The purpose of this document is to define some coding standards to be 
used in the library for dUFLP, Please attempt to follow these standards 
as closely as possible when creating Functions and Procedures to be 
included in this library. Thank you ... (most of the text from this 
point on is DiFalco's own words, except where we've added/modified items
to the lists)

FINALLY: Note that these are GUIDELINES, not hard-and-fast rules. It
doesn't make a bit of difference to dBASE itself if you use these
guidelines for writing code. The purpose is to make your code readable
by other developers ...

------------------------------------------------------------------------

Let me start off by stating that these are only my opinions on naming
conventions for xBase programming. In my opinion these methods are
extensible to C, ASM, BASIC and just about any other programming
language. It looks very similar to Hungarian notation as outlined by
Charles Simonyi of Microsoft Corporation. Don't be fooled, however, this
is much different. I find it more intuitive and logical though that may
pertain only to my thinking.

These conventions take in the same factors as outlined by Charles 
Simonyi for creating names in a program. The factors listed below are 
directly quoted from his monograph.

Begin quote:
1. Mnemonic value   - so that the programmer can remember the name.

2. Suggestive value - so that others can read the code easily.

3. "Consistency"    - this is often viewed as an aesthetic idea, yet it
                      also has to do with the information efficiency of 
                      the program text. Roughly speaking, we want 
                      similar names for similar quantities.

4. Speed of decision- we cannot spend too much time pondering the name 
                      of a single quantity, nor is there time for typing
                      and editing extremely long variable names.
End quote

In dBase, versions prior to Visual dBASE (and maybe dBASE 5.0 for Windows)
our variable names have even a more pressing reason for short
identifiers since we only have 10 characters to work with. To alleviate
using needless characters, we will use lowerUpper combinations instead 
of dividing underscores. In later versions, the character limit has
gone up (32 recognized characters). In addition, in Visual dBASE 7 (and 
later), the naming of properties and methods has gone to "lowerUpper" 
as well -- i.e., "onGotFocus".

=====================================
Procedure/Function Naming conventions
=====================================
Procedures and Functions will be heretofore called "Functions". Function
names will not be "typed" as variables. As dBase in general heads 
towards object oriented approaches it is important to allow our 
Functions to return multiple types. This negates the approach of typing
Functions by return variable type. Instead we will apply a "loose" set 
of rules to Functions. Native language functions will be in all 
lowercase while 3rd party or "home grown" functions (UDF or User-
Defined Functions) will be mixed case beginning with a single Capital
letter.

-------------
UDF Name Case
-------------
All User Defined Functions will be mixed case, with no underscores. The
first letter will be upper case, e.g. AllTrim.

1. Functions will start with a capital letter followed by lower case
   letters thus distinguishing them from variables. If the Function name
   can be better expressed by two or three identifiers an UpperLower
   combination will be used rather than underscores to delimit 
   identifiers. Consider the following Examples:

   ClrSet()    - Sets colors
   GetPass()   - Gets a password
   Choose()    - Menu of items to "choose" from

2. Methods will start with a lower case letter, but may use a similar
   construct as above. When creating your own method for a class,
   you might create methods with names like:

   getPass()
   str2Arr()

   Etc.

3. Conversion Functions will start with the value they take and end with
   converted value separated by the number 2. Some examples would be as
   follows:

   Str2Arr()  - Changes a string to an array.
   Hex2Dec()  - Changes a Hex string into a decimal numeric.
   Clr2Attr() - Changes a color string to an integer attribute.
   Dbf2Arr()  - Loads a DBF into an array.

4. Where possible, use standard qualifiers as outlined in the section
   dedicated to "Variable Naming Conventions". A few examples follow.

   cFName   = qCustomer.rowset.fields["FNAME"].value
   cLName   = qCustomer.rowset.fields["LNAME"].value
   cAddr    = qCustomer.rowset.fields["ADDR"].value
   nAge     = qCustomer.rowset.fields["AGE"].value
   lActive  = qCustomer.rowset.fields["ACTIVE"].value
   nBalance = qCustomer.rowset.fields["BALANCE"].value
   ( Please note that the storage operators ( "=" ) are lined up for 
     easy reading giving a table appearance. )

5. Where possible, express the function or procedure in less than three
   qualifiers ( names ). Refer to the examples given for Rule 1.

------------------
Reserved Word Case
------------------
All dBASE reserved words should be lower case.

------------
Case Summary
------------
all lower                 : built-in commands and functions
mIxed, fIrst lEtTer lOWer : memvars, methods
MiXed, First LetTer UpPer : UDFs
ALL UPPER                 : CONSTANTS defined with #DEFINE

=============================================
DBF and Field related Punctuation Conventions
=============================================
There are some rules noteworthy for DBF, MDX, and FIELD
operations to delineate them from Functions and Variables. FIELD names 
will NOT be typed by a lowercase type identifier as with Variables.

1. Table and Index files, as well as Field names will always be
   expressed in capital letters. As dBase's main point of existence is 
   the manipulation of DataFiles, this will make them stand out against 
   variables and other qualifiers. [Side note: almost no one uses
   this particular rule ...]

2. Where possible they will use the same standard qualifiers used for
   Variables and Functions. See the examples for Rule 3 of
   "Procedure/Function Naming Conventions".

3. Tables should be referenced in queries using the name of the table
   as part of the query object name. Consider the following.

   Ensure that your query object's references are ones that make sense, 
   such as:

       qAcct = new Query()

   This makes it easier to determine which query or rowset you
   are referring to in your code:

       qAcct.rowset.fields["ACCNUM"].value

   for example, is easier to read than:

       q.rowset.fields["ACCNUM"].value

4. Variables referencing Fields will have the same name as the Field 
   with the addition of the dHUNG type prefix.

   cFName   = qCustomer.rowset.fields["FNAME"].value
   cLName   = qCustomer.rowset.fields["LNAME"].value
   cAddr    = qCustomer.rowset.fields["ADDR"].value
   nAge     = qCustomer.rowset.fields["AGE"].value
   lActive  = qCustomer.rowset.fields["ACTIVE"].value
   nBalance = qCustomer.rowset.fields["BALANCE"].value

   ( Please note that the storage operators ( "=" ) are lined up for 
     easy reading giving a table appearance. )

5. With regard to DBF file names, data, index or otherwise they should
   all begin with a common prefix and that prefix is similar to the
   name.

   This insures that I have few naming conflicts with other systems
   that may reside on the computer and just about guarantees I can
   separate my files out if they get placed into a common subdirectory.

===============================
Command Punctuation Conventions
===============================
This area of my dHUNG naming conventions will probably meet with the 
most opposition. User Defined Commands will use descriptive names as 
outlined in "Procedure/Function Naming Conventions".  User Defined or 
not, Commands will have one Rule.

1. All Commands will be typed with lower case letters.

The reasons for this are simple. This will delineate commands from
variables, functions and DBF elements. Consider the following examples.
Note the use of the ":=" operator for assignment -- it is useful
to ensure you do not accidentally create new properties of objects,
and to ensure that the correct type is used for variables.

function CmdExample

   qCust            = new Query()
   qCust.sql        = "select * from HCUST"
   qCust.active    := true
   qCust.indexName := "lastname"

   cLName = "DiFalco"

   qCust.rowset.findKey( cLName )

   qCust.rowset.fields["Age"].value    := 28
   qCust.rowset.fields["Active"].value := true

   qCust.active := false

return 

===========================
Variable Naming Conventions
===========================
This is the heart of a well designed system. Variable names must give 
the most amount of information possible in its name while using the 
minimum number of characters possible.

All memory variables (memvars) are mixed case names, consisting of 
alphanumeric characters.  The first character is always a lower case
type prefix.  Memvar names should not repeat type prefix information.

But memvars may have a combination of tags that will in most cases 
appear in this order.

1. A single lower case variable defining its type as returned by a 
   type() function called a "Type Prefix".
2. An Optional state called a "State Qualifier"
3. A "Standard Qualifier Tag".
4. An Optional "Pointer Reference".

-------------
Type Prefixes
-------------
A type prefix is the first character of a variable that represents the
type the programmer intends for the variable.  Below is the list of
dBASE-specific type prefixes together with examples:

             Prefix          Type            Example
             ------          ----            -------
                a            Array           aList
                c            Character       cFName
                d            Date            dPmtDue
                f            Float           fAngle
                l            Logical         lExitMenu
                b            Boolean/Logical bReturn
                n            Numeric         nHours
                t            TimeStamp       tLogin
                x            undefined       xLookUp

For temporary variables of distinct type or pointers this single prefix 
can be used by itself. Consider this example.

n = 0
do while n < nFldMax
   n++
   aFldName[ n ] = form.rowset.fields[ n ].fieldName
enddo

-----------------------------------
OBJECT-ORIENTED xBASE TYPE PREFIXES
-----------------------------------
There are so many different types of controls that it may 
be easier to just not bother with a prefix, and and instead 
make sure that you use the name of the object type in the 
name, i.e.:

    FlavorCombobox
    LastNameEntryfield
    LastNameText

    etc.

---------------------------
Sample "Pointer References"
---------------------------
1,2,3 - State pointer references as in cSavClr1, cSavClr2, etc.
Max   - Strict upper limit as in nFldMax, maximum number of Fields
Min   - Strict lower limit as in nRecMin, minimum number of Records


These lists are to serve as samples and building blocks. They can and
should be added to. Lets look at a few examples of the conventions at 
work. This should dispel the myth that notation conventions cannot be 
applied to variables with a 10 character maximum length.

==========================================
Poorly Designed and Well Designed Examples
==========================================

WRONG       RIGHT       WHY
------------------------------------------------------------------------
nFldNum     nFld        Number is indicated by the Type Prefix making 
                        the word Num redundant and a needless use of 
                        character space.
Count       n           n serves as a temporary count index. Count has 
                        no Type Prefix - could also be called nCount.
Last_Name   cLName      This is one of the most horrendous mistakes. 
                        First we do not specify the variable type. 
                        Second we needlessly spell out LAST and worst of
                        all we use up a precious character by using an 
                        underscore instead of using the UpperLower 
                        combination.
SaveScreenA sSav1       No Type Prefix, needless use of characters. The
SaveScreenB sSav2       alphabetical reference is allowable though I 
SaveScreenC sSav3       prefer to use a numeric reference. Use of 's' 
                        type prefix removes need to use Scrn or sScreen.
ColorStr    xClr        No Type Prefix. Needless use of characters. This 
                        shows the usage of 'unknown' type with the Type 
                        Prefix 'x' (colors are character strings in 
                        specific formats, but do not require a special 
                        type).
PrintReset  xPrnReset   Also could have been shortened to cPrnRst.
MessageStr  cMsg        These are starting to become obvious, don't you
                        think?

-----------------
#DEFINE/Constants
-----------------
Constants can be defined in dBASE for Windows with the #DEFINE
statement. Suggested syntax is to use ALL CAPS, with underscores
between words. The Constant name should make sense, so some
prefix should be used to say what the #define is for. For example,
   
   ALIGNMENT_WRAP_CENTER  is better than simply  WRAP_CENTER


=============================
Assignment/Equality Operators
=============================
In dBASE versions prior to VdBASE 7.x the "=" sign was used to
both assign and compare equality.

In Visual dBASE 7.x you are really better off using the following
(and these conventions should be used in any new controls/functions
etc. for the dUFLP library):

Operator   Meaning
-----------------------------------------------------------------
  =        Assign a NEW property or variable a value
  :=       Assign a currently existing property or variable
           a value
  ==       Compare equality ...

The assignment operator (:=) will not work for a brand new custom
property of an object, nor for a previously undefined/unassigned
value for a variable. Instead, an error will occur -- this is
useful to ensure that you do not accidently create a new variable
or property for an object by typoing a name.

Also note that "==" really boils down to an "exactly equal" situation
similar to SET EXACT ON if you used the "=" sign ... (see online
help for more information ...)


======================
Standard Header Format
======================
Below is the recommended header format to be used for procedures/
functions. This will allow the automated maintenance of library 
functions as well as documenting the routine.  By using this header, it
will make it possible to create a routine either in dBASE or some other
software that can generate a library listing, giving the pertinent 
information. Please also note EoF/EoP comment at the END of the 
function or procedure. Finally, note that we are keeping text in 
particular, although it is useful to keep the code in the same limit, 
to a right margin of 72 characters. 

Use the following format for your headers (Note the change in the 
date format: due to international considerations, and the fact that 
some folk use MM/DD/YY and others use DD/MM/YY formats, and variations, 
it is easier to ensure we all understand each other if we start 
using the month spelled out ... otherwise it's hard to tell if that's 
the month or day ...):

function AllTrim 
/*
   -----------------------------------------------------------------------
   Programmer..: Ken Chan
   Date........: September 8, 1998
   Notes.......: Used to remove leading and trailing blanks from
                 a string.
   Written for.: dBASE IV, 1.1
   Rev. History: 05/23/1991 0.1 - Original version (CLW)
                 06/18/1991 0.2 - Revision to modify for dHUNG
                 06/19/1991 0.3 - Revised for ...
                 06/24/1991 0.4 - Revised for ...
                 06/25/1991 0.5 - Revised again by Ken Mayer
                                  to give smaller header ...
                 09/08/1998 0.6 - Revised header for VdBASE 7.x
                 January 7, 1999 - revised the header one more time ...
                  etc.
   Calls.......: None
   Called by...: Any
   Usage.......: AllTrim(<cArg>)
   Example.....: ? AllTrim("  Test string  ")
   Returns.....: String to be trimmed (i.e.:"Test string")
   Parameters..: cArg = String to be trimmed
   ---------------------------------------------------------------------
*/
       
   parameters cArg

return ltrim( rtrim( cArg ) )
// EoF: AllTrim()

-------------
Documentation
-------------
It is always a good idea to document code -- never assume you will be 
the only programmer to read your code. If it is being posted on 
CompuServe or the internet, a lot of people may download it. If they wish 
to understand what you are doing, or use just portions of your code, 
it is very useful to explain in at least some detail what your 
program/function/procedure is doing. We are not going to suggest more 
than attempt to make the documentation neat, concise, and to the point 
(don't ramble).

-----------
dUFLP NOTES
-----------
Thinking of contributing to the dBASE Users' Function Library Project?
If so, please consider the following:

1) Margins 72 characters wide (both documentation _and_ code).
2) Use of the dot at the end of macro substitution calls (&macro.).
3) Use spaces, rather than tabs, and please try to indent the code to
   three spaces (for each indent), rather than 8, which is the dBASE/DOS
   default tab.
4) Please use the header as shown above for all code.
5) Please use the "private" statement for all memvars used within your
   function or procedure. 

   Also, please read the file: CONTRIB.TXT.

----------------------
dHUNG Revision History
----------------------
1991-05-23  0.1  Initial revision (clw)
1991-06-18  0.2  Revision after notations vote (clw)
1991-06-19  0.3  Memvars, Files, Fields, UDFs, Case Summary (HazMatZak)
1991-08-20  0.4  Added official header example (clw)
1991-08-26  0.5  Combined original DiFalco document (HUNG14.ZIP) with 
                 CLW's dHUNG documentation, and the header information
                 (KenMayer).
1991-08-30  0.6  Minor corrections to make this dBASE specific 
                 (KenMayer).
1992-04-16  0.7  Minor corrections to make this 'Politically Correct'.
                 (Ken Mayer (KenMayer))
1993-07-23  0.8  Changed text to fit 72 character right margin, and 
                 added 'M->' to sample code.
1994-03-02  1.0  Based on suggestions by Ken Chan (Zak), added the
                 object-oriented UI prefixes for the stock classes.
1994-04-20  1.1  Minor modifications of above.
1994-08-05  1.2  Added definition off #DEFINE syntax.
1998-09-08  1.3  Minor VdBASE 7.x comments scattered throughout (Ken Mayer)
January 7, 1999
            1.4  More VdBASE 7.x comments. Some out-of-date/DOS stuff
                 deleted. (KJM)
May 2, 2002
            1.5  Removed a few older format issues for headers and such. (KJM)
November, 2004
            1.6  Removed more of the XDML stuff ... (KJM)