home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
326.lha
/
requester.library_v1.3
/
FileIO.DOC.pp
/
FileIO.DOC
Wrap
Text File
|
1990-01-02
|
87KB
|
1,827 lines
FileIO Requester
User and Programmer Manual
From the Amiga Programmer's Suite Book 1, by RJ Mical
Copyright (C) 1987, Robert J. Mical
Additional notes concerning the requester library have been added by
Jeff Glatt who converted the original C into an assembly language library.
This document describes the FileIO Requester library, both for users of
the requester and for programmers who will utilize the library.
The main sections of this document are:
o FROM THE USER'S POINT OF VIEW
o PROGRAMMER'S REFERENCE
o DEMO PROGRAM NOTES
o TECHNICAL REFERENCE
o USING THE AMIGA PROGRAMMER'S SUITE
o APPENDIX A: FileIO Library Function Calls
============================================================================
=== FROM THE USER'S POINT OF VIEW ==========================================
============================================================================
This section presents the FileIO Requester from the user's point of view.
This is a example of the sort of documentation that might be supplied to the
end user of this FileIO Requester. Simply clip from here to the Programmer's
section, and include this as a chapter in the user manual.
=== The FileIO Requester ========================================
This program employs a file requester based upon R.J. Mical's ProSuite
unit, though this library implementation has been modified extensively.
The FileIO Requester allows you an easy way to select which file you want
to use for input or output. The following describes how you go about using
the FileIO Requester.
The FileIO Requester consists of several parts:
o the "Select a Name" list which allows you to choose a file name
simply by scrolling through a list of names until you find the one
you want, pointing at the name and clicking the left mouse button
o the OK! gadget which you use to acknowledge that the name you've
chosen is the one you wanted
o 3 string gadgets which allow you to type in the name directly rather
than using the "Select a Name" gadgets to find the file you want
o a NEXT DISK gadget which allows you to examine one disk after another
o the CANCEL gadget, which you use when you've decided that you don't
want to select a file after all
The "Select a Name" list presents you with a list of file names in the
current drawer. You use the mouse to scan easily through the list and select
one of the filenames simply by pointing at it and clicking.
The "Select a Name" feature consists of:
o a box of where some of the list of file names are displayed
o a slider which lets you scan quickly through the list of files
o an up gadget and a down gadget which allow you to move through the
list one filename at a time
There are 3 types of entries in the list of file names.
At the top of the list are the file names that you can choose. These names
are listed in alphabetical order (case insensitive).
At the bottom of the list there are special entries which allow you to move
around through the drawers of a disk, much like you move around through
drawers on the Workbench display.
The entries that start with the ">>>>" characters allow you to "open" a
drawer and examine the names of the files in that drawer. For example, when
examining a Workbench disk, at the bottom of the list you would find an
entry that looked like ">>>> Demos" which means that you can go into the
drawer named "Demos". If you selected ">>>> Demos" you would see, after a
short pause, a new list of file names: the names of the files that are in
the "Demos" drawer.
In the "Demos" drawer you would also find a special entry,
"<<<< PRIOR DRAWER". If you select this entry, you will move back to
the drawer that contained your current drawer.
An alternate way to change drawers is to type the name of the drawer you
want in the string gadget labeled "Drawer". It is located beneath the
filename list. You select the gadget, type in the name, and hit return.
If you type the name of a drawer which does not exist, the FileIO will send
you back to the root directory of that disk. The length of the string that
you type into the drawer gadget is limited to 132 characters. Since AmigaDOS
limits the length of all file, drawer, and disk names to 30 characters, this
means that you can safely nest drawers (one inside of another) up to four
drawers deep. Beyond that, you should make sure that your drawer names are
less than 30 chars each. The FileIO will not allow you to go any deeper after
the drawer gadget has 132 chars in it.
Once you have a list of file names to choose from in the file name box,
there's a slider gadget to help you scroll around through the names. The
slider is to the right of the file names. It has a knob which you move to
scroll through the names. The knob will be different sizes depending on the
number of names in the file list. If the knob is small, this means that you
can see only a small number of the total file names. The smaller the knob,
the more names there are to see. On the other hand, if you can see all the
names in the list, the knob will fill up the entire slider and you won't be
able to move it.
To view the file names, you "grab" the slider's knob and move it up and down.
You grab the knob by pointing at it and pressing and HOLDING the left mouse
button. When you have grabbed the knob, you can move the pointer and scan
quickly through the list of file names.
Also, you can view the list of names one page at a time by clicking to either
side (but not on) the slider's knob. If you want fine control of your
movement through the file list, the up and down arrows let you adjust the
list of names one name at a time. If you hold the mouse button down while on
top of either arrow, the filenames will scroll in that direction. When you
release the button, scrolling stops, but if instead you move off the arrow
before releasing, the scrolling continues. Auto-scroll will continue until
you click on a scrolling filename, or until the end of the list is reached.
Once you have found the file name that you want to choose, you select it by
pointing at it and clicking. When you do this, the name will be highlighted
and it will appear in a box labeled "Name" beneath the list. When you've
decided that this is really the name you wanted to choose, click on the OK!
gadget. Another way to tell the program that you're sure you want to select
a certain file name is by double-clicking on the file name in the same way
that you double-click on a Workbench icon. Double-clicking is exactly the
same as selecting a name and then OK!
If you don't want to use the "Select a Name" feature, you can select a name
by clicking on the string gadget labeled "Name", typing the desired filename,
and then hitting return or clicking on the OK! gadget. Hitting return after
typing the name you want is the same as selecting OK! You can select and
type into the string gadgets at any time. You don't have to wait for the
wait pointer to change before you hit return! If you type in the name of a
disk that is not mounted, and then refuse to insert it into the drive when
AmigaDOS asks you for it, the FileIO switches to another disk that is
mounted (if another floppy exists).
To view the files of a different disk, select the NEXT DISK gadget. When you
do, the name of the next disk is displayed in the Disk string gadget and the
disk is then searched. If this disk isn't the one you wanted, you can press
NEXT DISK again even though you may be seeing the wait pointer. You can
press NEXT DISK quickly as many times as you want until you see the name of
the disk you want in the Disk gadget. If you prefer, you can also type the
name of the disk you want directly into the Disk string gadget. If the disk
you want to examine is not in the drive, you may remove the disk that the
requester has last examined (after the light goes out of course), and insert
the desired disk in that drive. Now wait for the requester to automatically
update its display. You should not change disks while the file requester is
drawing the list of filenames. Wait until the requester "settles down" before
removing and inserting disks. After inserting a disk, the requester will
automatically redraw the list.
Alternately, you may select a new disk by clicking the RIGHT MOUSE button.
The filenames will be replaced by a list of all the mounted volumes (or
devices). The name of the disk that you are currently examining will be
highlighted. You can scroll through this list of disk names using the slider.
When you see the disk name that you would like to examine, click the LEFT
MOUSE button on it. The FileIO will then display the contents of that disk.
You might notice that the ZZZ-cloud wait pointer looks a little different
from the ones you're used to on the Amiga. The FileIO Requester's ZZZ-cloud
pointer has a small tab at the top left which allows you to continue
pointing and making selections even though the ZZZ-cloud is displayed.
The FileIO Requester's ZZZ-cloud tells you that it's working, but it
doesn't make you wait.
You might notice also that the file names start appearing one by one
alphabetically in the list. You can select one of these names even before
all of the names have been added to the list, though this can be a bit
tricky as they move around a lot. While the list is being built, you can
use the slider to look at what names have already been added. If you see the
name that you want to select, you can stop the building of the file name
list by clicking on a spot inside the requester but outside of all the
gadgets. For instance, if you click above (but not on) the OK! gadget, this
will stop the list from being constructed. Then you can select the name you
want as usual. To restart the building of the file name list, click on
either the Drawer or Disk string gadget and hit return. You can also stop
the display of filenames temporarily by grabbing and holding the scroll
gadget. When you release, the display will continue.
For some reason, the requester may not be able to open. Maybe another
program is already displaying it. Only one program can be displaying it at a
time. Or perhaps you have used up too much memory. In either case, instead
of a requester, you will see this prompt in the title bar of the window.
Filename >
This will be followed by a cursor and whatever filename you last chose
with the requester. You must now type in the complete name (including the
drive and drawer names) as you would in the CLI. For example,
Extras:BasicDemos/ConvertFD
If the window is not full size, you should move it to the upper left
corner of the monitor display, and resize it to fully open. Then press any
cursor key to redisplay the cursor. If there was no previous filename, then
you will see the ":" current directory sign. Move the cursor past this and
type in the filename that you wish to save or load if it is on the current
disk. Otherwise, you need to type the name of the disk upon which the file
can be found. The disk name goes in front of the ":", and the drawers and
filename go after the ":". (If the file is on the current disk, and in the
current drawer, you only need to type the filename. Otherwise, you must
specify which disk and drawer you really want.) If the filename that is
initially displayed is the one that you want, simply press RETURN.
You can use the cursor keys to move about in the filename, deleting charac-
ters with the delete or backspace keys. Holding the shift key while pressing
the cursor keys will move to the beginning and end of the typed filename.
When you are satisfied with your choice, hit RETURN. Otherwise, hit the
escape key to cancel.
You have the facility to "customize" the requester for each application.
After the requester comes up, the function keys have the following purposes:
F1 - Operates the same as selecting the Next Disk gadget.
F2 - Toggles between using the volume name or the device name of the floppy.
For example, if you place your WorkBench disk in the internal drive
and you are using volume names, "WorkBench 1.3:" will appear for the
Disk name. If using device names, "DF0:" will appear instead.
F3 - Any filename that ends in ".info" will not be displayed. To disable
this feature, select F3 again.
F4 - Only displays filenames that end with a phrase that you provide.
You will be prompted to enter a string in the title bar of the window.
If for example, you typed .library, then the requester would display
all drawers, but only those files that end with .library. The word
need not be an extension. You could also specify that only files that
end with the word, picture, be displayed. To disable this feature,
select F4 again. The program that you are using must support this
feature for it to work. If the program doesn't support it, F4 will do
nothing.
F5 - This toggles ON/OFF the facility for double-clicking on a filename to
select it as your final choise. If OFF, you must click on the
filename, and then select OK! before the requester will accept your
choise as final. Otherwise, 2 quick clicks will be the same thing.
F6 - This will cause the requester not to initially reconstruct the filename
list on subsequent uses. The advantage is that the next time the req-
uester comes up, the names will appear immediately. The disadvantage is
that if you save a file, it will not appear in the list until you turn
this feature back on (momentarily anyway). Turn it on/off by pressing F6.
F7 - WorkBench matching ON/OFF. If ON, this only displays those names that
end in .info (just like WorkBench does). Also, a prompt asks you whether
you want only those names that are TOOLS, PROJECTS, or any kind. An example
of a TOOL is a program that you can run, like NotePad. An example of a
PROJECT is a data file, like a note you might write using NotePad.
The names of disks are never displayed in the filename list.
F8 - Not implemented at this point.
F9 - Same as the CANCEL gadget.
F10 - Same as the OK! gadget.
When you customize the requester, it only affects that one application, so
different programs can have different "customized" requesters.
============================================================================
=== PROGRAMMER'S REFERENCE =================================================
============================================================================
This section is for the programmer who wants to use the FileIO Requester
library routines in her or his program.
The Workbench names for DOS objects have been used in the FileIO Requester,
and are used throughout this document for simplicity. For your reference,
a directory is referred to as a "drawer" and volumes, or DOS filesystem
devices, are referred to as "disks".
These are the subsections of this section:
o Basic Operation
o Multiple FileIO Structures
o Workbench-style Filename Operations
o Filtering by Extension
o No Icon (.info) files
o FileIO Flags
o DoFileIO() and DoFileIOWindow() are non-reentrant
o Procedure for Opening and Using the FileIO Requester library
o Displaying Lists of Strings (non-disk operation)
========================== Basic Operation ============================
The FileIO routines base all of their work on a data structure called
the FileIO structure. You are allocated one of these structures when you
call the GetFileIO() routine. The structure is initialized with reasonable
default values for you. Conversely, you can declare and pre-initialize a
FileIO structure as long as all fields are set to zero or an appropriate
value. At the very least, you must set the FileIO's Buffer field to point to
where you want string input stored, and initialize the DrawMode, PenA, and
PenB fields to desired values. The buffer size should be > = 202 bytes.
The FileIO structure is used when calling the DoFileIO() and DoFileIOWindow()
routines, which are the routines that actually present the requester to
the user and get the user's filename selection. DoFileIOWindow() is the same
as DoFileIO() except that the former opens a window for the requester. With
DoFileIO(), you must already have a window open.
There are several flags and data fields in the FileIO structure that you
may choose to initialize before calling DoFileIO(). By setting or clearing
these flags, you define how information is to be presented to the user.
These flags are described below in "FileIO Flags". Also, the user can
change these flags for each FileIO via the function keys.
The DoFileIO() function returns one of 2 values:
1). The address of the buffer where the complete pathname (disk, drawer,
and filename as one, NULL-terminated string) has been stored. This
buffer will be the one that you supply in the FileIO's buffer field.
2). A -1 if the user selected the cancel gadget.
The DoFileIOWindow() function may return this additional value:
3). A zero if the window didn't open.
You can call these routines any number of times with the same FileIO
structure. Also, your program can have more than one FileIO structure at a
time. An example of why you would want more than one FileIO structure: you
might want to have separate structures for getting input filenames and
output filenames from the user. Another example: you might have one
structure for letting the user select text files and another for the
selection of graphics files each with different options/features. Also,
there are some lib routines that do not deal with disk file IO, but use the
FileIO structure nonetheless and you might want a FileIO with a special
string buffer for these routines.
Finally, when you're finished with your FileIO structure (usually not until
your program is terminating) then you call ReleaseFileIO() to deallocate all
the resources that it's accumulated. If the FileIO was obtained via
GetFileIO(), this routine also frees it for you.
====================== DoFileIO() is non-reentrant ========================
The DoFileIO() routine is non-reentrant. For the sake of memory efficiency,
it uses global data and variables rather than creating local copies of these
for each caller. What this means is that only 1 task can use the library
functions DoFileIO() or DoFileIOWindow() at a time, though all other lib
functions are re-entrant. If you attempt to call DoFileIO() or DoFileIOWindow()
while another task is using it, the library will automatically prompt the
user to type in the complete filename, instead of displaying the requester.
The area where the user types in the filename is in the title bar of the
window where the requester opened. The prompt
Filename >
will be displayed in the window's titlebar, along with a cursor. Several
line editing features are supported including cursor key movement (with the
ability to insert characters), backspace, delete, shift-right and shift-left
cursor to the start and end of the string, and escape. The window's title is
later restored. In fact, this feature of being able to use the title bar for
getting user input can be used with your own prompts. It is a handy alterna-
tive to having a string gadget (which takes up window space and also requires
allocating several structures), plus allows for displaying custom prompts.
Note that many tasks can open the library simultaneously, but only 1 can be
displaying the FileIO requester at a given moment.
This redirection to entering the filename via the title bar is completely
invisible to your application. Upon return from DoFileIO() or DoFileIOWindow()
you will receive one of the 2 (or 3), previously described return values.
========== Interpreting the return value of DoFileIO() ================
As mentioned before, there are 3 possible return values from DoFileIOWindow
and 2 returns from DoFileIO(). If there is not enough memory for the window
to open with DoFileIOWindow(), then the return value is 0 and the FileIO's
Errno field = ERR_WINDOW. If this happens, you will have to find another way
to get the filename. If you already have a window open, use DoFileIO(). This
routine will never fail. Alternately, you might have the user type the path
as he would from the CLI, and call ParseString() to put it in the FileIO.
If the user selects the CANCEL gadget, (or hits ESCAPE when entering the
filename in the titlebar, or RETURN with no chars input), both routines will
return -1.
In all other cases, the address of the FileIO's Buffer will be returned.
This indicates that the user selected OK, or typed something in the string
gadgets or title bar. This does not mean that the filename is valid for
your purpose though. Let's assume that you called DoFileIO() from a load
routine. Naturally, you want the user to select an existing file to load,
but let's say that he types a non-existant file in the Name gadget or just
selects a disk or drawer without eventually choosing a file before selecting
OK. You can determine what the user did by examining 2 FileIO fields. The
FileIO's Filename buffer contains just the filename portion of the complete
path (separated from all the drawer and disk names). If this buffer is NULL,
then the user did not select a filename. If the buffer is not NULL, then he
either selected a filename, or typed one in. If he typed one in, how do
you know if the filename exists? The FileIO's FileSize field will be 0 if
the filename doesn't exist (or couldn't be examined because the user refused
to mount the file's disk). In this case, you would abort the load. If the
FileSize is not 0, then the file exists and this is how large it is in bytes.
In conclusion, here are the steps you should take for a load routine:
1). Call DoFileIO() with the FileIO's Buffer set to the address of your
path buffer, and the DrawMode, PenA, and PenB fields initialized.
2). Examine the return. If -1, then CANCEL. (If 0 for DoFileIOWindow, then
get the filename another way).
3). Check the FileIO's filename buffer for NULL. If NULL, then abort load
posting "This is not a loadable file."
4). Check the FileIO's FileSize field. If zero, post "File doesn't exist."
5). Otherwise, use the path buffer to open the file for reading.
Here are the steps you should take for a save routine:
1). Same as load routine step 1
2). Same as load routine step 2
3). Check the filename buffer for NULL. If NULL, then abort posting
"Did not supply a filename."
4). Check the FileSize field. If it's not 0, then the user must have selected
a filename that already exists on the chosen disk and in the specified
drawer. Post "File exists. Should we overwrite it?" Get a yes or no
response from the user to continue or abort.
5). Otherwise, use the path buffer to open the file for writing.
======================== Internal Error Handling ==========================
The requester is set up so that if the user types in a non-existant disk
name or refuses to mount the chosen disk, the req will default to any other
mounted disk. If no disks mounted, then the default FILEIO_DISKNAME is ":".
For example, assume that the user types "Leroy:" in the disk string gadget,
but the disk is not in any drive. AmigaDOS will prompt for that disk. If
the user then CANCELs the system prompt, the FileIO req will display the
contents of some other disk that is mounted, adjusting the string gadgets
accordingly. In the case where no disks are mounted, the pathname buffer
that is returned will not contain any disk name.
If the user types a drawer name that is not in the current dir level, the
req will knock him back to the root of the current dir. For example, assume
that the user is looking inside of a drawer called "TireBiter". There is no
drawer called "George" inside here, but the user types this in the drawer
string gadget nonetheless. The requester will clear ALL the drawer names,
defaulting to the root of the disk.
The library will not return non-existant disk or drawer names. If you needed
the requester to do this though (maybe you want to pass the path buffer to
CreateDir) then the user should type the "new" drawer name by itself in the
Name gadget. Conversely he could enter the string via the titlebar like so:
WorkBench:Demos/Blort
where you simply treat Blort as a dir name instead of a filename. The lib
will copy Blort to the FileIO's Filename field nonetheless. Just check the
FileSize field to make sure that there isn't a file already named this.
If there is some error in obtaining the disk name and it defaults to ":",
then the returned pathname will not have a drawer name prepended to it.
For example, say the user typed "df0:" in the drawer string gadget, but the
drive was empty. The requester will automatically default to another mounted
disk/device, etc, until one can be examined, or finally ":" is used. If the
user then types "Papoon" in the Filename Gadget, the returned path will be:
Papoon
which will be stored in the FileIO's Filename buffer if its a Filename, or
the FileIO's Drawername buffer if it's a drawer. If it is a Filename that
exists in the current dir, the FileSize will be its size in bytes.
================= Quick Display (NO_CARE_REDRAW) ================
The data in the FileIO structure often remains valid between calls to
DoFileIO(), so with subsequent calls a flag has been provided to avoid
reconstructing the filename list. This allows the requester to appear very
quickly because the usually-lengthy process of accessing the disk is avoided.
Other times, it may be necessary to have the requester reconstruct its list
of filenames (i.e. when a disk is changed or a file created/deleted by an
application which does not communicate with the FileIO requester). Perhaps,
as in a save routine, it may not be important to show the user what other
recent files are on the disk as long as proper file protection is provided.
The library uses the NO_CARE_REDRAW flag to discern whether to reconstruct
the list, or simply to use the FileIO's previous names. If you set this flag,
the old list is simply redrawn. Once you set this flag, the list will not
be reconstructed on subsequent calls until you explicitly clear NO_CARE_REDRAW.
(i.e. you always get the same, non-updated list unless the user changes dirs
or disables the feature himself via the Function keys).
When GetFileIO() creates a FileIO structure for you, this flag is cleared
to specify that the structure doesn't contain an updated list of filenames.
Thus the first call to DoFileIO() causes the filename list to be constructed.
After the call to DoFileIO() is the time to set the flag. You must do a bit
of work if you wish to make use of this feature. You are obliged to watch
for IDCMP events of class DISKINSERTED and to clear the NO_CARE_REDRAW flag
in any of your FileIO structures whenever you see this event. The
DISKINSERTED event occurs when the user has switched around the disks. When
the user has changed disks, you can't be sure that your FileIO's filename
list is still valid, so as a courtesy to the user you must cause the filename
list to be reconstructed. In the case that some disk activity occurs in a
program that doesn't use the FileIO library, you will never know about this
activity. Also, if the disk is changed or files are created/deleted by some
other task using the library, you will have no way to determine this. For
these reasons, you may elect to forgo this feature entirely. If you don't use
this feature, you need not bother looking for DISKINSERTED events. Because
the library has been completely rewritten in optimized assembly, it doesn't
take too long for the requester to construct its list anew. Also, the user
can toggle this feature ON/OFF using function key 6 if he wants. The example
applications don't use this feature. You can use the FileIO Requester library
to get the name of a file to be used for output. If you do, and the
specified file doesn't currently exist, AmigaDOS will create it anew when
you open it (mode NEWFILE). From the FileIO Requester point of view, this
means that a file now exists that isn't in your FileIO list. To get the name
in the list, clear the NO_CARE_REDRAW (if it was SET). The next time that
the FileIO structure is used for a call to DoFileIO() or DoFileIOWindow(),
the new file name will appear alphabetized in with the other file names.
Once again, this is not applicable if you don't ever set NO_CARE_REDRAW.
If you have more than one FileIO structure, remember that you must clear
the NO_CARE_REDRAW flag in all of them whenever you see Intuition's
DISKINSERTED IDCMP event class (if you're using the NO_CARE_REDRAW feature).
Also, regarding new disks, there's an extra procedure that you must follow.
If the user changes the disk while you've called DoFileIO() or DoFileIOWindow(),
you won't actually see a DISKINSERTED event (as the event will have been
processed by the library before control is returned to you). So how will you
know to clear the NO_CARE_REDRAW flag in your other structures? Well, the
library records the fact that a DISKINSERTED event was handled by setting
the DISK_HAS_CHANGED flag in your FileIO structure. So on return from a call
to DoFileIO() or DoFileIOWindow you should check to see whether your FileIO
structure has the DISK_HAS_CHANGED flag set. If it does, you should clear
the DISK_HAS_CHANGED flag in the structure and then clear the NO_CARE_REDRAW
flag in all of your other FileIO structures. This assures that when you
call DoFileIO() with any of your other support structures, the filename lists
will be reconstructed, as they should. Please note that all this needs to be
done ONLY IF YOU'RE SETTING NO_CARE_REDRAW.
=============== Workbench-style Filename Operations ====================
You can have file names appear in the FileIO Requester using the same rules
that govern how files appear on the Workbench display, by using the Workbench
.info file mechanism.
To attempt to match Workbench patterns, you must set the WBENCH_MATCH flag
in your FileIO structure, as described below.
The Workbench .info file mechanism is a detailed topic that will not be
delved into here. Please read the Amiga ROM Kernel Manual for a description
of the Workbench operation and data types. What follows is a cursory
description of the Workbench technique, which is described only well enough
to explain how you can interact with it via your FileIO structure.
The Workbench program examines the directory of a disk and displays icons
for the files it finds that end with a ".info" suffix (hereafter referred to
as .info files). The file names displayed beneath the icons have the
".info" suffix removed. The Workbench .info files contain information
regarding what type of data is contained in the file (executable program,
project data, et cetera).
You can choose to have only .info files displayed to the user (with the
".info" removed) in the same way that the Workbench does. You get this
by setting the WBENCH_MATCH flag. Any executables without icons (.info files
) will not be displayed. The same is true of drawers.
If you wish, you can further filter the names that appear. There are two
techniques that you can employ for filtering which file names will be added
to the list: you can ask for only those files that match a particular
Workbench object type and only those files that match a particular tool type.
You elect to match the object type by setting the MATCH_OBJECTTYPE flag in
your FileIO structure. The object types typically of interest are WBTOOL
and WBPROJECT. By selecting one of these 2 types, your filename list will
consist only of executable files or data files respectively (except that all
.info drawer names are always displayed). If this is confusing, refer to the
ROM Kernel manual for a discussion of object types.
You can also request to match a Workbench tool type. By matching tool types,
you can, for instance, have your file list display only those data files
that were created by a specific application. See the section entitled
"The ToolTypes Array" in the Workbench chapter of the ROM Kernel manual for
a description of how tool types work. You elect to match tool types by
setting the MATCH_TOOLTYPES flag in your FileIO structure. A pointer to the
ToolTypes text that you must supply should be stored in the ToolTypesText
field of your FileIO structure.
=========================== No Info Files ============================
Setting the INFO_SUPPRESS flag is exactly the opposite of Workbench
matching. All files that end in .info will be ignored, and not displayed.
This is handy if the user doesn't have a .info file to go with every file
that he wishes to peruse. With WB MATCH, those files would not be displayed.
With INFO_SUPPRESS set, they would be displayed but no .info files would
clutter the display. This gives the impression of WB MATCH while enabling
files without icons to also be seen. On the down side, that means that the
user will see ALL files without icons including those that are best left
alone (i.e. translator.library). All drawers are displayed regardless.
When the user makes his selection, the .info is not added to the pathname.
==================== Filtering by Extension =====================
Sometimes, you may have an application that only wants to see filenames
that end with a certain string (i.e. ".iff"). You can specify an extension
by storing the address of this string in the Extension field of the
FileIO. Also, you need to specify the length (don't count the terminating
NULL byte) and store this value in the ExtSize field. For the preceding
example, the length would be 4 (counting the .). Finally, you must set the
EXTENSION_MATCH flag. If the EXTENSION_MATCH flag is clear, the extension
fields will be ignored. In this way, you can quickly enable and disable the
feature with the one flag. Only the files that END with this extension (case
insensitive) will be displayed. Incidentally, this need not be a real exten-
sion. You can match any ending at all. For example, you could only display
those files that end with the string "picture". In this case, the length
would be 7. If you set the EXTENSION_MATCH flag, then clear the INFO_SUPPRESS
flag. Because only those files that end in your specified extension are seen,
.info files won't be displayed anyway (unless your specified extension is
".info" in which case you'll get nothing but .info files. An icon editor,
maybe?) All drawers will be displayed regardless. Please note that the
extension string that you supply MUST HAVE ALL LETTERS IN LOWER CASE.
In order for the user to take advantage of this feature via the F4 key,
you must set up the FileIO for it. First you must supply a buffer for the
user's typed extension. Place the address in the FileIO's Extension field.
The buffer must be at least 20 bytes long. Don't enable the EXTENSION_MATCH
flag.
If you don't want the user to take advantage of extension match, then
clear the EXTENSION_MATCH flag AND zero the Extension pointer field. There
is the possibility that you may have supplied an Extension to be matched
and while the requester was displayed, the user changed the match string.
For this reason, the buffer should always be at least 20 bytes if you use
this feature. Also, don't assume that the returned filename is definitely
ending with the extension you initially passed. If the user changed the
match string, it won't be the same extension. Also, you should re-initialize
your extension buffer string each time before you call DoFileIO(). The
returned pathname and FILEIO_FILENAME buffer have the extension added.
========================== FileIO Flags ===========================
Remember that the user can always adjust these himself with the function
keys. For this reason, you might simply go with the defaults.
NO_CARE_REDRAW
This flag designates whether the filename data contained in the
FileIO is to be reconstructed before initially drawing the requester.
USE_DEVICE_NAMES
When you leave this flag CLEAR, the AmigaDOS volume names will
be used for the disk names in the requester. If you SET
this flag, the device names will be used instead. The default is to
follow the Workbench convention and use volume names.
DISK_HAS_CHANGED
If the user changes the disk while the FileIO Requester is being
displayed, this flag is set in the FileIO structure. The only time you
must pay attention to this flag is when you have set the NO_CARE_REDRAW
flag. If you find that DISK_HAS_CHANGED has been set, you must clear
that flag in this FileIO structure and then clear the NO_CARE_REDRAW
flag in all of your FileIO structures.
DOUBLECLICK_OFF
Normally, the user can double-click on a filename to select it.
You may choose to disable this feature, for instance, when you want the
user to be very certain about the filename selection (perhaps if the
file is about to be destroyed, or something equally drastic). To disable
double-clicking, set the DOUBLECLICK_OFF flag. Then the user will have
to explicitly select OK! or type the filename and hit return for the
selection to be made.
WBENCH_MATCH
You set this flag to specify that you want Workbench-style .info file
logic to be used when constructing the filename list. This flag is
cleared when your FileIO structure is first created.
MATCH_OBJECTTYPE
When you set this flag (and the WBENCH_MATCH flag), the MatchType field
of your FileIO structure will be compared with the do_Type field of the
.info file's DiskObject structure. If they match, the file will be
displayed. Both the MATCH_TOOLTYPE and the MATCH_OBJECTTYPE flags can
be set at the same time.
MATCH_TOOLTYPE
If you set this flag (and the WBENCH_MATCH flag), then Workbench-style
ToolType pattern matching will be performed and must be successful
before the filename will be included in the list. You specify your
selection of ToolType in the FileIO structure's ToolType pointer field.
Both the MATCH_TOOLTYPE and the MATCH_OBJECTTYPE flags can be set at
the same time.
INFO_SUPPRESS
All .info files are suppressed from the display if you SET this.
EXTENSION_MATCH
Filters filenames that end with a certain string if you SET this.
CUSTOM_HANDLERS
Allows adding custom handlers to the internal library
handlers of GADGETUP, GADGETDOWN, MOUSEMOVE, RAWKEY, DISKINSERTED,
and initial REQSET. You can supply an additional handler for any and all of
these events that will be invoked along with the internal library handler
(or in place of it). Once you call DoFileIO(), the handlers will be installed
and active until the requester ends. Set or Clear this flag before calling
DoFileIO(). If the requester can't open or is being used by another task,
the user will get titlebar entry, and your handlers will be ignored.
SPECIAL_REQ
Allows using the FileIO requester to display lists of strings not
relating to disk drive operations.
======================= RAM DISK bug ============================
There seems to be a bug in 1.2 AmigaDOS. For some reason, whenever one
attempts to get an AmigaDOS Lock on the volume named "RAM DISK:" a
software error occurs. The problem doesn't necessarily lie in AmigaDOS,
but the truth is that the error occurs with little provocation
of AmigaDOS (for instance:
dir "RAM DISK:"
can and does crash the Amiga). Though 1.3 resolves this bug, the FileIO
code provides a work-around for 1.2 by changing "RAM DISK:" to "RAM:"
which locks successfully and does not crash the machine. This solution
has a problem: if the user has given the name "RAM DISK:" to some
non-RAM: disk (such as a floppy) then this fix will fail and the floppy
named "RAM DISK:" wouldn't be seen. This isn't too bad of a problem,
because if the user has been silly enough to name a floppy "RAM DISK:"
the user is probably experiencing lots of other problems already and this
will provide just one more reason why one shouldn't name a floppy
"RAM DISK:" don'cha know.
======================= Free Disk Space ================================
The FileIO's FREEBYTES field indicates how many free bytes remain on the
disk that the user has chosen. This is useful for a save routine. After all,
you wouldn't want to start saving a 230K file to a disc that only has 229K
free. Unfortunately, AmigaDOG always says that the RAM DISK: has 0 bytes
free. Actually, it has as many bytes free as mem that is available. Whenever
the user selects RAM: or RAM DISK:, the FileIO's FREEBYTES is set to
0xFFFFFFFF (the largest size possible). If you encounter this condition, you
may wish to use Exec's AvailMem to determine if you can do the save.
========== Procedure for Using the FileIO Requester library ===========
This section presents a step-by-step procedure for utilizing the FileIO
Requester library with your own program.
Copy the requester.library into the libs directory of your boot disk. For
workbench users, double-click on the inclosed program "CopyLib" and place
your Workbench disk in the drive when you see the DOS requester. CopyLib
will display the FileIO requester if all went well. Select the requester's
CANCEL and exit the program by closing the window.
You have to include FileIO.h in every C module that refers to your FileIO
structure.
#include "FileIO.h"
For assembly language users, (WOW! We hardly ever get real support for
programming on the Amiga), include FileIO.i
Open the library via a call to exec's OpenLibrary and store the pointer at
a variable called RequesterBase (MUST BE CALLED THIS FOR C PROGRAMMERS).
if (!(RequesterBase = (APTR) OpenLibrary("requester.library", 0L)))
exit(0);
Declare a pointer to a FileIO structure (initialized to 0), and then fill
that pointer with the address of one of the structures.
struct FileIO *myFileIO = 0;
myFileIO = GetFileIO();
<<<< IF USING NO_CARE_REDRAW >>>>>
Your NewWindow structure should have the DISKINSERTED flag set along with
your other IDCMP flags. Whenever you receive a DISKINSERTED event, you
should clear the NO_CARE_REDRAW flag (if SET) in every FileIO structure you
control. The following code could be added to the case switch where you
handle IDCMP events.
switch (imessageclass)
{
case DISKINSERTED:
/* You should clear the NO_CARE_REDRAW flag
* whenever you detect that a new disk was
* inserted.
*/
if (myFileIO)
ClearFlag(myFileIO->Flags, NO_CARE_REDRAW);
break;
}
Alternately, you may elect to leave NO_CARE_REDRAW clear in which case the
requester display will be updated every time it is used and you won't need
to bother with receiving DISKINSERTED events.
Set the FileIO's Buffer field to the address of a buffer that you have
allocated. This is where the complete path will be constructed for you.
(i.e Disk:drawer1/drawer2...etc/filename ) Also initialize the FileIO's
DrawMode, PenA, and PenB. You might also want to set the FileIO's X and Y
fields where the requester will open within your window (relative upper left).
If using DoFileIO(), and your window is not full size, include a sizing
gadget so that if the user needs to type via the title bar he can expand it.
When you want to present the FileIO Requester to the user, call DoFileIO() or
DoFileIOWindow(). If these routines return the address of the passed buffer
where you want the full path name to be stored, the user did not cancel the
operation, nor was there an error in opening the window (for DoFileIOWindow
only). A -1 and 0 will be returned respectively for the two error conditions.
The following code is an example of presenting the FileIO Requester to the
user and then reacting to the result.
/* This set-up need only be done once, though you can change them later */
UBYTE buffer[204];
myFileIO->Buffer = buffer;
myFileIO->DrawMode = JAM1;
myFileIO->PenA = 1;
myFileIO->PenB = 0;
/* ================================================================ */
if (myFileIO)
{
result = (DoFileIO(myFileIO, window));
if (result==&buffer[0])
{
/* Here, do something like read or write the file.
*/
if (writefile)
{
if (myFileIO->FileName[0])
{
if (!myFileIO->FileSize)
{
/* Open the file (MODE_NEWFILE) */
/* Write the file */
/* Close the file */
}
/* Otherwise, tell the user that he's about to overwrite */
}
/* Error in entering filename */
}
if (readfile)
{
if (myFileIO->FileName[0])
{
if (myFileIO->FileSize)
{
/* Open the file (MODE_OLDFILE) */
/* Read the file */
/* Close the file */
}
/* Otherwise, tell the user that the file doesn't exist */
}
/* Not a loadable file */
}
}
if (result==0)
{
/* This only happens if DoFileIOWindow() bombs. Call DoFileIO() */
}
/* Otherwise, CANCEL must have been selected. Never mind. */
}
Finally, when you're done with your FileIO structure (usually when
your program is exiting), you can free up the structure and its resources
with a simple call to ReleaseFileIO(), like this:
if( RequesterBase ) ReleaseFileIO(myFileIO);
Also, you need to close the library upon exit.
if( RequesterBase ) CloseLibrary( RequesterBase );
When you link your C program, you'll need to assemble and link with
FileInterface.asm. This is the usual assembly poot needed by C programs in
order to call assembly language libraries. You want efficiency, write in
assembly. Assembly programmers can simply use the _LVO library offsets as
provided in FileIO.i. See the example applications for details.
ONE FINAL NOTE: The lib needs to trap RIGHT MOUSE buttons for displaying
the list of disk names. When exiting, the lib clears the RMBTRAP bit of
your window's flags, so if you had it set before calling DoFileIO(), then
you'll have to set it again upon return by going to the Flags field of
your window structure and setting bit #16.
============ USING THE REQUESTER TO DISPLAY LISTS OF STRINGS =============
There may be times when you need to display a list of strings in a
requester so that a user can scroll around the list via the mouse and
choose an item in the list. The amount of code and IDCMP hassle of construct-
ing such a requester can certainly be considerable, especially if you want to
include a Prop scroll bar, scroll arrows, a string gadget, CANCEL and OK
gadgets, etc.
The latest version of the FileIO requester library has a feature whereby
you can use the lib's requester to display your list of strings. The lib
handles all user interaction, list display, and IDCMP. You simply set the
SPECIAL_REQ flag of the FileIO before calling DoFileIO() or DoFileIOWindow()
and the requester will display your list of strings. The requester is no
longer a disk I/O tool. In fact, the Disk and Drawer string gadgets are re-
moved from the display, and the NextDisk gadget no longer has anything to do
with switching dirs.
The user can employ the Prop and Arrow gadgets (with auto-scroll) to scroll
through the list of strings. The size of the Prop's knob reflects the per-
centage of visible strings just like in the disk I/O version.
The user can click on any string to make it the currently selected one,
and it will be highlighted and copied to a string gadget below. Or the user
can type his selection directly into the string gadget. A double-click on
a string will end the requester with that string as the chosen one.
The chosen string will be copied to the FileIO's Filename buffer. Note
that with SPECIAL_REQ, you do not need a Pathname buffer. (In fact, the
FileIO's BUFFER field will be overwritten.)
With SPECIAL_REQ, DoFileIO() or DoFileIOWindow will return the following:
1). A -1 if the user selected the CANCEL gadget.
2). A -2 if the library was being used by another task (i.e. the same
note about non-reentrant code applies here).
3). A 0 if there is a problem opening the FileIO window (for DoFileIOWindow)
4). The address of the FileIO's Filename buffer (i.e. where the selected
string is copied) if all went well and the user selected OK, or double-
clicked on a string, or typed in his selection in the Name gadget.
So how do you give your list of strings to the lib? There are 2 new
functions, NewEntryList() and AddEntry() that you use to make the list.
Here are the passed parameters.
EntryNum = AddEntry(ID_num, StringAddress, FileIO);
d0 d1 a0 a1
NewEntryList(FileIO);
a1
Each FileIO can have its own list attached to it. NewEntryList frees
any previous list (if one exists) that was made for the passed FileIO. For
this reason, you should call NewEntryList first before using AddEntry to
add strings. You can then add strings to the list by subsequent calls
to AddEntry. (AddEntry adds the one passed string into the list. The list is
alphabetized as each string is added to it so that the strings are always
displayed in alphabetical order.) ID_num is some value that you want asso-
ciated with the string. When the user selects that string, it is copied into
the FileIO's Filename buffer and the ID is copied into the FileIO's FileSize
field. This ID is a LONG, and can be any value you desire (i.e. maybe even
a pointer to some data structure associated with that string). The only
restriction is that ID cannot be -1 (i.e. 0xFFFFFFFF).
The returned EntryNum is where the string has been alphabetically placed
in the list (i.e. the first string in the list returns 0). If you receive
a negative number from AddEntry(), this means that there wasn't enough memory
to add the string to the list. Actually, AddEntry copies the string, and
adds the copy to the list, so you need not keep the original string after it
is added to the list.
When you finally call ReleaseFileIO(), any list associated with the FileIO
is freed.
Here is how you might create a list with the following 3 items and display
it in the FileIO requester:
/* You should have opened the requester lib and allocated a FileIO */
if (myFileIO)
{
NewEntryList(myFileIO);
error = AddEntry(1L, "This is One", myFileIO);
if (error<0) break;
error = AddEntry(2L, "Two", myFileIO);
if (error<0) break;
error = AddEntry(3L, "Three", myFileIO);
if (error<0) break;
result = (DoFileIO(myFileIO, window));
if (result==myFileIO->FileName)
{
/* FileName buffer contains the string, and FileSize the ID
*/
}
if (result==0)
{
/* This only happens if DoFileIOWindow() bombs. Call DoFileIO() */
}
if (result==-2)
{
/* This happens if someone is using the library. Come back later */
}
/* Otherwise, CANCEL must have been selected. Never mind. */
}
There is a possibility that the user may type a string that is not in the
list, directly into the Name gadget. Before exiting, the requester lib will
check if the string is in the list. If not, the string is copied to the
FileIO FileName buffer as before, but the FileSize field is set to -1. A
FileSize of -1 means "this string isn't in the list". That is why you should
not assign an ID of -1 to any string. The lib ignores the case of the string
when comparing items in the list (i.e. "Amiga" and "amIGA" are the same),
but it does not trim away any leading or trailing spaces.
With SPECIAL_REQ, the "Next Disk" gadget can be a custom gadget for your
use. You place into the FileIO's FileIOText field a pointer to the string
that you want displayed in the gadget. This string should be no more than 11
characters (not counting the end NULL). You should pad the head of the
string with spaces to properly center inside the gadget. You should also
store in the FileIO's FileIORoutine field a pointer to a routine that is to
be executed everytime the user releases the mouse over the custom gadget.
The library calls this routine passing the FileIO and Window (that the
requester opened in), and the Requester Structure.
BOOL yourRoutine(Requester, Window, FileIO)
a5 a3 a2
This function should return TRUE to end the requester, or FALSE to con-
tine. If FALSE, the FileIO display will be refreshed when your function
returns. (In case your custom routine added/removed something from the list,
or changed lists). If you return TRUE, the requester will end with the
FileIO's Errno field will be set to ERR_APPGADG.
If your FileIO's FileIORoutine field is set to NULL when you call
DoFileIO, the custom gadget is removed from the display.
Finally, there is a routine that you can use to determine if a certain
string is in the list.
entryNum = IsEntryThere(String, FileIO)
d0 a0 a1
where String is the address of the string you wish to check for.
This returns the entryNum (like AddEntry) of the string if it is found
in the list, or a -1 if it is not in the list. For assembly programmers,
if found, the address of the Remember structure is returned in a0.
The list is created using the Intuition function, AllocRemember. The
"anchor" of the list is the FileIO's FileList field. So each string has
its own Remember structure. The Remember's rm_Memory points to my own
Entry structure. An Entry structure looks like this:
struct Entry {
LONG EntryID;
UBYTE EntryFlags; /* Don't alter this! */
UBYTE EntryString[size of the string not counting end NULL];
};
In asm,
EntryID dc.l 0
EntryFlags dc.b 6
EntryString dc.b [the bytes comprising the NULL-terminated string]
You can use one FileIO to alternately display several lists. The key is
to properly set the FileIO's NameCount, NameStart, CurrentPick, and FileList
fields before calling DoFileIO(). You should make a list as in the above
example, and then copy the FileList field to some global. Then zero out the
FileList field. Do this for all your lists. Now when you want to display one
list, pass the appropriate global to a routine that does the following:
1). Clear the FileList field.
2). Call NewEntryList() (to initialize the NameStart and CurrentPick)
3). Set the FileIO's NameCount to the number of items in the list
4). Set the FileIO's FileList to the passed global.
5). Set the SPECIAL_REQ flag. (If it wasn't set previously.)
6). Call DoFileIO()
7). Clear the FileList field.
Here's a C function to implement the above. It returns TRUE if all went
well, and FALSE if error or user cancel.
BOOL ShowList(ListAddr,NumOfItems,window,fileio)
struct Remember *ListAddr; /* the contents of the FileIO's FileList field
after you made the list with AddEntry(). */
SHORT NumOfItems; /* number of entries in Remember List */
struct Window *window;
struct FileIO *fileio;
{
UBYTE *address;
fileio->FileList = 0; /* original value you previously stored in global
after making the list */
NewEntryList(fileio);
fileio->NameCount = NumOfItems;
fileio->FileList = ListAddr;
SetFlag(fileio->Flags, SPECIAL_REQ);
address = DoFileIO(fileio, window);
fileio->FileList = 0;
if( address <= 0 )
return( FALSE );
else
return( TRUE );
}
When exiting your program, you must de-Allocate all the lists. For each,
1). Set the FileIO's FileList to the passed global.
2). Call NewEntryList()
void FreeProgList(fileio, filelist)
struct FileIO *fileio;
struct Remember *filelist;
{
fileio->FileList = filelist; /* original value you previously stored in global
after making the list */
NewEntryList(fileio);
fileio->FileList = 0;
}
Consult the examples, CustomList, for how to use SPECIAL_REQ.
=============================================================================
=== DEMO PROGRAM NOTES ======================================================
=============================================================================
This section briefly describes the demo programs that drive some of the
FileIO Requester library's features. There is a C demo, an assembly demo,
and an AmigaBasic demo (no joke).
If you invoke the C or asm demos without a second argument, a window will be
opened in the Workbench screen. If you invoke these demos with any second
argument, a hi-res screen will be opened for the requester window.
The C demo uses two FileIO structures to demonstrate the techniques that you
should use when managing multiple FileIOs. These techniques include processing
DISKINSERTED events and discovering on return from DoFileIO() that the
DISK_HAS_CHANGED flag is set. (As long as you're using the NO_CARE_REDRAW
feature). The first support structure, fileio1, is used in its vanilla state
as created by GetFileIO(). The other support structure, fileio2, is
initialized to do Workbench-style .info file handling where the filename
list will consist of only .info objects of type WBPROJECT. Also, fileio1
uses volume names and the other uses device names. You activate fileio1 when
you click the right mouse button. You activate fileio2 when you press any
key. Finally, when you do any of the selection techniques where you accept
your selection, the pathname to your selection is displayed in a FileIO
autorequester. If you choose CANCEL to end the FileIO process, nothing happens.
To stop the program, click on the window close gadget (when the requester
is not displayed).
The assembly demo only uses 1 FileIO structure. There is a menu to
demonstrate various features. You should manually deselect the features
you want disabled, and select those that you want enabled. For example,
select CUSTOM to see how a custom handler is installed for the REQSET event.
Also, this program can look for files that only end in certain strings if
you select the EXTENSION menu item. When you enable the extension feature,
the application uses the PromptUserEntry() function. Notice how the prompt
appears in the window titlebar with a cursor. You can type in the string
that you want to match, and hit return. Now when you call up the requester,
only those filenames that end in that extension will be displayed (along
with any dirs). This works just like the F4 Function key option.
The amigabasic demo asks the user if he wants to display only those files
with a certain extension, and inputs the extension. Otherwise, it suppresses
all .info files. It then copies the pathname to a string variable which can
be better utilized for basic manipulation. Also this demos a few of the
library's autorequester functions. When running this program, the included
bmap for the FileIO requester library must be in the same directory.
Additionally, there are examples to demonstrate using the requester to dis-
play lists of strings.
========================================================================
INSTALLING CUSTOM HANDLERS
You can install custom handlers for any of several events that might occur
in the requester. You need to set the CUSTOM_HANDLERS flag of the FileIO, and
fill the FileIO's HandlerBlockPtr field with the address of a HandlerBlock
structure. The HandlerBlock structure (defined in FileIO.h) holds the
addresses of the handlers for REQSET, DISKINSERTED, GADGETDOWN (and UP),
RAWKEY, and MOUSEMOVE. If you have no handler for a particular event, NULL
its HandlerBlock field. Each FileIO can have its own custom handlers.
For REQSET, and DISKINSERTED, if your handler returns a 1, then the
library's internal handler will be skipped. Otherwise, the library routine
will be executed if you return a 0.
For GADGETDOWN and GADGETUP, your handler will be called only if the Gadget
ID is not one of the requester's gadgets. Your handler will be passed the ID
in d0 (as well as other parameters). Your handler should return a 0 in order
to continue, or a 1 if you wish to end the requester. (You can check that
your custom handler ended the requester if the FileIO's Errno = ERR_APPGADG).
The only two requester gadgets that the library no longer controls are the CANCEL
and OK gadgets. Control of these two is passed to your custom handler. These
two gadgets have IDs of 32672 and 32673 respectively. If you receive either
of these IDs, you should return a 1. On the other hand, you could simply
cause these gadgets to be ignored by returning a 0. In any event, your
handler will have to return a 1 eventually in order to exit the requester,
or the user would have to type the Filename in the Filename string Gadget.
Do not use gadget IDs between 32672 to 32682 as these are reserved by the
library.
For MOUSEMOVE, the events are "collected" (i.e. you only receive one event
when the user stops moving the mouse). Also, you won't receive MOUSEMOVE when
the user is operating the requester's scroll (prop) gadget. Your handler
doesn't need a return value.
For RAWKEY, you won't receive any function keys. No return value is needed.
The requester calls your handler with the following items in these
registers:
a2 - the address of your FileIO
a3 - the address of the window in which the requester is open
a4 - the IAddress of the event (not valid for REQSET or DISKINSERTED)
d6 - MouseX position (for RAWKEY handler, this is the Code instead)
d7 - MouseY position (for RAWKEY handler, this is the Qualifier)
d2 - Seconds
d5 - Micros
d0 - for GADGETUP and DOWN only, the gadgetID (need not be saved)
You MUST save these registers if you plan on altering them.
If your handler is written in C (yech!), I've provided a mechanism for
receiving these parameters passed on the stack like all good, inefficient C
programs should. Let's face it, C just doesn't have enough power to do the
sophisticated, efficient things that we do in assembly. But if you'd like to
fool yourself into thinking otherwise, I've tried to accomodate your
delusions. After filling in the HandlerBlock's pointers to the desired
routines, you must call SetFileIOHandlers(HandlerBlock). This routine
will see to it that your handler receives the following parameters except
where previously noted.
yourHandler(IAddress,Window,FileIO,MouseY,MouseX,Micros,Seconds,GadgID)
Unfortunately, unlike the assembly implementation, if you want to have
different FileIO's with unique custom handler routines, you'll have to
call SetFileIOHandlers() before each call to DoFileIO(). Hey, you're writing
in C, so you should be used to giving up some flexibility.
If you're using Manx small data model, you'll probably have to call geta4
or savea4 (whatever). a4 will definitely not have the base of your program's
data section. These are the types of problems you should expect if you allow
a C compiler to determine 68000 register usage. Also, since register a6 is
"reserved" for library base vectoring on the Amiga, the C interface to the
library does not save this register. If your compiled program crashes because
of this, its time to buy a better compiler, or perhaps solve these headaches
once and for all with an assembler.
struct HandlerBlock {
APTR StartUpCode; /* Called when the requester first opens */
APTR DiskInsertedCode; /* Called whenever a disk is inserted */
APTR GadgetCode; /* Called whenever a gadget UP or DOWN */
APTR KeyCode; /* Called whenever a rawkey occurs */
APTR MouseMoveCode; /* Called when the mouse is moved */
};
assembly:
dc.l AddrOfStartCode
dc.l AddrOfDiskInsertCode
dc.l AddrOfGadgetCode
dc.l AddrOfRawkeyCode
dc.l AddrOfMouseMoveCode
Please note that if you should you DoFileIO() as opposed to DoFileIOWindow()
if using custom handlers.
=============================================================================
=== TECHNICAL REFERENCE =====================================================
=============================================================================
The FileIO files include:
requester.library the actual library (slightly < 10K in size)
manual The documentation. You've obviously found it.
FileIO.h includes for an C application using the library
FileInterface.asm glue routines for a C application to use the
library. (poot) Expects all integers passed 32bit
FileIO.i assembly programmer's include file
main.c an application in C
CustomList.c an C demo using SPECIAL_REQ
Test.asm an application in assembly
CustomList.asm an asm application using SPECIAL_REQ
StartUp.asm the startup code for the assembly examples
TestFileIO an executable of the assembly application
MakeTest execute this script file to make the asm example
BasicFileIO an AmigaBasic application (do you believe me now?)
BasicString an AmigaBasic demo of SPECIAL_REQ
requester.bmap the bmap file for AmigaBasic
requester_lib.fd the fd file used to make the bmap file
CopyLib a utility to copy libraries to a boot disk
================= USING THE AMIGA PROGRAMMER'S SUITE =======================
The following is the message that appeared with RJ Mical's ProSuite code
on Fred Fish Disc #107. That version of FileIO was not a library. It was a
C code module that needed to be compiled and linked with your application.
At this point, the code for this library is significantly different than
the original, and quite incompatible with R.J's Includes and Defines. Also,
there are differences in both functionality and features. But R.J. started
the ball rolling so....
The Amiga Programmer's Suite Book 1 is copyrighted but freely distributable.
All copyright notices and all file headers must be retained intact.
The Amiga Programmer's Suite Book 1 may be compiled and assembled, and the
resultant object code may be included in any software product. However, no
portion of the source listings or documentation of the Amiga Programmer's
Suite Book 1 may be distributed or sold for profit or in a for-profit
product without the written authorization of the author, RJ Mical.
If you use the Amiga Programmer's Suite, I wouldn't mind if you gave me
some mention somewhere.
Good luck! Program hard, program well. -RJ Mical
Make lots of money and become a arrogant, self-serving pain-in-the-ass.
-Jeff Glatt (my personal philosophy is a bit more philanthropic than RJ's)
=== APPENDIX A: FileIO Function Calls ======================================
CONTENTS:
GetFullPathname()
GetFileIO()
DoFileIO() ;only 1 task at a time
DoFileIOWindow() ;only 1 task at a time
ReleaseFileIO()
SetWaitPointer()
ResetBuffer()
AutoMessage()
AutoFileMessage()
AutoPrompt3()
UserEntry()
PromptUserEntry()
TypeFilename()
GetRawkey()
DecodeRawkey()
ParseString()
NewEntryList()
AddEntry()
*********************** GetFullPathname() *********************
NAME
GetFullPathname -- Build a file pathname using a FileIO struct
SYNOPSIS
Buffer = GetFullPathname(FileIO, Buffer);
d0 a0 a1
FUNCTION
Builds the text for a pathname using the FileName[], DrawerName[] and
DiskName[] fields of the specified FileIO structure after the structure
has been used in a successful call to DoFileIO(), DoFileIOWindow(), or
TypeFilename(). Writes the text into the Buffer.
INPUTS
FileIO = the address of a FileIO structure
Buffer = address of the buffer to receive the file pathname
RESULT
The address of the passed buffer. Also, for assembly programmers the
address of the terminating NULL is in a1 so you can quickly determine
the string length by subtracting d0 from a1 with the result in a1.
SEE ALSO
DoFileIO()
********************* GetFileIO() ************************
NAME
GetFileIO -- Allocate and initialize a FileIO structure
SYNOPSIS
struct FileIO *GetFileIO();
FUNCTION
Allocates and initializes a FileIO structure for use with
calls to DoFileIO(), DoFileIOWindow(), TypeFileName(), PromptUserEntry().
You may want to further initialize the structure before calling these
routines. At least the FileIO's Buffer, DrawMode, PenA, and PenB fields
should be initialized. Instead of allocating a FileIO via this routine,
you may declare one globally or statically as long as all fields are
initialized to zero or an approprite value.
When you're done with the structure, call ReleaseFileIO() regardless of
whether it was allocated or declared to free up resources.
INPUTS
None
RESULT
If all goes well, returns the address of a FileIO structure.
If anything goes wrong (out of memory), returns NULL.
BUGS
None known
SEE ALSO
DoFileIO(), DoFileIOWindow, ReleaseFileIO()
*********************** DoFileIO() **********************************
NAME
DoFileIO -- Gets a file name for input/output from the user
DoFileIOWindow() -- The same, but opens a window for the requester.
SYNOPSIS
ULONG address = DoFileIO(fileio, window);
d0 a0 a1
ULONG address = DoFileIOWindow(fileio, screen);
d0 a0 a1
FUNCTION
This routine creates a filename requester which allows the user to browse
through the AmigaDOS filesystem and select one of the filenames found
there.
The fileio argument is a pointer to a FileIO structure, which is allo-
cated and initialized via a call to GetFileIO(), or declared in your
application.
You may preset the FileIO parameters before calling this routine,
or you may leave them set at their default values. See the FileIO
documentation and include files for complete details.
The window argument is the pointer to the window structure returned
by a call to Intuition's OpenWindow() function. As this routine
opens a requester and requesters open in windows, you must have
already opened a window before calling this routine, even if it's
a window opened for no other purpose than to call this routine.
DoFileIOWindow() is provided to circumvent this problem. It simply opens
a window on the passed screen before calling DoFileIO, and closes it
upon exit. By setting screen to NULL, the window opens on the WorkBench
screen. Also, you might use DoFileIOWindow if you wanted a requester
that could be moved or depth arranged by the user in an existing screen.
The title that appears in the window will be gotten from the address in
the FileIO's Title field.
You must initialize the FileIO's Buffer field to hold the address of a
buffer where the full pathname string (i.e. disk:drawer.../filename) will
be constructed. The size should be no less than 202 bytes. Also, the
FileIO's DrawMode, PenA, and PenB fields should be set to the values
you want restored when the requester closes.
This routine returns a 0 if DoFileIOWindow's window couldn't open, a -1
if the user selected CANCEL, or the address of the FileIO's Buffer if
all went well and the user selected a filename. The full path name will
have been constructed in the buffer. The filename itself will have
all leading and trailing blanks removed (in case the user typed in a
filename with extraneous spaces) and stored in the FileIO's FileName[].
Likewise, the disk and drawer names can be found in the text
fields DiskName[] and DrawerName[] of the FileIO. You can always call
GetFullPathname() to build the pathname from the separate fields of the
FileIO.
There's a *lot* more to be said about this function. Please
read the documentation.
NOTE: This routine is not re-entrant. What this means is that if some
other task is calling DoFileIO() or DoFileIOWindow(), this routine
will automatically call TypeFilename() for the 2nd application.
INPUTS (for DoFileIO)
fileio = pointer to a FileIO structure, as allocated
via a call to GetFileIO()
window = pointer to a Window structure, as created via a call
to Intuition's OpenWindow()
RESULT
0 if an error in opening DoFileIOWindow() window. You will not get this
error for DoFileIO()
-1 if the user selected CANCEL
the address of the Buffer if all went well and a file was selected. Also
for assembly programmers the end of the string is in a1 like GetFullPathname.
BUGS
None known
SEE ALSO
GetFullPathname(), GetFileIO(), ReleaseFileIO()
************************* ReleaseFileIO() **************************
NAME
ReleaseFileIO -- Release the FileIO structure and all local memory
SYNOPSIS
ReleaseFileIO(fileio);
a1
FUNCTION
Releases the FileIO structure by freeing all local memory attached
to the structure and then freeing the structure itself if it is an
ALLOCATED_FILEIO (i.e. not pre-initialized in your application).
Restores the directory that was established when the FileIO was first
sent to DoFileIO() or DoFileIOWindow(). (You should not unlock the
initial dir that is contained in the FileIO's originalLock field.)
INPUTS
fileio = the address of a FileIO structure
RESULT
None
SEE ALSO
GetFileIO()
************************** SetWaitPointer() *************************
NAME
SetWaitPointer - Sets the zzz cloud pointer in the passed window.
SYNOPSIS
SetWaitPointer(window);
a0
FUNCTION
If you want to have a wait pointer appear in a window, you can use this
function which already has set up the pointer data in CHIP mem. Then
when you want to restore the pointer, call Intuition's ClearPointer().
INPUTS
window = the address of a window structure
RESULT
None
************************* AutoMessage() ************************
NAME
Automessage - an easy implementation of an AutoRequester
SYNOPSIS
AutoMessage(message, window);
d0 a0
AutoMessageLen(message, window, length);
d0 a0 d1
FUNCTION
This displays the passed string (whose address is in d0) in a simple
AutoRequester. It manages the dimensions (automatically sizes to the
passed message) and the IntuiText structure for you. Use AutoMessageLen
if you know the length of the string to be displayed.
INPUTS
window = the address of a window structure
message = address of the string to be displayed
RESULT
None
************************* AutoFileMessage() ****************************
NAME
AutoFilemessage - AutoMessage with preset strings to choose from
SYNOPSIS
BOOL AutoFileMessage(messagenumber, window);
d1 a0
FUNCTION
The requester library has several messages it uses for internal use.
You can have one of these messages displayed just by passing the number
of the message you want. See Include file for available messages.
Some of the messages have two responses "YES" and "OK". Others have just
the "OK".
INPUTS
window = the address of a window structure
messagenumber = number of the string to be displayed
RESULT
Returns FALSE (d0 = 0) if the user selects "NO" or TRUE (d0 = 1) if the
user selects "OK".
************************ AutoPrompt3() **************************
NAME
AutoPrompt3 - AutoRequester with up to 3 lines of Text
SYNOPSIS
BOOL AutoPrompt3(message1, message2, message3, window);
a1 a2 a3 a0
FUNCTION
Displays up to 3 passed strings in an autorequester. Automatically
dimensions the requester to the size of the longest string, and
positions the other strings for a symmetrical display. Returns with
user's response to "YES" or "NO". You can also display only 2 or even
1 string if you pass NULL for the other messages.
INPUTS
window = the address of a window structure
message1 = address of the top string to be displayed
message2 = address of the 2nd string to be displayed or NULL if none
message3 = address of the 3nd string to be displayed or NULL if none
RESULT
Returns FALSE (d0 = 0) if the user selects "NO" or TRUE (d0 = 1) if the
user selects "YES".
************************ ResetBuffer() *********************************
NAME
ResetBuffer - Resets the cursor within a StringInfo's buffer to the
first position. Also, can NULL out the buffer itself and
reset the number of chars to 0.
SYNOPSIS
ResetBuffer(stringinfo, resetFlag);
a0 d0
FUNCTION
If you have a String gadget whose cursor you'd like to set back at the
first position, you can use this function. Also, if resetFlag is TRUE
(1) then the gadget's buffer will be NULLED. You must refresh the gadget
yourself after this call.
INPUTS
stringinfo = the address of a StringInfo structure
resetFlag = whether to NULL or not
RESULT
NONE
;********************* TypeFilename ***************************
NAME
TypeFilename - Uses the window's titlebar to obtain the path name instead
of the file requester (an alternative). Displays the prompt
"Filename >"
SYNOPSIS
buffer =TypeFilename(FileIO, Window);
a0 a1
FUNCTION
If you really don't like the requester, and would prefer to have the
user type in the full path via the window's title bar, then use this.
Also, you might use this within a save routine so that the user has to
deliberately type his choice. The pathname contained within the FileIO's
Disk, Drawer, and Filename fields is what is initially presented to the
user. This routine is automatically called if an application tries to
call DoFileIO() or DoFileIOWindow() when another task is displaying the
FileIO requester. Also called if there is not enough mem to open/display
the requester. This routine sets up the FileIO's Disk, Drawer, Filename,
FileSize, and FreeBytes fields in the same manner as DoFileIO so that
you can interpret the results in exactly the same manner.
INPUTS
Window = the address of a window
FileIO = the FileIO structure
RESULT
Returns the address of the FileIO's Buffer or a -1 if the user bailed
out without entering anything. An ESC will return -1, but will store an
ESC char ($1B) and then NULL char in the buffer.
;*************************** UserEntry ***************************
NAME
UserEntry - Uses the window's titlebar to obtain user input.
SYNOPSIS
buffer = UserEntry(charlimit, initBuffer, FileIO, Window);
d0 a1 a2 a3
FUNCTION
This clears the window's titlebar, displays a cursor, and allows the user
to type in chars up to the limit, or until CR or ESC is pressed. The NULL
terminated result is placed in the FileIO's Buffer. When the charlimit is
reached, the routine automatically terminates. You must set the FileIO's
PenA, PenB, and DrawMode fields so that these may be restored by the lib
when the function is finished.
The initBuffer string is what is presented to the user (and what he may
edit). The passed window must have RAWKEY IDCMP set, and the FileIO's
RawCode field set to 0 in order to use the default decoding routine,
GetRawkey(). Otherwise, decoding will be redirected to the routine specified
in the FileIO's RawCode field. (Maybe you want VANILLAKEY instead. Or
maybe you also want to handle other IDCMP events while "inside" of UserEntry.
GetRawkey disposes of all but RAWKEY events. Or maybe you've set up your
own custom IDCMP port and RAW handling routine.) Regardless, your RawCode
routine must go to the window's IDCMP port to get a message or wait if
there is no message. It should handle all IDCMP messages except RAWKEY or
VANILLAKEY. If one of these messages, exit with an UWORD representing the
character as follows:
$20 to $7F for ascii chars, $DF for delete, $08 for BACKSPACE, $0D for
RETURN, $1B for ESCAPE, $010C for LEFT Cursor, $010D for Right Cursor,
$020C for SHIFT-LEFT Cursor, and $020D for SHIFT-RIGHT Cursor.
UserEntry will continue calling your RawCode for each char, and terminate
upon receiving an $0D or $1B, or reaching the charlimit.
Since the titlebar can hold approx 70 chars between the CLOSEGADGET and
FRONT/BACK, the FileIO's Buffer might be set to 70 bytes. It must be at
least as big as charlimit. If the charlimit is greater than 70 bytes, the
user can still enter chars, but he will not see them. Upon return, your
window's title is restored.
INPUTS
Window = the address of a window
FileIO = the FileIO structure
charlimit = the number of characters to accept from the user
initBuffer = the NULL-terminated string to initialize the FileIO's
buffer to, or NULL if no initialization desired
RESULT
Returns the address of the FileIO's Buffer or a 0 if the user bailed
out without entering anything. An ESC will return 0, but will store an
ESC char ($1B) and then NULL char in the buffer.
;******************** PromptUserEntry ***************************
NAME
PromptUserEntry - Uses the window's titlebar to obtain user input.
SYNOPSIS
buffer = PromptUserEntry(charlimit,prompt,initBuffer,FileIO,Window);
d0 a0 a1 a2 a3
FUNCTION
This works just like UserEntry except that it first displays the
passed prompt string in the titlebar. The FileIO's Buffer should always
be greater than the number of chars in the prompt plus charlimit.
INPUTS
Window = the address of a window
FileIO = the FileIO structure
charlimit = the number of characters to accept from the user
buffer = the buffer where the user's input is placed
prompt = NULL-terminated prompt to display
initBuffer = the NULL-terminated string to initialize the FileIO's
buffer to, or 0 if no initialization desired
RESULT
Returns the address of the FileIO's Buffer or a 0 if the user bailed
out without entering anything. An ESC will return 0, but will store an
ESC char ($1B) and NULL char in the buffer.
******************* SetTitle() ********************************
NAME
SetTitle - Uses the window's titlebar to display 1 or 2 strings.
SYNOPSIS
SetTitle(String1,String2,FileIO,Window);
a0 a1 a2 a3
INPUTS
Window = the address of a window
FileIO = the FileIO structure
String1 = the NULL-terminated string to the left
String2 = NULL-terminated string placed to the right of String1. If you
pass a zero instead, no 2nd string displayed.
FUNCTION
This will display the 2 strings in the window's titlebar (saving the
initial title to the FileIO's Title field), and return immediately with
the strings still displayed. Subsequent calls can be made to display
different strings, but when ResetTitle() is finally called, the initial
titlebar is restored. This routine is useful for displaying error msgs to
the user without halting program execution (like a requester does), and
allows the msg to remain visible for as long as it is needed. Furthermore,
it doesn't require that the user respond to it. This function makes temp-
orary use of the FileIO's Buffer, so you must supply a buffer whose address
is stored at the FileIO Buffer field. This buffer must be large enough to
contain both Strings.
******************* ResetTitle() ********************************
NAME
ResetTitle - Restores the window's titlebar after calls to SetTitle
(if any calls were made at all)
SYNOPSIS
ResetTitle(FileIO,Window);
a2 a3
INPUTS
Window = the address of a window
FileIO = the FileIO structure
FUNCTION
Resets the initial title (stored in FileIO's Title field) if it detects
that any calls were made to SetTitle. Otherwise, it does nothing.
*********************** ParseString() *******************************
NAME
ParseString - Separate a path string into separate components
SYNOPSIS
ParseString(FileIO,String)
a0 a1
INPUTS
The FileIO structure
The address of the NULL-terminated path
FUNCTION
This takes the NULL-terminated path as it would be typed on a CLI line
Diskname:TopDrawer/....etc.../BottomDrawer/Filename
and parses it for "weird" typos or non-existant disk or drawer names.
Of course, there may not be any Disk or Drawer names. It then copies the
individual components of the Disk, drawer, and filename to the FileIO's
respective buffers, and sets the FILEIO_FILESIZE and FILEIO_FREEBYTES
fields accordingly. (i.e. If the path turns out to be a drawer or disk
only, then FileIO's Filename is NULLED and FileSize = 0. If a non-existant
file, it copies the Filename to FileIO, but FileSize = 0. If it is a
loadable file, it copies the Filename and sets FileSize accordingly.)
The parsed result is placed into the FileIO's Buffer (cannot be the same
buffer as the passed string).
This is useful for processing the initial argv argument passed to
_main for the StartUp code. It will initialize the FileIO buffers to
this passed name, and set-up the FileSize and Filename buffer so that
it can be determined what kind of object this is. Also, it makes it
possible to use the same load routine for the initial passed argv as
you would for DoFileIO() or TypeFilename(). For Basic programmer's this
can be used to set up the FileIO based upon a string gotten via an Input
statement.
******************* AddEntry(), NewEntryList() ***********************
NAME
AddEntry - For adding a string to a list to be displayed by the FileIO
SYNOPSIS
AddEntry(ID_num, String, FileIO)
d1 a0 a1
INPUTS
The FileIO structure
The address of the NULL-terminated string to be added
A ULONG (or LONG if you define it that way) that is associated with the
string
FUNCTION
When the SPECIAL_REQ flag of the FileIO is set, then DoFileIO() and DoFile-
IOWindow() no longer do disk operations. Instead, the FileIO operates on a
list of strings which you create via AddEntry().
NewEntryList() deletes any list associated with the FileIO.
This returns the same values as DoFileIOWindow() plus a -2 if some other
task is using the FileIO requester.