CW CHAPTER 2

From Atari Wiki
Jump to navigation Jump to search









CHAPTER 2: HANDLING THE FILE SELECTOR
--------------------------------------

[NOTE: Words enclosed in asterisks (i.e. *word*) should be 
read as italicized text. This text file is copyright 1993 by 
Clayton Walnum. All rights reserved.]

As we said in the previous chapter, the AES supplies us with 
several ready-made forms that we can use in our programs. 
Now that we know how to use one of the simpler forms, the 
alert box, we can move on to one of GEM's most frequently 
used form, the file selector. In this chapter, we'll learn 
to call up a file selector and to use the information it 
returns to create a full pathname for any file the user 
selects.

--What Is a File Selector?--

If you've used your ST at all, there's no doubt that you're 
already familiar with the file selector. Virtually every GEM 
program written for the ST uses the file selector to get 
file information from users. The file selector's basic 
function is simple: it allows the user to select a file. 
However, because selecting a file requires the ability to 
move from one directory to another, as well as scroll 
through a list of filenames too large to fit into the 
selector's window, things are a little more complicated.
	Figure 2.1 shows a typical file selector. At the top is 
the directory line, which shows the directory the user is 
currently logged into. In the figure, the user is logged 
into the DEVPAC folder of the D: drive. Notice the *.* 
following the path. These wild cards mean that the file 
selector should show every file listed in the directory. If 
the file portion of the path was changed by the programmer 
to, say, *.PRG, only programs with a .PRG extension would 
appear in the file selector's window, as shown in figure 
2.2.

[INSERT FIGURES 2.1 AND 2.2 HERE]

	The user cannot change the file-filter portion of the 
pathname, but he can change the directory. There are three 
ways to do this: 1) by clicking the directory line, typing 
the new path, and then clicking the top of the file window; 
2) by clicking a directory in the file window to move to 
that directory; or 3) by clicking the button in the upper-
left corner of the file window to move back one directory.
	To the right of the file window is the filename field. 
This field is usually blank until the user selects a file. 
However, the programmer can give GEM a default filename to 
display when he calls the file selector box. The user can 
select a file three ways: 1) by typing the file into the 
filename field and then clicking the OK button; 2) by 
clicking the filename in the file window and then selecting 
the OK button; or 3) by simply double-clicking the filename 
in the file window.
	Besides its button and file bar, the file window also 
contains scroll bars, which allow the user to see files that 
are not currently displayed in the window. This scroll bar 
is operated by clicking it with the mouse pointer.

--The Program--

In the CHAP2 folder of your *ST Assembly Language Workshop* 
disk, you'll find two files. PROG2.S is the source code for 
this chapter's sample program, which is reprinted at the end 
of this chapter. PROG2.PRG is the assembled, runnable 
program file. If you would like to assemble the program 
yourself, please consult your assembler's manual or refer to 
this book's Appendix A.
	When you run the program, a file selector box appears 
on the screen. Use the file selector to move from one 
directory to another. Finally, select a file, and then click 
the OK or Cancel button. If you select the cancel button the 
program will return to the desktop. If you select the OK 
button, the program will display the full pathname for the 
file you chose. Press Return to return to the desktop.

--Getting the Current Drive--

Now, let's look at the program's code, to see what's 
happening. The program begins just like our previous one, by 
setting up a stack, releasing unused memory, and 
initializing the GEM application with a call to *appl_init*. 
After that, the fun begins.
	When you call the file selector box, you need to give 
it a path for its pathname line. This could be any path you 
like. However, it is standard practice to have the file 
selector already set to the currently active path, usually 
the path from which the program was run. To get this 
information for the file selector, we must first get the 
current drive letter and the current path. Then we must 
combine these into a single string.
	Right after our call to *appl_init*, you'll see the 
code in which we get the current drive letter. It looks like 
this:

move    #DGETDRV,-(sp)
trap    #1
addq.l  #2,sp
add     #'A',d0
move.b  d0,pathname
move.b  #':',pathname+1

The first three lines are a call to GEMDOS function #25, 
*Dgetdrv*, which returns in D0 a number representing the 
currently active drive. A 0 indicates drive A, a 1 indicates 
drive B, a 2 indicates drive C, and so on.
	Once we have the drive number in D0, we need to convert 
it to an ASCII character for our path string. We do this in 
line 4 above. The *#'A'* is just another way of representing 
the ASCII value of "A." By adding the ASCII value of "A" to 
the drive number, we end up with the drive letter we want. 
We did this type of conversion in volume 1 of *The Assembly 
Language Workshop*.
	The last step is to move the drive letter to the first 
byte of our pathname string, and place a colon in the second 
byte of the pathname string. This is accomplished in the 
last two lines above. Note that the label *pathname* 
represents the address of a 128-byte string. You can find 
this string in the program's BSS. Why do we need 128 bytes? 
Because the file selector will use this area to return the 
user's selected path to us. Because paths can be long, we 
must be sure to provide plenty of space. Otherwise, other 
data may get overwritten by the pathname string returned by 
the file selector.

--Getting the Current Path--

Now that we have the current drive letter, we need to get 
the current path. The five lines of code following the call 
to *Dgetdrv* accomplish this task. The code looks like this:

move    #0,-(sp)
move.l  #pathname+2,-(sp)
move    #DGETPATH,-(sp)
trap    #1
addq.l  #8,sp

	The above is a call to GEMDOS function #71, *Dgetpath*. 
