001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdi.internal;
011:
012: import java.io.PrintWriter;
013: import java.util.ArrayList;
014: import java.util.List;
015: import java.util.Map;
016:
017: public class VerboseWriter {
018: /** Length of verbose description. */
019: public static final int VERBOSE_DESCRIPTION_LENGTH = 21;
020: /** Number of hexadecimal verbose bytes per line. */
021: public static final int VERBOSE_HEX_BYTES_PER_LINE = 16;
022: /** Width of hex dump. */
023: public static final int VERBOSE_HEX_WIDTH = 16 * 3 + 2;
024:
025: /** Number extra verbose lines. These are caused by hex dumps that span more than one line. */
026: int fExtraVerboseLines = 0;
027:
028: /** PrintWriter that is written to. */
029: private PrintWriter fOutput;
030: /** Buffer for output: one StringBuffer entry per line. */
031: private List fLineBuffer;
032: /** Position from where buffer is written to. */
033: private int fPosition;
034: /** True if the current line has not yet been written to. */
035: private boolean fNewLine = true;
036:
037: /**
038: * Creates new VerboseWriter that writes to the given PrintWriter.
039: * Output is buffered and previous entries in the buffer can be rewritten.
040: */
041: public VerboseWriter(PrintWriter out) {
042: fOutput = out;
043: fLineBuffer = new ArrayList();
044: fPosition = 0;
045: fLineBuffer.add(new StringBuffer());
046: }
047:
048: /**
049: * Terminate the current line by writing the line separator string.
050: * If autoflush is set and there are extra vebose lines caused by printHex, these lines are
051: * also printed.
052: */
053: public void println() {
054: while (fExtraVerboseLines > 0) {
055: fExtraVerboseLines--;
056: markLn();
057: }
058:
059: markLn();
060: }
061:
062: /**
063: * Prints verbose line.
064: */
065: public void println(String description, byte value) {
066: printDescription(description);
067: printHex(value);
068: println();
069: }
070:
071: /**
072: * Prints verbose line.
073: */
074: public void println(String description, short value) {
075: printDescription(description);
076: printHex(value);
077: println();
078: }
079:
080: /**
081: * Prints verbose line.
082: */
083: public void println(String description, int value) {
084: printDescription(description);
085: printHex(value);
086: println();
087: }
088:
089: /**
090: * Prints verbose line.
091: */
092: public void println(String description, long value) {
093: printDescription(description);
094: printHex(value);
095: println();
096: }
097:
098: /**
099: * Prints verbose line.
100: */
101: public void println(String description, byte value,
102: Map valueToString) {
103: printDescription(description);
104: printHex(value);
105: printValue(value, valueToString);
106: println();
107: }
108:
109: /**
110: * Prints verbose line.
111: */
112: public void println(String description, short value,
113: Map valueToString) {
114: printDescription(description);
115: printHex(value);
116: printValue(value, valueToString);
117: println();
118: }
119:
120: /**
121: * Prints verbose line.
122: */
123: public void println(String description, int value, Map valueToString) {
124: printDescription(description);
125: printHex(value);
126: printValue(value, valueToString);
127: println();
128: }
129:
130: /**
131: * Prints verbose line.
132: */
133: public void println(String description, byte value,
134: String[] bitNames) {
135: printDescription(description);
136: printHex(value);
137: printValue(value, bitNames);
138: println();
139: }
140:
141: /**
142: * Prints verbose line.
143: */
144: public void println(String description, short value,
145: String[] bitNames) {
146: printDescription(description);
147: printHex(value);
148: printValue(value, bitNames);
149: println();
150: }
151:
152: /**
153: * Prints verbose line.
154: */
155: public void println(String description, int value, String[] bitNames) {
156: printDescription(description);
157: printHex(value);
158: printValue(value, bitNames);
159: println();
160: }
161:
162: /**
163: * Prints verbose line.
164: */
165: public void println(String description, String value) {
166: printDescription(description);
167: printHex(value);
168: print(value);
169: println();
170: }
171:
172: /**
173: * Prints verbose line.
174: */
175: public void println(String description, boolean value) {
176: printDescription(description);
177: printHex(value);
178: print(Boolean.valueOf(value).toString());
179: println();
180: }
181:
182: /**
183: * Prints verbose line.
184: */
185: public void println(String description, char value) {
186: printDescription(description);
187: printHex(value);
188: print(value);
189: println();
190: }
191:
192: /**
193: * Prints verbose line.
194: */
195: public void println(String description, double value) {
196: printDescription(description);
197: printHex(value);
198: print(new Double(value).toString());
199: println();
200: }
201:
202: /**
203: * Prints verbose line.
204: */
205: public void println(String description, float value) {
206: printDescription(description);
207: printHex(value);
208: print(new Float(value).toString());
209: println();
210: }
211:
212: /**
213: * Prints verbose line.
214: */
215: public void println(String description, byte[] value) {
216: printDescription(description);
217: printHex(value);
218: println();
219: }
220:
221: /**
222: * Prints string with right size.
223: */
224: public void printWidth(String str, int width) {
225: print(str);
226: int spaces = width - str.length();
227: if (spaces > 0) {
228: for (int i = 0; i < spaces; i++) {
229: print(' ');
230: }
231: }
232: }
233:
234: /**
235: * Prints description string with right size plus its seperator spaces.
236: */
237: public void printDescription(String str) {
238: printWidth(str, VERBOSE_DESCRIPTION_LENGTH);
239: }
240:
241: /**
242: * Prints hex substitution string with right size plus its seperator spaces.
243: */
244: public void printHexSubstitution(String str) {
245: // Note that bytes also start with a space.
246: print(' ');
247: printWidth(str, VERBOSE_HEX_WIDTH - 1);
248: }
249:
250: /**
251: * Appends hex representation of given byte to an array.
252: */
253: private static void appendHexByte(byte b, char[] buffer, int pos) {
254: int count = 2;
255:
256: int abspos = 3 * pos;
257: buffer[abspos] = ' ';
258: do {
259: int t = b & 15;
260: if (t > 9) {
261: t = t - 10 + 'a';
262: } else {
263: t += '0';
264: }
265: buffer[count-- + abspos] = (char) t;
266: b >>>= 4;
267: } while (count > 0);
268: }
269:
270: /**
271: * Appends remaining spaces to hex dump.
272: */
273: private static void appendHexSpaces(char[] buffer, int pos) {
274: for (int i = 3 * pos; i <= VERBOSE_HEX_WIDTH - 3; i += 3) {
275: buffer[i] = ' ';
276: buffer[i + 1] = ' ';
277: buffer[i + 2] = ' ';
278: }
279:
280: // Two extra spaces as seperator
281: buffer[VERBOSE_HEX_WIDTH - 1] = ' ';
282: buffer[VERBOSE_HEX_WIDTH - 2] = ' ';
283: }
284:
285: /**
286: * Prints hex representation of a byte.
287: */
288: public void printHex(byte b) {
289: char buffer[] = new char[VERBOSE_HEX_WIDTH];
290: appendHexByte(b, buffer, 0);
291: appendHexSpaces(buffer, 1);
292: print(buffer);
293: }
294:
295: /**
296: * Prints hex representation of an int.
297: */
298: public void printHex(short s) {
299: char buffer[] = new char[VERBOSE_HEX_WIDTH];
300: for (int i = 1; i >= 0; i--)
301: appendHexByte((byte) (s >>> i * 8), buffer, 1 - i);
302: appendHexSpaces(buffer, 2);
303: print(buffer);
304: }
305:
306: /**
307: * Prints hex representation of an int.
308: */
309: public void printHex(int integer) {
310: char buffer[] = new char[VERBOSE_HEX_WIDTH];
311: for (int i = 3; i >= 0; i--)
312: appendHexByte((byte) (integer >>> i * 8), buffer, 3 - i);
313: appendHexSpaces(buffer, 4);
314: print(buffer);
315: }
316:
317: /**
318: * Prints hex representation of a long.
319: */
320: public void printHex(long l) {
321: char buffer[] = new char[VERBOSE_HEX_WIDTH];
322: for (int i = 7; i >= 0; i--)
323: appendHexByte((byte) (l >>> i * 8), buffer, 7 - i);
324: appendHexSpaces(buffer, 8);
325: print(buffer);
326: }
327:
328: /**
329: * Prints hex representation of a long.
330: */
331: public void printHex(boolean b) {
332: printHexSubstitution("<boolean>"); //$NON-NLS-1$
333: }
334:
335: /**
336: * Prints hex representation of a long.
337: */
338: public void printHex(char c) {
339: printHexSubstitution("<char>"); //$NON-NLS-1$
340: }
341:
342: /**
343: * Prints hex representation of a long.
344: */
345: public void printHex(double d) {
346: printHexSubstitution("<double>"); //$NON-NLS-1$
347: }
348:
349: /**
350: * Prints hex representation of a long.
351: */
352: public void printHex(float f) {
353: printHexSubstitution("<float>"); //$NON-NLS-1$
354: }
355:
356: /**
357: * Prints hex representation of a String.
358: */
359: public void printHex(String str) {
360: printHexSubstitution("<string>"); //$NON-NLS-1$
361: }
362:
363: /**
364: * Prints hex representation of a byte array.
365: * Note that this can span more than one line, but is considered to be part of one
366: * 'verbose line'. Therefore, a println after a printHex can result in more than one line
367: * being printed to the PrintWriter.
368: */
369: public void printHex(byte[] bytes) {
370: int startPosition = position();
371: char linebuf[] = new char[VERBOSE_HEX_WIDTH];
372: int extraLines = 0;
373: int byteOnLine = 0;
374:
375: for (int i = 0; i < bytes.length; i++) {
376: if (byteOnLine == VERBOSE_HEX_BYTES_PER_LINE) {
377: appendHexSpaces(linebuf, VERBOSE_HEX_BYTES_PER_LINE);
378: if (extraLines++ > 0) {
379: printDescription(""); //$NON-NLS-1$
380: }
381: print(linebuf);
382: markLn();
383: byteOnLine = 0;
384: }
385: appendHexByte(bytes[i], linebuf, byteOnLine++);
386: }
387: appendHexSpaces(linebuf, byteOnLine);
388: if (extraLines > 0) {
389: printDescription(""); //$NON-NLS-1$
390: }
391:
392: fExtraVerboseLines += extraLines;
393: print(linebuf);
394: if (extraLines > 0) {
395: gotoPosition(startPosition);
396: }
397: }
398:
399: /**
400: * Prints string representation of a value given a Map from values to strings.
401: */
402: public void printValue(int value, Map valueToString) {
403: Integer val = new Integer(value);
404: if (valueToString == null) {
405: print(val.toString());
406: return;
407: }
408: String result = (String) valueToString.get(val);
409: if (result == null) {
410: print(val.toString()
411: + JDIMessages.VerboseWriter___unknown_value__1);
412: } else {
413: print(result);
414: }
415: }
416:
417: /**
418: * Prints string representation of a value given a Vector with the names of the bits.
419: */
420: public void printValue(byte value, String[] bitNames) {
421: printValue(value & 0xff, bitNames);
422: }
423:
424: /**
425: * Prints string representation of a value given a Vector with the names of the bits.
426: */
427: public void printValue(short value, String[] bitNames) {
428: printValue(value & 0xffff, bitNames);
429: }
430:
431: /**
432: * Prints string representation of a value given a Vector with the names of the bits.
433: */
434: public void printValue(int value, String[] bitNames) {
435: Integer val = new Integer(value);
436: if (bitNames == null) {
437: print(val.toString());
438: return;
439: }
440:
441: boolean bitsSet = false;
442:
443: for (int i = 0; i < bitNames.length; i++) {
444: // Test if bit is set in value.
445: if ((1 << i & value) == 0) {
446: continue;
447: }
448:
449: // See if we have a desciption for the bit.
450: String bitString = bitNames[i];
451: if (bitString == null) {
452: bitString = JDIMessages.VerboseWriter__unknown_bit__2;
453: }
454:
455: if (!bitsSet) {
456: print(bitString);
457: } else {
458: print(" & "); //$NON-NLS-1$
459: print(bitString);
460: }
461: bitsSet = true;
462: }
463:
464: if (!bitsSet) {
465: print(JDIMessages.VerboseWriter__none__4);
466: }
467: }
468:
469: /**
470: * Checks if a new line is written to. If so, first erase any data on that line.
471: * Line is marked 'not new' after this command.
472: */
473: private void checkForNewLine() {
474: if (fNewLine) {
475: ((StringBuffer) (fLineBuffer.get(fPosition))).setLength(0);
476: fNewLine = false;
477: }
478: }
479:
480: /**
481: * Print a String.
482: */
483: public void print(String str) {
484: checkForNewLine();
485: ((StringBuffer) (fLineBuffer.get(fPosition))).append(str);
486: }
487:
488: /**
489: * Print a Character.
490: */
491: public void print(char c) {
492: checkForNewLine();
493: ((StringBuffer) (fLineBuffer.get(fPosition))).append(c);
494: }
495:
496: /**
497: * Print array of Characters.
498: */
499: public void print(char[] c) {
500: checkForNewLine();
501: ((StringBuffer) (fLineBuffer.get(fPosition))).append(c);
502: }
503:
504: /**
505: * Print a String and then terminate the line.
506: */
507: public void println(String str) {
508: print(str);
509: println();
510: }
511:
512: /**
513: * Flush buffer.
514: * If autoflush is off, this method is synchronized on the PrintWriter given in the constructor.
515: */
516: public void flush() {
517: synchronized (fOutput) {
518: int bufSize = fLineBuffer.size();
519:
520: for (int i = 0; i < bufSize - 1; i++)
521: fOutput.println(new String((StringBuffer) fLineBuffer
522: .get(i)));
523:
524: // The last line should be printed without an extra newline
525: StringBuffer lastLine = (StringBuffer) fLineBuffer
526: .get(bufSize - 1);
527: if (lastLine.length() > 0)
528: fOutput.print(new String(lastLine));
529:
530: fOutput.flush();
531: fLineBuffer.clear();
532: fPosition = 0;
533: fLineBuffer.add(new StringBuffer());
534: }
535: }
536:
537: /**
538: * Go to the given position in the buffer.
539: * If the given position is smaller than the current position,
540: * subsequent print commands overwrite existing lines in the buffer.
541: * Else, new lines are added to the buffer.
542: */
543: public void gotoPosition(int pos) {
544: int delta = pos - fPosition;
545: if (delta < 0) {
546: fPosition = pos;
547: } else {
548: while (delta-- > 0)
549: println();
550: }
551: }
552:
553: /**
554: * Prints given number of lines.
555: */
556: public void printLines(int lines) {
557: gotoPosition(fPosition + lines);
558: }
559:
560: /**
561: * @return Returns current position in buffer.
562: */
563: public int position() {
564: return fPosition;
565: }
566:
567: /**
568: * Terminate the current line by writing the line separator string, start at end of next line.
569: */
570: public void markLn() {
571: if (++fPosition == fLineBuffer.size()) {
572: fLineBuffer.add(new StringBuffer());
573: }
574:
575: fNewLine = true;
576: }
577: }
|