õR:¯èAs you probably already know; AmigaBasic SUCKS! It can't handle structures.N:¯èYet another shoddy Microsoft product. Actually, this is about the fifthM:¯èbasic program I've ever written. The other four were done in a 15 weekQ:¯ècourse some years back in college. I'm an assembly programmer, and usuallyP:¯èI don't touch this crap, but someone had to write an example. The code isP:¯èprobably not too efficient, but it's the first basic program I've writtenQ:¯èin years, the first in AmigaBasic, and was done in about 2 hours (I had toP:¯èread the AmigaBasic instruction book. Really.) I cannot begin to tell youK:¯èhow excruciating the AmigaBasic editor is to an assembly programmer.øƒ øÅ ,C¬ "Demo AmigaBasic program using the FileIO requester library." øÅ , <¬ "Literally hacked together by Jeff Glatt (dissidents)"MøÖ í :¯èIMPORTANT! All variables are longs (for the library calls)D:¯èrequester.bmap and exec.bmap must be in the current directoryøÌ "requester.library"øÌ "exec.library"øÔ øÕ () øÌ3øÔ øÕ () øÌ :¯èThese are in the FileIO lib.3øÔ øÕ () øÌ :¯èOther functions in the lib do<øÔ øÕ () øÌ :¯ènot return values, and so do not$øÔ øÕ  () øÌ :¯èneed declaringøÔ øÕ 5() øÌøÔ øÕ <() øÌøÔ øÕ =() øÌøÔ øÕ >() øÌøÔ øÕ ?() øÌøÔ øÕ @() øÌøÔ øÕ ª() øÌQ:¯èFirst we must get a buffer for the pathname. The FileIO's DoFileIOWindow()O:¯èwill copy the complete pathname there. The complete path looks just like:¯èa CLI line:C:¯è Diskname:TopDrawer/SubDrawer...etc...BottomDrawer/FilenameQ:¯èOf course, the user may only select a disk or drawer, but no filename, andO:¯èso the final "/Filename" will not be there. Also, the Filename might notO:¯èbe in any drawers, and so it will appear directly after the diskname. IfG:¯èthis format looks weird to you, you need to learn about the CLI.6:¯èWe'll get our buffer from Exec via AllocMem(). + ê  :  ê  : j ê Ê<ê(j,ì ) :¯èA buffer to copy the pathname to˜  ê  æ — ‰ N:¯èNow we need to get a buffer if we want to allow the user to utilize the:¯èextention match feature.† ê ƒê(†,ì )˜ ƒ ê  æ — ˆ > ê() :¯èGet the address of the FileIO structureW:¯èActually you don't need to pass the 0, but AmigaBasic seems to want something...?˜  ê  æ —  :¯è0 means that you don't have a FileIO.J:¯èSet the FileIO's Buffer field to our allocated PathBuffer's addressú‚  ìø,<ú‚  ìÞ,ƒ :¯èSet the address of the extention stringR:¯èSet the title that will displayed in the FileIO window. This can be changedO:¯èfor each call so that you might have the title read "Save File" during a!:¯èsave routine, for example.!I$ ê "FileIO Basic Example"ú‚  ìô,ø×(I$)O:¯èSet the fore pen, back pen, and draw mode for title bar routines to someM:¯èdefaults. We always need to do this in case the requester is in use byO:¯èanother program and we get automatic title bar file entry. To demo this,M:¯èrun this program twice simultaneously with one of them having the fileL:¯èrequester displayed. Note that the title bar entry appears in the 2ndQ:¯èwindow. This is because only 1 task can be displaying the FileIO requesterQ:¯èat a time. Other simultaneous calls get redirected to the title bar entry.#ø¤  ì, :¯èJAM2 DrawMode#ø¤  ì, :¯èPenA = Color1#ø¤  ì, :¯èPenB = Color0ø V$(Ê)ø $()ø l$()ø Z$(„);:  ê R:¯èFirst I'll demo 2 things you can do with the Flags field of the FileIO. TheS:¯èFileIO is a structure, and our variable name FileIO is just the start (base)Q:¯èof that structure (block of memory). We can access any field of the FileION:¯èby PEEKing and POKEing various fields. You should POKE a value into theR:¯èFileIO, and retrieve a value by PEEKing. Some fields are larger than 1 byteQ:¯èand you must use PEEKW, PEEKL, POKEW, POKEL. You need to know how far awayT:¯èthe field is from the base of the structure. The flags field is the the firstV:¯èfield, so to access it we PEEK or POKE to FileIO+0. The previous initializationQ:¯èwe did for the window title was at an offset of 244 from the base, and was>:¯èa LONGWORD (4 bytes). That's why I added the L to POKE.M:¯èSince the user can always set these features up for himself via the 10P:¯èfunctions keys (see the doc), normally you wouldn't bother with the FlagsL:¯èfield unless you had something particular in mind...but for a demo... øÅ ,Q:¯èSee if the user wants only those filenames that end in a certain extentionQ:¯èActually, the user can change this string after the requester opens via F4O:¯èso you should never assume that the returned filename will indeed end inV:¯èthis string. If the user changes it, he probably knows what he's doing. Ha, ha.Oš "Do you want only those filenames with a certain extention (y or n)";/$˜ /$ ëé "y" æ — 0=š "Type the extention, 14 chars max (i.e., .device)";1$2ê(1$)˜ 2 ê  æ — 0#˜ 2 é  æ — 0 :¯ètoo long7:¯èEnable the extention match feature of the FileIOAú  ì, :¯èTurn on extention match feature only4ú  ìâ,2 :¯èGet the length of the string3:¯èCopy the user string to the extention buffer” % ê  å  &$ ê 1$(%)* ê (&$)<˜ * é @ ñ * ë [ æ *ê*ì :¯èmust be lower caseø¤(ƒì%),* © % ø¤(ƒì2),— Œ 0:3:¯èOtherwise, at least suppress the .info filesú  ì,€Œ:,:¯èAsk about multiple filename selection(š "Multiple Filename selection";/$˜ /$ ëé "y" æ — 3* ê úƒ( ì)* ê * ò @ú( ì),*  ê 3:A ê( ,) :¯èdo the FileIO selection on WB screen A˜  ëé í æ — " :¯è-1 means the user selected CANCEL.'#$ ê "User selected CANCEL."ì…()aƒ 6(ø×(#$),øÃ(),) :¯è21 is the number of chars in Message$ not counting the CHR$(0) — ":Q:¯è0 means the FileIO window couldn't open due (probably due to lack of mem).Y:¯èToo bad! You'll have to get the filename some other way. Maybe an INPUT statement?%˜  ëé  æ — ( R:¯èMessage number 0 in the FileIO lib says "Out of memory for this operation"  ê (,øÃ())š "Type path: ";V$ƒ ‚( ,ø×(V$)) — k3(: :¯èWe got a selection from the user!N:¯èNow, our PathBuffer$ has the complete pathname of the last chosen item.Q:¯èThe FileIO's Filename buffer has just the Filename separated from the diskQ:¯èand drawer names (which are also separated into their own FileIO buffers)!N:¯èIf no multiple filename select, let's copy out each of these buffers soM:¯èthat we can print the separate pieces, plus copy the complete path. IfR:¯èmultiple select, the disk and drawer names are gotten from their respectiveO:¯èbuffers, but we'll call the FileIO function, RetrieveEntry(), to get and:¯èdisplay each filename. © ê %Y: :¯èCopy out all the drawers Z$ ê ""” % ê  å „* ê ø£( ì ì%)˜ * ê  æ — m&$ ê …(*)Z$ ê Z$ì&$ © %"m: :¯èCopy out the diskname l$ ê ""” % ê  å * ê ø£( ì¤ì%)˜ * ê  æ — k&$ ê …(*)l$ ê l$ì&$ © %k: $ ê ""˜  ê  æ — §© ê ª(ø³(©), )5˜ © ê  æ — Q :¯èNo more multiple filenames6:¯èget the fileEntry's EntryString (i.e. filename)° ê ú„(©ì)” % ê  å * ê ø£(°ìì%)˜ * ê  æ — «&$ ê …(*)$ ê $ì&$ © % «:V$ ê l$ ì Z$ ì $ — '§:*:¯èCopy out the Filename to Filename$.” % ê  å * ê ø£( ìì%)˜ * ê  æ — ¦&$ ê …(*)$ ê $ì&$ © %¦: V$ ê ""” % ê  å Ê* ê ø£(ì%)˜ * ê  æ — '&$ ê …(*)V$ ê V$ì&$ © % <': :¯èPrint out all the info available in the FileIO5:¯èdisplay our complete path in a requester firstƒ (ø×(V$),øÃ())øƒ øÅ ,7:¯èLet's print out the disk, drawers, and filename.¬ "The Diskname is ",l$!¬ "The Drawernames are ",Z$F¬ "The Filename is ",$ :¯èNote that there is no Filename if the+$:¯èuser selected only a disc or drawer.O:¯èLet's get the amount of free disk space on the disk that the user chose.O:¯èThis could be important if we were trying to save something to this diskP:¯èand there wasn't enough room. Also, if the user typed in a disc or drawerK:¯èthat didn't exist or he refused to place that disc in the drive, theC:¯èreturned default disc is ":" which is the current directory..¬ "Free disk space: ",ú„( ìì)," bytes."O:¯èNow if this is a loadable file, the FileIO has it's size. If it's only aR:¯èdisc name or dir, or the file doesn't exist, then the size = 0. If multipleP:¯èselect, then we need to examine the fileEntry's size. Note that we ignoreO:¯èwhatever the user may have typed in the Filename gadget, as we only careG:¯èabout displaying those filenames that he (multiple) clicked on. ˜  ê  æ — ¬­ ê ú„(°ì) — ¯¬:C2ê($) :¯èDid the user finally select a file?9˜ 2 ê  æ — L :¯èMust be a disk or drawer only ­ ê ú„( ìð)O˜ ­ ê  æ — ] :¯èAha! User typed in a Filename that doesn't yet exist¯:'¬ "Size of file: ",­," bytes."Q:¯è Now, you might want to do a load or save routine using this user selected[:¯è pathname. You can check the FileIO's FILE.BYTESIZE (FileIO+240) field to see if theP:¯è user actually selected an existing file, or typed in a new, non-existantP:¯è name. For example, say that the user selected a directory but not a file<:¯è within the directory. The returned pathname might be%:¯è DF0:SomeDrawerNameS:¯è In this case, the FILE.BYTESIZE field would be 0 and if you tried to "load"P:¯è the file, you would get a DOS error message. Likewise, if the user typesO:¯è in a non-existant file name, this field is also 0, but you can open theO:¯è file for writing (save). If the user's selected pathname is the name ofP:¯è an object file (not just a dir or disk), then this is the only time thatQ:¯è FILE.BYTESIZE will not be 0. In fact, it will be the size of the file. InP:¯è conclusion, if you were doing a load routine, you would do the following:¯è steps at this point:O:¯è 1). Check if there is some name in the FileIO's Filename field. If not,T:¯è this means that the user selected a disk or drawer only. Abort the load.N:¯è 2). Check to see if the FILE.BYTESIZE field is 0. If it is 0, then theQ:¯è user has typed in a file that doesn't exist (in whichever dir that heM:¯è finally chose). Display a message that says "File doesn't exist".Q:¯è 3). If the FILE.BYTESIZE is not 0, then you can open the file for readingQ:¯è and copy this many bytes into memory. Since AmigaBasic doesn't have aN:¯è facility for loading blocks of bytes, I recommend the DOS library.:¯è :¯è LIBRARY "dos.library"):¯è LIBRARY "intuition.library" ,:¯è DECLARE FUNCTION Open() LIBRARY,:¯è DECLARE FUNCTION Read() LIBRARY.:¯è DECLARE FUNCTION Write() LIBRARY +:¯è Filehandle=Open(BufferPtr,1005&).:¯è IF Filehandle <> 0 THEN GOTO GotIt Q:¯è Message$ = "Cannot locate this file!"+CHR$(0) 'Oops Can't find it.@:¯è CALL AutoMessageLen(SADD(Message$),WINDOW(7),24&):¯è GOTO BadLoad :¯èGotIt:):¯è CALL SetWaitPointer(WINDOW(7))":¯è Bytes=PEEKL(FileIO+240)E:¯è DIM DataBuffer(Bytes) 'read the file into this 1-D array>:¯è Result=Read(Filehandle,VARPTR(DataBuffer(0)),Bytes)!:¯è CALL Close(Filehandle)B:¯è CALL ClearPointer(WINDOW(7)) 'must have intuition open0:¯è IF Result = Bytes THEN GOTO GoodLoad W:¯è boolean=AutoFileMessage(2&,WINDOW(7)) 'tell the user that an error occured:¯è GOTO BadLoad:¯èGoodLoad:N:¯è You can now "pull out" data from DataBuffer as you need it (like weJ:¯è extracted data from FileIO except perhaps you might not want to0:¯è convert the value to ascii via CHR$).M:¯è If you were doing a save routine to disk, you would do the following:O:¯è 1). Check if there is some name in the FileIO's Filename field. If not,T:¯è this means that the user selected a disk or drawer only. Abort the save.P:¯è 2). Check if FILE.BYTESIZE is not 0. If not 0, inform the user that thisO:¯è file already exists and if you save using this name, you will writeP:¯è over the other file. Ask the user if he wants to do the save anyway.R:¯è 3). If FILE.BYTESIZE is 0, this file doesn't already exist. Check that theO:¯è free disk space is greater than the number of bytes that we want to@:¯è save, or else we'll run out of room during the save.:¯èN:¯è Let's say that you stored the data in a big 1-D array called DataTank8:¯è and the number of bytes you want to save is 32.:¯è:¯è Bytes=32&):¯è Filehandle=Open(BufferPtr,1006&)/:¯è IF Filehandle <> 0 THEN GOTO CreateIt P:¯è Message$ = "Cannot create the file!"+CHR$(0) 'Oops Can't save it.@:¯è CALL AutoMessageLen(SADD(Message$),WINDOW(7),23&):¯è GOTO BadSave':¯è CALL SetWaitPointer(WINDOW(7));:¯è Result=Write(Filehandle,VARPTR(DataTank(0)),Bytes):¯è CALL Close(Filehandle)&:¯è CALL ClearPointer(WINDOW(7)) -:¯è IF Result = Bytes THEN GOTO GoodSaveW:¯è boolean=AutoFileMessage(2&,WINDOW(7)) 'tell the user that an error occured:¯è GOTO BadSave:¯èGoodSave:H:¯èIf multiple filenames, go back to see if another one was selected˜  ê  æ — kQ:@#$ ê "This has been a test of the FileIO library." ì …())9$ ê "Do you want to retry?" ì …()*ê5(ø×(#$),ø×(9$),,øÃ())øƒ˜  ê  æ — ;I:¯èNote how the lib automatically spaces these messages symmetrically=#$ ê "Example program and asm lib by Jeff Glatt" ì …() 9$ ê "(dissidents)" ì …()/:$ ê "Original FileIO by RJ Mical" ì …()/ê5(ø×(#$),ø×(9$),ø×(:$),øÃ())  : ?ƒ P( ,øÃ()) :¯èMaybe we changed it for the error msgs.2ƒ ( ) :¯èFree the FileIO structure:ƒ (ƒ,†)ˆ:ƒ (,j) ‰: øÌ ‡øP:¯è For these 2 errors, let's see how the SetTitle function works. This willQ:¯è display in the window's title bar string1 followed by string2, but unlikeN:¯è a requester, returns control back to the program. When we finally callP:¯è ResetTitle, the original title is restored. We can call SetTitle withoutN:¯è needing a ResetTitle inbetween and vica versa. Notice how this messageQ:¯è appears in the window and requester title bars. Subsequent calls to theseM:¯è error routines (answer "Yes" to the again requester and cause anotherK:¯è error) will change the title bar further. Yet, when we finally callR:¯è ResetTitle upon exit, the initial title is restored. As you can see, theseR:¯è routines are good for posting error msgs that don't halt the program (likeF:¯è requesters) but remain visible for as long as they are needed.L:#$ ê "Dir only - "ì…()#:¯èString2 will be our Pathname&ƒ A(ø×(#$),ø×(V$), ,øÃ()) — Q]:*#$ ê "This file doesn't exist."ì…()M:¯èNote how we indicate that we don't want String2. You must have string1):¯èthough, even it were just a space.#ƒ A(ø×(#$),, ,øÃ()) — QDoFileIOWindowLIBRARYDECLAREDoFileIOSetWaitPointerGetFullPathname GetFileIO ReleaseFileIO ResetBuffer AutoMessageAutoFileMessageFileIObufferLIBinitResultenditbooleanSAD straddressaZCloseUpAllocMemMEMFPUBLICFilename BUFFERSIZE BufferPtrCloseUp1CloseUp2FreeMemCloseUp3 MEMF.PUBLIC MEMF.CLEARFILENAME.BUFFERSIZE CheckErrormessage PrintPathnameichar PrintPath GotPathnamelettervaluebytescopiedthe followingAnsSkipExtEXTextsizeDoIOdf0 AutoPrompt3AutoMessageLenminusendingMessage2Message3Again TypeFilename UserEntryPromptUserEntry GetRawkey DecodeRawkeySetTitleGetExtCanceledOTitleBarSkipSizeEXTFLAGnoExt WindowTitle defaults. DISC.ERROR DiscOrDir DiscErrorSetIt PRINTMessage ResetTitleRetry ClearTitleTitlewillcopyPathnamehere.we CopyDrawer DrawerNameCopyDiskDisknameNoExistexistin whicheverdirthathefinallychoseDisplaysays ExtraFilenameFILENAME.BUFSIZEBUFSIZECopyFNVolNameCopyVoldidndefaultiswhich.changeAnflagSpacesmaybeaboutexecute.verygood.way EXTENTIONMATCHfeaturewas implemented ParseStringExtPtrGOTDoneExtBUFSIZE2NoMemNoMem2NoMem1ADDmyvalueMultiple multNameshasjust separatedfromdiskdrawernameswhicharealsointotheirownbufferseachofthesesocanseparatepiecespluscompletepath.CopyPathRegNameRegPath fileEntry RetrieveEntryDoneFNRegSizemysizeChkSizeDoSizeentrystring filestring requesterfirst