1(* 	$Id: Path.Mod,v 1.5 2004/11/24 03:53:09 sgreenhill Exp $	 *)
2MODULE OS:Path;
3(*  Manipulation of file and directory names.
4    Copyright (C) 2000, 2001, 2003  Michael van Acken
5
6    This module is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public License
8    as published by the Free Software Foundation; either version 2 of
9    the License, or (at your option) any later version.
10
11    This module is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with OOC. If not, write to the Free Software Foundation,
18    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19*)
20
21IMPORT
22  Object, ADT:StringBuffer;
23
24CONST
25  sep = "/";
26
27PROCEDURE DirName*(path: STRING): STRING;
28(**Calculates the directory name of pathname @oparam{path}.  *)
29  VAR
30    i, j: LONGINT;
31  BEGIN
32    i := path.LastIndexOf(sep, path.length);
33    IF (i >= 0) THEN
34      (* if dirname is not composed exclusively of slashes, remove any
35         trailing "/" characters *)
36      j := i;
37      WHILE (j > 0) & (path.CharAt(j-1) = sep) DO
38        DEC(j);
39      END;
40      IF (j = 0) THEN     (* include path separator at position `i' *)
41        INC(i);
42      ELSE                       (* discard all trailing separators *)
43        i := j;
44      END;
45      RETURN path.Substring(0, i);
46    ELSE                      (* plain file name, no directory part *)
47      RETURN "";
48    END;
49  END DirName;
50
51PROCEDURE BaseName* (path: STRING): STRING;
52(**Calculates the basename of pathname @oparam{path}.  The basename is the last
53   pathname component of @oparam{path}.  It never contains a slash.  If
54   @oparam{path} ends with a slash, then the basename is the empty string.  If
55   path does not contain a slash, then the basename equals path.  *)
56  VAR
57    i: LONGINT;
58  BEGIN
59    i := path.LastIndexOf(sep, path.length);
60    IF (i >= 0) THEN
61      RETURN path.Substring(i+1, path.length);
62    ELSE
63      RETURN path;
64    END;
65  END BaseName;
66
67PROCEDURE SplitExt* (path: STRING; VAR root, ext: STRING);
68(**Splits the pathname @oparam{path} into a pair @samp{(@oparam{root},
69   @oparam{ext})} such that @samp{concat(@oparam{root},@oparam{ext}) =
70   @oparam{path}}.  The extension @oparam{ext} is empty or begins with a period
71   and contains at most one period.  The extension string does not contain a
72   slash character.  *)
73  VAR
74    i: LONGINT;
75  BEGIN
76    i := path.LastIndexOf(".", path.length);
77    IF (i >= 0) & (path.IndexOf(sep, i) < 0) THEN
78      root := path.Substring(0, i);
79      ext := path.Substring(i, path.length);
80    ELSE
81      root := path;
82      ext := "";
83    END;
84  END SplitExt;
85
86
87PROCEDURE Encode*(path: STRING): Object.CharsLatin1;
88(**Encode the file path or command @oparam{path} as a system-specific sequence
89   of bytes.
90
91   The default implementation returns a string with all character codes above
92   @samp{0FFX} replaced with the character @samp{_}.  That is, non ISO Latin1
93   characters are discarded.  For instances of @otype{Object.String8}, it is
94   the identity operation.  *)
95  VAR
96    path8: Object.String8;
97  BEGIN
98    path8 := path.ToString8("_");
99    RETURN path8.CharsLatin1();
100  END Encode;
101
102PROCEDURE Decode*(path[NO_COPY]: ARRAY OF CHAR): STRING;
103(**Convert a system-specific sequence of bytes @oparam{path} representing a
104   file path into a string instance.  This is the inverse of @oproc{Encode}.  *)
105  BEGIN
106    RETURN Object.NewLatin1(path);
107  END Decode;
108
109PROCEDURE QuoteForShell* (path : STRING) : STRING;
110(**Convert a path to a form suitable for passing as a command-line argument to
111   a system command. Certain characters cannot be directly used in command-line
112   path arguments because the characters have special significance to the
113   system shell. For example, spaces are used to separate arguments in command
114   lines, so a path containing spaces must be quoted to cause the shell to
115   treat it as a literal.
116
117   This function determines if @oparam{path} needs to be quoted. If so, it
118   returns a quoted version. Otherwise, the original @oparam{path} is returned.
119   *)
120
121 CONST
122    escapeChar = "\";
123    quoteChars = escapeChar + '"';
124
125  PROCEDURE EscapeReservedChars(s, reserved : STRING; escape : CHAR) : STRING;
126  VAR
127    i : LONGINT;
128    sb : StringBuffer.StringBuffer;
129    c : UCS4CHAR;
130    needQuote : BOOLEAN;
131  BEGIN
132    needQuote := FALSE;
133    sb := StringBuffer.New('"');
134    FOR i := 0 TO s.length - 1 DO
135      c := s.CharAt(i);
136      IF reserved.IndexOf(c, 0) >= 0 THEN
137        sb.AppendLatin1Char(escape);
138        needQuote := TRUE;
139      ELSIF c = ' ' THEN
140        needQuote := TRUE;
141      END;
142      sb.AppendChar(c);
143    END;
144    sb.AppendChar('"');
145    IF needQuote THEN
146      RETURN sb.ToString();
147    ELSE
148      RETURN s;
149    END;
150  END EscapeReservedChars;
151
152  BEGIN
153    RETURN EscapeReservedChars(path, quoteChars, escapeChar);
154  END QuoteForShell;
155
156END OS:Path.
157