source: branches/0.17.x/abcl/src/org/armedbear/lisp/LogicalPathname.java

Last change on this file was 12254, checked in by ehuelsmann, 16 years ago

Remove 'throws ConditionThrowable?' method annotations:

it's an unchecked exception now, so no need to declare it thrown.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.7 KB
Line 
1/*
2 * LogicalPathname.java
3 *
4 * Copyright (C) 2004-2005 Peter Graves
5 * $Id: LogicalPathname.java 12254 2009-11-06 20:07:54Z ehuelsmann $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import java.util.HashMap;
37import java.util.StringTokenizer;
38
39public final class LogicalPathname extends Pathname
40{
41    private static final String LOGICAL_PATHNAME_CHARS =
42        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-;*.";
43
44    private static final HashMap map = new HashMap();
45
46    public LogicalPathname()
47    {
48    }
49
50    public LogicalPathname(String host, String rest)
51    {
52        final int limit = rest.length();
53        for (int i = 0; i < limit; i++) {
54            char c = rest.charAt(i);
55            if (LOGICAL_PATHNAME_CHARS.indexOf(c) < 0) {
56                error(new ParseError("The character #\\" + c + " is not valid in a logical pathname."));
57                return;
58            }
59        }
60
61        this.host = new SimpleString(host);
62
63        // "The device component of a logical pathname is always :UNSPECIFIC;
64        // no other component of a logical pathname can be :UNSPECIFIC."
65        device = Keyword.UNSPECIFIC;
66
67        int semi = rest.lastIndexOf(';');
68        if (semi >= 0) {
69            // Directory.
70            String d = rest.substring(0, semi + 1);
71            directory = parseDirectory(d);
72            rest = rest.substring(semi + 1);
73        } else {
74            // "If a relative-directory-marker precedes the directories, the
75            // directory component parsed is as relative; otherwise, the
76            // directory component is parsed as absolute."
77            directory = new Cons(Keyword.ABSOLUTE);
78        }
79
80        int dot = rest.indexOf('.');
81        if (dot >= 0) {
82            String n = rest.substring(0, dot);
83            if (n.equals("*"))
84                name = Keyword.WILD;
85            else
86                name = new SimpleString(n.toUpperCase());
87            rest = rest.substring(dot + 1);
88            dot = rest.indexOf('.');
89            if (dot >= 0) {
90                String t = rest.substring(0, dot);
91                if (t.equals("*"))
92                    type = Keyword.WILD;
93                else
94                    type = new SimpleString(t.toUpperCase());
95                // What's left is the version.
96                String v = rest.substring(dot + 1);
97                if (v.equals("*"))
98                    version = Keyword.WILD;
99                else if (v.equals("NEWEST") || v.equals("newest"))
100                    version = Keyword.NEWEST;
101                else
102                    version = PACKAGE_CL.intern("PARSE-INTEGER").execute(new SimpleString(v));
103            } else {
104                String t = rest;
105                if (t.equals("*"))
106                    type = Keyword.WILD;
107                else
108                    type = new SimpleString(t.toUpperCase());
109            }
110        } else {
111            String n = rest;
112            if (n.equals("*"))
113                name = Keyword.WILD;
114            else if (n.length() > 0)
115                name = new SimpleString(n.toUpperCase());
116        }
117    }
118
119    private static final String LOGICAL_PATHNAME_COMPONENT_CHARS =
120        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-";
121
122    public static final SimpleString canonicalizeStringComponent(AbstractString s)
123
124    {
125        final int limit = s.length();
126        for (int i = 0; i < limit; i++) {
127            char c = s.charAt(i);
128            if (LOGICAL_PATHNAME_COMPONENT_CHARS.indexOf(c) < 0) {
129                error(new ParseError("Invalid character #\\" + c +
130                                      " in logical pathname component \"" + s +
131                                      '"'));
132                // Not reached.
133                return null;
134            }
135        }
136        return new SimpleString(s.getStringValue().toUpperCase());
137    }
138
139    public static Pathname translateLogicalPathname(LogicalPathname pathname)
140
141    {
142        return (Pathname) Symbol.TRANSLATE_LOGICAL_PATHNAME.execute(pathname);
143    }
144
145    private static final LispObject parseDirectory(String s)
146
147    {
148        LispObject result;
149        if (s.charAt(0) == ';') {
150            result = new Cons(Keyword.RELATIVE);
151            s = s.substring(1);
152        } else
153            result = new Cons(Keyword.ABSOLUTE);
154        StringTokenizer st = new StringTokenizer(s, ";");
155        while (st.hasMoreTokens()) {
156            String token = st.nextToken();
157            LispObject obj;
158            if (token.equals("*"))
159                obj = Keyword.WILD;
160            else if (token.equals("**"))
161                obj = Keyword.WILD_INFERIORS;
162            else if (token.equals("..")) {
163                if (result.car() instanceof AbstractString) {
164                    result = result.cdr();
165                    continue;
166                }
167                obj= Keyword.UP;
168            } else
169                obj = new SimpleString(token.toUpperCase());
170            result = new Cons(obj, result);
171        }
172        return result.nreverse();
173    }
174
175    @Override
176    public LispObject typeOf()
177    {
178        return Symbol.LOGICAL_PATHNAME;
179    }
180
181    @Override
182    public LispObject classOf()
183    {
184        return BuiltInClass.LOGICAL_PATHNAME;
185    }
186
187    @Override
188    public LispObject typep(LispObject type)
189    {
190        if (type == Symbol.LOGICAL_PATHNAME)
191            return T;
192        if (type == BuiltInClass.LOGICAL_PATHNAME)
193            return T;
194        return super.typep(type);
195    }
196
197    @Override
198    protected String getDirectoryNamestring()
199    {
200        FastStringBuffer sb = new FastStringBuffer();
201        // "If a pathname is converted to a namestring, the symbols NIL and
202        // :UNSPECIFIC cause the field to be treated as if it were empty. That
203        // is, both NIL and :UNSPECIFIC cause the component not to appear in
204        // the namestring." 19.2.2.2.3.1
205        if (directory != NIL) {
206            LispObject temp = directory;
207            LispObject part = temp.car();
208            if (part == Keyword.ABSOLUTE) {
209            } else if (part == Keyword.RELATIVE)
210                sb.append(';');
211            else
212                error(new FileError("Unsupported directory component " + part.writeToString() + ".",
213                                     this));
214            temp = temp.cdr();
215            while (temp != NIL) {
216                part = temp.car();
217                if (part instanceof AbstractString)
218                    sb.append(part.getStringValue());
219                else if (part == Keyword.WILD)
220                    sb.append('*');
221                else if (part == Keyword.WILD_INFERIORS)
222                    sb.append("**");
223                else if (part == Keyword.UP)
224                    sb.append("..");
225                else
226                    error(new FileError("Unsupported directory component " + part.writeToString() + ".",
227                                         this));
228                sb.append(';');
229                temp = temp.cdr();
230            }
231        }
232        return sb.toString();
233    }
234
235    @Override
236    public String writeToString()
237    {
238        final LispThread thread = LispThread.currentThread();
239        boolean printReadably = (Symbol.PRINT_READABLY.symbolValue(thread) != NIL);
240        boolean printEscape = (Symbol.PRINT_ESCAPE.symbolValue(thread) != NIL);
241        FastStringBuffer sb = new FastStringBuffer();
242        if (printReadably || printEscape)
243            sb.append("#P\"");
244        sb.append(host.getStringValue());
245        sb.append(':');
246        if (directory != NIL)
247            sb.append(getDirectoryNamestring());
248        if (name != NIL) {
249            if (name == Keyword.WILD)
250                sb.append('*');
251            else
252                sb.append(name.getStringValue());
253        }
254        if (type != NIL) {
255            sb.append('.');
256            if (type == Keyword.WILD)
257                sb.append('*');
258            else
259                sb.append(type.getStringValue());
260        }
261        if (version.integerp()) {
262            sb.append('.');
263            int base = Fixnum.getValue(Symbol.PRINT_BASE.symbolValue(thread));
264            if (version instanceof Fixnum)
265                sb.append(Integer.toString(((Fixnum)version).value, base).toUpperCase());
266            else if (version instanceof Bignum)
267                sb.append(((Bignum)version).value.toString(base).toUpperCase());
268        } else if (version == Keyword.WILD) {
269            sb.append(".*");
270        } else if (version == Keyword.NEWEST) {
271            sb.append(".NEWEST");
272        }
273        if (printReadably || printEscape)
274            sb.append('"');
275        return sb.toString();
276    }
277
278    // ### canonicalize-logical-host host => canonical-host
279    private static final Primitive CANONICALIZE_LOGICAL_HOST =
280        new Primitive("canonicalize-logical-host", PACKAGE_SYS, true, "host")
281    {
282        @Override
283        public LispObject execute(LispObject arg)
284
285        {
286                AbstractString s = checkString(arg);
287                if (s.length() == 0) {
288                    // "The null string, "", is not a valid value for any
289                    // component of a logical pathname." 19.3.2.2
290                    return error(new LispError("Invalid logical host name: \"" +
291                                                s.getStringValue() + '"'));
292                }
293                return canonicalizeStringComponent(s);
294        }
295    };
296
297    // ### %make-logical-pathname namestring => logical-pathname
298    private static final Primitive _MAKE_LOGICAL_PATHNAME =
299        new Primitive("%make-logical-pathname", PACKAGE_SYS, true, "namestring")
300    {
301        @Override
302        public LispObject execute(LispObject arg)
303
304        {
305            // Check for a logical pathname host.
306            String s = arg.getStringValue();
307            String h = getHostString(s);
308            if (h != null) {
309                if (h.length() == 0) {
310                    // "The null string, "", is not a valid value for any
311                    // component of a logical pathname." 19.3.2.2
312                    return error(new LispError("Invalid logical host name: \"" +
313                                                h + '"'));
314                }
315                if (Pathname.LOGICAL_PATHNAME_TRANSLATIONS.get(new SimpleString(h)) != null) {
316                    // A defined logical pathname host.
317                    return new LogicalPathname(h, s.substring(s.indexOf(':') + 1));
318                }
319            }
320            return error(new TypeError("Logical namestring does not specify a host: \"" + s + '"'));
321        }
322    };
323}
Note: See TracBrowser for help on using the repository browser.