1 package gnu.kawa.functions; 2 import gnu.text.*; 3 import java.text.ParseException ; 4 import java.text.Format ; 5 import gnu.mapping.*; 6 import gnu.lists.*; 7 8 public class ParseFormat extends Procedure1 9 { 10 public static final ParseFormat parseFormat = new ParseFormat(false); 11 12 boolean emacsStyle = true; 13 public static final int PARAM_UNSPECIFIED = LispFormat.PARAM_UNSPECIFIED; 14 public static final int PARAM_FROM_LIST = LispFormat.PARAM_FROM_LIST; 15 16 public ParseFormat (boolean emacsStyle) 17 { 18 this.emacsStyle = emacsStyle; 19 } 20 21 public static final int SEEN_MINUS = 1; 22 public static final int SEEN_PLUS = 2; 23 public static final int SEEN_SPACE = 4; 24 public static final int SEEN_ZERO = 8; 25 public static final int SEEN_HASH = 16; 26 27 public ReportFormat parseFormat(LineBufferedReader fmt) 28 throws java.text.ParseException , java.io.IOException 29 { 30 return parseFormat(fmt, emacsStyle ? '?' : '~'); 31 } 32 33 public static ReportFormat parseFormat(LineBufferedReader fmt, char magic) 34 throws java.text.ParseException , java.io.IOException 35 { 36 StringBuffer fbuf = new StringBuffer (100); 37 int position = 0; 38 java.util.Vector formats = new java.util.Vector (); 39 Format format; 40 for (;;) 41 { 42 int ch = fmt.read(); 43 if (ch >= 0) 44 { 45 if (ch != magic) 46 { 47 fbuf.append((char) ch); 49 continue; 50 } 51 ch = fmt.read(); 52 if (ch == magic) 53 { 54 fbuf.append((char) ch); 55 continue; 56 } 57 } 58 int len = fbuf.length(); 59 if (len > 0) 60 { 61 char[] text = new char[len]; 62 fbuf.getChars(0, len, text, 0); 63 fbuf.setLength(0); 64 formats.addElement(new LiteralFormat(text)); 65 } 66 if (ch < 0) 67 break; 68 int digit; 69 if (ch == '$') 70 { 71 ch = fmt.read(); 72 position = Character.digit((char) ch, 10); 73 if (position < 0) 74 throw new ParseException ("missing number (position) after '%$'", 75 -1); 76 for (;;) 77 { 78 ch = fmt.read(); 79 digit = Character.digit((char) ch, 10); 80 if (digit < 0) 81 break; 82 position = 10 * position + digit; 83 } 84 position--; 85 } 86 87 int flags = 0; 88 for (;; ch = fmt.read()) 89 { 90 switch ((char) ch) 91 { 92 case '-': flags |= SEEN_MINUS; continue; 93 case '+': flags |= SEEN_PLUS; continue; 94 case ' ': flags |= SEEN_SPACE; continue; 95 case '0': flags |= SEEN_ZERO; continue; 96 case '#': flags |= SEEN_HASH; continue; 97 } 98 break; 99 } 100 101 int width = PARAM_UNSPECIFIED; 102 digit = Character.digit((char) ch, 10); 103 if (digit >= 0) 104 { 105 width = digit; 106 for (;;) 107 { 108 ch = fmt.read(); 109 digit = Character.digit((char) ch, 10); 110 if (digit < 0) 111 break; 112 width = 10 * width + digit; 113 } 114 } 115 else if (ch == '*') 116 width = PARAM_FROM_LIST; 117 118 int precision = PARAM_UNSPECIFIED; 119 if (ch == '.') 120 { 121 if (ch == '*') 122 precision = PARAM_FROM_LIST; 123 else 124 { 125 precision = 0; 126 for (;;) 127 { 128 ch = fmt.read(); 129 digit = Character.digit((char) ch, 10); 130 if (digit < 0) 131 break; 132 precision = 10 * precision + digit; 133 } 134 } 135 } 136 137 switch (ch) 138 { 139 case 's': 140 case 'S': 141 format = new ObjectFormat(ch == 'S', precision); 142 break; 143 144 case 'x': 145 case 'X': 146 case 'i': 147 case 'd': 148 case 'o': 149 int base; 150 int fflags = 0; 151 if (ch == 'd' || ch == 'i') 152 base = 10; 153 else if (ch == 'o') 154 base = 8; 155 else 156 { 157 base = 16; 158 if (ch == 'X') fflags = IntegerFormat.UPPERCASE; 159 } 160 boolean seenColon = false; 161 boolean seenAt = false; 162 char padChar 163 = (flags & (SEEN_ZERO+SEEN_MINUS)) == SEEN_ZERO ? '0' : ' '; 164 if ((flags & SEEN_HASH) != 0) 165 fflags |= IntegerFormat.SHOW_BASE; 166 if ((flags & SEEN_PLUS) != 0) 167 fflags |= IntegerFormat.SHOW_PLUS; 168 if ((flags & SEEN_MINUS) != 0) 169 fflags |= IntegerFormat.PAD_RIGHT; 170 if ((flags & SEEN_SPACE) != 0) 171 fflags |= IntegerFormat.SHOW_SPACE; 172 if (precision != PARAM_UNSPECIFIED) 173 { 174 flags &= ~ SEEN_ZERO; 175 fflags |= IntegerFormat.MIN_DIGITS; 176 format = IntegerFormat.getInstance(base, precision, 177 '0', PARAM_UNSPECIFIED, 178 PARAM_UNSPECIFIED, fflags); 179 } 180 else 181 format = IntegerFormat.getInstance(base, width, 182 padChar, PARAM_UNSPECIFIED, 183 PARAM_UNSPECIFIED, fflags); 184 break; 185 case 'e': 186 case 'f': 187 case 'g': 188 format = new ObjectFormat(false); break; 190 default: 191 throw new ParseException ("unknown format character '"+ch+"'", -1); 192 } 193 if (width > 0) 194 { 195 char padChar = (flags & SEEN_ZERO) != 0 ? '0' : ' '; 196 int where; 197 if ((flags & SEEN_MINUS) != 0) 198 where = 100; 199 else if (padChar == '0') 200 where = -1; 201 else 202 where = 0; 203 format = new gnu.text.PadFormat(format, width, padChar, where); 204 } 205 formats.addElement(format); 210 position++; 211 } 212 int fcount = formats.size(); 214 if (fcount == 1) 215 { 216 Object f = formats.elementAt(0); 217 if (f instanceof ReportFormat) 218 return (ReportFormat) f; 219 } 220 Format[] farray = new Format[fcount]; 221 formats.copyInto(farray); 222 return new CompoundFormat(farray); 223 } 224 225 public Object apply1 (Object arg) 226 { 227 return asFormat(arg, emacsStyle ? '?' : '~'); 228 } 229 230 public static ReportFormat asFormat (Object arg, char style) 231 { 232 try 233 { 234 if (arg instanceof ReportFormat) 235 return (ReportFormat) arg; 236 if (style == '~') 237 return new LispFormat(arg.toString()); 238 else 239 { 240 InPort iport; 241 if (arg instanceof FString) 242 { 243 FString str = (FString) arg; 244 iport = new CharArrayInPort(str.data, str.size); 245 } 246 else 247 iport = new CharArrayInPort(arg.toString()); 248 try 249 { 250 return parseFormat(iport, style); 251 } 252 finally 253 { 254 iport.close(); 255 } 256 } 257 } 258 catch (java.io.IOException ex) 259 { 260 throw new RuntimeException ("Error parsing format ("+ex+")"); 261 } 262 catch (ParseException ex) 263 { 264 throw new RuntimeException ("Invalid format ("+ex+")"); 265 } 266 catch (IndexOutOfBoundsException ex) 267 { 268 throw new RuntimeException ("End while parsing format"); 269 } 270 } 271 } 272 | Popular Tags |