This page contains the discussion for the proposed spath verb to be put into stdlib.

-- OlegKobchenko 2006-10-08 14:19:20

Thanks for the suggestions.

-- DonGuinn 2012-05-25 06:38:22

-- ZachReiter 2006-10-10 22:53:10

Thanks Zach

-- DonGuinn 2012-05-25 06:38:22

   load'files'
   NB. Create a file in the local directory called foo.ijs that uses spath
   0 : 0 fwrite 'foo.ijs'
smoutput spath 'somefile'
)
26
   fread'foo.ijs'
smoutput spath 'somefile'

   spath_z_=: 3 : 0
z=.''
if. _1-:z=.4!:4<'z' do. z return. end.
jhostpath y,~PATHSEP_j_([,~i:~{.]);z{4!:3''
)
   load'foo.ijs'
/Volumes/192.168.45.1/j/somefile
   load'./foo.ijs'
/Volumes/192.168.45.1/j/./somefile
   script<'./foo.ijs'
./somefile
   script<'foo.ijs'
foo.ijs/somefile

The first three of these worked because the path ;z{4!:3'' contains a / (which is PATHSEP_j_ in this case) The last didn't work, because the entire script path is 'foo.ijs' which doesn't contain a /. Compare

   PATHSEP_j_
/
   '/' ([,~i:~{.]) 'foo.ijs'
foo.ijs/
   '/' ([,~i:~{.]) './foo.ijs'
./

If spath is redefined as

   spath_z_=: 3 : 0
z=.''
if. _1-:z=.4!:4<'z' do. z return. end.
jhostpath y,~PATHSEP_j_(''"_)`([,~i:~{.])@.e.;z{4!:3''
)

which is what I was suggesting earlier or

spath_z_ =: 3 : 0
z=.''
if. _1-:z=.4!:4<'z' do. z return. end.
jhostpath y,~ }. PATHSEP_j_ ([,~i:~{.]) PATHSEP_j_, ;z{4!:3''
)

which is perhaps simpler, then the examples above all work

   load'foo.ijs'
/Volumes/192.168.45.1/j/somefile
   load'./foo.ijs'
/Volumes/192.168.45.1/j/./somefile
   script<'./foo.ijs'
./somefile
   script<'foo.ijs'
somefile

I noticed this corner case because script<'foo.ijs' is an old habit of mine; perhaps I should just learn to use load'foo.ijs' which has the bonus of being shorter. :-)

-- ZachReiter 2006-10-11 01:31:17

I use Windows and had no idea that there was a case in UNIX where PATHSEP_j_ would not be part of the directory path. Added your test for that case. While I was at it I put a _z_ onto jhostpath.

-- DonGuinn 2012-05-25 06:38:22

Thanks Don.

-- ZachReiter 2006-10-12 09:08:24

-- OlegKobchenko 2006-10-13 21:43:56

After thinking about canonicalization some more I really don't understand what you want. As I think I understand it, "jhostpath" should do what you want so my changing "jhostpath" to "jpath" really didn't accomplish anything.

-- DonGuinn 2012-05-25 06:38:22

Here's a shot at it

NB.*spath v path relative to current script
NB.   returns arg if not in script
NB.   resolves host path and leading '../'
spath_z_=: 3 : 0
  if. _1-:z=. 4!:4<'y' do. y return. end.
  if. '.'~:{.y=. jhostpath y do. c=. 0 else.
     c=. -('..',PATHSEP_j_) +/@E. y end.
  p=. ; c }. (<;.2~ =&PATHSEP_j_) jhostpath z{::4!:3''
  p , (-c*3) }. y
)

NB. =========================================================
NB. test

smoutput spath 'test.ijs'
smoutput spath 'qq/test.ijs'
smoutput spath 'qq\test.ijs'
smoutput spath '../test.ijs'
smoutput spath '../../qq/test.ijs'
smoutput spath 'qqzz/../../test.ijs'

With a result

   load 'g:\math\j601\user\spath.ijs'
g:\math\j601\user\test.ijs
g:\math\j601\user\qq\test.ijs
g:\math\j601\user\qq\test.ijs
g:\math\j601\test.ijs
g:\math\qq\test.ijs
g:\math\j601\user\qqzz\..\..\test.ijs

-- OlegKobchenko 2006-10-15 00:00:59

Very nice. I have used "..\" a lot and I never had a problem with the OS not handling the reducing the file name to the simplest form. But I have only used J on Windows. It may not work in the MAC or UNIX. But I was using "..\" in conjunction with "jpath".

It seems to me that the code to handle canonicalization would be better placed in either "jpath" or "jhostpath". Since right now "spath" calls "jpath" then your code would handle both verbs. Why don't you add a request for the modification of "jpath" to include your code?

-- DonGuinn 2012-05-25 06:38:22

jpath is for working with ~folders, whereas spath is for relaive paths. jpath would not handle ../ because it's arguments start with ~ and there is already a different mechanism to handle upper paths there, ~., etc.

jhostpath as its name suggests is for converting slashes to the host convention. So it's not a place for ../ resolution.

Whereas spath deals with the notion of relativity, thus ../ is very natural in this context. If it's left out, then it's usability is reduced.

-- OlegKobchenko 2006-10-15 06:11:19

I use jpath with ..\ to find the j.exe as follows:

require 'task'
fork (jpath '~system\..\j.exe'),' -jijx "',(jpath '~',}.f),'"'

In my system 1!:45'' does not have the j.exe directory in its path. Why? Because I pull all my stuff out of the J directory. It's even on a different drive. For me, changing J versions consists of loading the new version and updating a shortcut to the new directory. I can even share my stuff between J versions executing simultaneously.

My point is that it's not necessary for the ../ to be first in the argument to jpath. Given the ability for users to create their own ~folder names it's easy to imagine situations where ../ could be used with jpath.

-- DonGuinn 2012-05-25 06:38:22

../ should never appear inside the path. Note, again, correct use of jpath:

   jpath '~system\..\j.exe'          NB. incorrect
/Users/user/j601/system/../j.exe
   jpath '~.system\j.exe'            NB. correct
/Users/user/j601/j.exe

However, it's perfectly natural to use leading ../ in the relative spath.

-- OlegKobchenko 2006-10-15 14:48:14

It's not incorrect. It's just an alternative way to get to the same place. I believe that the meaning of canonicalization is to reduce to a standard form the various ways something can be written. In this case I needed to move up from the first directory in ~system. ..\ would be the only way to do it if I needed to move up from a point further down in the path. I have a network drive which my wife and I use for backup and keeping pictures etc. I defined a ~folder name of ~bd to find it more easily. In order to see all the root folders on the drive I have to use ..\ twice. How else could I get there other than specifying the full network path?

To say that ../ should never appear inside a path is not true and is a risky assumption. It is legal and therefore it is likely somebody will figure out a way to need and use it. I have used ..\ in many places and Windows has handled it quite nicely. It has not been necessary to canonicalize the path before passing it to Windows.

But it really doesn't matter to me on whether or not spath canonicalizes the path or not. If Jsoftware decides to implement the facility it may not even be called spath and what the code actually looks like could be quite different. I only wanted to suggest a facility that I feel is needed and would be useful to others.

I think that this discussion is excellent and maybe show Jsoftware that such a tool would be useful and now better thought out.

   jpath '~system'
c:\program files\j\j601\system
   jpath '~user'
d:\juser
   jpath '~bd'
\\buffalodrive\don\d drive\juser
   fdir jpath '~bd\..\..\*.*'
┌─────────┬──────────────────┬─┬───┬──────┐
│Video    │2006 7 13 20 47 38│0│rw-│----d-│
├─────────┼──────────────────┼─┼───┼──────┤
│JUser    │2006 7 26 7 40 21 │0│rw-│----d-│
├─────────┼──────────────────┼─┼───┼──────┤
│launa    │2006 7 29 23 12 12│0│rw-│----d-│
├─────────┼──────────────────┼─┼───┼──────┤
│D Drive  │2006 7 10 12 54 29│0│rw-│----d-│
├─────────┼──────────────────┼─┼───┼──────┤
│W Drive  │2006 7 12 18 57 23│0│rw-│----d-│
├─────────┼──────────────────┼─┼───┼──────┤
│E Drive  │2006 7 12 21 19 44│0│rw-│----d-│
├─────────┼──────────────────┼─┼───┼──────┤
│pocket pc│2006 7 16 8 21 33 │0│rw-│----d-│
└─────────┴──────────────────┴─┴───┴──────┘

-- DonGuinn 2012-05-25 06:38:22

I agree it's a useful discussion. And I also don't care about exact implementation. I provide the code to get the message across and show rather how it works.

Though unlikely in paractice, but to foolproof the "risky assumption", here is a version that removes all ../

NB.*spath v path relative to current script
NB.   returns arg if not in script
NB.   resolves host path and '../'
spath_z_=: 3 : 0
  if. _1-:z=. 4!:4<'y' do. y return. end.
  s=. PATHSEP_j_
  p=. ({.~ >:@i:&s) jhostpath z{::4!:3''
  q=. (<;.2~ =&s) p , s,~^:(~:{:) y=. }.^:(s={.) jhostpath y
  }:^:(s~:{:y) ;((({.~0&>.@<:),(}.~>:))~^:(< #)~ i.&(<'..',s))^:_ q
)

NB. =========================================================
NB. test

smoutput@spath;._2 (0 : 0)
test.ijs
qq/test.ijs
\qq\test.ijs
../test.ijs
../../qq/test.ijs
qqzz/../../test.ijs
../../../../../../../../test.ijs
fld/
\fld\
../fld/
fld/qq/../zz/
../
)

With a result

/Users/user/j601/temp/test.ijs
/Users/user/j601/temp/qq/test.ijs
/Users/user/j601/temp/qq/test.ijs
/Users/user/j601/test.ijs
/Users/user/qq/test.ijs
/Users/user/j601/test.ijs
test.ijs
/Users/user/j601/temp/fld/
/Users/user/j601/temp/fld/
/Users/user/j601/fld/
/Users/user/j601/temp/fld/zz/
/Users/user/j601/

System/Library/Requests/spath (last edited 2008-12-08 10:45:51 by )