Exploring the NAME attribute
Posted September 1 1997
Perhaps one of the most confusing distinctions in the Clarion language is that between a Label and a Name. Many experienced Clarion programmers have not mastered this distinction. Because understanding the difference between a Label and a Name puts so much power and flexibility at your finger tips, it is important to master it.
What can understanding this do for you? Among other things, it makes distributed processing possible from a Clarion program. It allows you to handle multiple physical files without additional file declarations. That is, multiple physical disk files can be manipulated by the same code with only one dictionary declaration. It allows you to write programs even though you do not yet know where the data files will physically reside, or even what they will be called.
Examples will come later. First, let us get our terms under control.
A Label is the way we refer to variables, data structures (like windows, queues, views and files), Procedures, Functions and Routines. It is tempting to describe a Label as the name of a variable, structure, etc. For example, in the declaration:
Counter ULONG
"Counter" appears to name a ULONG variable. Similarly...
GetDates PROCEDURE
appears to name a procedure "GetDates."
This is handy until you declare a file:
Customer FILE
and this is where the confusion arises. What is the name of this file? "Customer," of course - or so it seems.
"Customer" is the label of the file, not its name. The file's name might also be Customer; perhaps, perhaps not. The file's name is more likely to be Customer.dat or Customer.tps or Customer.dbf. But, especially with TopSpeed files and SQL databases, there might not even be a file on the disk named Customer anything. The file's name could be Arnold.
Properly speaking, the Name of a file is what the operating system displays in its directory/folder listing.
"Name," as TopSpeed uses that word in the language is designed to reflect this latter usage:
- The NAME attribute on a FILE statement specifies the DOS filename for the file driver. If the constant or variable does not contain a drive and path, the current drive and directory are assumed. If the extension is omitted, the directory entry assumes the file driver's default value.
Thus, every file you create has one Label and one (or more) names.
Setting the name of a file
A file's "name" comes from what you declare in the Full Path field (in figure 1, the file's label is Authors; the file's name is contained in the variable Authors_). If you leave this blank and the driver supplies no extension then, and only then, is the Name the same as the Label, but this is merely coincidence.
Of Labels
A label, as stated, is a way to refer to data. More accurately, a label simply marks a specific place in the source code. You can just place a label in your source code (non-generated source, that is; generated source rarely allows you access to column 1, where a label must start), with nothing else on the line. Thus, labels are exactly like Basic or Fortran line numbers and, like line numbers, enable you to locate a particular place in your code.
- (What's the big deal about line numbers? Fortran never actually required them and Basic doesn't any more. For those of us whom Bruce Barrington describes as "dinosaurs," (that is, we learned programming in punch card - and earlier - days) the first time you drop your card deck, you get the message behind line numbers ... rather quickly.)
When you complete the "Name" prompt on the File Properties worksheet, you are actually specifying the label of the file (in this, TopSpeed is not really helping clarify the distinction between "Label" and "Name").
Grammatically, then, a Label is like a proper noun.
- Very important point: your code always refers to this label, nothing else.
And of Names
In Clarion, Name is an attribute.
Attributes are not Clarion statements; they cannot be used in assignments or expressions. Rather, attributes are like adjectives and, as you may remember from grammar lessons long ago, adjectives modify nouns. In Clarion, those nouns are labels. Therefore, attributes modify labels.
The name attribute can modify a variable, function, procedure, record, queue or file label. When modifying a file label, the name attribute is a string constant or variable containing the file specification as the operating system sees it. For example, with the declaration:
InvoiceBody FILE,DRIVER('Clarion'),NAME('Invoice')
the developer refers to InvoiceBody, while the Dir command will show Invoice.Dat in the current directory, e.g.,
.\INVOICE.DAT
That is, if you examine the code (generated or not) you will see "Invoice" exactly once, in the file declaration. Everywhere else in the code, you will see "InvoiceBody."
Indeed, in C4 beta 1, you must use the name attribute if your file label is longer than eight characters. This is because C4 supports long file names, but the compiler will truncate the Label for 16 bit compatibility. The above declaration would expect to find Invoiceb.dat in the current directory.
Similarly,
Details FILE,DRIVER('Topspeed'),NAME('\Orders\LineItem.Dat')
will expect to find a file LineItem.Dat in a subdirectory called Orders immediately below the root directory. The program will look for this file at runtime, regardless of where you install the executable.
The examples so far have used string constants in the name attribute. But the name attribute also supports variables. This is a much more flexible and powerful use of the attribute. However, for the moment what is imperative to reiterate is that files (indeed, all data with the Name attribute attached) are always referenced in code by the label and never by the name.
In the last example, a developer would never make LineItem the object of a Clarion statement. The O/S specification never functions as a noun in the database verb-noun grammar.
Only when using a variable in the name attribute and only when the file is about to be opened do we need the full O/S specification (though, as we shall see, it can be specified sooner). If, for example, your file declaration looks like the examples above, the compiler will handle everything for you. On the other hand, if your declaration looks like:
Invoice FILE,NAME(Invoice_)
(the absence of apostrophes indicates that this is a variable and not a string constant) you must provide a value for Invoice_ and you must do so before the first attempt to open the file is made. If Invoice_ is not primed, CheckOpen(Invoice) or Manage:Invoice.Open (depending on whether you are using 2003 or C4) will fail with an error. But, again, the only time you would need to refer to Invoice_'s value is immediately before attempting to open it.
- By way of digression, it is important that you establish conventions and stick to them. Because my memory is not always what it should be, when I use a variable in name, I tend to use the label plus an underscore. This way I only have to remember the label and, because no reserved words end in an underscore, I am guaranteed a unique variable.
Using Names
Suppose you have an application from which you want to export a file. The target file is to be commas and quotes ASCII. Further, the file, when written, is to be written directly to a diskette. (Yes, there are still plenty of sneaker-nets out there.)
Further suppose that the machine that will read this diskette has only a 3.5" floppy, but the PC's that will write the file have both 5.25" and 3.5" drives (and on some, the 5.25" drive is A:>, on others B:>). So, you cannot say with confidence that the target diskette is A:> or B:> when creating the file. (No, I am not making this up; it is exactly because I had this situation at work that I had to learn about labels and names.)
The solution is to use the name attribute when you declare the ASCII file in the dictionary (Listing 1).
Listing 1
DATA_OUT FILE,Driver('BASIC'),NAME(GLO:FileName),PRE(OUT)
RECORD RECORD
PROVIDER STRING(5)
DATE LONG
SSN STRING(9)
SERVICETYPE STRING(4)
COURSE STRING(7)
GRADE STRING(1)
SERVICEHOURS REAL
VOC_ED BYTE
ETHNIC BYTE
TUTOR STRING(5)
END
END
Assuming you create a screen on which the user selects the target drive when creating the file, you can create the required contents of the name variable (GLO:FileName, in this case). You do this just before attempting to access the file, as in Listing 2.
Listing 2
GetDeviceName IF GlobalResponse <> RequestCompleted DO ProcedureReturn END Glo:FileName = Loc:Drive & ':\daniel' OPEN(Date_Out) IF ErrorCode() = 2 CREATE(Data_Out) OPEN(Data_Out) ELSE STOP(ERROR()) END EMPTY(Data_Out) SET(Service) LOOP !processing code END
In this case, we know the label of the target file (Data_Out), but not its fully qualified directory entry. By capturing the target drive in Loc:Drive, the code constructs the full name of the file, assigns it to the name variable and, finally, uses the information to open or create the file.
Notice that the file that will physically exist on the diskette will be named Daniel, but it could be any string that satisfies the O/S' requirements. As mentioned earlier, the only time this is ever referenced is immediately before I/O statements, like Open(), Create(), CheckOpen(), Manage:Data_Out.Open and Relate:Data_Out.Open. Every other reference is to the file's Label, Data_Out.
Now, we want to import the files created on these remote computers. For the sake of discussion, suppose we know none of the parameters of the fully qualified name. We require a value in Glo:FileName and we can get it easily enough:
Glo:FileName = FILEDIALOG()
by populating a DOSFileLookUp Control Template onto a Window.
Afterwards, all references in the code to read and process the data will be to the file's Label, Data_Out.
To further emphasize my point that we need the Name variable's contents only immediately before opening the file, consider Listing 3.
Listing 3
N = 0 !Initialize iteration counter
LOOP N = 1 TO 5 !Set for sequential processing of
CASE N !five mainframe files
OF 1 !read in reverse order so that
Spasfil = Loc:Credit !unduplicating favors vocational
OF 2 !enrollments
Spasfil = Loc:TechCtr
OF 3
Spasfil = Loc:ALSP
OF 4
Spasfil = Loc:RemDev
OF 5
Spasfil = Loc:ESL
END !Case N
OPEN(Spas_File) !Attempt to open file
IF ERRORCODE() !If not found
!remainder of processing code
END
END
Here, Spasfil is the variable in name, Spas_File is the file's label and a screen exists to capture the names of five different ASCII files, of identical structure, to be imported.
The code sequentially seeks the five different files and processes them. Because their structures are identical, only one file declaration is necessary.
Exactly the same kind of processing can happen in reverse. Suppose I were to store my student rosters by fiscal year. If my file declaration contained:
Students FILE,NAME(Students_)
I could open the correct file for fiscal year 1998 with:
Students_ = 'FY98.DAT' Open(Students)
Appointment calendars, rolodex files (see the Solodex sample program distributed with Clarion) and sets of accounts are other types of data that obviously benefit from using the NAME attribute.
Rules for Name-ing
The essential points for using the NAME attribute, as applied to files are:
- Always use the file label as declared on the File Properties worksheet (figure 1) or, if declared directly in code, the structure's Label in all Clarion language statements
- When using a variable in the name attribute, initialize it before any attempt to OPEN() the file
- A variable used as a file name may contain any O/S-valid string
- To use a variable, pre-pend the Full Pathname entry on the File Properties worksheet with an exclamation point.
- The variable label, if used, must be unique
- The variable, if used, must be declared in your application, at either the Global or Module level, with the Static (Storage) attribute
N.B.: include files work really nicely for this purpose
- Initialize the variable not later than the Before Opening Files embed
N.B.: include files work really nicely for this purpose, too.
Perhaps the most common circumstances are (1) where the executable is installed on the client while the files are on a server and (2) where the executable and the files are in different directories on the same machine.
In these cases, you can initialize all your name variables in the Global Program Setup embed or in the main procedure's Procedure Setup or Before Opening Files embeds. For example:
Listing 4
!read INI file
SchoolName = GETINI('General','SchoolName',,'JOBTRAK.INI')
SchoolCode = GETINI('General','SchoolCode',,'JOBTRAK.INI')
OfficeTitle = GETINI('General','OfficeTitle',,'JOBTRAK.INI')
ContactPers = GETINI('General','ContactPers',,'JOBTRAK.INI')
Phone = GETINI('General','Phone',,'JOBTRAK.INI')
EMail = GETINI('General','EMail',,'JOBTRAK.INI')
NumberOF = GETINI('General','NumberOF',,'JOBTRAK.INI')
FilePath = GETINI('JtMatch','FilePath',,'JOBTRAK.INI')
!check INI file for required fields
IF ~SchoolName OR ~SchoolCode OR ~OfficeTitle OR ~ContactPers |
or ~NumberOF OR ~FilePath
ConfigurationForm !Call configuration utility
END
!Set Names (variables previously defined and given default values)
Contacts_ = CLIP(FilePath ) & CLIP(Contacts_)
Ecodes_ = CLIP(FilePath ) & CLIP(Ecodes_)
JCode_ = CLIP(FilePath ) & CLIP(JCode_)
Listings_ = CLIP(FilePath ) & CLIP(Listings_)
Programs_ = CLIP(FilePath ) & CLIP(Programs_)
RCodes_ = CLIP(FilePath ) & CLIP(RCodes_)
Referals_ = CLIP(FilePath ) & CLIP(Referals_)
SCodes_ = CLIP(FilePath ) & CLIP(SCodes_)
Students_ = CLIP(FilePath ) & CLIP(Students_)
Types_ = CLIP(FilePath ) & CLIP(Types_)
Appoint_ = CLIP(FilePath ) & CLIP(Appoint_)
EvTypes_ = CLIP(FilePath ) & CLIP(EvTypes_)
AptMajors_ = CLIP(FilePath ) & CLIP(AptMajors_)
Schemes_ = CLIP(FilePath ) & CLIP(Schemes_)
DefTimes_ = CLIP(FilePath ) & CLIP(DefTimes_)
Events_ = CLIP(FilePath ) & CLIP(Events_)
Archives_ = CLIP(FilePath ) & CLIP(Archives_)
Placed_ = CLIP(FilePath ) & CLIP(Placed_)
Note that each variable is given an initial value in the Dictionary Editor or in the include file when they are first declared. And, to ensure that I have a good path to the data file(s), I often enclose the code that gets it in a Loop:
Listing 5
!Get correct file path
LOOP
CheckOpen(Control,1,42h)
GET(Control,1)
IF ERRORCODE () = 33 or ERRORCODE() = 35
UpdateControl
CheckOpen(Control,,42h)
GET(Control,1)
ELSIF ~CON:FilePath
GetPath
ELSE
BREAK
END
END
Since the file path is a required field in the Control file, the only way out of this loop is to have completed it. To ensure that the files I am looking for exist in the directory specified by the user during data entry, I use two functions I have written for that purpose.
Variables used as file names
As the examples show, this rule is the real powerhouse. Because any O/S-valid expression is acceptable, you have tremendous flexibility (within any limits described in the Known Limitations section of the documentation).
You can define a file's location at runtime, as in the example of exporting and importing Data_Out. You can install a program in one directory and its data files in another. You can, similarly, use a data file in one location to serve multiple programs in various locations.
It does not matter whether the drives and directories are local or not. After all, the point behind networking is to make physically remote drives appear to be local resources in order to share these resources. The only requirement is that the string containing the drive, path and file spec be syntactically valid for the O/S. Indeed, contrary to the direct implication of the documentation, this applies to CWIC web-enabled applications also (on my CWIC web site, not a single data file resides in the same directory as the executables).
There really is only one other thing to worry about when accessing files across a network. Prudence demands that any network log-on and drive redirection be effected before initializing the name and attempting to access files.
TopSpeed Files
TopSpeed files support a special syntax to allow multiple tables to be stored in a single file.
By using the special escape sequence '\!' in the NAME() attribute of a TopSpeed file declaration, you can specify that a single .TPS file will store more than one table.
The general format of the Name entry is file_name/!table_name which seems to preclude using a variable in the Name attribute of a TopSpeed file. This implication is all the stronger because, as the documentation states, the Name attribute is used to hold the escape sequence.
Fortunately, this is not the case. Designate your variable on the File Properties worksheet and initialize it in exactly the same way as any other Name, but use the special syntax:
Authors_ = 'cwjfil\!Authors' Contents_ = 'cwjfil\!Contents' Subject_ = 'cwjfil\!Subject'
to initialize the variables. In my program to index articles on Clarion, this works just fine, thank you. (In fact, the file in figure 1 is a TopSpeed file.)
Summary
Name is useful in creating applications when you know a file's layout, but not its location or its file specification. It is also useful in creating applications when you wish to access a series of identically structured files but whose data must be in physically distinct files. Appointment calendars supporting multiple persons, multiple accounts and multi-company accounting immediately come to mind.
Additionally, it can be used to allow one file to serve multiple applications. And, those applications can be on different servers.
You cannot access SQL databases without using the Name attribute, since this is used to store the table owner and table name.
Clearly, the distinction between Label and Name is worth the time to master.
Article comments
Search ClarionMag
From the archives
The Best Thing About Clarion 7
12/27/2010 12:00:00 AM
Steve Parker was just plain gobsmacked when he realized he had found something in C7 that improved his code and did so with virtually no effort on his part.

Steve
Parker started his professional life as a Philosopher but now tries to imitate
a Clarion developer. He has been attempting to subdue Clarion since version 2007 (DOS,
that is). He reports that, so far, Clarion is winning. Steve has been writing
about Clarion since 1993.