[comp.sys.amiga.tech] File Requesters

karl@sugar.uu.net (Karl Lehenbauer) (10/28/88)

Speaking of file requesters, it's really nice when the file requester puts
the scroll bar back where it was (showing the same files) as the last time 
one was in the file requester.  This is great when using a requester to
access every file in a directory, as when listening to all the sounds in an
audio program's sound directory, for example.
-- 
-- "We've been following your progress with considerable interest, not to say
-- contempt."  -- Zaphod Beeblebrox IV
-- uunet!sugar!karl, Unix BBS (713) 438-5018

rap@rap.ardent.com (Rob Peck) (05/06/89)

Perry's posting about file requesters made me think just a little bit
about my own preferences on file requesters.

My BIGGEST problem with them is that all that I have seen thusfar
place the FIRST 8 (5, 7 10?) files in the directory as the available
choices and you have to scroll down to get to the file you want.
Often when I am transferring files and so on, I wanna do the files
in sequence, so the file requester should present me with my list
of files, with its pointer positioned WHERE I LAST LEFT IT.

Also related to that same topic, I'd like to see an option that could
be enabled to allow me to delete a file from a file requester, in
addition to all of the other things that the file requester does.
If using a re-entrant file requester, this option should be disable-able
on a per-task basis.  E.G. if I have transferred this file already,
I may want to remove it and therefore not see it in the requester
any more.

Third wish - cacheing of the file directory contents on a per-task
basis, so that it is not necessary to seek all over creation to
build the file list for the requester.  Especially if there are
120 file and so on in a single directory (strange practice, but
it happens).  Suggest that each task pass a pointer to a data
structure of some kind similar to this:

	#define NEWFILEDIR 0
	#define SEARCHFILE 1
	#define ENDFILEDIR 2

	struct FileDir {
		char *dir;	/* pointer to full pathname */
		char *dirlist;  /* pointer to first character of
				 * a string of filenames,
				 * each name a null-terminated string*/
		char *chosen;	/* pointer to the filename that was chosen
				 * or to a string that describes a directory
				 * for which a list is to be built */
		int pathsize;	/* size of the pathname string */
				/* (REDUNDANT, available from strlen) */
		int listsize;	/* size of the filename list */
		int chosensize; /* size of the chosen filename */
				/* (REDUNDANT, available from strlen) */
		int action;	/* what to do this time */
		int sliderpos;  /* where did I leave the slider? */
		struct DateStamp ds; /* when did we build this list */
	};

User allocates one of these data structures for EACH directory
he wishes to cache.  Then sends the address of this data structure
to the file requester.

(BEGIN PSEUDOCODE)

switch (pointer->action)

