Set your editor's TAB width to 3 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, point- ing 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 that you wanted o 3 string gadgets which allow you to type in the name directly rather than using the "Select a Name" list to choose the file that 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 (to the right of the box) which lets you quickly scan through the list of files o an up arrow gadget and a down arrow gadget (above and below the slider) 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 ">>>> Devs" which means that you can go into the drawer named "Devs". If you selected ">>>> Devs" you would see, after a short pause, a new list of file names: the names of the files that are in the "Devs" drawer. In the "Devs" 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 you name your drawers less than 30 characters 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 releas- ing, 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. 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. Note that all of your logical assigns are also displayed (i.e. LIBS, FONTS, etc.) If you wish to only see the actual disk names, press function key #5 while the requester is open. 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, although 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 of 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. If there is any text extending beyond the border of the window, you can scroll to it using the cursor keys. Holding the ALT 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. When you type any string into the NAME gadget, the extention will automatically be added. F5 - This toggles ON/OFF the facility for displaying the logical assigns in your system. A logical assign is the C: directory for example. This directory might be on your hard drive DH0:. If you toggle the assigns OFF, then you'll just see DH0: in the list of devices when you click the right mouse button. If you toggle assigns ON, then you'll see both C: and DH0: in the list. Remember that you can also choose to use the volume or device names (as toggled by F2). 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 - Alphabetize feature ON/OFF. When ON, the filenames are alphabetized in the display. When OFF, newer files are listed at the top of the display. 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 DoFileIO() is non-reentrant o Interpreting the return values of DoFileIO() o Internal Error Handling o Quick Display (NO_CARE_REDRAW) o Workbench-style Filename Operations o .Info File Suppression o Filtering by Extension o No Icon (.info) files o FileIO Flags o RAM Disk Bug o Free Disk Space o Procedure for Opening and Using the FileIO Requester library o Using the requester to display lists of strings o Filename and Custom Lists o Multiple Filenames o Installing Custom Handlers ========================== 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. If you use multiple FileIOs, when you go to free them, free the FileIO that you first used for disk IO last. (ie The first FileIO to be used with DoFileIO, DoFileIOWindow, ParseString, ParentPath, or ParentLock, without the SPECIAL_REQ flag set). ====================== 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, although 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, alt-right and alt-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 alternative to having a string gadget (which takes up window space and also requires allocating several structures), plus allows for displaying custom prompts. The user can scroll to any text beyond the boundaries of the window title bar borders. 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 values 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 deter- mine 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 file- name, 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, via DoFileIO perhaps). 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 I 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, you'll need to install a custom handler for DISKINSERTED events (see the section on Custom Handlers), and within this function you should clear the NO_CARE_REDRAW flag in all of your 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, etc). 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 placing a pointer to the ToolTypes text in the ToolTypes field of your FileIO structure. If this field is left zero, then the TOOLTYPES will be ignored. ====================== .Info File Suppression ========================= Setting the INFO_SUPPRESS flag is exactly the opposite of Workbench matching. All files that end in .info will be ignored, and are 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. For SPECIAL_REQ, the extention is ignored. ========================== 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 Setting this means that the filename data is NOT to be reconstructed before initially drawing the requester. The previous list is instead redrawn. 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. EXCLUDE_ASSIGNS If set, then when the list of device or volume names is displayed, no logical assigns appear in the list. Only the actual disk device names appear. The default is to allow logical assignments. Note that when you pre-initialize the fileIO's DiskName[], you should set the USE_DEVICE_NAMES and EXCLUDE_ASSIGNS to the desired values before calling DoFileIO(). For example, if you wish the file requester to open up displaying all of the files on DF0:, then set USE_DEVICE_NAMES, copy the string "df0:" into the DiskName[] buffer, clear the Drawer and FileName[], and call DoFileIO. If you want to display all the files in the LIBS: drawer, make sure that EXCLUDE_ASSIGNS is clear, copy "libs:" into the DiskName[], clear the Drawer and Filenames, and call DoFileIO. (USE_DEVICE_NAMES won't matter since logical assigns are added whether device or volumes names are displayed.) 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. Affects SPECIAL_REQ 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. The WBENCH_MATCH flag must also be set. MULTIPLE_FILES Set this flag for multiple filename selection. All selections must be in the same directory. You must examine the EntryFlags (selected bit) of each Entry structure to determine which files were selected. This flag cannot be changed by the user unless an application allows him to do so. Affects SPECIAL_REQ 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. Cannot be changed by the user. Affects SPECIAL_REQ NO_ALPHA When clear, the filenames are alphabetized in the display. When SET, newer files are listed at the top of the display. Affects SPECIAL_REQ SPECIAL_REQ Allows using the FileIO requester to display lists of strings not relating to disk drive operations. Cannot be changed by the user. =========================== 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. 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", 1L))) 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) /* the class field from an Intui Message */ { 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 you intend to use DoFileIO(). Initially, you might want to set the FileIO to open in the directory from where your application was invoked. You do this by passing a 0 to ParentLock(). Alternately, if you expect to receive an argument filename from the user (via Workbench or the CLI), you would use ParentPath() to set up the FileIO to that filename and complete path. 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 those 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 = JAM2; 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 */ } /* Else tell the user that he's about to overwrite */ } /* Error in entering filename (i.e. did not enter a 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 constructing 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 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 inter- action, 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 removed 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 (if DoFileIOWindow doesn't open, or the requester doesn't open). 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 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 alpha- betical order, unless you set the NO_ALPHA flag. With NO_ALPHA, each entry is added to the tail of the list.) ID_num is some value that you want associated 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). NOTE: Your strings must be limited to 192 bytes (counting the final null). The file requester only displays the first 29 bytes of the string. Furthermore, when the string is copied to the FileIO's Filename buffer, the size of that buffer is 192 bytes (ie Filename[192]) instead of 30 as with normal disk I/O. 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. Once you setup a FileIO's list, it remains this way until you perform NewEntryList, or use that FileIO for disk IO. You do not have to remake the same list everytime that you call DoFileIO. 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 continue. 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 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. ====================== Filename and Custom Lists ===================== The list of filenames (or custom list created via AddEntry) 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] I have redefined the Remember structure as a FileEntry structure since that is easier to reference: struct FileEntry { struct FileEntry *nextEntry; ULONG EntrySize; struct Entry *filePart; }; Don't use sizeof on these structures. The library makes them for you. The 3rd field of the Entry structure is a variable length, NULL-terminated string. This structure has been defined simply so that you can get access to the EntryID, EntryFlags, and EntryString. These structures are used for both custom lists and the list of filenames. For filenames, each filename has a FileEntry structure. Its EntryID is the filesize. Bit #7 of the EntryFlags is set if the filename was selected by the user. The EntryString is the NULL-terminated filename (separated from its dir). When the SPECIAL_REQ flag is set, the Entry's EntryID is your passed ID to AddEntry(). All the FileEntry structures are linked together, and the FileIO's FileList field points to the first FileEntry in the list. You can use one FileIO to alternately display several custom 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; /* you stored the original value in the global ListAddr 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. ========================= Multiple Selections =========================== You can allow the user to make multiple selections from a custom list or the filename list by setting the FileIO's MULTIPLE_FILES flag. When the user clicks on a name, it will be highlighted. The user can then select more filenames, with all of them simultaneously selected. The library sets bit #7 of each selected file's Entry structure's EntryFlags. If a user clicks on a filename that is already selected, then the filename is de-selected. Note that double- clicking on a filename still can terminate the requester. The last selected name is the one that appears in the FileIO's FileName buffer. When the user double-clicks, or selects CANCEL or OK, the requester ends. At this point, you must go through the FileIO's FileList, examining each Entry structure's EntryFlags for bit #7 set to determine which files were selected. The caveat is that all files must be in the same directory because the Entry- String does not contain the full path, only the filename. (The path can be constructed with the FileIO's Disk and Drawer buffers. The best approach is to copy the filename to the FileIO's FileName buffer and then call GetFullPathname to add the FileIO's Disk and Drawers.) There is a library function to aid in locating the selected files: FileEntry = RetrieveEntry( FileEntryPtr, FileIO ); d0 a0 a1 FileEntryPtr should point to a FileEntry structure in the FileIO's FileList or be set to 0. If 0, this routine locates the first selected FileEntry structure in the FileList, updates the passed FileEntryPtr to point to that structure, and returns that address. The next time that this function is called, FileEntryPtr will not be 0, and so this function will return the next selected FileEntry structure, etc. When there are no more selected files, a 0 is returned and the FileEntryPtr is cleared. Another function: ClearEntries(FileIO); a1 clears the selected bit of all EntryFlags in the FileIO's FileList. This is useful for clearing selections after a custom list has been presented to the user, or for when the user has set NO_CARE_REDRAW. If the user types a filename directly into the Filename gadget, the library will NOT check if the filename is in the current list and set its selected bit if so. You can determine whether the filename exists in the current dir by the value of the FILEIO_FILESIZE field as before. For SPECIAL_REQ, the library DOES set the selected bit if the entered text is one of the displayed choises. Consult the examples for how to use MULTIPLE_FILES. ========================== 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 - (need not be saved) For GADGETUP and DOWN, the gadgetID For RAWKEY handler, the ascii value as returned from DecodeRawkey() 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. BOOL yourHandler(IAddress,Window,FileIO,MouseY,MouseX,Micros,Seconds,GadgID); Note that GadgID is the ascii value (UWORD) for the RAWKEY handler. 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 */ }; In assembly: HandlerBlock dc.l AddrOfStartCode dc.l AddrOfDiskInsertCode dc.l AddrOfGadgetCode dc.l AddrOfRawkeyCode dc.l AddrOfMouseMoveCode ============================================================================= === DEMO PROGRAM NOTES ====================================================== ============================================================================= This section briefly describes the demo programs that drive some of the FileIO Requester library's features. There are C, assembly, and AmigaBasic demos (no joke). If you invoke some of the C or asm demos without a second argument on the CLI, 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, TestFileIO.c, uses two FileIO structures to demonstrate the tech- niques that you should use when managing multiple FileIOs. The first FileIO structure, fileio1, is used in its default state as created by GetFileIO(). The other one, 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). CustomList.c demos setting up a custom list of strings. 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 Prompt- UserEntry() 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 that 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. Also of interest is the Multiple menu item which toggles MULTIPLE_FILES. With this on, note how several files can be clicked and selected. When you select OK, the asm example then prints out the pathbuffer, followed by all files selected. Note that the selected files do not contain the full path. The amigabasic demo, BasicFileIO 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. BasicList demos how to use the FileIO to display a list of your own strings. MultipleList and MultipleFile demo how to handle multiple selections for both filename and custom lists in BASIC. ============================================================================= === TECHNICAL REFERENCE ===================================================== ============================================================================= The FileIO files include: requester.library the actual library (slightly < 11K in size) FileIO.doc 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 TestFileIO.c a C example of filename selection CustomList.c a C example using SPECIAL_REQ TestFileIO.asm an assembly example of filename selection CustomList.asm an assembly example using SPECIAL_REQ StartUp.asm the startup code for the assembly examples TestFileIO an executable of the assembly filename example CustomList an executable of the assembly SPECIAL_REQ example BasicFileIO an AmigaBasic application of single filename selection BasicList an AmigaBasic demo of SPECIAL_REQ MultipleFileIO an AmigaBasic application of multiple filenames MultipleList an AmigaBasic demo of SPECIAL_REQ with multiple select requester.bmap the bmap file for AmigaBasic requester_lib.fd the fd file used to make the bmap file ================= 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: AddEntry() AddFileGadgs() AutoMessage() AutoMessageLen() AutoPrompt3() AutoFileMessage() BW_Restore() ClearEntries() DecodeRawkey() DoFileIO() ;only 1 task at a time DoFileIOWindow() ;only 1 task at a time FindName() GetFullPathname() GetFileIO() GetRawkey() IsEntryThere() NewEntryList() ParentLock() ParentPath() ParseString() PromptUserEntry() PutProjIcon() ReleaseFileIO() ResetBuffer() RetrieveEntry() SetWaitPointer() TypeFilename() UserEntry() Window_BW() ««««««««««««««««««««««««««« FILENAME FUNCTIONS »»»»»»»»»»»»»»»»»»»»»»»»»»»»»» *********************** DoFileIO(), DoFileIOWindow() ********************** 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 Clears the RMBTRAP bit of Window's Flags. ********************* FindName() ************************ NAME FindName -- Isolate the filename part from a complete pathname SYNOPSIS pathend = FindName(buffer,pathname); d0 a0 a1 FUNCTION Separates the filename part from the passed, complete pathname string. The pathname may contain drawer and disk names (i.e. df0:someDrawer/filename). The filename part is then copied to the passed buffer, and this is stripped from the pathname. INPUTS FileIO pathname - a pointer to a null-terminated path string RESULT Returns the address of the terminating null byte of pathname so that you can quickly append a new filename to this path (dir) ********************* 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. *********************** 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. *********************** ParentLock(), ParentPath() ************************* NAME ParentPath, ParentLock - Create an entire path from a filename or lock and parse it into the FileIO SYNOPSIS ParentPath(FileIO,Name) a0 a1 ParentLock(FileIO,Lock) a0 a1 INPUTS The FileIO structure The address of the NULL-terminated filename (for ParentPath) An amigaDOS lock (for ParentLock) FUNCTION These 2 functions recreate an entire path from just a filename or a lock. They are very useful for interpreting the args from Workbench or the CLI when your program is started. They create the entire path in the FileIO's Buffer, then call ParseString() to separate the components into the FileIO Filename, Drawername, and Diskname buffers, and set the FILEIO_FILESIZE and FREEBYTES. For example, assume that your program takes the following file- name arg from the CLI: 1> MyProg Let's assume that the user's current directory is a drawer in RAM: called "Blort". He runs your program as so: 1> MyProg MyName Now, how do you know where MyName is if the user didn't specify the entire path of RAM:blort/MyName? Well, you can pass the string that he did type to ParentPath() and your fileio buffer will be returned with that complete path (and the FILESIZE and FREEBYTES set accordingly). The fileIO FileName will contain "MyName", the DrawerName will be "blort", and the DiskName will be "RAM:". When the user calls up the file requester, this is how it will open. ParentLock() creates the entire path based upon a Lock. For example, some program sends you a lock on a file. You can create the entire path and parse it into the FileIO with this function. From WB, the user may click on the icon for the data file. You simply get the wa_Name from the arg for the data file and call ParentPath(). As a third example, you may wish to obtain the complete pathname for your program (ie tool name) since the user may have renamed it. You'll want to save icons with this tool name string. This is done with ParentPath in the same manner as with the data file examples. 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. Note that for non-existant paths or filenames, this will NULL out the path buffer. In such a case, it may be necessary to strip off the filename part using FindName, and call ParentPath with this new path. Then, you can reappend the filename part by copying it back to the FileIO FILENAME buffer, and calling GetFullPathname to finally recreate the complete path. All of this hassle is due to the fact that AmigaDOS, a very inadequate DOS, has no facility to easily obtain the complete working path of a CLI's current directory. (When is CBM going to fix this???) *********************** 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 can be used in place of the slower ParentPath() as long as you're sure that the complete path (including all dir levels) is part of the string. Otherwise, the FileIO is set up to default to the current directory. For example, if you wanted to check for the existance of a file without bringing up the requester, and you know the complete path, use this. ************************* 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 ;********************* 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. «««««««««««««««««««««««««« RAWKEY STRING INPUT »»»»»»»»»»»»»»»»»»»»»»»»»»»» ;*************************** DecodeRawkey() *************************** NAME DecodeRawkey() - Takes the passed RAWKEY Code and Qualifier and returns an ascii value based on the System KeyMap. SYNOPSIS value = DecodeRawkey(Qualifier, Code); d0 a1 FUNCTION Because there exists different Amiga keyboard configurations and alternate keymaps, there are only 2 proper methods for your program to translate user keystrokes into ascii chars: 1). Use the console device. 2). Use VANILLA_KEY IDCMP. The problem with #1 is that you have to deal with the console.device, IO blocks, and Function, cursor, and other keys being translated as character strings. Very UGLY!!!! The problem with #2 is that you don't receive Function, cursor, or Help keystrokes. Very unfriendly!!! This routine solves both pro- blems by managing the console device for you, and by "extending" the ascii char set, it defines single ascii values for each Function, cursor, and Help key. INPUTS Code - the code field of a RAWKEY IntuiMessage Qualifier - the qualifier field of a RAWKEY IntuiMessage RESULT The return is a UWORD (not a byte as is usually the case with ascii chars). This is because I have "extended" the ascii char set beyond hex FF in order to define values for the Function, cursor, and Help keys. A zero is returned if the key is undefined or if it is a KEYUP event. Plain Function keys return hex 100 to 109 for the 10 keys. The 4 cursor keys are hex 10A to 10D for UP, DOWN, RIGHT, and LEFT respectively. The Help key returns hex 10e. Shifted Function keys return hex 200 to 209. Shifted cursor keys are hex 20A to 20D. Shifted Help key is 20E. Alt Function keys are hex 400 to 409. All other keys (and combos) return whatever value the System KeyMap contains (except that all char strings are ignored and return 0). ;*************************** 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, $7F 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. 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 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. ««««««««««««««««««««««««««««««« CUSTOM LISTS »»»»»»»»»»»»»»»»»»»»»»»»»»»»»» ******************* AddEntry() *********************** NAME AddEntry - For adding a string to be displayed in the FileIO's FileList SYNOPSIS ID_num = AddEntry(ID_num, String, FileIO); d0 d1 a0 a1 INPUTS The FileIO structure The address of a NULL-terminated string to become the EntryString. 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's FileList is list of FileEntry structures which you create via AddEntry(). The passed string becomes the EntryString and the passed ID_num is the EntryID. RETURN This returns the passed ID_num if the string was added to the FileIO's FileList, or a -2 if no mem to add the string. ******************* ClearEntries() *********************** NAME ClearEntries - For de-selecting all of the FileIO FileList's FileEntries SYNOPSIS ClearEntries(FileIO); a1 INPUTS The FileIO structure FUNCTION This clears bit #7 of EntryFlags for all the FileEntry structures in the FileIO's FileList. This may be useful for clearing selections after you have processed MULTIPLE_FILES within a custom list (SPECIAL_REQ). RETURN NONE ************************ DeleteEntry() ************************** SYNOPSIS DeleteEntry( PrevEntry, DeleteEntry, FileIO) d1 a0 a1 INPUTS The FileIO structure Pointer to the entry (Remember structure) to remove Pointer to the entry before the entry to remove (Previous entry) FUNCTION Removes DeleteEntry from the list. Needs the PrevEntry which is the Remember struct preceding the one to be deleted from the linked list. This is used mostly in conjunction with RetrieveEntry() or IsEntryThere(). RETURN NONE ************************ FindDeleteEntry() ************************** SYNOPSIS FindDeleteEntry(String, FileIO) a0 a1 INPUTS The FileIO structure Pointer to the null-terminated string to find in the list and remove FUNCTION Searches the FileIO's list for the first instance of the string. Case- insensitive match. If found, it removes that Remember structure. RETURN NONE ******************* IsEntryThere() ********************** SYNOPSIS entrynum = IsEntryThere(String, FileIO) d0 a0 a1 INPUTS The FileIO structure Pointer to null-terminated string to find in the list RETURN Returns the FileEntry number whose string matches the passed string. (Case- insensitive). The numbers start from 0 with the first FileEntry structure in the FileList being 0. For example, if your string matches the third entry in the list, a 2 will be returned. A -1 is returned if the string is not in the list. Also, the address of the matching Remember structure is stored at the variable ThisEntry (in FileInterface.asm), and the previous Remember struct in the list is stored at the variable PrevEntry (or 0 if this is the head of the list). These two variables are used with DeleteEntry(). For asm programmers, these 2 are returned in a0 and d1. ******************* NewEntryList() *********************** NAME NewEntryList - For freeing any previous FileIO FileList and resetting the FileIO variables. SYNOPSIS NewEntryList(FileIO); a1 INPUTS The FileIO structure FUNCTION This deletes the FileIO's FileList (i.e. all of the FileEntry and Remember structures created with AddEntry). RETURN NONE ******************* RetrieveEntry() *********************** NAME RetrieveEntry - For locating the next selected FileEntry structure within the FileIO's FileList. (Used with MULTIPLE_FILES selection). SYNOPSIS FileEntry = RetrieveEntry(FileEntryPtr, FileIO); d0 a0 a1 INPUTS The FileIO structure A PTR (the address) to a FileEntry structure within the FileIO's FileList or a cleared PTR. FUNCTION When the MULTIPLE_FILES flag of the FileIO is set, then the library sets bit #7 of the EntryFlags of every FileEntry that the user selected. This routine helps you locate which files were selected, one at a time. The first time that you call this function, FileEntryPtr should be cleared so that the function will start at the first FileEntry in the FileIO's FileList. RETURN This routine updates FileEntryPtr to point to the next selected FileEntry structure, and returns this address. If there is no next selected file, a 0 is returned, and FileEntryPtr is cleared. If a FileEntryPtr not equal to 0 is returned, you can access the FileEntry's Entry structure to get the EntryID and EntryString. This are the FileSize and Filename, respectively. If SPECIAL_REQ set, these are the ID and string, respectively. Also, if the returned FileEntry is not the first in the list, the variable PrevEntry (in the module FileInter- face.asm which you link with your C code) is the address of the previous FileEntry. This may be used for DeleteEntry(). If the returned FileEntry is the head of the list, PrevEntry will be 0. For asm programmers, the PrevEntry address is returned in d1. «««««««««««««««««««««««««««««« MISC ROUTINES »»»»»»»»»»»»»»»»»»»»»»»»»»»»»» ************************* AddFileGadgs() **************************** NAME AddFileGadgs - Adds file gadgets to the requester (while opened) SYNOPSIS AddFileGadgs(Gadgets, window, requester); a0 a2 a5 FUNCTION This is used to add gadgets to the requester after it has opened. The most logical place to do this would be in a call to your custom StartHandler. To remove those gadgets later (while the requester is still open), pass a null (0) for Gadgets. The requester and window parameters are the same as the library passes to your custom vectors. NOTE: The library automatically removes any gadgets that you added when the requester disappears. ************************* 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". ******************** AutoMessage(), AutoMessageLen() ******************** 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 ************************ 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". ************************ PutProjIcon() ************************** NAME PutProjIcon - Like icon lib's PutIcon, but for image PROJECT icons only SYNOPSIS error = PutProjIcon(name, DiskObject); a0 a1 FUNCTION Most applications only need to save PROJECT icons as opposed to TOOL, or DRAWER icons. Furthermore, most programs save image as opposed to border icons. This routine is meant to replace the icon.library's PutIcon or PutDiskObject for those icons. If the only function in the icon library you use is PutIcon or PutDiskObject, you'll definitely want to get rid of your calls to an ugly, 6K C library and use this. You need to declare a DiskObject structure. Set the GADGHIMAGE bit of the imbedded Gadget's Flags field. The GadgetRender and SelectRender should point to initialized Image structs that point to the icon data and define its Width, Height, and Depth. Set do_DefaultTool to point to your NULL-terminated tool name, or NULL if no default tool. The do_ToolTypes and do_DrawerData must be 0. INPUTS name - the name of the icon file to create (the .info will be added later) DiskObject - an amigaDOS DiskObject structure RESULT Returns zero if successful. -1 if the icon couldn't be created. -2 if a write error (i.e. ran out of space on the disk). If an error occurs, the icon file is deleted. ************************ 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 ************************** 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 ************************** Window_BW() ************************* NAME Window_BW - Changes the window's colors 0 and 1 to black and white SYNOPSIS oldColors = Window_BW(window) d0 a0 SYNOPSIS If you present the file requester (or any of the auto-requesters) in a window where color #0 and #1 are very similiar, the text and graphics for the requester will be very difficult to distinguish from the background. This scenario is quite possible when loading an ILBM picture into a window and then bringing up the requester. Calling this function before DoFileIO() will result in your window colors #0 and #1 being changed to black and white. When the requester appears, it will be rendered in a satisfactory manner. Upon return from DoFileIO, you can then call BW_Restore to restore those colors to the original state. Basic users note that these functions are called Window.BW and BW.Restore for your use. RESULTS ULONG oldColors - the previous colors as a ULONG ************************** BW_Restore() ************************* NAME BW_Restore - Restores the window's colors 0 and 1 to oldColors SYNOPSIS BW_Restore(oldColors, window) d0 a0