[comp.sys.amiga] The 1001 Paths

john13@garfield.UUCP (John Russell) (03/15/88)

Seems to me like the "set" command is the ideal way to deal with the idea
of multiple possible paths to any particular file. Manx supplies one with
their compiler, and ARP contains a (much, much smaller) freely redistributable
set command which is compatible with the Manx format.

So anyone writing applications is quite free to use this method, for instance
you can do something of the form

set FONTS=fonts:!fontdisk1:fonts/!wb:fonts/!dpaint:fonts/

and write a little parse routine to search all locations for any given file.
This isn't system-wide, but can certainly be added to new and old applications
alike. To the fellow that wanted include files searched for this way, this is
just the method that Manx uses. Of course it's up to the application to
support it, but then an "include file" is specific to a certain type of
application.

And depending on the sort of application you were writing, you could define
whether or not you would be presented with a requester for a disk in the
path, or if the disk wasn't mounted it would just be skipped.

John

kim@amdahl.uts.amdahl.com (Kim DeVaughn) (03/16/88)

In article <4587@garfield.UUCP>, john13@garfield.UUCP (John Russell) writes:
> Seems to me like the "set" command is the ideal way to deal with the idea
> of multiple possible paths to any particular file.
> 
> So anyone writing applications is quite free to use this method, for instance
> you can do something of the form
> 
> set FONTS=fonts:!fontdisk1:fonts/!wb:fonts/!dpaint:fonts/
> 
> and write a little parse routine to search all locations for any given file.
> This isn't system-wide, but can certainly be added to new and old applications
> alike. To the fellow that wanted include files searched for this way, this is
> just the method that Manx uses. Of course it's up to the application to
> support it, but then an "include file" is specific to a certain type of
> application.

You're right, of course, but I'd really like to see the support for this
initiated at the OS level (i.e., supported by CBM).

Reason is that old bugaboo, standardization.  What happens when you have
two different applications that are expecting to use an environment variable
named FONT, but assume differing string formats?  Or one program wants
the env var named FONT, and another wants FONTS, and another wants ...

Just to muddy the water a bit more, some developers will choose to use to
use the Manx/ARP method, and some will use the new method developed by Bill
Hawes for his WShell (ENV:), and some will continue to use the more limited
"assign" command.

Pretty confusing, especially for non-developer types.

Anyone from CATS want to pick up on this, so we don't have endless religious
discussions about the "best" way?  Or worse, something "designed by committee"?

/kim


-- 
UUCP:  kim@amdahl.amdahl.com
  or:  {sun,decwrl,hplabs,pyramid,ihnp4,uunet,oliveb,cbosgd,ames}!amdahl!kim
DDD:   408-746-8462
USPS:  Amdahl Corp.  M/S 249,  1250 E. Arques Av,  Sunnyvale, CA 94086
CIS:   76535,25

pds@quintus.UUCP (Peter Schachte) (03/17/88)

> Seems to me like the "set" command is the ideal way to deal with the idea
> of multiple possible paths to any particular file. Manx supplies one with
> their compiler, and ARP contains a (much, much smaller) freely redistributable
> set command which is compatible with the Manx format.


> set FONTS=fonts:!fontdisk1:fonts/!wb:fonts/!dpaint:fonts/

There are two problems with this approach, relative to having path assigns
like this:

    assign FONTS fonts:, fontdisk1:fonts, wb:fonts, dpaint:fonts

Firstly, using "set" means that only the programmer has the power to
create a path.  The PROGRAMMER can say he will search $FONTS for the
desired font.  But the USER cannot say, for example, that a compiler
should look for includes in $INCLUDE, or that shell scripts are kept in
$S. And an existing program that looks in FONTS:  and doesn't know about
$FONTS won't search my font path.  We have a nice existing mechanism for
specifying "virtual directories."  We can extend it to cover paths, too,
and this would solve the path problem in an upward-compatible way.  Thus
ANY filename could be a path specification.  There's lots of power
there!  Much more than only allowing programmers to decide when paths
will be searched!  Of course, if you have a syntax for file names that
includes expanding path variables, and any attempt to open a file will
respect the path, then this complaint goes away.  Is that what you're
suggesting?