case NEWFILEDIR - (also to "reuse" an existing one, "pointer" is
			address of start of the data structure,
			does NOT present the file requester to the user)

	if (pointer->path != NULL) 
	    FreeMem(pointer->path, pathsize)
        if (pointer->dirlist != NULL)
	    FreeMem(pointer->dirlist, listsize)
		if chosen == NULL, build path string for CURRENT dir.
		else               build pathstring for CHOSEN dir.
	    pointer->path = AllocMem(sizeof(pathstring+TRAILING NULL)
	    COPY pathstring to pointer->path
	    pointer->pathsize = 1 + strlen(pointer->path)
	    BuildFileList()  [ searches files in chosen path,
				allocates memory for dirlist
				and sets listsize
				and sets datestamp
				and sets slider to first file]
	    return(0) if no errors along the way, else return error value

case SEARCHFILE
	See if file directory's last-modified date is later than
	the datestamp in the data structure.  If directory modified,
	do NEWFILE case, otherwise present the directory from the
	current dirlist. (No disk seeking -- super-speedy because
	the lists are already in memory) If user chooses a directory 
	rather than a file, modify everything in the structure and present 
	the information for that new directory instead.  When user chooses
	a file instead of a directory, return (0) and delete the file
	requestor.  Set sliderpos to have this file name at the top
	of the list the next time the requester is presented.
	User finds the chosen path in "path" and the
	file in "chosen".  Otherwise error code is the return value.

case ENDFILEDIR
	Deallocate everything "attached" to the passed in FileDir
	structure, and set the pointer values to NULL and the
	sizes to zero.

(END PSEUDOCODE)

The reason I propose something like this is then a program can
maintain as many "cached" directories as it wishes, and pass to the
file requester the pointer to the one it wants to choose from.

The above proposal may, of course, be incomplete, but I hope it
gives the re-entrant file requester writers something to think about.

And, for that matter, perhaps this pointer can be part of an AREXX
message so that we get the benefit of AREXX compatibility at the
same time.

Rob Peck			...uunet!ardent!rap

youngb@pur-ee.UUCP (H. Bret Young) (05/06/89)

From article <6342@ardent.UUCP>, by rap@rap.ardent.com (Rob Peck):
-> Perry's posting about file requesters made me think just a little bit
-> about my own preferences on file requesters.
-> 
-       [stuff deleted]
-> 
-> Third wish - cacheing of the file directory contents on a per-task
-> basis, so that it is not necessary to seek all over creation to
-> build the file list for the requester.  Especially if there are
-> 120 file and so on in a single directory (strange practice, but
-> it happens).  Suggest that each task pass a pointer to a data
-> structure of some kind similar to this:
-> 
-> 	#define NEWFILEDIR 0
-> 	#define SEARCHFILE 1
-> 	#define ENDFILEDIR 2
-> 
-> 	struct FileDir {
-> 		char *dir;	/* pointer to full pathname */
-> 		char *dirlist;  /* pointer to first character of
-> 				 * a string of filenames,
-> 				 * each name a null-terminated string*/
-> 		char *chosen;	/* pointer to the filename that was chosen
-> 				 * or to a string that describes a directory
-> 				 * for which a list is to be built */
-> 		int pathsize;	/* size of the pathname string */
-> 				/* (REDUNDANT, available from strlen) */
-> 		int listsize;	/* size of the filename list */
-> 		int chosensize; /* size of the chosen filename */
-> 				/* (REDUNDANT, available from strlen) */
-> 		int action;	/* what to do this time */
-> 		int sliderpos;  /* where did I leave the slider? */
-> 		struct DateStamp ds; /* when did we build this list */
-> 	};
-> 
-> User allocates one of these data structures for EACH directory
-> he wishes to cache.  Then sends the address of this data structure
-> to the file requester.
-> 
-> (BEGIN PSEUDOCODE)
->
-      [code deleted]
-> 
-> (END PSEUDOCODE)
-> 
-> The reason I propose something like this is then a program can
-> maintain as many "cached" directories as it wishes, and pass to the
-> file requester the pointer to the one it wants to choose from.
-> 
-> The above proposal may, of course, be incomplete, but I hope it
-> gives the re-entrant file requester writers something to think about.
-> 
-> And, for that matter, perhaps this pointer can be part of an AREXX
-> message so that we get the benefit of AREXX compatibility at the
-> same time.
-> 
-> Rob Peck			...uunet!ardent!rap

You know ... I was just thinking today that I wish I had file completion
in my ARP shell. I was trying to figure out a nice way to do this (i.e. fast)
when I read the above posting. Unless I am missing something, wouldn't the 
above method of cacheing file directories to get faster and better file
requestors also give as an immediate side effect the ability to implement
file completion with almost no extra cost. I like it. What do you think?

				Bret

ARPA:    youngb@eg.ecn.purdue.edu
UUCP:    youngb@pur-ee.uucp

papa@pollux.usc.edu (Marco Papa) (05/06/89)

The RJ Mical file requester seems to implement all of your requsted features
(caching, leaving pointer fixed among separate invocations).  One thing that I
really don't like (for example) of the new Arp1.3 file requester is the fact 
that each time I the programs call it, it recomputes the list of files  
again. Is this an inherent flaw of the file requester or of the application 
program that uses it?

-- Marco Papa 'Doc'
BTW, the RJ mical file requster is not reentrant but can be "multiply" 
instantiated.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
uucp:...!pollux!papa       BIX:papa       ARPAnet:pollux!papa@oberon.usc.edu
 "There's Alpha, Beta, Gamma and Diga!" -- Leo Schwab [quoting Rick Unland]
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

cmcmanis%pepper@Sun.COM (Chuck McManis) (05/06/89)

In article <6342@ardent.UUCP> rap@rap.ardent.com (Rob Peck) writes:
>         ...  Suggest that each task pass a pointer to a data
>structure of some kind similar to this:

You were doing great up until right here. Having designed a file requester
from scratch I thought about many of the same issues. The point I kept 
coming back to was :
	Q) What does a file requester replace ?
	A) A text exchange between user/program which requests a 
	   a filename and returns it.

