/* * STDFILE -- Standard File Requestor. Version 2.0a 15 June 1987 * * AUTHOR -- Peter da Silva US (713) 497-4372 * * Reorganized by Matthew Dillon for use with * and ?. Added: * -device name in File string gadget transfered to directory * gadget without closing the window. * -bug when requesting volume ""... current directory lock would * get unlocked! * -additional intuitive features added * -coding reorganized * * Copyright (c) 1987 Peter da Silva, all rights reserved. * Changes (c)Copyright 1987 Matthew Dillon, all rights reserved. * * This module may be freely used in any product, commercial or * otherwise, provided credit is given for this module and * and provided this notice remains intact in the source. The * intent of this module is to provide a standard file requestor * such as is available on the Macintosh, in GEM on the IBM-PC * and Atari ST, and in the Microsoft Windows software on the * IBM-PC. The advantage this module has over other requestors * is that it minimises disk accesses: an important consideration * given the structure of AmigaDos directories. If you need to * modify it for your needs, by all means go ahead... but please * conform to the intent of this program as stated above. If you * have suggestions for improvements, by all means call me at * the number listed above. * * Enhancements in the current version: * * Gadgets now boxed. Display generally cleaned up. * * True "dictionary order" for searches. * * Default pattern can now be specified. Default file name now * specified in a single argument. * * Directories always match. * * Null pattern converted to "#?" universal wildcard. * * If you attempt to build a file name longer than 128 characters the * screen will flash and the operation will be aborted. * * "Volumes" gadget, using the device list code in "mounted". This * gadget brings up a list of all currently mounted volumes for * selection. Volumes leaves the directory specification intact, so * you can quickly return to where you left off. * * With these enhancements it is now possible to select any file on * any device without touching the keyboard. This is now release 2.0, * as it is significantly better than 1.0. * * Acknowledgements: * * Thanks to Jeff Lydiatt for the pattern matching code in PatMatch.c * Thanks to Jay Miner, =RJ= and the whole Amiga team for the Amiga * itself. * * Environment: * * IntuitionBase and GfxBase must be open. dos.library must be open * under the name "DosLibrary". Link with PatMatch.o and VolList.o. * * Usage: * * #define MAXFILENAME 128 * * int stdfile(title, default_file, default_pat, name); * char *title; * char *default_file; * char *default_pattern; * char name[MAXFILENAME]; * * +-----------------------------------+ * |o| Title ------------------- | | | title parameter, or "File Name" * |-----------------------------------| * | Directory: [ ] | Directory parameter, or current. * | File name: [ ] | Default parameter, or empty. * | Pattern: [ ] | Initially empty, if the user * | +-------------------------------+ | enters anything here it will * | | [Filename] | | | be used to select files. The * | | [Filename] | | | file display will also be empty * | | [Filename] |@@| | to start with to avoid excess * | | [Filename] |@@| | disk I/O. If the user selects * | | |@@| | here the directory will be * | | |@@| | scanned looking for files * | | | | | matching the specified pattern, * | | | | | or "*" if no pattern is given. * | | | | | * | +-------------------------------+ | ACCEPT returns 1. CANCEL * | [ACCEPT] [VOLUMES] [CANCEL] | or the close gadget return 0. * +-----------------------------------+ VOLUMES displays volume names. * * The number of filenames displayed is specified at compile time in the * constant MAXFILES. The maximum size of a filename is specified in the * constant MAXNAME. The parameter "Default file" will be broken into * directory and file parts. */ char *Copyright = "stdfile V2.0a. Copyright (c) 1987 Peter da Silva. All rights reserved."; #include #include #include #include #include typedef unsigned char ubyte; typedef unsigned short uword; typedef unsigned long ulong; typedef struct FileInfoBlock FIB; typedef struct DeviceList DEVLIST; typedef struct DosLibrary DOSLIB; typedef struct DosInfo DOSINFO; typedef struct RootNode ROOTNODE; typedef struct IntuiMessage IMESS; extern void CalcPropGadget(); extern void ProcessFileName(); extern void *malloc(); extern void *GetMsg(); extern struct Window *OpenWindow(); #define MAXFILES 8 #define MAXNAME 32 #define MAXFULL (MAXNAME*4) /* SIZING PARAMS */ #define Z NULL #define INDENT 6 #define LEFTMAR (INDENT-1) #define BORDER 3 #define CHSIZ 8 #define HT CHSIZ #define BASELINE 6 /* GADGET BORDERS */ #define IN1 LEFTMAR+10*CHSIZ #define IN3 LEFTMAR+3 #define IN4 -(INDENT+6*CHSIZ+1) #define IN5 -(INDENT+CHSIZ*2) #define IN6 ((WINWD-WD6)/2) #define WD1 -(INDENT+IN1) #define WD3 (6*CHSIZ) #define WD4 (6*CHSIZ) #define WD5 (CHSIZ*2+2) #define WD6 (7*CHSIZ) #define TP1 (CHSIZ+BORDER) #define TP2 (TP1+HT+1) #define TP3 (TP2+HT+1) #define TP4 -(BORDER+HT4-1) #define TP5 (TP3+HT+BORDER) #define HT4 (HT+1) #define HT5 CHSIZ*MAXFILES+INDENT #define WINHT (TP5 + HT5 + (-TP4) + BORDER) #define WINWD (INDENT*4 + (MAXNAME+2)*CHSIZ) #define WININ (640-WINWD)/2 #define WINTP (200-WINHT)/2 #define HOMEX (INDENT+LEFTMAR) #define HOMEY (TP5+BORDER) #define LASTX (HOMEX+MAXNAME*CHSIZ) #define LASTY (HOMEY+MAXFILES*CHSIZ) #define BTP TP5 #define BIN LEFTMAR #define BWD (WINWD-INDENT-BIN) #define BHT (WINHT-BTP-(-TP4+BORDER+1)) #define SF GADGHCOMP|GRELWIDTH #define SEL SELECTED #define BF1 GADGHCOMP|GRELBOTTOM #define BF2 GADGHCOMP|GRELBOTTOM|GRELRIGHT #define PF GRELRIGHT #define SA RELVERIFY #define CEN STRINGCENTER #define BA RELVERIFY #define PA RELVERIFY #define SI(n) (APTR)&STD_String[n] #define G(n) &STD_Gadget[n] #define IMAG (APTR)&STD_Image #define PROP (APTR)&STD_Prop #define SG STRGADGET #define BG BOOLGADGET #define PG PROPGADGET #define FP AUTOBACKPEN #define BP AUTOFRONTPEN #define OKTEXT &STD_OK #define NOTEXT &STD_CANCEL #define VLTEXT &STD_VOLUME static int DoneFlag; #define DirName SBuffer[0] #define FileName SBuffer[1] #define PatName SBuffer[2] #define STRINGS 3 static UBYTE SBuffer[STRINGS][MAXFULL]; static UBYTE Undo[MAXFULL]; static struct StringInfo STD_String[STRINGS] = { {SBuffer[0],Undo,0,MAXFULL,0}, {SBuffer[1],Undo,0,MAXFULL,0}, {SBuffer[2],Undo,0,MAXFULL,0} }; static struct PropInfo STD_Prop = { AUTOKNOB|FREEVERT, 0, 0, 0, 0 }; static struct IntuiText STD_OK = { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"ACCEPT", Z }; static struct IntuiText STD_CANCEL = { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"CANCEL", Z }; static struct IntuiText STD_VOLUME = { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"VOLUMES", Z }; #define BUTTONS 3 #define BUTVEC 8 static SHORT butvecs[BUTTONS][BUTVEC*2] = { { -2, HT4, -2, -1, WD3+1,-1, WD3+1,HT4, -3, HT4, -3,-1, WD3+2,-1, WD3+2, HT4 }, { -2, HT4, -2, -1, WD4+1,-1, WD4+1,HT4, -3, HT4, -3,-1, WD4+2,-1, WD4+2, HT4 }, { -2, HT4, -2, -1, WD6+1,-1, WD6+1,HT4, -3, HT4, -3,-1, WD6+2,-1, WD6+2, HT4 } }; static struct Border ButBorder[BUTTONS] = { {0, 0, FP, BP, JAM1, BUTVEC, butvecs[0], NULL}, {0, 0, FP, BP, JAM1, BUTVEC, butvecs[1], NULL}, {0, 0, FP, BP, JAM1, BUTVEC, butvecs[2], NULL} }; #define BB(n) (APTR)&ButBorder[n] static struct Image STD_Image; #define DIRID 0 #define FILID 1 #define PATID 2 #define YESID 3 #define CANID 4 #define VOLID 5 #define BARID 6 #define GADGETS 7 static struct Gadget STD_Gadget[GADGETS] = { /*NEXT, LFT, TP,WDTH, H, FLAG, ACT, TYP, REND, Z, TXT, Z, SPEC, ID, Z */ { G(1), IN1,TP1, WD1,HT, SF, SA, SG, Z, Z, Z, Z, SI(0), 0, 0 }, { G(2), IN1,TP2, WD1,HT, SF|SEL, SA, SG, Z, Z, Z, Z, SI(1), 1, 0 }, { G(3), IN1,TP3, WD1,HT, SF, SA, SG, Z, Z, Z, Z, SI(2), 2, 0 }, { G(4), IN3,TP4, WD3,HT4,BF1, BA, BG,BB(0), Z, OKTEXT, Z, Z, 3, 0 }, { G(5), IN4,TP4, WD4,HT4,BF2, BA, BG,BB(1), Z, NOTEXT, Z, Z, 4, 0 }, { G(6), IN6,TP4, WD6,HT4,BF1, BA, BG,BB(2), Z, VLTEXT, Z, Z, 5, 0 }, { NULL, IN5,TP5, WD5,HT5,PF, PA, PG, IMAG, Z, Z, Z, PROP, 6, 0 } }; static struct NewWindow STD_NewWindow = { WININ, WINTP, WINWD, WINHT, -1, -1, REFRESHWINDOW|MOUSEBUTTONS|GADGETUP|CLOSEWINDOW, WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SIMPLE_REFRESH|ACTIVATE, G(0), NULL, (ubyte *)"File Name Requestor", NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN }; static struct Window *STD_Window; #define NVEC 6 static SHORT Vectors[NVEC*2] = { BIN+1, BTP, BIN+1, BTP+BHT, BIN+BWD, BTP+BHT, BIN+BWD, BTP, BIN, BTP, BIN, BTP+BHT }; static struct Border STD_FileBox = { 0, 0, FP, BP, JAM1, NVEC, Vectors, NULL }; static struct IntuiText STD_Text[3] = { { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Directory:", NULL }, { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"File Name:", NULL }, { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Pattern:", NULL } }; static OpenFileWindow() { extern struct IntuitionBase *IntuitionBase; int i; /* Rebuild gadget list */ STD_NewWindow.FirstGadget = &STD_Gadget[0]; for(i = 0; i < GADGETS; i++) STD_Gadget[i].NextGadget = (i==GADGETS-1)?(0):(&STD_Gadget[i+1]); for(i = 0; i < STRINGS; i++) { STD_String[i].BufferPos = strlen(SBuffer[i]); STD_String[i].DispPos = 0; } STD_Prop.VertBody = 0xFFFF; STD_Prop.VertPot = 0; if (!(STD_Window = OpenWindow(&STD_NewWindow))) return(0); /* This optional line will activate a string gadget */ if (IntuitionBase->LibNode.lib_Version > 32) ActivateGadget(G(1),STD_Window,0L); CalcPropGadget(); PaintFileWindow(); return (1); } static CloseFileWindow() { STD_NewWindow.LeftEdge = STD_Window->LeftEdge; STD_NewWindow.TopEdge = STD_Window->TopEdge; if (STD_Window) CloseWindow(STD_Window); } static int State; #define INITIAL 0 #define DIRECTORY 1 static PaintFileWindow() { DrawBorder(STD_Window->RPort, &STD_FileBox, 0, 0); PrintIText(STD_Window->RPort, &STD_Text[0], LEFTMAR, TP1); PrintIText(STD_Window->RPort, &STD_Text[1], LEFTMAR, TP2); PrintIText(STD_Window->RPort, &STD_Text[2], LEFTMAR, TP3); if (State == DIRECTORY) PrintFileNames(); } static int FirstFile; static int Selected; static int NumFiles; static struct dirent { struct dirent *nextfile; SHORT filetype; char *filename; } *NameList, **NameTable; #define FILETYPE 0 #define DIRTYPE 1 #define VOLTYPE 2 static PrintFileNames() { int i; for (i = 0; i < MAXFILES; ++i) { SetBPen(STD_Window->RPort, BP); SetAPen(STD_Window->RPort, BP); RectFill(STD_Window->RPort, HOMEX, HOMEY+i*CHSIZ, LASTX, HOMEY+(i+1)*CHSIZ); if (i+FirstFile < NumFiles) PrintName(i+FirstFile, i+FirstFile == Selected); } } static PrintName(file, hilite) int file; int hilite; { int i; i = file - FirstFile; Move(STD_Window->RPort, HOMEX, HOMEY+i*CHSIZ+BASELINE); if (hilite == 0) { SetBPen(STD_Window->RPort, BP); if(NameTable[file]->filetype == FILETYPE) SetAPen(STD_Window->RPort, FP); else SetAPen(STD_Window->RPort, 3); } else { SetAPen(STD_Window->RPort, BP); if(NameTable[file]->filetype == FILETYPE) SetBPen(STD_Window->RPort, FP); else SetBPen(STD_Window->RPort, 3); } Text(STD_Window->RPort, NameTable[file]->filename, strlen(NameTable[file]->filename)); } static void CalcPropGadget() { int VertPot, VertBody; if (State == INITIAL) return; if (NumFiles <= MAXFILES) { VertBody = 0xFFFF; VertPot = 0; FirstFile = 0; } else { VertBody = ((MAXFILES<<16)-1) / NumFiles; VertPot = 0; FirstFile = 0; } ModifyProp(&STD_Gadget[BARID], STD_Window, NULL, STD_Prop.Flags, 0, VertPot, 0, VertBody ); } static void CalcFilePosition() { short old_pos; if (State == INITIAL) return; old_pos = FirstFile; if (NumFiles<=MAXFILES) { FirstFile = 0; } else { int VertPot = STD_Prop.VertPot; FirstFile = ((VertPot+1)*(NumFiles-MAXFILES))>>16; } if (old_pos != FirstFile) PrintFileNames(); } FreeList(list) struct dirent *list; { struct dirent *ptr; while(list) { ptr = list->nextfile; if (list->filename) free(list->filename); free(list); list = ptr; } } static ReadNewDir() { struct dirent *NewList, **NewTable, *ptr; int NewCount; FIB *fib; BPTR dirlock; if (State != DIRECTORY) { NameTable = 0; NameList = 0; } if (DirName[0]) { dirlock = Lock(DirName, ACCESS_READ); } else { BPTR ram; if (ram = Lock("RAM:", ACCESS_READ)) { dirlock = CurrentDir(ram); CurrentDir(dirlock); dirlock = DupLock(dirlock); /* added */ UnLock(ram); } } if (!dirlock) return(0); if ((fib = (FIB *)malloc(sizeof(FIB))) == NULL) { UnLock(dirlock); return 0; } if (!Examine(dirlock, fib)) { UnLock(dirlock); free(fib); return 0; } if (fib->fib_DirEntryType < 0) { UnLock(dirlock); free(fib); return 0; } NewList = 0; NewCount = 0; while(ExNext(dirlock, fib)) { NewCount += 1; ptr = (struct dirent *)malloc(sizeof(struct dirent)); if (ptr == 0) { FreeList(NewList); UnLock(dirlock); free(fib); return(0); } ptr->nextfile = NewList; ptr->filetype = (fib->fib_DirEntryType<0)?FILETYPE:DIRTYPE; ptr->filename = malloc(strlen(fib->fib_FileName)+1); if (ptr->filename == 0) { FreeList(ptr); UnLock(dirlock); free(fib); return(0); } strcpy(ptr->filename, fib->fib_FileName); NewList = ptr; } free(fib); if (DirName[0]) UnLock(dirlock); NewTable = malloc(sizeof(struct dirent *) * NewCount); if (NewTable==0) { FreeList(NewList); return(0); } FreeList(NameList); NameList = NewList; if (NameTable) free(NameTable); NameTable = NewTable; if (PatName[0]==0) SetPatName("*"); State = DIRECTORY; Selected = -1; ReCalcPattern(); } static ReadVol() { struct dirent *NewList, **NewTable, *ptr; int NewCount; char name[MAXNAME]; if (State != DIRECTORY) { NameTable = 0; NameList = 0; } OpenVolList(); NewList = 0; NewCount = 0; while(ReadVolList(name)) { if (strcmp(name, "RAM Disk:") == 0) strcpy(name, "ram:"); NewCount += 1; ptr = (struct dirent *)malloc(sizeof(struct dirent)); if (ptr==0) { FreeList(NewList); return(0); } ptr->nextfile = NewList; ptr->filetype = VOLTYPE; ptr->filename = malloc(strlen(name)+1); if (ptr->filename == 0) { FreeList(ptr); return(0); } strcpy(ptr->filename, name); NewList = ptr; } CloseVolList(); NewTable = malloc(sizeof(struct dirent *)*NewCount); if (NewTable==0) { FreeList(NewList); return(0); } FreeList(NameList); NameList = NewList; if (NameTable) free(NameTable); NameTable = NewTable; if (PatName[0]==0) SetPatName("*"); State = DIRECTORY; Selected = -1; ReCalcPattern(); } /* this routine does a true dictionary search: * * Devs < devs but Devs > devices */ static table_compare(p1, p2) struct dirent **p1, **p2; { char *s1, *s2; char c1, c2; char firstdiff; s1 = (*p1)->filename; s2 = (*p2)->filename; firstdiff = 0; while(*s1 && *s2) { c1 = *s1++; c2 = *s2++; if (firstdiff==0) firstdiff = c1 - c2; if (c1 >= 'A' && c1 <= 'Z') c1 = c1+'@'; if (c2 >= 'A' && c2 <= 'Z') c2 = c2+'@'; if (c1 != c2) return c1 - c2; } return firstdiff; } static sort_table() { qsort(NameTable, NumFiles, sizeof(struct dirent *), table_compare); return 1; } static ReCalcPattern() { if (State != DIRECTORY) { ReadNewDir(); } else { struct dirent *ptr; if (!PatName[0]) SetPatName("*"); NumFiles = 0; for (ptr = NameList; ptr; ptr=ptr->nextfile) { /* Directories always match. Is this good? */ if (ptr->filetype == DIRTYPE || ptr->filetype == VOLTYPE || newwildcmp(PatName, ptr->filename)) { NameTable[NumFiles] = ptr; NumFiles++; } } sort_table(); CalcPropGadget(); Selected = -1; PrintFileNames(); } } static SetGadgetText(id, text) int id; char *text; { int position; position = RemoveGadget(STD_Window, G(id)); if (position != -1) { strcpy(SBuffer[id], text); STD_String[id].BufferPos = strlen(text); position = AddGadget(STD_Window, G(id), -1); if (position != -1) RefreshGadgets(G(id), STD_Window, NULL); } } static SetDirName(name) char *name; { char buffer[MAXFULL+1], *ptr; int index; char lastchar; /* Can't enter a file name too long. */ if (strlen(DirName) + strlen(name) + 1 > MAXFULL) { DisplayBeep(); return(0); } index = 0; lastchar = 0; for (ptr = (char *)DirName; *ptr; ptr++) buffer[index++] = lastchar = *ptr; if (lastchar != ':' && lastchar != 0) buffer[index++] = '/'; strcpy(&buffer[index], name); SetGadgetText(DIRID, buffer); SetGadgetText(FILID, ""); return(1); } static SetFileName(name) char *name; { /* Can't enter a file name too long. */ if (strlen(DirName) + strlen(name) + 1 > MAXFULL) { DisplayBeep(); return(0); } SetGadgetText(FILID, name); return(1); } static SetPatName(name) char *name; { SetGadgetText(PATID, name); } static ProcessGadget(id) int id; { switch(id) { case DIRID: ReadNewDir(); break; case FILID: ProcessFileName(); break; case PATID: ReCalcPattern(); break; case BARID: CalcFilePosition(); break; case YESID: DoneFlag = 1; break; case CANID: DoneFlag = -1; break; case VOLID: ReadVol(); break; } } /* * ProcessFileName() added by Matthew Dillon. If the requested file is * actually a directory, do a ReadNewDir() instead of quiting. */ void ProcessFileName() { register char *ptr; register short len; BPTR fillock; char buf[128]; FIB *fib = (FIB *)malloc(sizeof(FIB)); if (fib == NULL) { DoneFlag = 1; return; } for (ptr = (char *)FileName; *ptr; ++ptr) { if (*ptr == ':') { DirName[0] = '\0'; break; } } strcpy(buf, DirName); if (FileName[0]) { if (len = strlen(buf)) { if (buf[len-1]!=':') strcat(buf, "/"); } strcat(buf, FileName); if (fillock = Lock(buf, ACCESS_READ)) { if (Examine(fillock, fib)) { if (fib->fib_DirEntryType > 0) { SetGadgetText(DIRID, buf); SetGadgetText(FILID, ""); ReadNewDir(); free(fib); UnLock(fillock); return; } } UnLock(fillock); } } free(fib); DoneFlag = 1; } static ProcessMouse(x, y, code, seconds, micros) { int NewSelected; static int oseconds = 0, omicros = 0; if (x < HOMEX || y < HOMEY || x >= LASTX || y >= LASTY) return; if ((code & SELECTUP) == SELECTUP) return; if (State != DIRECTORY) { ReadNewDir(); return; } NewSelected = (y-HOMEY)/CHSIZ + FirstFile; if (NewSelected == Selected) { if (Selected != -1) { if (DoubleClick(oseconds, omicros, seconds, micros)) { if (NameTable[Selected]->filetype == DIRTYPE) { if (SetDirName(NameTable[Selected]->filename)) ReadNewDir(); } else if (NameTable[Selected]->filetype == VOLTYPE) { SetGadgetText(DIRID, NameTable[Selected]->filename); SetGadgetText(FILID, ""); ReadNewDir(); } else if (!SetFileName(NameTable[Selected]->filename)) { Selected = -1; DoneFlag = 1; } } } } else { if (Selected != -1 && Selected >= FirstFile && Selected < FirstFile+MAXFILES) PrintName(Selected, 0); Selected = NewSelected; if (Selected >= NumFiles) { Selected = -1; } else { if (SetFileName(NameTable[Selected]->filename)) PrintName(Selected, 1); else Selected = -1; if (IntuitionBase->LibNode.lib_Version > 32) ActivateGadget(G(1),STD_Window,0L); } } oseconds = seconds; omicros = micros; } stdfile(title, deffile, defpat, name) char *title, *deffile, *defpat, *name; { IMESS *im; if(title) STD_NewWindow.Title = (UBYTE *)title; else STD_NewWindow.Title = (UBYTE *)"Enter File Name"; if (deffile) { int i; for (i = strlen(deffile)-1; i >= 0; --i) { if (deffile[i]==':' || deffile[i]=='/') { int hold; strcpy(FileName, &deffile[i+1]); if (deffile[i]==':') i++; hold = deffile[i]; deffile[i] = 0; strcpy(DirName, deffile); deffile[i] = hold; break; } } if (i < 0) { strcpy(FileName, deffile); DirName[0] = 0; } } else { DirName[0] = 0; FileName[0] = 0; } if (defpat) strcpy(PatName, defpat); else PatName[0] = 0; State = INITIAL; NameTable = 0; NameList = 0; if(!OpenFileWindow()) return(0); DoneFlag = 0; while (!DoneFlag) { Wait(1<UserPort->mp_SigBit); while(im = GetMsg(STD_Window->UserPort)) { switch(im->Class) { case CLOSEWINDOW: DoneFlag = -1; break; case MOUSEBUTTONS: ProcessMouse(im->MouseX, im->MouseY, im->Code, im->Seconds, im->Micros); break; case GADGETUP: ProcessGadget(((struct Gadget *)im->IAddress)->GadgetID); break; case REFRESHWINDOW: BeginRefresh(STD_Window); PaintFileWindow(); EndRefresh(STD_Window, 1); break; } ReplyMsg(im); } } CloseFileWindow(); FreeList(NameList); if (NameTable) free(NameTable); if (DoneFlag == 1) { int len; strcpy(name, DirName); if (FileName[0]) { if (len = strlen(name)) { if (name[len-1]!=':') strcat(name, "/"); } strcat(name, FileName); return(1); } } return(0); } /* * VOLLIST.C */ #define toAPTR(b) ((b)<<2) #define toBPTR(a) ((a)>>2) struct DeviceList *list; OpenVolList() { extern DOSLIB *DOSBase; ROOTNODE *root; DOSINFO *info; root = (ROOTNODE *)DOSBase->dl_Root; info = (DOSINFO *)toAPTR(root->rn_Info); list = (DEVLIST *)toAPTR(info->di_DevInfo); } ReadVolList(name) char *name; { register DEVLIST *next; while(list) { next = (DEVLIST *)toAPTR(list->dl_Next); if (list->dl_Type == DLT_VOLUME) { char *ptr; int count; ptr = (char *)toAPTR((BPTR)list->dl_Name); count = *ptr++; if (count > 30) count = 30; strncpy(name, ptr, count); name[count++] = ':'; name[count] = 0; list = next; return(1); } list = next; } return(0); } CloseVolList() { }