> and write a little parse routine to search all locations for any given file.

And this is my second complaint about this approach.  Why should every
program have to know about paths?  By hiding this mess in open(), we
simplify every program that wants to handle paths, and give paths for
free to every program that doesn't want to bother with them.
-- 
-Peter Schachte
pds@quintus.uucp
...!sun!quintus!pds

aleks@well.UUCP (Brian J. Witt) (03/21/88)

on't believe in line eaters]

Bear with my first posting..


In article <4587@garfield.UUCP> john13@garfield.UUCP (John Russell) writes:
>Seems to me like the "set" command is the ideal way to deal with the idea
>of multiple possible paths to any particular file. Manx supplies one with
>their compiler, and ARP contains a (much, much smaller) freely redistributable
>set command which is compatible with the Manx format.
>
>set FONTS=fonts:!fontdisk1:fonts/!wb:fonts/!dpaint:fonts/
>
>and write a little parse routine to search all locations for any given file.
>This isn't system-wide, but can certainly be added to new and old applications
>alike. To the fellow that wanted include files searched for this way, this is
>just the method that Manx uses. Of course it's up to the application to
>support it, but then an "include file" is specific to a certain type of
>application.
>

  What you need to do is write Open() so it understands these pathnames!
  That way it is transparent to all applications...  Just think of all
  those linked directories you could search!  You must however, put
  in some rule about when an off-line volume is encountered.
 
"I got my opinions from a shoebox that spoke to me.."

pds@quintus.UUCP (Peter Schachte) (03/22/88)

In article <5489@well.UUCP>, aleks@well.UUCP (Brian J. Witt) writes:
>   What you need to do is write Open() so it understands these pathnames!
>   That way it is transparent to all applications...  Just think of all
>   those linked directories you could search!  You must however, put
>   in some rule about when an off-line volume is encountered.

Yea!  A voice of wisdom emerges from the amid the din!  See, there's
another person who sees the beauty of this approach!  If we keep
following up each other's postings on this, maybe people will think
there are lots of us, and CA will DO something about this.
-- 
-Peter Schachte
pds@quintus.uucp
...!sun!quintus!pds

peter@nuchat.UUCP (Peter da Silva) (03/24/88)

This is a fantasy...

1> mount PATH:
1> Assign C: PATH:df0:c!df1:c!ram:c
1> list c:
Directory "c:" on Thursday 23-Mar-00
df0:c                        Dir rwed Tuesday   06:19:29
df1:c                        Dir rwed Tuesday   06:19:29
ram:c                        Dir rwed Tuesday   06:19:29
3 directories - 1 block used
1> assign
...
c               PATH:df0:c!df1:c!ram:c
...
1> Assign include: PATH:df0:include!vd0:include!Aztec:include
1> set INCLUDE=include:
1> 