This is a very simple operation. And to be effective should stay simple. 
Generally, some guidelines I had considered when looking at this :
	o Colors/Layout - There are two choices here, Tool Compatibile
		so that the requester has the same "look" as the rest
		of the tool, or User Preferred which is set up via some
		preferences mechanisim.

		The second case implies an out of band interface to the
		users preferences.

	o No clicking/sliding required. What we are replacing is :
		"enter filename :" with a sophisticated file selection`
		service. We shouldn't lose sight of the fact that 
		this original technique was quite functional. 

	o No worries about resource/directory/memory tracking. Let 
		the requester worry about that for me.

My ideal interface is :

	FileLock = Request("Prompt", DirLock, Access_mode);

Everything else should be handled inside the requester.

--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
These opinions are my own and no one elses, but you knew that didn't you.
"A most excellent barbarian ... Genghis Kahn!"

peter@sugar.hackercorp.com (Peter da Silva) (05/08/89)

In article <103440@sun.Eng.Sun.COM>, cmcmanis%pepper@Sun.COM (Chuck McManis) writes:
> This is a very simple operation. And to be effective should stay simple. 

> 	FileLock = Request("Prompt", DirLock, Access_mode);

Too complex. What if I want a file name? What if I want to open it later?
How about handling overwritten/nonexistent files?

	Status = Request(Title, DirectoryLock, Buffer)

Buffer should be initialised to the default file name, so you can provide
a hint. Also, it's sometimes useful to provide a pattern:

	Status = Request(Title, Pattern, DirectoryLock, Buffer);
-- 
Peter "Have you hugged your wolf today" da Silva      `-_-'
...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`

rap@rap.ardent.com (Rob Peck) (05/09/89)

While at the Amy Forum in Dallas yesterday, I mentioned file requesters
to a few folks and received another few ideas, among them was to have
the requester implement a keyboard shortcut as well as the other stuff
I had suggested earlier.  Also, have pattern matching of sorts, so as
to show only particular kinds (or NOT show) of files. E.G. don't list
the .info files and remember this next time.

So, for example, if string-gadget for file name or for path-name
is NOT active, interpret keyboard entries as the first, second etc
character of the file we wanna find and have the file listing jump
to put the selected file name at the top of the (alphabetical) list
of files that become selectable.

For the other case, setting file requester preferences would enable
or disable the pattern matching to a user's specs.

Re Chuck's comment about having the file requester manage everything,
thereby keeping the program simple... that is exactly what I WAS proposing,
but with the re-entrant approach, give the program the OPPORTUNITY to
receive pointers to these lists of files and the controlling structure
THAT THE FILE REQUESTER ITSELF creates and destroys for you, and USES
when you pass that pointer to it.  Maybe I did not make that point
clear enough in the original posting.   And if one makes the file
requester code a part of a sharable (reentrant) library, the function
"malloc" could be used to allocate these buffers in the first place
so that the user code need never even "free" the buffers on exit
since this is usually done when a program exists anyhow.  Of course
it is not good programming practice but if one forgets to tell the
file requester to deallocate all of the cached file buffers, if the
filereq.library used malloc, it should not cause any problems.

Rob Peck

shf@well.UUCP (Stuart H. Ferguson) (05/09/89)

+-- peter@sugar.hackercorp.com (Peter da Silva) writes:
| In article <>, cmcmanis%pepper@Sun.COM (Chuck McManis) writes:
| > This is a very simple operation. And to be effective should stay simple. 
| > 	FileLock = Request("Prompt", DirLock, Access_mode);
| 
| Too complex. What if I want a file name? What if I want to open it later?
| How about handling overwritten/nonexistent files?
 [...]
| 	Status = Request(Title, Pattern, DirectoryLock, Buffer);

What if I want a LIST of files?  Like, open a requester and let the user
select a whole bunch then say OK and crunch on them in sequence.

Is a filename equivalent to a lock?  A lock would have the advantage that
the file won't go away while you're waiting to process it, but a name
would have the advantage that you could handle the exceptions yourself.
What's the tradeoff here?
-- 
		Stuart Ferguson		(shf@well.UUCP)
		Action by HAVOC

new@udel.EDU (Darren New) (05/10/89)

In article <11584@well.UUCP> shf@well.UUCP (Stuart H. Ferguson) writes:
>Is a filename equivalent to a lock?  A lock would have the advantage that
>the file won't go away while you're waiting to process it, but a name
>would have the advantage that you could handle the exceptions yourself.
>What's the tradeoff here?

One obvious problem with returning a Lock is that the file must exist
for you to lock it. If I want a "Save File" requester, this is clearly
unacceptable. Possibly yet another flag to indicate whether locks or
names should be returned is appropriate, given that we are
building the Ultimate File Requester (tm). -- Darren

reynaldo@athena.mit.edu (Reynaldo Villareal) (05/10/89)

*******************************************************************************
* Why be nice when you look good - Me Nice guys are the doormat of the        *
*  of the world.                                                              *
*******************************************************************************

elg@killer.Dallas.TX.US (Eric Green) (05/11/89)

in article <6374@ardent.UUCP>, rap@rap.ardent.com (Rob Peck) says:
[lots of stuff about file requesters... then:]

> clear enough in the original posting.   And if one makes the file
> requester code a part of a sharable (reentrant) library, the function
> "malloc" could be used to allocate these buffers in the first place
> so that the user code need never even "free" the buffers on exit
> since this is usually done when a program exists anyhow.  Of course

Uh, Rob, slight problem here. "malloc" works somewhat like the
Intuition function "AllocRemember", i.e., it calls AllocMem and then
adds an entry into its memory list. The pointer to its memory list is
in the program's static memory, and the address of that pointer is
hard-wired into "malloc" and "exit" at link time. A shared library's
copy of "malloc" will thus have a different RememberList than the
program's copy of "malloc"... meaning that when the program's copy of
Exit goes and cleans up the RememberList, it will only clean up the
stuff allocated by the program's copy of "malloc", not by the shared
library's.

What this means is that any call to malloc will have to be done in the
link library/calling program, not in the shared library. No big deal,
really... just put a wrapper around it. As far as the programmer's
concerned, he's just calling "FileRequest" with a bunch of parameters
(or maybe a struct, considering that's what most Amiga OS functions
expect ;-) The fact that his wrapper is malloc'ing the needed buffers
shouldn't be something he should worry about (unless he has already
allocated his own buffers and doesn't want the "malloc" routine linked
into his program....). 

--
|    // Eric Lee Green              P.O. Box 92191, Lafayette, LA 70509     |
|   //  ..!{ames,decwrl,mit-eddie,osu-cis}!killer!elg     (318)989-9849     |
|  //    Join the Church of HAL, and worship at the altar of all computers  |
|\X/   with three-letter names (e.g. IBM and DEC). White lab coats optional.|

rap@rap.ardent.com (Rob Peck) (05/12/89)

In article <8077@killer.Dallas.TX.US> elg@killer.Dallas.TX.US (Eric Green) writes:
>in article <6374@ardent.UUCP>, rap@rap.ardent.com (Rob Peck) says:
>[lots of stuff about file requesters... then:]
>
>> clear enough in the original posting.   And if one makes the file
>> requester code a part of a sharable (reentrant) library, the function
>> "malloc" could be used to allocate these buffers in the first place
>
>Uh, Rob, slight problem here. "malloc" works somewhat like the
>Intuition function "AllocRemember", i.e., it calls AllocMem and then
>adds an entry into its memory list. The pointer to its memory list is
>in the program's static memory, and the address of that pointer is
>hard-wired into "malloc" and "exit" at link time. A shared library's
>copy of "malloc" will thus have a different RememberList than the
>program's copy of "malloc"... meaning that when the program's copy of

OK, thanks for the feedback.  I guess the best thing to suggest, (based
on my original posting then, with the data structure, would be to add to
that structure an AllocRemember base pointer and INSIST that the user
call the file requester one last time to clean up for every file
directory that be cached.  Sounds reasonable.

To all who replied, directly or via the net, thanks for the info about
the actual implementation of malloc.  If the Amiga ROM had malloc built in
and could tell which task did each allocation (bigger memlists, eh?)
then as a task exited, the UnloadSeg or something could walk the internal
malloc lists looking to free everything associated with a particular task.
But with the malloc code in its current state, as described above, and
linked into the file-requester code, it would not be reentrant and would
indeed cause problems.  

Hmm, maybe if we make it a full process instead of a shared library,
and then REZ it (instead of RESIDENT), we have yet another way to solve
the single global pointer malloc problem...  REZ is (Jim Goodnow's 
equivalent of RESIDENT, but done differently.  Each incarnation of 
the program would get its own private data segment, thereby providing 
a local copy of what woulda been a global pointer.  Yet another way 
to go perhaps.

Rob Peck

jdow@gryphon.COM (J. Dow) (05/12/89)

In article <17044@usc.edu> papa@pollux.usc.edu (Marco Papa) writes:
>The RJ Mical file requester seems to implement all of your requsted features
>(caching, leaving pointer fixed among separate invocations).  One thing that I
>really don't like (for example) of the new Arp1.3 file requester is the fact 
>that each time I the programs call it, it recomputes the list of files  
>again. Is this an inherent flaw of the file requester or of the application 
>program that uses it?
>
>-- Marco Papa 'Doc'
>BTW, the RJ mical file requster is not reentrant but can be "multiply" 
>instantiated.
>-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>uucp:...!pollux!papa       BIX:papa       ARPAnet:pollux!papa@oberon.usc.edu
> "There's Alpha, Beta, Gamma and Diga!" -- Leo Schwab [quoting Rick Unland]
>-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

I have been using ATALK3 of late for some modeming work. Alas it uses the
RJMical file requester. It drives me to distraction with its asumptions,
behavior, and very small size. Other than that it is "cute". I much prefer
the ARP file requester and others that are generally laid out similarly.

-- 
Sometimes a bird in the hand leaves a sticky deposit.
Perhaps it were best it remain there in the bush with the other one.

{@_@}
	jdow on bix (where else?)	Sometimes the dragon wins. Sometimes
	jdow@gryphon.CTS.COM		the knight. Does the fair maiden ever
	{backbone}!gryphon!jdow		win? Surely both the knight and dragon
					stink. Maybe the maiden should suicide?
					Better yet - she should get an Amiga and
					quit playing with dragons and knights.

peter@sugar.hackercorp.com (Peter da Silva) (05/12/89)

In article <11584@well.UUCP>, shf@well.UUCP (Stuart H. Ferguson) writes:
> +-- peter@sugar.hackercorp.com (Peter da Silva) writes:
> | In article <>, cmcmanis%pepper@Sun.COM (Chuck McManis) writes:
> | > This is a very simple operation. And to be effective should stay simple. 
> | > 	FileLock = Request("Prompt", DirLock, Access_mode);

> | Too complex. What if I want a file name? What if I want to open it later?
> | How about handling overwritten/nonexistent files?

> | 	Status = Request(Title, Pattern, DirectoryLock, Buffer);

> What if I want a LIST of files?  Like, open a requester and let the user
> select a whole bunch then say OK and crunch on them in sequence.

You can use my InstantApplication tool, which works something like:

	Status = Instant(Title, Pattern, DirectoryLock, Buffer, Funclist);

Where FuncList looks something like:

	struct {
		int (*Function)();
		char *Tag;
	} FuncList[];

And it provides a menu and lets the user can select files and pass them to
your functions. A very early version of what became Browser.

[ locks versus names ]

What Browser uses internally, by the way, is a WBArg structure containing
a lock and a pointer to a filename in the directory referred to by that lock.
This gives you the best of both worlds.
-- 
Peter "Have you hugged your wolf today" da Silva      `-_-'
...texbell!sugar!peter, or peter@sugar.hackercorp.com  'U`

dillon@HERMES.BERKELEY.EDU (Matt Dillon) (05/13/89)

	Should one return a lock or list of locks for the selected files or
just the filename?

	What happens when somebody selects a file that does not exist yet?

		...
	
	Obviously a list of names should be returned...

						-Matt