Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!husc6!think!ames!ucbcad!zen!ucbvax!s.cc.purdue.edu!peter
From: peter@sugar.UUCP (Peter DaSilva)
Newsgroups: comp.sources.amiga
Subject: filerequestor example/template
Message-ID: <361@s.cc.purdue.edu>
Date: Sun, 28-Jun-87 17:33:38 EDT
Article-I.D.: s.361
Posted: Sun Jun 28 17:33:38 1987
Date-Received: Sun, 28-Jun-87 22:38:23 EDT
Sender: doc@s.cc.purdue.edu
Reply-To: doc@s.cc.purdue.edu (Craig Norborg)
Distribution: world
Organization: Purdue University Computing Center
Lines: 1401
Approved: doc@s.cc.purdue.edu
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 " 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
#include
#include
#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
#include
#include
#include
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=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=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<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
#include
#include
#include
#include
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
#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