'nuff said?
-- 
-- a clone of Peter (have you hugged your wolf today) da Silva  `-_-'
-- normally  ...!hoptoad!academ!uhnix1!sugar!peter                U
-- Disclaimer: These aren't mere opinions... these are *values*.

jesup@pawl11.pawl.rpi.edu (Randell E. Jesup) (03/25/88)

In article <850@nuchat.UUCP> peter@nuchat.UUCP (Peter da Silva) writes:
>1> mount PATH:
>1> Assign C: PATH:df0:c!df1:c!ram:c
>1> list c:
>Directory "c:" on Thursday 23-Mar-00
>df0:c                        Dir rwed Tuesday   06:19:29
>df1:c                        Dir rwed Tuesday   06:19:29
>ram:c                        Dir rwed Tuesday   06:19:29
>3 directories - 1 block used
>1> assign
>...
>c               PATH:df0:c!df1:c!ram:c
>...
>1> Assign include: PATH:df0:include!vd0:include!Aztec:include
>1> set INCLUDE=include:

What happens when someone opens c:filename for write if a) it exists in one
of the directories, b) exists in more than one, c) exists in none?

What does one get back when one Examine()s the result of Lock("c:",...)?
Or when one ExNext()s it?

Sorry, I'm afraid this will remain a fantasy.  Why not just use shell
variables?  List won't find them, but then again list wouldn't produce the
output you showed anyway.

It would be twit to write a routine to a) get the shell var, b) try to open
the file in each of the directories in turn.  If you do, then post it to
the net (if it's done nicely.)

     //	Randell Jesup			      Lunge Software Development
    //	Dedicated Amiga Programmer            13 Frear Ave, Troy, NY 12180
 \\//	beowulf!lunge!jesup@steinmetz.UUCP    (518) 272-2942
  \/    (uunet!steinmetz!beowulf!lunge!jesup) BIX: rjesup

(-: The Few, The Proud, The Architects of the RPM40 40MIPS CMOS Micro :-)

pds@quintus.UUCP (Peter Schachte) (03/26/88)

In article <850@nuchat.UUCP>, peter@nuchat.UUCP (Peter da Silva) writes:
> This is a fantasy...
> 1> mount PATH:
> 1> Assign C: PATH:df0:c!df1:c!ram:c
...
> 'nuff said?

Yea! !!!  (That's me jumping up and down for emphasis.)  Great!  Are
you offering? :-)

Only two reservations:  1)  Is this syntax going to pass through
assign, or would it barf?  I'm not near my amiga, so I can't try it.
2)  Could this be implemented efficiently?  At all?  Remember, you need
to do something different when you go to open such a file for output
(creation) than when you open one for input (preexisting).

Oops.  A third reservation, or actually a recommended extension.  It
would be nice if you had a syntax for specifying the directory to
CREATE a file in.  In the common case where you are caching some files
on ram: disk for speed, this ram: directory would want to go first in
the search path.  But this would be a bad place to put a newly created
file specified by path.  Let me clarify:

1> assign c:  path:ram:c!df0:c!df1:c
1> copy development:neathack c:

You wouldn't (usually) want neathack to be copied to ram:c, but
probably to df0:c (lets assume this for argument's sake).  So the rule
that you create the file in the first directory in the path just isn't
good.  I suppose you could create it in the first non-ram disk
directory but this seems sloppy (you might WANT to create it in ram:),
and requires the implementation to figure out what is a ram disk.  A
better solution would be to extend the syntax to allow the explicit
specification of the directory to create new files in.  E.g.,

1> assign c:  path:ram:c!df0:c!df1:c#df0:c

Not pretty, I know.  I don't care about the syntax (not much), I care
about the capability.

I'd be interested in discussing this further with you offline, if you'd
mail something to me to give me a return path (all my attempts to mail
to you seem to get nowhere).
-- 
-Peter Schachte
pds@quintus.uucp
...!sun!quintus!pds

jdh@bsu-cs.UUCP (John Hiday) (03/26/88)

In article <582@imagine.PAWL.RPI.EDU> beowulf!lunge!jesup@steinmetz.UUCP writes:
>In article <850@nuchat.UUCP> peter@nuchat.UUCP (Peter da Silva) writes:
>>
>> [description of how a PATH: device would function deleted...]
>
>What happens when someone opens c:filename for write if a) it exists in one
>of the directories, b) exists in more than one, c) exists in none?
>
>What does one get back when one Examine()s the result of Lock("c:",...)?
>Or when one ExNext()s it?
>
>Sorry, I'm afraid this will remain a fantasy.  Why not just use shell
>variables?  List won't find them, but then again list wouldn't produce the
>output you showed anyway.

List, dir, whatever would work as advertised.  

Such a beast exists on... (dare I say it?) VMS.  Here is a description
of how VMS handles the situations you bring up:

1) Open a file for write
  a) File exists in one directory - the one file is opened for write.
  b) Exists in more than one dir - the first file it finds is opened for
     for write.
  c) Exists in none - If create on non-exist is set, a new file is created
     in the first directory in the path, if create isn't specified then
     it returns an error just like it would if you weren't using a path.

2) Result of Examine() - finds the first file in the first directory.

3) Result of ExNext() - finds the next file in the current directory, or
   if you just got the last file in the current dir it finds the first
   file in the next dir.  When you get to the last file in the last dir
   it returns a no-more-files error just like it would if you weren't
   using paths.

Basically it just makes the path look like one big directory, except that
the files are grouped by directory inside the big one.

-- 
== John Hiday                UUCP: <backbones>!{iuvax,pur-ee,uunet}!bsu-cs!jdh
== Ball State University / University Computing Services        GEnie: JDHIDAY
== Muncie, IN 47306

pds@quintus.UUCP (Peter Schachte) (03/29/88)

In article <582@imagine.PAWL.RPI.EDU>, jesup@pawl11.pawl.rpi.edu (Randell E. Jesup) writes:
> In article <850@nuchat.UUCP> peter@nuchat.UUCP (Peter da Silva) writes:
> >1> mount PATH:
> >1> Assign C: PATH:df0:c!df1:c!ram:c
> >1> list c:
> >Directory "c:" on Thursday 23-Mar-00
> >df0:c                        Dir rwed Tuesday   06:19:29
> >df1:c                        Dir rwed Tuesday   06:19:29
> >ram:c                        Dir rwed Tuesday   06:19:29
> >3 directories - 1 block used
>
> What happens when someone opens c:filename for write if a) it exists in one
> of the directories, b) exists in more than one, c) exists in none?

I addressed this in a followup to Peter's posting:  extend the proposal
to allow users to explicitly specify which directory a file is to be
written in if the user wants to open a file for output in a path.  My
suggestion was:
	1> Assign C: PATH:df0:c!df1:c!ram:c#df0:c
Given this, in cases a), b), and c), the file would be created in
df0:c/.  No problem.

> What does one get back when one Examine()s the result of Lock("c:",...)?
> Or when one ExNext()s it?

Hmmm.  I think you've pointed out a flaw in Peter's posting.  I think
the list c: command should print out all the contents of all the
directories in the path, rather than the top-level directories.  Then
the behavior of Examine() and ExNext() should be clear.  Isn't it?

> Sorry, I'm afraid this will remain a fantasy.  Why not just use shell
> variables?

I've said this before, but I'll say it again because I think it's
important.

The problem with shell variables is that they give the power to specify
paths to the PROGRAMMER.  If a given program doesn't EXPLICITLY have
code to search a path, the program CANNOT be told to do so.  Existing
programs couldn't take advantage of a FONTS: path, or a C: path, or an
INCLUDES: path, etc.  This is a pointless and painful restriction.  It
often happens that a programmer doesn't envision all the uses his
program will be put to, and as such, he may not see where paths will be
useful.

A path is just a generalized sort of directory.  With a path assignment
I'm just saying that FOO: is a pseudo-directory which always contains
all the files in each of its constituent directories (except where the
one file shadows another of the same name in a directory later in the
path).  It's really a simple, elegant concept.  Shell variables don't
allow this elegance.

The implementation of assignments is immaterial to this argument.  The
reason assignments are the right way to implement paths, and shell
variables are not, is that the SYNTAX for specifying a file name
includes assignments, and doesn't include shell variables.  If you fix
Open() and Lock() to understand shell variables, they would be fine.
But it is important that the specification of a path to search should
be part of the FILE NAME, and not implicit in the program that tries to
open the file.

I have a proposal that is similar to Peter's, but might be a bit easier
to implement (I'm not sure):

1> mount PATH:		; may not have to do this:  addpath might be able to
1> addpath c ram:c, df0:c, df1:c createin df0:c
1> addpath fonts df0:fonts fontdisk:
1> assign c: path:c	; addpath should do this too, if possible
1> assign fonts: path:fonts	; ditto
1> list path:
c                        Dir rwed Tuesday   06:19:29
fonts                    Dir rwed Tuesday   06:19:29
1> list path:c
< all the files in ram:c, df0:c, and df1:c >
1> list c:
< the same >

The idea is that path: is sort of like a directory, but its top-level
constituents are actual paths, and attempts to Open(), Lock(),
Examine(), or ExNext() files there will search the path.  Peter, what
do you think?
-- 
-Peter Schachte
pds@quintus.uucp
...!sun!quintus!pds

ccplumb@watmath.waterloo.edu (Colin Plumb) (03/30/88)

pds@quintus.UUCP (Peter Schachte) wrote:
>I have a proposal that is similar to Peter's, but might be a bit easier
>to implement (I'm not sure):
>
>1> mount PATH:		; may not have to do this:  addpath might be able to
>1> addpath c ram:c, df0:c, df1:c createin df0:c
>1> addpath fonts df0:fonts fontdisk:
>1> assign c: path:c	; addpath should do this too, if possible
>1> assign fonts: path:fonts	; ditto
>1> list path:
>c                        Dir rwed Tuesday   06:19:29
>fonts                    Dir rwed Tuesday   06:19:29
>1> list path:c
>< all the files in ram:c, df0:c, and df1:c >
>1> list c:
>< the same >
>
>The idea is that path: is sort of like a directory, but its top-level
>constituents are actual paths, and attempts to Open(), Lock(),
>Examine(), or ExNext() files there will search the path.  Peter, what
>do you think?

I *like* this idea.  I *really* like this idea.  Unless there's some
problem with having DOS devices call each other, this is a fully
backwards-compatible way to get the desired functionality.  Can anyone
see any problems?

There could be some wierdness in that path: could return some names
twice in an ExNext stream (e.g. ram:dir and sys:c/dir), but I can't
envision it being a problem in practice.

It's certainly possible to do things the current path command doesn't
allow, such as removing directories from a path, or rearranging things
somewhat, and it may be possible to implement "don't search if not
mounted" bits.  All is wonderful!

I haven't got the expertise, but, please, some master hacker get on
this right away!
--
	-Colin (watmath!ccplumb)

Zippy says:
FEELINGS are cascading over me!!!

peter@nuchat.UUCP (Peter da Silva) (03/30/88)

In article <582@imagine.PAWL.RPI.EDU>, jesup@pawl11.pawl.rpi.edu (Randell E. Jesup) writes:
> In article <850@nuchat.UUCP> peter@nuchat.UUCP (Peter da Silva) writes:
> >1> mount PATH:
> >1> Assign C: PATH:df0:c!df1:c!ram:c
> >1> list c:
> >Directory "c:" on Thursday 23-Mar-00
> >df0:c                        Dir rwed Tuesday   06:19:29
> >df1:c                        Dir rwed Tuesday   06:19:29
> >ram:c                        Dir rwed Tuesday   06:19:29
> >3 directories - 1 block used
> >1> assign
> >...
> >c               PATH:df0:c!df1:c!ram:c
> >...
> >1> Assign include: PATH:df0:include!vd0:include!Aztec:include
> >1> set INCLUDE=include:

OK, let me answer your immediate questions, and then advance my fantasy.

> What happens when someone opens c:filename for write if a) it exists in one
> of the directories, b) exists in more than one, c) exists in none?

The safest thing would be to refuse the packet, and have open return an error.

> What does one get back when one Examine()s the result of Lock("c:",...)?
> Or when one ExNext()s it?

You'll get "C:" the first time, with some semi-reasonable FIB. Afterwards
you'll get the result of sending an Examine packet to each element of the
PATH: name.

> Sorry, I'm afraid this will remain a fantasy.  Why not just use shell
> variables?

Because dPaint won't find them.

> List won't find them, but then again list wouldn't produce the
> output you showed anyway.

Sure it will, if Examine and ExNext work the way I described above.

> It would be twit to write a routine to a) get the shell var, b) try to open
> the file in each of the directories in turn.  If you do, then post it to
> the net (if it's done nicely.)


Sorry, won't do what *I* want. One of these days I might implement PATH:...

But I have been convinced that the behaviour should be:

1> mount PATH:
1> Assign C: PATH:df0:c!df1:c!ram:c
1> list c:
Directory "c:" on Thursday 23-Mar-00
Run                         2324 rwed Future    14:18:53
Fault                       2728 rwed Future    14:18:54
Install                     1800 rwed Future    14:18:55
stack                        296 rwed Future    14:18:55
... <contents of df0:c>...
More                        8640 rwed Future    14:21:28
viewilbm                   11472 rwed Future    14:21:30
disksalv                   12796 rwed Future    14:21:33
unshar                      9884 rwed Future    14:21:35
dmp                         8008 rwed Future    14:21:36
... <contents of df1:c>...
c:copy                      8128 rwed Future    14:19:14
c:cd                         496 rwed Future    14:19:17
c:list                      8440 rwed Future    14:19:16
... <contents of ram:c>...
247 files - 2700 blocks used
1> assign
...
c               PATH:df0:c!df1:c!ram:c
...
1> Assign include: PATH:df0:include!vd0:include!Aztec:include
1> set INCLUDE=include:

Let's go back and look at your problems in context of this variant...

> What happens when someone opens c:filename for write if a) it exists in one
> of the directories, b) exists in more than one, c) exists in none?

The safest thing would still be to refuse the packet, and have open return
an error, just as if it was a read-only file system.

But if you really want this feature:

	a) writes to that one.
	b) writes to the first it finds.
	c) writes to the first directory.

This isn't as safe, but so long as it's consistent...

> What does one get back when one Examine()s the result of Lock("c:",...)?
> Or when one ExNext()s it?

Examine returns something that looks like a directory. ExNext returns each
file in turn. Really, it behaves much like Matt Dillon's sample RAM: driver.
-- 
-- a clone of Peter (have you hugged your wolf today) da Silva  `-_-'
-- normally  ...!hoptoad!academ!uhnix1!sugar!peter                U
-- Disclaimer: These aren't mere opinions... these are *values*.

