KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > Ostermiller > util > Tabs


1 /*
2  * Adjusts tabs and spaces.
3  * Copyright (C) 2002 Stephen Ostermiller
4  * http://ostermiller.org/contact.pl?regarding=Java+Utilities
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * See COPYING.TXT for details.
17  */

18
19 package com.Ostermiller.util;
20
21 import java.io.*;
22 import gnu.getopt.*;
23 import java.text.MessageFormat JavaDoc;
24 import java.util.ResourceBundle JavaDoc;
25 import java.util.Locale JavaDoc;
26
27 /**
28  * Stream editor to alter the line separators on text to match
29  * that of a given platform.
30  * More information about this class is available from <a target="_top" HREF=
31  * "http://ostermiller.org/utils/LineEnds.html">ostermiller.org</a>.
32  *
33  * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
34  * @since ostermillerutils 1.00.00
35  */

36 public class Tabs {
37
38     /**
39      * Version number of this program
40      *
41      * @since ostermillerutils 1.00.00
42      */

43     public static final String JavaDoc version = "1.0";
44
45     /**
46      * Locale specific strings displayed to the user.
47      *
48      * @since ostermillerutils 1.00.00
49      */

50      protected static ResourceBundle JavaDoc labels = ResourceBundle.getBundle("com.Ostermiller.util.Tabs", Locale.getDefault());
51
52
53     /**
54      * Can be passed instead of a spaces argument to use tabs instead.
55      *
56      * @since ostermillerutils 1.00.00
57      */

58     public final static int TABS = -1;
59
60     /**
61      * Converts the tabs in files, or standard input.
62      * Run with --help argument for more information.
63      *
64      * @param args Command line arguments.
65      *
66      * @since ostermillerutils 1.00.00
67      */

68     public static void main(String JavaDoc[] args){
69         // create the command line options that we are looking for
70
LongOpt[] longopts = {
71             new LongOpt(labels.getString("help.option"), LongOpt.NO_ARGUMENT, null, 1),
72             new LongOpt(labels.getString("version.option"), LongOpt.NO_ARGUMENT, null, 2),
73             new LongOpt(labels.getString("about.option"), LongOpt.NO_ARGUMENT, null, 3),
74             new LongOpt(labels.getString("width.option"), LongOpt.REQUIRED_ARGUMENT, null, 'w'),
75             new LongOpt(labels.getString("guess.option"), LongOpt.NO_ARGUMENT, null, 'g'),
76             new LongOpt(labels.getString("tabs.option"), LongOpt.NO_ARGUMENT, null, 't'),
77             new LongOpt(labels.getString("spaces.option"), LongOpt.REQUIRED_ARGUMENT, null, 's'),
78             new LongOpt(labels.getString("force.option"), LongOpt.NO_ARGUMENT, null, 'f'),
79             new LongOpt(labels.getString("quiet.option"), LongOpt.NO_ARGUMENT, null, 'q'),
80             new LongOpt(labels.getString("reallyquiet.option"), LongOpt.NO_ARGUMENT, null, 'Q'),
81             new LongOpt(labels.getString("verbose.option"), LongOpt.NO_ARGUMENT, null, 'v'),
82             new LongOpt(labels.getString("reallyverbose.option"), LongOpt.NO_ARGUMENT, null, 'V'),
83             new LongOpt(labels.getString("noforce.option"), LongOpt.NO_ARGUMENT, null, 4),
84         };
85         String JavaDoc oneLetterOptions = "w:gts:fVvqQ";
86         Getopt opts = new Getopt(labels.getString("tabs"), args, oneLetterOptions, longopts);
87         int inputTabWidth = TABS;
88         int outputTabWidth = 4;
89         boolean force = false;
90         boolean printMessages = false;
91         boolean printExtraMessages = false;
92         boolean printErrors = true;
93         int c;
94         while ((c = opts.getopt()) != -1){
95             switch(c){
96                     case 1:{
97                     // print out the help message
98
String JavaDoc[] helpFlags = new String JavaDoc[]{
99                         "--" + labels.getString("help.option"),
100                         "--" + labels.getString("version.option"),
101                         "--" + labels.getString("about.option"),
102                         "-w --" + labels.getString("width.option") + " <" + labels.getString("s.arg") + ">",
103                         "-g --" + labels.getString("guess.option"),
104                         "-t --" + labels.getString("tabs.option"),
105                         "-s --" + labels.getString("spaces.option") + " <" + labels.getString("s.arg") + ">",
106                         "-f --" + labels.getString("force.option"),
107                         "--" + labels.getString("noforce.option"),
108                         "-V --" + labels.getString("reallyverbose.option"),
109                         "-v --" + labels.getString("verbose.option"),
110                         "-q --" + labels.getString("quiet.option"),
111                         "-Q --" + labels.getString("reallyquiet.option"),
112                     };
113                     int maxLength = 0;
114                     for (int i=0; i<helpFlags.length; i++){
115                         maxLength = Math.max(maxLength, helpFlags[i].length());
116                     }
117                     maxLength += 2;
118                     System.out.println(
119                         labels.getString("tabs") + " [-" + StringHelper.replace(oneLetterOptions,":","") + "] <" + labels.getString("files") + ">" + "\n" +
120                         labels.getString("purpose.message") + "\n" +
121                         " " + labels.getString("stdin.message") + "\n" +
122                         " " + StringHelper.postpad(helpFlags[0] ,maxLength, ' ') + labels.getString("help.message") + "\n" +
123                         " " + StringHelper.postpad(helpFlags[1] ,maxLength, ' ') + labels.getString("version.message") + "\n" +
124                         " " + StringHelper.postpad(helpFlags[2] ,maxLength, ' ') + labels.getString("about.message") + "\n" +
125                         " " + StringHelper.postpad(helpFlags[3] ,maxLength, ' ') + labels.getString("w.message") + "\n" +
126                         " " + StringHelper.postpad(helpFlags[4] ,maxLength, ' ') + labels.getString("g.message") + " (" + labels.getString("default") + ")\n" +
127                         " " + StringHelper.postpad(helpFlags[5] ,maxLength, ' ') + labels.getString("t.message") + "\n" +
128                         " " + StringHelper.postpad(helpFlags[6] ,maxLength, ' ') + labels.getString("s.message") + " (" + labels.getString("default") + "=4)\n" +
129                         " " + StringHelper.postpad(helpFlags[7] ,maxLength, ' ') + labels.getString("f.message") + "\n" +
130                         " " + StringHelper.postpad(helpFlags[8] ,maxLength, ' ') + labels.getString("noforce.message") + " (" + labels.getString("default") + ")\n" +
131                         " " + StringHelper.postpad(helpFlags[9] ,maxLength, ' ') + labels.getString("V.message") + "\n" +
132                         " " + StringHelper.postpad(helpFlags[10] ,maxLength, ' ') + labels.getString("v.message") + "\n" +
133                         " " + StringHelper.postpad(helpFlags[11] ,maxLength, ' ') + labels.getString("q.message") + " (" + labels.getString("default") + ")\n" +
134                         " " + StringHelper.postpad(helpFlags[12] ,maxLength, ' ') + labels.getString("Q.message") + "\n"
135                     );
136                     System.exit(0);
137                 } break;
138                 case 2:{
139                     // print out the version message
140
System.out.println(MessageFormat.format(labels.getString("version"), (Object JavaDoc[])new String JavaDoc[] {version}));
141                     System.exit(0);
142                 } break;
143                 case 3:{
144                     System.out.println(
145                         labels.getString("tabs") + " -- " + labels.getString("purpose.message") + "\n" +
146                         MessageFormat.format(labels.getString("copyright"), (Object JavaDoc[])new String JavaDoc[] {"2002", "Stephen Ostermiller (http://ostermiller.org/contact.pl?regarding=Java+Utilities)"}) + "\n\n" +
147                         labels.getString("license")
148                     );
149                     System.exit(0);
150                 } break;
151                 case 'w':{
152                     try {
153                         inputTabWidth = Integer.parseInt(opts.getOptarg());
154                     } catch (NumberFormatException JavaDoc x){
155                         inputTabWidth = -1;
156                     }
157                     if (inputTabWidth<1 || inputTabWidth>20){
158                         System.err.println(labels.getString("widtherror"));
159                         System.exit(1);
160                     }
161                 } break;
162                 case 'g':{
163                     inputTabWidth = TABS;
164                 } break;
165                 case 's':{
166                     try {
167                         outputTabWidth = Integer.parseInt(opts.getOptarg());
168                     } catch (NumberFormatException JavaDoc x){
169                         outputTabWidth = -1;
170                     }
171                     if (outputTabWidth<1 || outputTabWidth>20){
172                         System.err.println("widtherror");
173                         System.exit(1);
174                     }
175                 } break;
176                 case 't':{
177                     outputTabWidth = TABS;
178                 } break;
179                 case 'f':{
180                     force = true;
181                 } break;
182                 case 4:{
183                     force = false;
184                 } break;
185                 case 'V':{
186                     printExtraMessages = true;
187                     printMessages = true;
188                     printErrors = true;
189                 } break;
190                 case 'v':{
191                     printExtraMessages = false;
192                     printMessages = true;
193                     printErrors = true;
194                 } break;
195                 case 'q':{
196                     printExtraMessages = false;
197                     printMessages = false;
198                     printErrors = true;
199                 } break;
200                 case 'Q':{
201                     printExtraMessages = false;
202                     printMessages = false;
203                     printErrors = false;
204                 } break;
205                 default:{
206                     System.exit(1);
207                 }
208             }
209         }
210
211         int exitCond = 0;
212         boolean done = false;
213         for (int i=opts.getOptind(); i<args.length; i++){
214             boolean modified = false;
215             done = true;
216             File source = new File(args[i]);
217             if (!source.exists()){
218                 if(printErrors){
219                     System.err.println(MessageFormat.format(labels.getString("doesnotexist"), (Object JavaDoc[])new String JavaDoc[] {args[i]}));
220                 }
221                 exitCond = 1;
222             } else if (!source.canRead()){
223                 if(printErrors){
224                     System.err.println(MessageFormat.format(labels.getString("cantread"), (Object JavaDoc[])new String JavaDoc[] {args[i]}));
225                 }
226                 exitCond = 1;
227             } else if (!source.canWrite()){
228                 if(printErrors){
229                     System.err.println(MessageFormat.format(labels.getString("cantwrite"), (Object JavaDoc[])new String JavaDoc[] {args[i]}));
230                 }
231                 exitCond = 1;
232             } else {
233                 try {
234                     if(convert (source, inputTabWidth, outputTabWidth, !force)){
235                         if (printMessages){
236                             System.out.println(MessageFormat.format(labels.getString("modified"), (Object JavaDoc[])new String JavaDoc[] {args[i]}));
237                         }
238                     } else {
239                         if (printExtraMessages){
240                             System.out.println(MessageFormat.format(labels.getString("alreadycorrect"), (Object JavaDoc[])new String JavaDoc[] {args[i]}));
241                         }
242                     }
243                 } catch (IOException x){
244                     if(printErrors){
245                         System.err.println(args[i] + ": " + x.getMessage());
246                     }
247                     exitCond = 1;
248                 }
249             }
250         }
251         if (!done){
252             if(inputTabWidth == TABS){
253                 System.err.println(labels.getString("stdinguess"));
254                 exitCond = 1;
255             } else {
256                 try {
257                     convert (System.in, System.out, inputTabWidth, outputTabWidth, !force);
258                 } catch (IOException x){
259                     System.err.println(x.getMessage());
260                     exitCond = 1;
261                 }
262             }
263         }
264         System.exit(exitCond);
265     }
266
267     private final static int DEFAULT_INPUT_TAB_WIDTH = 4;
268     private final static int DEFAULT_INPUT_FILE_TAB_WIDTH = TABS;
269     private final static int DEFAULT_OUTPUT_TAB_WIDTH = 4;
270
271     private final static boolean DEFAULT_MODIFY_BINARY = false;
272
273     /**
274      * Read form the input stream, changing the tabs at the beginning of each line
275      * to four spaces, write the result to the output stream.
276      *
277      * @param in stream that contains the text which needs line number conversion.
278      * @param out stream where converted text is written.
279      * @return true if the output was modified from the input, false if it is exactly the same
280      * @throws BinaryDataException if non-text data is encountered.
281      * @throws IOException if an input or output error occurs.
282      *
283      * @since ostermillerutils 1.00.00
284      */

285     public static boolean convert(InputStream in, OutputStream out) throws IOException {
286         return convert(in, out, DEFAULT_INPUT_TAB_WIDTH, DEFAULT_OUTPUT_TAB_WIDTH, DEFAULT_MODIFY_BINARY);
287     }
288
289     /**
290      * Read form the input stream, changing the tabs at the beginning of each line
291      * to the specified number of spaces, write the result to the output stream.
292      *
293      * @param in stream that contains the text which needs line number conversion.
294      * @param out stream where converted text is written.
295      * @param inputTabWidth number of spaces used instead of a tab in the input.
296      * @return true if the output was modified from the input, false if it is exactly the same
297      * @throws BinaryDataException if non-text data is encountered.
298      * @throws IOException if an input or output error occurs.
299      * @throws IllegalArgumentException if tab widths are not between 1 and 20 or TABS.
300      *
301      * @since ostermillerutils 1.00.00
302      */

303     public static boolean convert(InputStream in, OutputStream out, int inputTabWidth) throws IOException {
304         return convert(in, out, inputTabWidth, DEFAULT_OUTPUT_TAB_WIDTH, DEFAULT_MODIFY_BINARY);
305     }
306
307     /**
308      * Read form the input stream, changing the tabs at the beginning of each line
309      * to the specified number of spaces or the other way around, write the result
310      * to the output stream.
311      *
312      * The current system's line separator is used.
313      *
314      * @param in stream that contains the text which needs line number conversion.
315      * @param out stream where converted text is written.
316      * @param inputTabWidth number of spaces used instead of a tab in the input.
317      * @param outputTabWidth TABS if tabs should be used, otherwise, number of spaces to use.
318      * @return true if the output was modified from the input, false if it is exactly the same
319      * @throws BinaryDataException if non-text data is encountered.
320      * @throws IOException if an input or output error occurs.
321      *
322      * @since ostermillerutils 1.00.00
323      */

324     public static boolean convert(InputStream in, OutputStream out, int inputTabWidth, int outputTabWidth) throws IOException {
325         return convert(in, out, inputTabWidth, outputTabWidth, DEFAULT_MODIFY_BINARY);
326     }
327
328     /**
329      * Read form the input stream, changing the tabs at the beginning of each line
330      * to the specified number of spaces or the other way around, write the result
331      * to the output stream.
332      *
333      * The current system's line separator is used.
334      *
335      * @param in stream that contains the text which needs line number conversion.
336      * @param out stream where converted text is written.
337      * @param inputTabWidth number of spaces used instead of a tab in the input.
338      * @param outputTabWidth TABS if tabs should be used, otherwise, number of spaces to use.
339      * @param binaryException throw an exception and abort the operation if binary data is encountered and binaryExcepion is false.
340      * @return true if the output was modified from the input, false if it is exactly the same.
341      * @throws BinaryDataException if non-text data is encountered.
342      * @throws IOException if an input or output error occurs.
343      *
344      * @since ostermillerutils 1.00.00
345      */

346     public static boolean convert(InputStream in, OutputStream out, int inputTabWidth, int outputTabWidth, boolean binaryException) throws IOException {
347         if ((inputTabWidth < 1 || inputTabWidth > 20) && inputTabWidth != TABS){
348             throw new IllegalArgumentException JavaDoc(labels.getString("widtherror"));
349         }
350         if ((outputTabWidth < 1 || outputTabWidth > 20) && outputTabWidth != TABS){
351             throw new IllegalArgumentException JavaDoc(labels.getString("widtherror"));
352         }
353         int state = STATE_INIT;
354         int spaces = 0;
355         int tabs = 0;
356         int tabStops = 0;
357         int extraSpaces = 0;
358         boolean modified = false;
359
360         byte[] buffer = new byte[BUFFER_SIZE];
361         int read;
362         while((read = in.read(buffer)) != -1){
363             for (int i=0; i<read; i++){
364                 byte b = buffer[i];
365                 if(binaryException && b!='\r' && b!='\n' && b!='\t' && b!='\f' && (b & 0xff)<32){
366                     throw new BinaryDataException(labels.getString("binaryexcepion"));
367                 }
368                 switch (b){
369                     case ' ': {
370                         if (state == STATE_INIT) {
371                             spaces++;
372                             extraSpaces++;
373                             if (extraSpaces == inputTabWidth){
374                                 tabStops++;
375                                 extraSpaces = 0;
376                             }
377                         } else {
378                             out.write(b);
379                         }
380                     } break;
381                     case '\t': {
382                         if (state == STATE_INIT) {
383                             if (spaces > 0){
384                                 // put tabs before spaces
385
modified = true;
386                             }
387                             tabs++;
388                             tabStops++;
389                             extraSpaces = 0;
390                         } else {
391                             out.write(b);
392                         }
393                     } break;
394                     case '\r': case '\n': {
395                         out.write(b);
396                         spaces = 0;
397                         tabs = 0;
398                         tabStops = 0;
399                         extraSpaces = 0;
400                         state = STATE_INIT;
401                     } break;
402                     default: {
403                         if (state == STATE_INIT){
404                             if (outputTabWidth == TABS){
405                                 for (int j=0; j<tabStops; j++){
406                                     out.write((byte)'\t');
407                                 }
408                             } else {
409                                 extraSpaces += tabStops * outputTabWidth;
410                                 tabStops = 0;
411                             }
412                             for (int j=0; j<extraSpaces; j++){
413                                 out.write((byte)' ');
414                             }
415                             if (extraSpaces != spaces || tabStops != tabs) modified = true;
416                         }
417                         out.write(b);
418                         state = STATE_SOMETHING;
419                     } break;
420                 }
421             }
422         }
423         return modified;
424     }
425
426     /**
427      * Change the tabs at the beginning of each line of the file to four spaces.
428      * Guess the tab width of the input file.
429      *
430      * @param f File to be converted.
431      * @return true if the file was modified, false if it was already in the correct format
432      * @throws BinaryDataException if non-text data is encountered.
433      * @throws IOException if an input or output error occurs.
434      *
435      * @since ostermillerutils 1.00.00
436      */

437     public static boolean convert(File f) throws IOException {
438         return convert(f, DEFAULT_INPUT_FILE_TAB_WIDTH, DEFAULT_OUTPUT_TAB_WIDTH, DEFAULT_MODIFY_BINARY);
439     }
440
441     /**
442      * Change the tabs at the beginning of each line of the file
443      * to the specified number of spaces.
444      *
445      * @param f File to be converted.
446      * @param inputTabWidth number of spaces used instead of a tab in the input, or TAB to guess.
447      * @return true if the output was modified from the input, false if it is exactly the same
448      * @throws BinaryDataException if non-text data is encountered.
449      * @throws IOException if an input or output error occurs.
450      * @throws IllegalArgumentException if tab widths are not between 1 and 20 or TABS.
451      *
452      * @since ostermillerutils 1.00.00
453      */

454     public static boolean convert(File f, int inputTabWidth) throws IOException {
455         return convert(f, inputTabWidth, DEFAULT_OUTPUT_TAB_WIDTH, DEFAULT_MODIFY_BINARY);
456     }
457
458     /**
459      * Change the tabs at the beginning of each line of the file
460      * to the specified number of spaces or the other way around.
461      *
462      * @param f File to be converted.
463      * @param inputTabWidth number of spaces used instead of a tab in the input, or TAB to guess.
464      * @param outputTabWidth true if tabs should be used, false if spaces should be used.
465      * @return true if the output was modified from the input, false if it is exactly the same
466      * @throws BinaryDataException if non-text data is encountered.
467      * @throws IOException if an input or output error occurs.
468      *
469      * @since ostermillerutils 1.00.00
470      */

471     public static boolean convert(File f, int inputTabWidth, int outputTabWidth) throws IOException {
472         return convert(f, inputTabWidth, outputTabWidth, DEFAULT_MODIFY_BINARY);
473     }
474
475     /**
476      * Change the tabs at the beginning of each line of the file
477      * to the specified number of spaces or the other way around.
478      *
479      * @param f File to be converted.
480      * @param inputTabWidth number of spaces used instead of a tab in the input, or TABS to guess.
481      * @param outputTabWidth true if tabs should be used, false if spaces should be used.
482      * @param binaryException throw an exception and abort the operation if binary data is encountered and binaryExcepion is false.
483      * @return true if the file was modified, false if it was already in the correct format
484      * @throws BinaryDataException if non-text data is encountered.
485      * @throws IOException if an input or output error occurs.
486      * @throws IllegalArgumentException if tab widths are not between 1 and 20 or TABS.
487      *
488      * @since ostermillerutils 1.00.00
489      */

490     public static boolean convert(File f, int inputTabWidth, int outputTabWidth, boolean binaryException) throws IOException {
491         File temp = null;
492         InputStream in = null;
493         OutputStream out = null;
494         boolean modified = false;
495         try {
496             if (inputTabWidth == TABS){
497                 inputTabWidth = guessTabWidth(new FileInputStream(f));
498             }
499             in = new FileInputStream(f);
500             temp = File.createTempFile("LineEnds", null, null);
501             out = new FileOutputStream(temp);
502             modified = convert(in, out, inputTabWidth, outputTabWidth, binaryException);
503             in.close();
504             in = null;
505             out.flush();
506             out.close();
507             out = null;
508             if (modified){
509                 FileHelper.move(temp, f, true);
510             } else {
511                 if (!temp.delete()){
512                     throw new IOException(
513                         MessageFormat.format(
514                             labels.getString("tempdeleteerror"),
515                             (Object JavaDoc[])new String JavaDoc[] {temp.toString()}
516                         )
517                     );
518                 }
519             }
520         } finally {
521             if (in != null){
522                 in.close();
523                 in = null;
524             }
525             if (out != null){
526                 out.flush();
527                 out.close();
528                 out = null;
529             }
530         }
531         return modified;
532     }
533
534     /**
535      * Buffer size when reading from input stream.
536      *
537      * @since ostermillerutils 1.00.00
538      */

539     private final static int BUFFER_SIZE = 1024;
540     private final static int STATE_INIT = 0;
541     private final static int STATE_SOMETHING = 1;
542
543     final private static int MAX_SPACES = 128;
544     final private static int MAX_TABS = 16;
545     final private static int MAX_COMBINED = 256;
546     /**
547      * Guess the number of spaces per tab at the beginning of each line.
548      *
549      * @return the least value (two or greater) which has some line that starts with n times spaces for n zero to max spaces starting a line.
550      *
551      * @since ostermillerutils 1.00.00
552      */

553     public static int guessTabWidth(InputStream in) throws IOException {
554         byte[] buffer = new byte[BUFFER_SIZE];
555         int[][] data = new int[MAX_SPACES][MAX_TABS];
556         int[] spaceData = new int[MAX_SPACES*MAX_TABS];
557         int read;
558         int state = STATE_INIT;
559         int tabs = 0;
560         int spaces = 0;
561         int mostTabs = 0;
562         int mostSpaces = 0;
563         boolean spaceUsed = false;
564         while((read = in.read(buffer)) != -1){
565             for (int i=0; i<read; i++){
566                 byte b = buffer[i];
567                 switch (b){
568                     case ' ': {
569                         if (state == STATE_INIT) spaces++;
570                     } break;
571                     case '\t': {
572                         if (state == STATE_INIT) tabs++;
573                     } break;
574                     case '\r': case '\n': {
575                         state = STATE_INIT;
576                         if (spaces < MAX_SPACES && tabs < MAX_TABS){
577                             data[spaces][tabs]++;
578                             if (tabs > mostTabs) mostTabs = tabs;
579                             if (spaces > mostSpaces) mostSpaces = spaces;
580                             spaces = 0;
581                             tabs = 0;
582                         }
583                     } break;
584                     default: {
585                         state = STATE_SOMETHING;
586                     } break;
587                 }
588             }
589         }
590         for (int tabWidth=2; tabWidth<=20; tabWidth++){
591             int mostCombined=0;
592             for (int tabInd=0; tabInd <= mostTabs; tabInd++){
593                 for (int spaceInd=0; spaceInd <= mostSpaces; spaceInd++){
594                     int totInd = spaceInd + (tabInd * tabWidth);
595                     if (totInd < MAX_COMBINED){
596                         int numLines = data[spaceInd][tabInd];
597                         if (numLines > 0){
598                             if (mostCombined < totInd) mostCombined = totInd;
599                             spaceData[totInd] += numLines;
600                         }
601                     }
602                 }
603             }
604             boolean found = true;
605             for(int combInd=0; found && combInd < mostCombined; combInd+=tabWidth){
606                 found = spaceData[combInd] > 0;
607             }
608             if (found) return tabWidth;
609         }
610         return 2;
611     }
612 }
613
Popular Tags