This page contains the discussion for the proposed spath verb to be put into stdlib.
It should apply jhostpath to the argument
It should also canonicalize "..", "../..", etc., as in load spath '../util.ijs'
The DUMMY should be erased
"," is redundant in require spath,'CImageList.ijs'
-- OlegKobchenko 2006-10-08 14:19:20
Thanks for the suggestions.
- It wouldn't hurt to put in "jhostpath" to the final result. Just in case y contained some path information. Added it.
- Won't .. etc. work as "spath" is defined? If one puts those in y the OS should take care of moving up the path. Same as with jpath.
- It would probably be better to erase "DUMMY". I thought of simply using a statement like "PATHSEP_j_=:PATHSEP_j_ which makes PATHSEP_j_ defined in the current script which is all that is needed is a global name defined by the current script. That way an erase is not needed and no extra name is left cluttering the j locale. Or possibly adding a 4!:6 which would return the directory/file name of the current script. What do you think?
- Sloppy of me. I didn`t have the comma in the actual code. Should be more careful when typing. Changed it.
-- DonGuinn 2012-05-25 06:38:22
A local name will work in place of DUMMY
- In my testing, .. and other relative paths work. If you remove the words "full directory" from the description, it might be more clear that this function does not canonicalize the path.
Changing ([,~i:~{.]) to (''"_)`([,~i:~{.])@.e. makes spath work in scripts loaded by script<'foo.ijs' where the script path does not contain PATHSEP_j_
- I agree that this is a very useful function and I think it belongs in the standard library.
-- ZachReiter 2006-10-10 22:53:10
Thanks Zach
- DUMMY_j_ replaced with a local name of "z", since it is already used in the verb.
- "full directory path" replaced with "directory path".
- I haven't done away with "PATHSEP_j_" yet. Since "spath" uses "jhostpath" which references "PATHSEP_j_" any situation, runtime or whatever, which would not have "PATHSEP_j_" defined would fail anyway when "jhostpath" is executed. If such situations exist then "spath" needs to have "jhostpath" removed as well.
-- DonGuinn 2012-05-25 06:38:22
Whoops, sorry. I'm not suggesting getting rid of PATHSEP_j_. Let me clarify.
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/somefileThe 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
- Canonicalized path may be required in places other than system I/O, such as DLL path; and it's also rather simple. Since it's a separate dedicated utility, it's worth to get some extra functionality to simplify usage.
jpath provides it's own canonicalization
jpath '~Phrases' d:\math\j601\system\examples\phrases jpath '~.Phrases/test.ijs' d:\math\j601\system\examples\test.ijs jpath '~..Phrases/test.ijs' d:\math\j601\system\test.ijs
In immediate mode it returns _1, but should return arg. Since it's a dedicated utility, it should be more robust.
spath 'qq.ijs' _1
-- OlegKobchenko 2006-10-13 21:43:56
- Ok, so changing "jhostpath" to "jpath"
- As far as a return when used outside of a script file I wanted the return to cause an error if used. Therefore, it is a number instead of a literal. Should it signal an error instead?
it's a pipeline verb, so the receiving verbs should be able to accept it's output, and if file error occurrs, they will be more qualified to handle or report it. -- OlegKobchenko 2006-10-14 23:50:37
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?
You just use ~..bd instead of ~bd/../..; to continue example above,
jpath '~..system\j.exe' /Users/user/j.exe
-- OlegKobchenko 2006-10-16 01:07:50
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/
