relpath.pro
5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
;+
; NAME:
; RELPATH
;
; AUTHOR:
; Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
; craigm@lheamail.gsfc.nasa.gov
; UPDATED VERSIONs can be found on my WEB PAGE:
; http://cow.physics.wisc.edu/~craigm/idl/idl.html
;
; PURPOSE:
; Construct a relative path between two absolute paths
;
; MAJOR TOPICS:
; Files, I/O
;
; CALLING SEQUENCE:
; RELPATH, FROM, [/FILE1,] TO, [/FILE2,] RELPATH, [CURRENT=, /INVERT]
;
; DESCRIPTION:
;
; RELPATH constructs a relative path between two absolute paths.
; That is, given two file name paths FROM and TO, RELPATH finds the
; relative path which starts from the current directory of FROM and
; ends in the directory of TO.
;
; Note that the /FILE1 or /FILE2 keywords can be used to say whether
; FROM or TO, respectively, is a file instead of a directory. This
; is important because RELPATH finds the relative paths between two
; directories, and so the file components are ignored for those
; purposes.
;
; The INVERT keyword is allows one to invert the path: to find the
; path from the current directory of TO, to the directory of FROM.
;
; If the user specifies the CURRENT keyword, then relative paths are
; assumed to originate in the CURRENT directory. Otherwise the
; actual current directory is used.
;
; NORMPATH should be platform independent. Note that the paths do
; not necessarily need to exist on the file system.
;
; INPUTS:
;
; FROM - scalar string, gives path of starting point (file or
; directory).
;
; TO - scalar string, gives path of ending point (file or
; directory).
;
; RELPATH - upon return, the relative path from FROM to TO.
;
; KEYWORDS:
; CURRENT - if specified, must be a scalar string which gives the
; path to the current directory used in forming the
; normalized path. If not specified, then the actual
; current directory is used.
;
; INVERT - invert the direction of the relative path, i.e. from TO
; to FROM.
;
; EXAMPLES:
;
; RELPATH, '/x/y/z', '/x/u/v', relpath & print, relpath
; '../../u/v'
;
; The two paths share a common root in /x. Therefore, to get to
; /x/u/v from /x/y/z, one must go up two directory levels and then
; down into u/v.
;
;
; MODIFICATION HISTORY:
; Written and documented, 12 Mar 2004 CM
; Replaced call to STRCAT with STRJOIN, 09 Aug 2006 CM
; Usage message, 23 Mar 2008 CM
;
; $Id: relpath.pro,v 1.3 2008/03/23 18:14:57 craigm Exp $
;
;-
; Copyright (C) 2004, 2006, 2008, Craig Markwardt
; This software is provided as is without any warranty whatsoever.
; Permission to use, copy, modify, and distribute modified or
; unmodified copies is granted, provided this copyright and disclaimer
; are included unchanged.
;-
pro relpath, from0, to0, relpath, cwd=cwd0, $
file1=file1, file2=file2, invert=invert
relpath = 1
dummy = temporary(relpath)
if n_params() EQ 0 then begin
message, 'USAGE:', /info
message, ' RELPATH, FROM, TO, RESULT, [/INVERT]', /info
message, ' FROM - scalar string, starting path', /info
message, ' TO - scalar string, ending path', /info
message, ' RESULT - upon return, relative path from start to end', /info
message, ' /INVERT - change sense of result: from end to start', /info
return
endif
;; OS dependent path separator and parent-directory indicator
psep = path_sep()
up = path_sep(/parent)
;; Default current directory is taken from task, if not otherwise
;; supplied
if n_elements(cwd0) EQ 0 then cd, current=cwd $
else cwd = strtrim(cwd0(0),2)
if n_elements(from0) EQ 0 then from = '.' $
else from = strtrim(from0,0)
if n_elements(to0) EQ 0 then to = '.' $
else to = strtrim(to0,0)
;; Apply current directory if the specified path(s) is/are relative
if strpos(from, psep) NE 0 then from = cwd + psep + from
if strpos(to, psep) NE 0 then to = cwd + psep + to
;; Make sure these are normalized paths
normpath, from, fromn
normpath, to, ton
;; Break into path components
fromc = str_sep(fromn, psep)
if keyword_set(file1) then begin
file1n = fromc(n_elements(fromc)-1)
fromc = fromc(0:n_elements(fromc)-2)
endif
toc = str_sep(ton, psep)
if keyword_set(file2) then begin
file2n = toc(n_elements(toc)-1)
toc = toc(0:n_elements(toc)-2)
endif
wh = where(fromc NE toc, ct)
if ct EQ 0 then begin
;; The paths match exactly, so special processing is required
relpath = ''
if NOT keyword_set(invert) AND keyword_set(file2) then $
relpath = relpath+file2n
if keyword_set(invert) AND keyword_set(file1) then $
relpath = relpath+file1n
return
endif
wh = wh(0)
fromc = fromc(wh:*)
toc = toc(wh:*)
if NOT keyword_set(invert) then begin
;; As seen from the directory of FROM, how do we traverse to the
;; directory/file of TO
relpathc = [replicate(up, n_elements(fromc)), toc]
if keyword_set(file2) then relpathc = [relpathc, file2n]
endif else begin
;; As seen from the directory of TO, how do we traverse to the
;; directory/file of FOM
relpathc = [replicate(up, n_elements(toc)), fromc]
if keyword_set(file1) then relpathc = [relpathc, file1n]
endelse
relpath = strjoin(relpathc, psep)
return
end