Include.java 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package kawa.standard;
  2. import gnu.expr.*;
  3. import gnu.lists.*;
  4. import gnu.kawa.io.*;
  5. import gnu.kawa.lispexpr.LispReader;
  6. import gnu.text.*;
  7. import kawa.lang.*;
  8. import java.io.*;
  9. import java.nio.charset.*;
  10. import java.util.*;
  11. /** Syntax class for source-file inclusion. */
  12. public class Include extends Syntax {
  13. boolean ignoreCase;
  14. boolean relative;
  15. public static final Include include =
  16. new Include("include", false, false);
  17. public static final Include includeRelative =
  18. new Include("include-relative", true, false);
  19. public static final Include includeCi =
  20. new Include("include-ci", true, true);
  21. public Include(String name, boolean relative, boolean ignoreCase) {
  22. super(name);
  23. this.relative = relative;
  24. this.ignoreCase = ignoreCase;
  25. }
  26. @Override
  27. public void scanForm(Pair st, ScopeExp defs, Translator tr) {
  28. process(st.getCdr(), tr, defs, ignoreCase);
  29. }
  30. @Override
  31. public Expression rewrite(Object obj, Translator tr) {
  32. return tr.rewrite_body(process(obj, tr, null, ignoreCase));
  33. }
  34. public LList process(Object rest, Translator tr, ScopeExp defs,
  35. boolean ignoreCase) {
  36. LList result = LList.Empty;
  37. Pair lastPair = null;
  38. if (tr.getState() == Compilation.PROLOG_PARSING)
  39. tr.setState(Compilation.PROLOG_PARSED);
  40. while (rest instanceof Pair) {
  41. Pair pair = (Pair) rest;
  42. Object paircar = pair.getCar();
  43. Object savePos1 = tr.pushPositionOf(pair);
  44. if (! (paircar instanceof CharSequence)) {
  45. tr.error('e', "include parameters must be strings");
  46. }
  47. String fname = paircar.toString();
  48. Path path;
  49. BinaryInPort inp;
  50. Iterator<CharSequence> searchIterator =
  51. getIncludeSearchPath().iterator();
  52. CharSequence searchElement = relative ? "|" : null;
  53. for (;; searchElement = null) {
  54. if (searchElement == null) {
  55. if (! searchIterator.hasNext()) {
  56. tr.error('e', "cannot open file \""+fname+"\"");
  57. return result;
  58. }
  59. searchElement = searchIterator.next();
  60. }
  61. Path pathElement;
  62. if (searchElement.length() > 0 && searchElement.charAt(0) == '|') {
  63. pathElement = tr.getMinfo().getSourceAbsPath();
  64. if (pathElement == null || ! pathElement.isPlainFile())
  65. pathElement = Path.currentPath();
  66. if (searchElement.length() > 1)
  67. pathElement = pathElement.resolve(searchElement.toString()
  68. .substring(1));
  69. }
  70. else
  71. pathElement = Path.valueOf(searchElement);
  72. try {
  73. path = pathElement.resolve(fname);
  74. InputStream istrm = path.openInputStream();
  75. try {
  76. inp = BinaryInPort.openHeuristicFile(istrm, path);
  77. } catch (Exception ex) {
  78. tr.error('e', ("error reading file \""+path
  79. +"\": "+ex.getMessage()));
  80. return result;
  81. }
  82. break;
  83. } catch (Exception ex) {
  84. }
  85. }
  86. tr.popPositionOf(savePos1);
  87. LispReader reader = new LispReader(inp, tr.getMessages());
  88. if (ignoreCase)
  89. reader.setReadCase('D');
  90. Lexer saveLexer = tr.lexer;
  91. tr.lexer = reader;
  92. try {
  93. if (inp.getCharset() == null && saveLexer != null) {
  94. InPort savePort = saveLexer.getPort();
  95. if (savePort instanceof BinaryInPort) {
  96. Charset saveCset =
  97. ((BinaryInPort) savePort).getCharset();
  98. if (saveCset != null)
  99. inp.setDefaultCharset(saveCset);
  100. }
  101. }
  102. for (;;) {
  103. Object sexp;
  104. try {
  105. sexp = reader.readCommand();
  106. if (sexp == Sequence.eofValue)
  107. break;
  108. } catch (Exception ex) {
  109. tr.error('e', "error reading file \""+path+"\": "+ex.getMessage());
  110. return result;
  111. }
  112. // FIXME do we need to handle Syntax context?
  113. if (defs != null) {
  114. // In scan context.
  115. tr.scanForm(sexp, defs);
  116. } else {
  117. // In rewrite context - create list.
  118. Pair npair = new Pair(sexp, LList.Empty);
  119. if (lastPair == null)
  120. result = npair;
  121. else
  122. lastPair.setCdrBackdoor(npair);
  123. lastPair = npair;
  124. }
  125. }
  126. } finally {
  127. tr.lexer = saveLexer;
  128. }
  129. rest = pair.getCdr();
  130. }
  131. if (rest != LList.Empty)
  132. tr.error('e', "improper list");
  133. return result;
  134. }
  135. public static final ThreadLocal<List<CharSequence>> searchPath
  136. = new InheritableThreadLocal<List<CharSequence>>();
  137. public static List<CharSequence> getIncludeSearchPath() {
  138. return getSearchPath(searchPath, "kawa.include.path", "|:.");
  139. }
  140. public static List<CharSequence> getSearchPath(ThreadLocal<List<CharSequence>> var,
  141. String propertyName,
  142. String defaultPath) {
  143. List<CharSequence> path = var.get();
  144. if (path != null)
  145. return path;
  146. String pstr = System.getProperty(propertyName);
  147. if (pstr == null) {
  148. if (defaultPath == null)
  149. return null;
  150. pstr = defaultPath;
  151. }
  152. StringTokenizer tokenizer =
  153. new StringTokenizer(pstr, File.pathSeparator);
  154. path = new ArrayList<CharSequence>();
  155. while (tokenizer.hasMoreTokens()) {
  156. String str = tokenizer.nextToken().trim();
  157. if (str.length() > 0)
  158. path.add(str);
  159. }
  160. var.set(path);
  161. return path;
  162. }
  163. }