pds@quintus.UUCP (Peter Schachte) (03/31/88)

In article <17904@watmath.waterloo.edu>, ccplumb@watmath.waterloo.edu (Colin Plumb) writes:
> There could be some wierdness in that path: could return some names
> twice in an ExNext stream (e.g. ram:dir and sys:c/dir), but I can't
> envision it being a problem in practice.

You'd have to make sure this didn't happen.  That would violate the
model of it being a virtual directory of the files in the constituent
directories.  It wouldn't be TOO hard, though, to keep a hash table of
the names returned so far, and supress returning files with the same
name again.  This might be a bit tricky, I don't know the
implementation details of ExNext and devices.

And thank you for your support.
-- 
-Peter Schachte
pds@quintus.uucp
...!sun!quintus!pds

eachus@mitre-bedford.ARPA (Robert Eachus) (03/31/88)

     I think  I now see  how this should,  can, and needs  to be done.
Someone who understands devices should write it, and  I all want is an
alpha copy...

     Let us suppose you create  a device PATH: which uses path.driver.
This  driver knows how  to parse a  create  command of some complexity
(which probably is done  by aREXX) but reads and  writes to the device
are "turned around" and actually sent  to the appropriate device. What
do we get?

     A device that for "normal"  uses (with the possible  exception of
makedir)  looks and  acts  like a  real disk  drive.  If makedir needs
replacing,  it is  because  you  want  a new  version  which  supplies
additional options, not to replace the AmigaDOS file system routines.

     A tool, interface, backdoor  (choose your  term) which allows you
to set  up arbitrary paths  with  different conditions such  as  "only
check  this directory if the  disk is present"  or "create directories
here first".

     A shining  example  of the  whole idea  behind  the ARP   and IPC
projects: compatibly extending the AmigaDOS environment  in a way that
allows existing software to use the new functionality.

     If anyone wants  to tackle this I'll  be glad  to  help develop a
grammer for the command interface, but I don't have the  time to do it
myself. Send me mail or look for  me at the  next BCS Amiga Developers
meeting.

					Robert I. Eachus

with STANDARD_DISCLAIMER;
use  STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...