peter@sugar.UUCP (Peter DaSilva) (06/29/87)
Here is a real nice file requestor example made by Peter DaSilva. Note that his makefile didn't work immediately for the following reasons, so I included one of my own called "makefile.manx". This can be found in this and in the lander program also written by him... -Craig Norborg comp.sources.amiga moderator >My makefile didn't work because I put "delete" in ram:c. make doesn't >do a path search for commands: they all have to be in c:. So my call >to delete to trash the old version of the file before making the new >one (to cut down on disk space during the make) would have failed on >you. I also supplied my own default rules for CC because I wasn't sure >I trusted Manx'. I have been burned with a make on the PC that had bad >default rules. # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # Xshar: Extended Shell Archiver. # This archive created: Sun Jun 28 16:15:52 1987 # By: Craig Norborg (Purdue University Computing Center) # Run the following text with /bin/sh to create: # makefile # makefile.manx # patmatch.c # readme # stdfile.c # test.c # vollist.c cat << \SHAR_EOF > makefile CFLAGS= -DTEST OFILES= stdfile.o PatMatch.o VolList.o CFILES= stdfile.c PatMatch.c VolList.c OTHERS= Makefile test readme SUFFIXES: .c .o .h c.o: @-ram:c/del $*.o cc $(CFLAGS) +P -S -B -DAMIGA $*.c test: stdfile.o PatMatch.o VolList.o @-ram:c/del test ln -o test stdfile.o PatMatch.o VolList.o -lcl32 stdfile.arc: $(CFILES) $(OTHERS) @-ram:c/del stdfile.arc arc a stdfile $(CFILES) $(OTHERS) print: $(CFILES) $(OTHERS) :pr $(CFILES) $(OTHERS) SHAR_EOF cat << \SHAR_EOF > makefile.manx CFLAGS= -DTEST +P -S -B -DAMIGA OBJ= stdfile.o PatMatch.o VolList.o test.o SRC= stdfile.c PatMatch.c VolList.c test.c OTHERS= Makefile readme test test: $(OBJ) ln -o test $(OBJ) -lcl32 stdfile.arc: ${CFILES} $(OTHERS) arc a stdfile $(CFILES) $(OTHERS) SHAR_EOF cat << \SHAR_EOF > patmatch.c /* PatMatch.c - Implements AmigaDos Regular Expression Pattern Matching. ** ** This program will test whether a string is an AmigaDos regular expression ** It may be used to implement wild expressions such as: ** ** "copy #?.c to <dir>" to copy any file ending in .c ** ** The program has two entry points: CmplPat, and Match. ** ** CmplPat - takes a pattern and returns an auxilliary integer vector ** which is used by Match. The pattern is not modified in ** any way. CmplPat returns 1 if no errors were detected ** while compiling the pattern; otherwise it returns 0; ** ** Match - takes the pattern, the auxilliary vector, and the string ** to be matched. It returns 1 if the string matches the ** pattern; otherwise it returns 0; ** ** Translated from BCPL by: ** Jeff Lydiatt ** Richmond B.C. Canada ** 16 May 1986. ** ** Source: "A Compact Function for Regular Expression Pattern Matching", ** Software - Practice and Experience, September 1979. ** ** Useage: ** To test if "file.c" matches the regular expression "#?.c" ** char *Pat = "#?.c"; ** char *Str = "file.c"; ** WORD Aux[128]; ** ** if ( CmplPat( Pat, Aux ) == 0 ) ** { ** printf("Bad Wildcard Expression\n"); ** exit(1); ** } ** if ( Match( Pat, Aux, Str ) == 1 ) ** printf("String matches the pattern\n"); ** else ** printf("String does NOT match the pattern\n"); **/ /*--- Included files ----*/ #include <stdio.h> #include <exec/types.h> #include <ctype.h> #define EOS '\0' /*--- Global Variables ---*/ static char Ch; /* The current character in Pattern */ static char *Pat; /* Pointer to the Pattern */ static int *Aux; /* Pointer to returned auxilliary vector */ static int PatP; /* Current position in Pat */ static int Patlen; /* strlen(pat) */ static BOOL Errflag; /* TRUE if error */ static int *Work; /* Pointer to Active work area */ static int Wp; /* Current position in work */ static BOOL Succflag;/* True if "str" matches "pat" */ /*----------------------------------------------------------------*/ /* The Interpreter */ /*----------------------------------------------------------------*/ static void Put(N) int N; { register int *ip; register int *to; if ( N == 0 ) Succflag = TRUE; else { for ( ip = &Work[ 1 ], to = &Work[ Wp ]; ip <= to; ip++) if ( *ip == N ) return; Work[ ++Wp ] = N; } } int Match( Pat, Aux, Str ) char Pat[]; int Aux[]; char Str[]; { int W[ 128 ]; int S = 0; int I, N, Q, P, Strlength; char K; int strlen(); void Put(); Work = W; Wp = 0; Succflag = FALSE; Strlength = strlen( Str ); Put( 1 ); if ( Aux[ 0 ] != 0 ) Put( Aux[ 0 ] ); for(;;) { /* First complete the closure */ for( N=1; N <= Wp; N++ ) { P = Work[ N ]; K = Pat[ P-1 ]; Q = Aux[ P ]; switch( K ) { case '#': Put( P + 1 ); case '%': Put( Q ); default : break; case '(': case '|': Put( P + 1); if ( Q != 0 ) Put( Q ); } } if ( S >= Strlength ) return Succflag; if ( Wp == 0 ) return FALSE; Ch = Str[ S++ ]; /* Now deal with the match items */ N = Wp; Wp = 0; Succflag = FALSE; for ( I = 1; I <= N; I++) { P = Work[ I ]; K = Pat[ P - 1 ]; switch( K ) { case '#': case '|': case '%': case '(': break; case '\'': K = Pat[ P ]; default : if ( _toupper( Ch ) != _toupper( K ) ) break; case '?': /* Successful match */ Put ( Aux[ P ] ); } /* End Switch */ } /* End For I */ } /* End for(;;) */ } /*----------------------------------------------------------------*/ /* The Compiler */ /*----------------------------------------------------------------*/ static void Rch() /* Read next character from Pat */ { if ( PatP >= Patlen ) Ch = EOS; else Ch = Pat[ PatP++ ]; } static void Nextitem() /* Get next char from Pat; recognize the ' escape char */ { if ( Ch == '\'' ) Rch(); Rch(); } static void Setexits( List, Val ) int List; int Val; { int A; do { A = Aux[ List ]; Aux[ List ] = Val; List = A; } while ( List != 0 ); } static int Join( A, B ) int A, B; { int T = A; if ( A == 0 ) return B; while ( Aux[ A ] != 0 ) A = Aux[ A ]; Aux[ A ] = B; return T; } static int Prim() /* Parse a Prim symbol */ { int A = PatP; char Op = Ch; int Exp(); void Setexits(), Nextitem(); Nextitem(); switch( Op ) { case EOS: case ')': case '|': Errflag = TRUE; default : return A; case '#': Setexits( Prim(), A ); return A; case '(': A = Exp( A ); if ( Ch != ')' ) { Errflag = TRUE; } Nextitem(); return A; } } static int Exp( AltP ) /* Parse an expression */ int AltP; { int Exits = 0; int A; int Prim(), Exits(), Join(); void Nextitem(), Setexits(); for (;;) { A = Prim(); if ( Ch == '|' || Ch == ')' || Ch == EOS ) { Exits = Join( Exits, A ); if ( Ch != '|' ) return Exits; Aux[ AltP ] = PatP; AltP = PatP; Nextitem(); } else Setexits( A, PatP ); } } int CmplPat( Pattern, CmplPattern) char Pattern[]; int CmplPattern[]; { int i, strlen(); void Rch(), Setexits(); Pat = Pattern; Aux = CmplPattern; PatP = 0; Patlen = strlen( Pat ); Errflag = FALSE; for ( i = 0; i <= Patlen; i++ ) Aux[ i ] = 0; Rch(); Setexits( Exp(0), 0 ); return (!Errflag); } SHAR_EOF cat << \SHAR_EOF > readme STDFILE is a module that can be linked with any Intuition based program to provide a standard file requestor. Documentation is provided in the source. The module "PatMatch" is a fast pattern matching routine written by Jeff Lydiatt of Richmond, British Columbia. He didn't provide a more precise address than that, I'm sorry. There are no copyright notices in his code, so I presume it's public domain. Mine, of course, has the usual selfserving "freeware" notice. If you want to deviate from the rather loose restrictions I impose, please give me a call... I'm sure I can be talked out of them. If you think my code is totally gross and you can do better, be my guest. I do the same thing myself (frex, this code doesn't contain a single line of code from anyone else's file requestors). -- Peter da Silva Houston, Texas 1987 Voice: Home (713) 497-4372 Data: Sugarland Fido (713) 933-2440 SHAR_EOF cat << \SHAR_EOF > stdfile.c /* STDFILE -- Standard File Requestor. Version 2.0a 15 June 1987 * * AUTHOR -- Peter da Silva US (713) 497-4372 * * Copyright (c) 1987 Peter da Silva, 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]; * * struct Screen *stdscreen; * * STDFILE puts up a file requestor (actually, it's a plain window) * in stdscreen. If stdscreen is NULL, the workbench screen is used. * The requestor looks like this (allowing for the limitations of * text): * * +-----------------------------------+ * |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 <intuition/intuitionbase.h> #include <intuition/intuition.h> #include <libraries/dos.h> #include <exec/memory.h> char *malloc(); #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) &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, "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->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 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 CalcFilePosition() { int 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; struct FileInfoBlock *FIB; BPTR dirlock; if(State != DIRECTORY) { NameTable = 0; NameList = 0; } if(DirName[0]) dirlock = Lock(DirName, ACCESS_READ); else { BPTR ram; ram = Lock("RAM:", ACCESS_READ); dirlock = CurrentDir(ram); CurrentDir(dirlock); UnLock(ram); } if(dirlock==0) return 0; /* FIB must be long word aligned, and aztec doesn't guarantee this, so: */ if((FIB = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC)) == 0) { UnLock(dirlock); return 0; } if(!Examine(dirlock, FIB)) { UnLock(dirlock); FreeMem(FIB, sizeof(struct FileInfoBlock)); return 0; } if(FIB->fib_DirEntryType < 0) { UnLock(dirlock); FreeMem(FIB, sizeof(struct FileInfoBlock)); 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); FreeMem(FIB, sizeof(struct FileInfoBlock)); 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); FreeMem(FIB, sizeof(struct FileInfoBlock)); return 0; } strcpy(ptr->filename, FIB->fib_FileName); NewList = ptr; } FreeMem(FIB, sizeof(struct FileInfoBlock)); 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)) { 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(); } static WORD PatCode[128]; static patcomp() { /* This is a judgement call: that no pattern should be equivalent to "#?". Perhaps it should do this invisibly, by adding a pointer to the real pattern name and making it PatName or "#?" as appropriate. */ if(!PatName[0]) SetPatName("#?"); return CmplPat(PatName, PatCode); } static patmatch(name) { return Match(PatName, PatCode, name); } /* 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; patcomp(); NumFiles = 0; for(ptr = NameList; ptr; ptr=ptr->nextfile) { /* Directories always match. Is this good? */ if(ptr->filetype == DIRTYPE || ptr->filetype == VOLTYPE || patmatch(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 = 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: DoneFlag = 1; break; case PATID: ReCalcPattern(); break; case BARID: CalcFilePosition(); break; case YESID: DoneFlag = 1; break; case CANID: DoneFlag = -1; break; case VOLID: ReadVol(); break; } } static ProcessMouse(x, y, code, seconds, micros) int x, y, code; { 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; } } oseconds = seconds; omicros = micros; } stdfile(title, deffile, defpat, name) char *title, *deffile, *defpat, *name; { 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()) { struct IntuiMessage *msg; DoneFlag = 0; while(!DoneFlag) { Wait(1<<STD_Window->UserPort->mp_SigBit); while(msg = GetMsg(STD_Window->UserPort)) { switch(msg->Class) { case CLOSEWINDOW: DoneFlag = -1; break; case MOUSEBUTTONS: ProcessMouse(msg->MouseX, msg->MouseY, msg->Code, msg->Seconds, msg->Micros); break; case GADGETUP: ProcessGadget( ((struct Gadget *)msg->IAddress)->GadgetID ); break; case REFRESHWINDOW: BeginRefresh(STD_Window); PaintFileWindow(); EndRefresh(STD_Window, 1); break; } ReplyMsg(msg); } } CloseFileWindow(); } else return 0; 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; } /* Here the user has accepted the name without providing a file name. I return true, but false may be more appropriate. What do you think? */ return 1; } return 0; } SHAR_EOF cat << \SHAR_EOF > test.c #include <intuition/intuitionbase.h> #include <intuition/intuition.h> #include <libraries/dos.h> #include <exec/memory.h> #include <stdio.h> struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct DosLibrary *DosLibrary; #define SECSPERDAY (60*60*24) #define SECSPERMIN 60 #define TICKSPERSEC TICKS_PER_SECOND #define MAXNAME 128 char *stdfile(); extern char *Copyright; main() { char name[MAXNAME]; if(!(IntuitionBase = OpenLibrary("intuition.library", 1))) { printf("Couldn't open intuition.library.\n"); exit(20); } if(!(GfxBase = OpenLibrary("graphics.library", 1))) { printf("Couldn't open graphics.library.\n"); CloseLibrary(IntuitionBase); exit(20); } if(!(DosLibrary = OpenLibrary("dos.library", 0))) { printf("Can't open dos.library\n"); CloseLibrary(IntuitionBase); CloseLibrary(GfxBase); exit(20); } printf("Testing STDFILE standard file requestor.\n%s\n", Copyright); name[0] = 0; while(stdfile("Display file", name, 0, name)) { BPTR stdlock; struct FileInfoBlock *stdfib; FILE *fp; long datestamp; int c; stdfib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC); if(!stdfib) { printf("Out of memory!\n"); break; } if(!(stdlock = Lock(name, ACCESS_READ))) { printf("Can't obtain lock for %s\n", name); FreeMem(stdfib, sizeof(struct FileInfoBlock)); continue; } if(!(Examine(stdlock, stdfib))) { printf("Can't examine %s\n", name); UnLock(stdlock); FreeMem(stdfib, sizeof(struct FileInfoBlock)); continue; } UnLock(stdlock); if(stdfib->fib_DirEntryType >= 0) { printf("%s is a directory.\n", name); FreeMem(stdfib, sizeof(struct FileInfoBlock)); continue; } if(!(fp = fopen(name, "r"))) { perror(name); FreeMem(stdfib, sizeof(struct FileInfoBlock)); continue; } datestamp = stdfib->fib_Date.ds_Days*SECSPERDAY + stdfib->fib_Date.ds_Minute*SECSPERMIN + stdfib->fib_Date.ds_Tick/TICKSPERSEC; printf("\n%s, %s\n", stdfib->fib_FileName, ctime(&datestamp)); while((c = getc(fp)) != EOF) putchar(c); fclose(fp); FreeMem(stdfib, sizeof(struct FileInfoBlock)); } CloseLibrary(IntuitionBase); CloseLibrary(GfxBase); CloseLibrary(DosLibrary); } SHAR_EOF cat << \SHAR_EOF > vollist.c #include <libraries/dosextens.h> #define toAPTR(b) ((b)<<2) #define toBPTR(a) ((a)>>2) struct DeviceList *list; OpenVolList() { extern struct DosLibrary *DosLibrary; struct RootNode *root; struct DosInfo *info; root = DosLibrary -> dl_Root; info = toAPTR(root->rn_Info); list = toAPTR(info->di_DevInfo); } ReadVolList(name) char name[32]; { struct DeviceList *next; while(list) { next = toAPTR(list->dl_Next); if(list->dl_Type == DLT_VOLUME) { char *ptr; int count; ptr = 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() { S][P, JA *D