Clover Coverage Report
Coverage timestamp: Fri May 24 2013 13:47:27 UTC
../../../../img/srcFileCovDistChart9.png 45% of files have more coverage
267   903   169   5.93
172   483   0.63   45
45     3.76  
1    
 
  TextInput       Line # 32 267 169 84.5% 0.84504133
 
  (266)
 
1    /* This file is part of the project "Hilbert II" - http://www.qedeq.org
2    *
3    * Copyright 2000-2013, Michael Meyling <mime@qedeq.org>.
4    *
5    * "Hilbert II" is free software; you can redistribute
6    * it and/or modify it under the terms of the GNU General Public
7    * License as published by the Free Software Foundation; either
8    * version 2 of the License, or (at your option) any later version.
9    *
10    * This program is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    * GNU General Public License for more details.
14    */
15   
16    package org.qedeq.base.io;
17   
18    import java.io.File;
19    import java.io.IOException;
20    import java.io.InputStream;
21    import java.io.Reader;
22    import java.math.BigInteger;
23   
24    import org.qedeq.base.utility.StringUtility;
25   
26   
27    /**
28    * This class provides convenient methods for parsing input.
29    *
30    * @author Michael Meyling
31    */
 
32    public class TextInput extends InputStream {
33   
34    /** Char marking end of data. */
35    public static final int EOF = -1;
36   
37    /** Char marking end of input line. */
38    // public final static char CR = '\n'; // LATER mime 20050613: delete if running on all platforms
39    public static final char CR = '\012';
40   
41    /** String for marking current reading position. */
42    private static final String MARKER = "#####";
43   
44    /** Holds the data. */
45    private final StringBuffer source;
46   
47    /** Current line number (starting with 0). */
48    private int lineNumber = 0;
49   
50    /** Current column (starting with 0). */
51    private int column = 0;
52   
53    /** Current reading position (starting with 0). */
54    private int position = 0;
55   
56    /** Maximum int value as BigInteger. */
57    private BigInteger maxIntValue = BigInteger.valueOf(Integer.MAX_VALUE);
58   
59    /**
60    * Constructor using <code>Reader</code> source.
61    *
62    * @param reader Data source. This reader will be closed (even if reading fails).
63    * @throws IOException Reading failed.
64    * @throws NullPointerException Argument was a null pointer.
65    */
 
66  128939 toggle public TextInput(final Reader reader) throws IOException {
67  128939 try {
68  128939 if (reader == null) {
69  1 throw new NullPointerException(
70    "no null pointer as argument accepted");
71    }
72  128938 this.source = new StringBuffer();
73    // TODO mime 20080307: optimize reading
74  128938 int c;
75  ? while (-1 != (c = reader.read())) {
76  488384933 this.source.append((char) c);
77    }
78    } finally {
79  128939 IoUtility.close(reader);
80    }
81    }
82   
83    /**
84    * Constructor using <code>StringBuffer</code> source.
85    *
86    * @param source data source
87    * @throws NullPointerException Argument was a null pointer.
88    */
 
89  2909 toggle public TextInput(final StringBuffer source) {
90  2909 if (source == null) {
91  2 throw new NullPointerException(
92    "no null pointer as argument accepted");
93    }
94  2907 this.source = source;
95    }
96   
97    /**
98    * Constructor using <code>String</code> source.
99    *
100    * @param source data source
101    * @throws NullPointerException Argument was a null pointer.
102    */
 
103  12928 toggle public TextInput(final String source) {
104  12928 if (source == null) {
105  5 throw new NullPointerException(
106    "no null pointer as argument accepted");
107    }
108  12923 this.source = new StringBuffer(source);
109    }
110   
111   
112    /**
113    * Constructor using <code>FILE</code> source.
114    *
115    * @param file Data source.
116    * @param encoding Take this encoding for file.
117    * @throws IOException File reading failed.
118    * @throws NullPointerException One argument was a null pointer.
119    */
 
120  3 toggle public TextInput(final File file, final String encoding) throws IOException {
121  3 if (file == null) {
122  1 throw new NullPointerException(
123    "no null pointer as argument accepted");
124    }
125  2 this.source = new StringBuffer();
126  2 IoUtility.loadFile(file, source, encoding);
127    }
128   
129    /**
130    * Reads a single character and increments the reading position
131    * by one. If no characters are left, <code>-1</code> is returned.
132    * Otherwise a cast to <code>char</code> gives the character read.
133    *
134    * @return Character read, if there are no more chars
135    * <code>-1</code> is returned.
136    */
 
137  354274119 toggle public final int read() {
138  354274119 if (position >= source.length()) {
139  79 return EOF;
140    }
141  2147483647 if (getChar() == CR) {
142  447474805 lineNumber++;
143  447474805 column = 0;
144    } else {
145  2147483647 column++;
146    }
147  354274040 return source.charAt(position++);
148    }
149   
150    /**
151    * Decrements the reading position by one and reads a single character.
152    * If no characters are left, <code>-1</code> is returned.
153    * Otherwise a cast to <code>char</code> gives the character read.
154    *
155    * @return Character read, if there are no more chars
156    * <code>-1</code> is returned.
157    */
 
158  1017274 toggle public final int readInverse() {
159  1017274 if (position <= 0) {
160  2 return -1;
161    }
162  1017272 final char c = source.charAt(--position);
163  1017272 if (c == CR) {
164  57 lineNumber--;
165  57 int pos = source.lastIndexOf("" + CR, position - 1);
166  57 if (pos < 0) {
167  5 column = position;
168    } else {
169  52 column = position - 1 - pos;
170    }
171    } else {
172  1017215 column--;
173  1017215 if (column < 0) {
174  2 throw new IllegalStateException("column less then 0");
175    }
176    }
177  1017270 return c;
178    }
179   
180    /**
181    * Reads a given amount of characters and increments the reading position
182    * accordingly.
183    *
184    * @param number amount of characters to read
185    * @return string read
186    */
 
187  8124 toggle public final String readString(final int number) {
188  8124 final StringBuffer result = new StringBuffer(number);
189  16549 for (int i = 0; i < number; i++) {
190  8434 final int c = read();
191  8434 if (c != -1) {
192  8425 result.append((char) c);
193    } else {
194  9 break;
195    }
196    }
197  8124 return result.toString();
198    }
199   
200    /**
201    * Skips a given amount of characters and increments the reading position
202    * accordingly.
203    *
204    * @param number Amount of characters to read. Must be positive - if not nothing happens.
205    */
 
206  6 toggle public final void forward(final int number) {
207  838 for (int i = 0; i < number; i++) {
208  833 final int c = read();
209  833 if (c == -1) {
210  1 break;
211    }
212    }
213    }
214   
215    /**
216    * Skips until a given keyword is reached. The position afterwards is at the start
217    * of the keyword or at the end of the text (if the keyword is not found).
218    *
219    * @param search Look for this keyword.
220    * @return Was the keyword found?
221    */
 
222  3744 toggle public final boolean forward(final String search) {
223  3744 final int pos = source.indexOf(search, position);
224  3744 if (pos < 0) {
225  2805 setPosition(getMaximumPosition());
226  2805 return false;
227    }
228  939 setPosition(pos);
229  939 return true;
230    }
231   
232    /**
233    * Reads a single character and does not change the reading
234    * position. If no characters are left, <code>-1</code> is returned.
235    * Otherwise a cast to <code>char</code> gives the character read.
236    *
237    * @return Character read at current position, if there are no more chars
238    * <code>-1</code> is returned
239    */
 
240  366715180 toggle public final int getChar() {
241  366715180 if (position >= source.length()) {
242  12222 return -1;
243    }
244  366702958 return source.charAt(position);
245    }
246   
247    /**
248    * Reads a single character and does not change the reading
249    * position. If offset addition leads out of the source,
250    * <code>-1</code> is returned. Otherwise a cast to <code>char</code>
251    * gives the character read.
252    *
253    * @param skip Offset from current reading position. Maybe negative.
254    * @return Character read, if position is out of scope
255    * <code>-1</code> is returned.
256    */
 
257  346 toggle public final int getChar(final int skip) {
258  346 if (position + skip < 0 || position + skip >= source.length()) {
259  40 return -1;
260    }
261  306 return source.charAt(position + skip);
262    }
263   
264   
265    /**
266    * Reads a substring. Doesn't change reading position. Throws never an Exception.
267    *
268    * @param from Absolute reading position.
269    * @param to Read to this position.
270    * @return Resulting string.
271    */
 
272  5345 toggle public final String getSubstring(final int from, final int to) {
273  5345 if (from >= to) {
274  86 return "";
275    }
276  5259 final int l = source.length();
277  5255 final int f = (from < 0 ? 0 : (from > l ? l : from));
278  5259 final int t = (to < 0 ? 0 : (to > l ? l : to));
279  5259 return source.substring(f, t);
280    }
281   
282    /**
283    * Get complete input source. Doesn't change reading position.
284    *
285    * @return Complete input string.
286    */
 
287  617 toggle public final String asString() {
288  617 return source.toString();
289    }
290   
291    /**
292    * Replace given interval with given string.
293    * If the current reading position is in the interval it is set
294    * to the end of the interval.
295    *
296    * @param from Absolute reading position.
297    * @param to Read to this position.
298    * @param replacement Replacement for interval.
299    */
 
300  3 toggle public final void replace(final int from, final int to, final String replacement) {
301  3 source.replace(from, to, replacement);
302  3 if (position > from && position < to) {
303  0 setPosition(from + replacement.length());
304  3 } else if (position > from) { // correct row (and column) information
305  2 setPosition(position - to + from + replacement.length());
306    }
307    }
308   
309    /**
310    * Skips white space, beginning from reading position.
311    * Changes reading position to next non white space
312    * character.
313    */
 
314  41181 toggle public final void skipWhiteSpace() {
315  46793 while (!isEmpty() && Character.isWhitespace((char) getChar())) {
316  5612 read();
317    }
318    }
319   
320    /**
321    * Skips white space, beginning from reading position.
322    * Changes reading position to next non white space
323    * character.
324    */
 
325  6 toggle public final void skipWhiteSpaceInverse() {
326  26 while (getPosition() > 0 && Character.isWhitespace((char) getChar(-1))) {
327  20 readInverse();
328    }
329    }
330   
331    /**
332    * Skip current position back to beginning of an XML tag.
333    * This is mainly something like <code>&lt;tagName</code>.
334    *
335    * @throws IllegalArgumentException No begin of XML tag found.
336    */
 
337  66738 toggle public final void skipBackToBeginOfXmlTag() {
338  66738 if ('<' == getChar()) {
339  40 return;
340    }
341  66698 boolean quoted = false;
342  66698 do {
343  1016972 if (-1 == readInverse()) {
344  0 throw new IllegalArgumentException("begin of xml tag not found");
345    }
346  1016972 if ('\"' == getChar()) {
347  93118 quoted = !quoted;
348    }
349  1016972 } while (quoted || '<' != getChar());
350    }
351   
352    /**
353    * Skip forward to end of line.
354    */
 
355  7 toggle public final void skipToEndOfLine() {
356  7 int c = 0;
357  7 do {
358  60 c = read();
359  60 } while (!isEmpty() && c != CR);
360    }
361   
362    /**
363    * Skip current position forward to end of an XML tag. It is assumed the current position is
364    * within the the XML tag. Now we search for <code>&gt;</code>. Quoted data is skipped.
365    *
366    * @throws IllegalArgumentException No end of XML tag found.
367    */
 
368  6 toggle public final void skipForwardToEndOfXmlTag() {
369  6 if ('>' == getChar()) {
370  0 return;
371    }
372  6 boolean quoted = false;
373  317 while (!isEmpty() && (quoted || '>' != getChar())) {
374  311 int c = read();
375  311 if ('\"' == c) {
376  21 quoted = !quoted;
377    }
378    }
379  6 if (isEmpty()) {
380  2 throw new IllegalArgumentException("end of xml tag not found");
381    }
382  4 read(); // skip '>'
383    }
384   
385    /**
386    * Reads tag or attribute name out of XML stream. Whitespace is skipped and
387    * characters are read till &quot;=&quot; or &quot;&gt;&quot; or &quot;&lt; or whitespace is
388    * found. We must be within the tag, so we can not start with something like &lt;.
389    *
390    * @return Name of tag or attribute.
391    * @throws IllegalArgumentException Next non white space character is &quot;=&quot;
392    * or &quot;&gt;&quot;.
393    */
 
394  9666 toggle public final String readNextXmlName() {
395  9666 skipWhiteSpace();
396  9666 if (isEmpty() || '=' == getChar() || '>' == getChar() || '<' == getChar()) {
397  13 throw new IllegalArgumentException(
398    "begin of attribute or tag expected");
399    }
400  9653 StringBuffer buffer = new StringBuffer();
401  49477 while (!isEmpty() && '=' != getChar() && '>' != getChar() && '<' != getChar()
402    && !Character.isWhitespace((char) getChar())) {
403  39824 buffer.append((char) read());
404    }
405  9653 return buffer.toString();
406    }
407   
408    /**
409    * Reads attribute value out of XML stream. Whitespace is skipped and an &quot;=&quot;
410    * is expected to follow. Again whitespace is skipped. If no quotation mark follows
411    * characters are read till whitespace or &quot;&gt;&quot; occurs. Otherwise data is
412    * read till an ending quotation mark comes.
413    *
414    * @return Value read.
415    * @throws IllegalArgumentException Following had not one of the following forms:
416    * <pre>
417    * = "value"
418    * </pre>
419    * <pre>
420    * = value
421    * </pre>
422    */
 
423  5099 toggle public final String readNextAttributeValue() {
424  5099 skipWhiteSpace();
425  5099 if (isEmpty() || '=' != getChar()) {
426  18 throw new IllegalArgumentException(
427    "\"=\" expected");
428    }
429  5081 read(); // read =
430  5081 skipWhiteSpace();
431  5081 if (isEmpty() || '>' == getChar()) {
432  0 throw new IllegalArgumentException(
433    "attribute value expected");
434    }
435  5081 StringBuffer buffer = new StringBuffer();
436  5081 if ('\"' == getChar()) {
437  5079 read(); // read "
438  39896 while (!isEmpty() && '\"' != getChar()) {
439  34817 buffer.append((char) read());
440    }
441  5079 if ('\"' != getChar()) {
442  2 throw new IllegalArgumentException("\" expected");
443    }
444  5077 read(); // read "
445    } else {
446  10 while (!isEmpty() && '>' != getChar()
447    && !Character.isWhitespace((char) getChar())) {
448  8 buffer.append((char) read());
449    }
450    }
451  5079 return StringUtility.unescapeXml(buffer.toString());
452    }
453   
454    /**
455    * Is there no data left for reading?
456    *
457    * @return is all data read?
458    */
 
459  1283974 toggle public final boolean isEmpty() {
460  1283974 return position >= source.length();
461    }
462   
463    /**
464    * Is there no data left for reading after skipping?
465    *
466    * @param skip Add this number to current position.
467    * @return Is data empty at that new position?
468    */
 
469  16 toggle public final boolean isEmpty(final int skip) {
470  16 return position + skip >= source.length();
471    }
472   
473    /**
474    * Reads the next string containing only letters or digits,
475    * leading whitespace is skipped.
476    * Changes reading position.
477    *
478    * @return read string
479    * @throws IllegalArgumentException if no such characters could
480    * be found
481    */
 
482  13 toggle public final String readLetterDigitString() {
483  13 skipWhiteSpace();
484  13 if (isEmpty() || !Character.isLetterOrDigit((char) getChar())) {
485  4 read(); // for showing correct position
486  4 throw new IllegalArgumentException(
487    "letter or digit expected");
488    }
489  9 StringBuffer buffer = new StringBuffer();
490  68 while (!isEmpty() && Character.isLetterOrDigit((char) getChar())) {
491  59 buffer.append((char) read());
492    }
493  9 return buffer.toString();
494    }
495   
496    /**
497    * Reads the next string until whitespace occurs,
498    * leading whitespace is skipped.
499    * Changes (probably) reading position.
500    *
501    * @return read string
502    */
 
503  0 toggle public final String readStringTilWhitespace() {
504  0 skipWhiteSpace();
505  0 StringBuffer buffer = new StringBuffer();
506  0 while (!isEmpty() && !Character.isWhitespace((char) getChar())) {
507  0 buffer.append((char) read());
508    }
509  0 return buffer.toString();
510    }
511   
512    /**
513    * Reads the next integer, leading whitespace is skipped. Signs like - or + are not
514    * accepted. Resulting integer
515    * Changes reading position.
516    *
517    * @return Read integer.
518    * @throws IllegalArgumentException if no digits where found or
519    * the number was to big for an <code>int</code>
520    */
 
521  12125 toggle public final int readNonNegativeInt() {
522  12125 skipWhiteSpace();
523  12125 if (isEmpty() || !Character.isDigit((char) getChar())) {
524  12 read(); // for showing correct position
525  12 throw new IllegalArgumentException(
526    "digit expected");
527    }
528  12113 StringBuffer buffer = new StringBuffer();
529  32372 while (!isEmpty() && Character.isDigit((char) getChar())) {
530  20259 buffer.append((char) read());
531    }
532  12113 final BigInteger big = new BigInteger(buffer.toString());
533  12113 if (1 == big.compareTo(maxIntValue)) {
534  2 throw new IllegalArgumentException("this integer is to large! Maximum possible value is "
535    + maxIntValue);
536    }
537  12111 return big.intValue();
538    }
539   
540    /**
541    * Reads the next (big) integer, leading whitespace is skipped.
542    * The first character might be a minus sign, the rest must be
543    * digits. Leading zero digits are not allowed, also "-0" is not
544    * accepted. <p>
545    * Changes reading position.
546    *
547    * @return read integer
548    * @throws IllegalArgumentException if no digits where found.
549    */
 
550  12 toggle public final String readCounter() {
551  12 skipWhiteSpace();
552  12 if (isEmpty()) {
553  2 throw new IllegalArgumentException("integer expected");
554    }
555  10 StringBuffer buffer = new StringBuffer();
556  10 if (getChar() == '-') {
557  0 buffer.append(read());
558    }
559  10 final int begin = getPosition();
560  10 if (!Character.isDigit((char) getChar())) {
561  4 throw new IllegalArgumentException("digit expected");
562    }
563  32 while (!isEmpty() && Character.isDigit((char) getChar())) {
564  26 buffer.append((char) read());
565    }
566  6 if (buffer.length() >= 2 && ('0' == buffer.charAt(0)
567    || '-' == buffer.charAt(0) && '0' == buffer.charAt(1))) {
568  2 setPosition(begin); // for showing correct position
569  2 throw new IllegalArgumentException("no leading zeros allowed");
570    }
571  4 return buffer.toString();
572    }
573   
574    /**
575    * Reads the next quoted string, leading whitespace is skipped.
576    * A correctly quoted string could be created by adding a leading and
577    * a trailing quote character and doubling each other quote character.
578    * The resulting string is dequoted.
579    * Changes reading position.
580    *
581    * @return Dequoted string read.
582    * @throws IllegalArgumentException No correctly quoted string was found.
583    */
 
584  10 toggle public final String readQuoted() {
585  10 skipWhiteSpace();
586  10 if (isEmpty() || read() != '\"') {
587  2 throw new IllegalArgumentException(
588    "\" expected");
589    }
590  8 StringBuffer unquoted = new StringBuffer();
591  8 char c;
592  8 do {
593  28 if (isEmpty()) {
594  0 throw new IllegalArgumentException(
595    "ending \" expected");
596    }
597  28 c = (char) read();
598  28 if (c != '\"') {
599  18 unquoted.append(c);
600    } else { // c == '\"'
601  10 if (isEmpty() || getChar() != '\"') {
602  8 break; // success
603    }
604  2 unquoted.append((char) read());
605    }
606    } while (true);
607  8 return unquoted.toString();
608    }
609   
610    /**
611    * Returns the current line number.
612    *
613    * @return Current line number (starting with line 1).
614    */
 
615  347046616 toggle public final int getRow() {
616  347046616 return lineNumber + 1;
617    }
618   
619    /**
620    * Returns the current column number.
621    *
622    * @return Current column number (starting with line 1).
623    */
 
624  4722496 toggle public final int getColumn() {
625  4722496 return column + 1;
626    }
627   
628    /**
629    * Returns the current line.
630    *
631    * @return Current line.
632    */
 
633  15 toggle public final String getLine() {
634  15 int min = position - 1;
635  78 while (min >= 0 && source.charAt(min) != CR) {
636  63 min--;
637    }
638  15 int max = position;
639  469 while (max < source.length()
640    && source.charAt(max) != CR) {
641  454 max++;
642    }
643  15 if (min + 1 >= max) {
644  0 return "";
645    }
646  15 return source.substring(min + 1, max);
647    }
648   
649    /**
650    * Returns the current position. Starting with 0. This is the number of characters
651    * from the beginning.
652    *
653    * @return Current position.
654    */
 
655  848706 toggle public final int getPosition() {
656  848706 return position;
657    }
658   
659    /**
660    * Returns the current position.
661    *
662    * @return Current position.
663    */
 
664  938 toggle public final SourcePosition getSourcePosition() {
665  938 return new SourcePosition(getRow(), getColumn());
666    }
667   
668    /**
669    * Returns the highest position number possible. This is equal
670    * to the length of the source.
671    *
672    * @return Maximum position.
673    */
 
674  2815 toggle public final int getMaximumPosition() {
675  2815 return source.length();
676    }
677   
678    /**
679    * Sets the current position (and indirectly the row and column number).
680    *
681    * @param position Set current position to this value.
682    */
 
683  13141 toggle public final void setPosition(final int position) {
684  13141 if (position >= source.length()) {
685  3300 this.position = source.length();
686  9841 } else if (this.position != position) {
687  7383 if (position < this.position) {
688  6435 this.position = 0;
689  6435 this.lineNumber = 0;
690  6435 this.column = 0;
691  2652181 for (int i = 0; i < position; i++) { // Q & D
692  2645746 read();
693    }
694    } else {
695  97153 for (int i = this.position; i < position; i++) {
696  96205 read();
697    }
698    }
699    }
700    }
701   
702    /**
703    * Sets the current position (and indirectly the row and column number).
704    *
705    * @param position Set current position to this value.
706    */
 
707  0 toggle public final void setPosition(final SourcePosition position) {
708  0 setRow(position.getRow());
709  0 setColumn(position.getColumn());
710    }
711   
712    /**
713    * Adds a given position to the current one and changes the row and column number accordingly.
714    * A delta position with one row and one column doesn't change the current position.
715    *
716    * @param delta Add this position to current one.
717    */
 
718  68 toggle public final void addPosition(final SourcePosition delta) {
719  68 addRow(delta.getRow() - 1);
720  68 addColumn(delta.getColumn() - 1);
721    }
722   
723    /**
724    * Sets the current line number (and indirectly the position).
725    *
726    * @param row Move to this line number.
727    */
 
728  129089 toggle public final void setRow(final int row) {
729  129089 int r = row;
730    // check if row is under lower bound
731  129089 if (r <= 0) {
732  0 r = 1;
733    }
734    // check if already at wanted position
735  129089 if (getRow() == r) {
736  4 return;
737    }
738    // check if already at end of file
739  129085 if (getPosition() >= source.length() && getRow() >= r) {
740  0 return;
741    }
742  129085 if (getRow() > r) {
743    // reset to begin of file
744  68 this.position = 0;
745  68 this.lineNumber = 0;
746  68 this.column = 0;
747    }
748  346648794 for (int i = 0; getRow() < r; i++) {
749  346519709 if (EOF == read()) {
750  0 return;
751    }
752    }
753    }
754   
755    /**
756    * Get given byte position as {@link SourcePosition}.
757    *
758    * @param find Get row and column information for this byte position.
759    * @return Row and column information.
760    */
 
761  540 toggle public final SourcePosition getPosition(final int find) {
762  540 int r = 0;
763  540 int c = 0;
764  540 int i = 0;
765  379449 while (i < source.length() && i < find) {
766  378909 if (CR == source.charAt(i)) {
767  5562 r++;
768  5562 c = 0;
769    } else {
770  373347 c++;
771    }
772  378909 i++;
773    }
774  540 return new SourcePosition(r + 1, c + 1);
775    }
776   
777    /**
778    * Get given byte position as {@link SourcePosition}.
779    *
780    * @param position Get row and column information for this byte position.
781    * @return Row and column information.
782    */
 
783  0 toggle public final int getPosition(final SourcePosition position) {
784  0 int find = 0;
785  0 int r = 0;
786  0 while (++r < position.getRow() && -1 < (find = source.indexOf("" + CR, find))) {
787    // nothing to do
788    }
789  0 if (find < 0) {
790  0 find = source.length();
791    }
792  0 find += position.getColumn();
793  0 if (find > source.length()) {
794  0 find = source.length();
795    }
796  0 return find;
797    }
798   
799    /**
800    * Get source area as string.
801    *
802    * @param area Get this area as string.
803    * @return Area itself.
804    */
 
805  0 toggle public final String getSourceArea(final SourceArea area) {
806  0 return source.substring(getPosition(area.getStartPosition()),
807    getPosition(area.getEndPosition()));
808    }
809   
810    /**
811    * Add the following rows and reset column (if <code>number == 0</code>).
812    *
813    * @param number Add this number of rows.
814    */
 
815  68 toggle public final void addRow(final int number) {
816  68 setRow(getRow() + number);
817    }
818   
819    /**
820    * Sets the current column position (and indirectly the position).
821    * If <code>column</code> is out of range the minimum value (1) or the maximum possible column
822    * value is taken.
823    *
824    * @param column Move to this column. First column has the number one.
825    */
 
826  129077 toggle public final void setColumn(final int column) {
827  129077 int c = column;
828    // check if column is out of lower bound
829  129077 if (c <= 0) {
830  0 c = 1;
831    }
832    // check if already at wanted position
833  129077 if (getColumn() == c) {
834  0 return;
835    }
836  129077 if (getColumn() > c) {
837  2 do {
838  34 this.position--;
839  34 this.column--;
840  34 } while (getColumn() > c);
841  2 return;
842    }
843  4370546 while (getChar() != CR && getChar() != EOF && getColumn() < c) {
844  4241471 read();
845    }
846    }
847   
848    /**
849    * Add the following columns.
850    *
851    * @param number Add this number of columns.
852    */
 
853  68 toggle public final void addColumn(final int number) {
854  68 setColumn(getColumn() + number);
855    }
856   
857    /**
858    * Show reading position.
859    *
860    * @return current line with mark at current reading position
861    */
 
862  0 toggle public final String showLinePosition() {
863  0 final String line = getLine();
864  0 final StringBuffer buffer = new StringBuffer();
865  0 final int col = getColumn() - 1;
866  0 if (col > 0) {
867  0 if (col < line.length()) {
868  0 buffer.append(line.substring(0, col));
869    } else {
870  0 buffer.append(line);
871    }
872    }
873  0 buffer.append(MARKER);
874  0 if (col < line.length()) {
875  0 buffer.append(line.substring(col));
876    }
877  0 return buffer.toString();
878    }
879   
880    // LATER mime 20050608: remove if no use
881    /*
882    public final int findCaretPosition(final int line, final int column, final String source) {
883    if (line == 1) {
884    return 0;
885    }
886    int k = 1;
887    for (int j = 0; j < source.length(); j++) {
888    if (source.charAt(j) == '\n') {
889    k++;
890    }
891    if (k == line) {
892    j += column - 1;
893    if (j > source.length()) {
894    j = source.length();
895    }
896    return j;
897    }
898    }
899    return 0;
900    }
901    */
902   
903    }