As you can see, the call requires that three parameters be 
placed on the stack. The first is the number of the drive 
for which you want to retrieve the path. For this word 
value, 0 represents drive A, 1 represents drive B, and so 
on. The second parameter is the address of the buffer where 
*Dgetdrv* should store the path string. In the second line 
above, we're giving the function the address of the third 
byte of our pathname string. Why? Because we've already got 
the drive letter and a colon on the first two bytes. By 
giving the function the address of the third byte, it'll not 
only return the path string to us, but will also 
automatically tack it onto our drive specifier. The third 
and final parameter is the function number.

--Pathnames, File Selector Style--

Even after we've got the entire pathname, we're still not 
ready to call up the file selector. We need to add a default 
file specification to the end of the path. The usual default 
is \*.*, which will allow the file selector to show every 
file in the current directory. However, you could use any 
default. For example, if you were asking the user for a 
DEGAS picture file, you'd probably want to use the default 
of \*.PI?, which filters out all files except those with 
extensions starting with PI.
	If you look at the sample program, right after the call 
to *Dgetpath*, you'll see where we add the \*.* to our path 
string. First, we must search for the end of the string. We 
do this by scanning the string from the beginning until we 
find a null. Once we've found the position of the null 
character, we simply tack on the \*.* characters.

--Calling the File Selector--

Now, our pathname string is ready for the file selector box. 
We now bring up the file selector and let the user choose 
the file. The code in our sample program that brings up the 
file selector box looks like this:

move    #FSEL_INPUT,control0
move    #0,control1
move    #2,control2
move    #2,control3
move    #0,control4
move.l  #pathname,addr_in
move.l  #filename,addr_in+4
jsr     aes

Because the file selector is an AES call (function #90, 
*fsel_input*), we must initialize the control array, as well 
as place the necessary values in the other arrays. With this 
call, the only other arrays we use are addr_in and int_out. 
We use the addr_in array to tell the file selector where the 
pathname and filename strings are. The file selector will 
also use these two strings to return the selected filename 
and pathname to us.
	The file selector will use the first two words of the 
int_out array to return an error code and a button code, 
respectively. The error code will be 0 if an error occurred 
or greater than 0 if no error occurred. The button code will 
be 0 for the cancel button and 1 for the OK button.
	Note that there is a slightly modified version of the 
*fsel_input* call for newer versions of GEM (Rainbow TOS) 
This new call, named *fsel_exinput*, allows the programmer 
to replace the "Item Selector" string that appears at the 
top of the file selector box with something more meaningful, 
such as "Choose file to load." A typical call to the new 
file selector looks like this:

move    #FSEL_EXINPUT,control0
move    #0,control1
move    #2,control2
move    #3,control3
move    #0,control4
move.l  #pathname,addr_in
move.l  #filename,addr_in+4
move.l  #string,addr_in+8
jsr     aes

There are only three differences between the *fsel_exinput* 
and the older *fsel_input* call. First, the function number 
for the new call, represented above by the constant 
FSEL_EXINPUT, is 91. Second, you must indicate that your 
addr_in array is three elements long by loading a 3 into 
control3. Finally, you need to store into the third element 
of addr_in the address of the string you want at the top of 
the file selector. Note that, on TOS versions earlier than 
1.4, the *fsel_exinput* will generate a run-time error (bad 
function number). If you want to use this call safely, you 
must, within your program, check for the version of TOS 
under which your program is currently running. If the 
version is earlier than 1.4, you must stick with the old 
*fsel_input* function.

--Constructing the Selected Path--

After the user selects a path and filename with the file 
selector, he closes the file selector by clicking the OK or 
Cancel buttons. If the value stored in the second element of 
int_out indicates that the OK button was pressed, we must 
build the final, complete pathname, using the information 
returned by the file selector. The chosen pathname will be 
in the *pathname* string, and the chosen filename will be in 
the *filename* string.
	The first step in constructing the final pathname is to 
scan the path string for the null that marks the end of the 
string. Once we've found the null, we must scan backward 
until we find a backslash character. We need to do this 
because the path, as returned from the file selector, still 
includes the default file specification. For example, the 
path may look like C:\UTILITY\*.*. We of course must replace 
the *.* with the actual file selected.
	Once we've found the backslash character, we tack the 
filename on. Using the example path above, our final path 
should look something like C:\UTILITY\FILECOPY.PRG. This 
final pathname contains all the information we need to 
access the chosen file.
	In the sample program, the code that creates the final 
pathname is fairly straight forward and heavily commented. 
You should have little trouble seeing how it works.
	After constructing the final pathname, the sample 
program simply displays the path on the screen and waits for 
the user to press a key, after which the application 
terminates and the program returns control to the desktop.

--Conclusion--

The file selector is typical of most GEM forms: It provides 
a convenient way for users to give information to a program. 
Likewise, it makes it easy for the programmer to request 
this information, by using an device with which the user is 
already familiar. Every GEM program you write should use the 
file selector wherever it's necessary for the user to choose 
a file.

--Summary--

* The GEMDOS function #25, *Dgetdrv*, returns the currently 
active drive in D0.

* The GEMDOS function #71, *Dgetpath*, returns the currently 
selected path into a string whose address is one of the 
function's parameters.

* The AES call #90, *fsel_input*, brings the file selector 
box up onto the screen.

* On TOS version 1.4 or newer, the AES call #91, 
*fsel_exinput*, lets you bring up a file selector and 
replace the standard "Item Selector" string with a string of 
your own.

* When the file selector returns the chosen pathname and 
filename, it's up to the programmer to use them to create 
the complete path.


CW_PROG2MAC.S (Source of the chapiter)

CW_PROG2.S (Source of the chapiter)

Back to Assembly_language_tutorials