95609bc3be232c1ddb061ee45d1b33753652adb6
[sbp.git] / src / edu / berkeley / sbp / chr / CharInput.java
1 // Copyright 2006 all rights reserved; see LICENSE file for BSD-style license
2
3 package edu.berkeley.sbp.chr;
4 import java.io.*;
5 import java.util.*;
6 import java.lang.reflect.*;
7 import java.lang.ref.*;
8 import edu.berkeley.sbp.*;
9 import edu.berkeley.sbp.util.*;
10 import edu.berkeley.sbp.misc.*;
11 import edu.berkeley.sbp.Input.Location;
12
13 public class CharInput extends Cartesian.Input<Character> {
14
15     private static class RollbackReader extends Reader {
16         private final Reader r;
17         public RollbackReader(Reader r) { this.r = r; }
18         
19         private char[] queue = new char[1024];
20         private int head = 0;
21         private int tail = 0;
22
23         private void unread(char c) {
24             if (tail >= queue.length) {
25                 if (tail - head > queue.length/2) {
26                     char[] queue2 = new char[queue.length * 2];
27                     System.arraycopy(queue, head, queue2, 0, tail-head);
28                 } else {
29                     System.arraycopy(queue, head, queue, 0, tail-head);
30                 }
31                 tail = tail-head;
32                 head = 0;
33             }
34             queue[tail++] = c;
35         }
36
37         public void close() throws IOException { r.close(); }
38         public int read() throws IOException {
39             if (tail>head)
40                 return queue[head++];
41             return r.read();
42         }
43         public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); }
44         public int read(char cbuf[], int off, int len) throws IOException {
45             if (tail>head) {
46                 int count = Math.min(len, tail-head);
47                 System.arraycopy(queue, head, cbuf, off, count);
48                 head += count;
49                 return count;
50             }
51             return r.read(cbuf, off, len);
52         }
53         public long skip(long n) throws IOException { return r.skip(n); }
54         public boolean ready() throws IOException { return true; }
55         public boolean markSupported() { return false; }
56         public void mark(int readAheadLimit) throws IOException { throw new IOException("not supported"); }
57         public void reset() throws IOException { throw new IOException("not supported"); }
58     }
59
60     private final RollbackReader r;
61     
62     public CharInput(String s)                { this(new StringReader(s)); }
63     public CharInput(Reader r)                { this(r, null); }
64     public CharInput(Reader r,      String s) { this.r = new RollbackReader(new BufferedReader(r)); }
65     public CharInput(InputStream i)           { this(i, null); }
66     public CharInput(InputStream i, String s) { this(new InputStreamReader(i), s); }
67
68     public CharInput(InputStream i, String s, boolean indent) {
69         this(new InputStreamReader(i), s);
70         this.indent = indent;
71     }
72
73     boolean cr = false;
74     boolean indent = false;
75     private int count = 0;
76     private StringBuilder cache = new StringBuilder();
77     
78     public void setCacheEnabled(boolean enabled) {
79         if (!enabled) cache = null;
80         else if (cache == null) cache = new StringBuilder();
81     }
82
83     int indentation = -1;
84     int lastIndentation = 0;
85     int delta = 0;
86
87     public boolean   isCR() { return cr; }
88     public Character _next() throws IOException {
89         Character ret = __next();
90         if (ret==null) return null;
91         char c = ret.charValue();
92         if (indent) {
93             if (ret==CharAtom.left)  System.out.print("\033[31m{\033[0m");
94             else if (ret==CharAtom.right) System.out.print("\033[31m}\033[0m");
95             else System.out.print(c+"");
96         }
97         return ret;
98     }
99     public Character __next() throws IOException {
100
101         cr = false;
102
103         int i = r.read();
104         if (i==-1) {
105             /*System.err.print("\r...done       \r"); */
106             if (indent && indentation >= 0) {
107                 redent(indentation - lastIndentation);
108                 //System.err.println("\r                   \rindent: " + (indentation - lastIndentation));
109                 lastIndentation = indentation;
110                 indentation = -1;
111                 return __next();
112             }
113             return null;
114         }
115         char c = (char)i;
116         if (cache != null) cache.append(c);
117         cr = c=='\n';
118
119         if (indent)
120             if (cr && ignore) {
121                 ignore = false;
122             } else if (cr) {
123                 while(true) {
124                     indentation = 0;
125                     do { i = r.read(); if (i==' ') indentation++; } while (i==' ');
126                     if (i=='\n') { /* FIXME */ continue; }
127                     if (i==-1) { /* FIXME */ }
128                      if (indentation - lastIndentation > 0) {
129                         r.unread('\n');
130                         for(int j=0; j<indentation; j++) r.unread(' ');
131                         redent(indentation - lastIndentation);
132                     } else {
133                         redent(indentation - lastIndentation);
134                         r.unread('\n');
135                         for(int j=0; j<indentation; j++) r.unread(' ');
136                     }
137                     if (i != -1) r.unread((char)i);
138                     ignore = true;
139                     break;
140                 }
141                 lastIndentation = indentation;
142                 indentation = -1;
143                 return __next();
144             }
145
146         return c;
147     }
148
149     private boolean ignore = false;
150
151     private void redent(int i) {
152         if (i<0) { r.unread(CharAtom.right); redent(i+1); return; }
153         if (i>0) { r.unread(CharAtom.left); redent(i-1); return; }
154     }
155
156     public String showRegion(Region<Character> rc) {
157         if (cache == null) return null;
158         Cartesian.Region r = (Cartesian.Region)rc;
159         int start = r.getStart().getScalar()+1;
160         int end = r.getEnd().getScalar()+1;
161         if (start < 0) start = 0;
162         if (end < start) end = start;
163         if (end > cache.length()) end = cache.length();
164         String ret;
165         if (end-start < 60) ret = cachesubstring(start, end);
166         else ret = cachesubstring(start, start+25) +
167                  "..." +
168                  cachesubstring(end-25, end);
169         return StringUtil.escapify(ret, "\n\r");
170     }
171
172     private String cachesubstring(int start, int end) {
173         if (start < 0) start = 0;
174         if (end < 0)   end = 0;
175         if (start >= cache.length()) start = cache.length();
176         if (end >= cache.length()) end = cache.length();
177         return cache.substring(start, end);
178     }
179
180 }