All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.Ostermiller.util.Tabs Maven / Gradle / Ivy

Go to download

Open source (GPL) Java utilities maintained by Stephen Ostermiller with help from many contributors.

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

package com.Ostermiller.util;

import java.io.*;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import java.util.Locale;

/**
 * Stream editor to alter the line separators on text to match
 * that of a given platform.
 * More information about this class is available from ostermiller.org.
 *
 * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
 * @since ostermillerutils 1.00.00
 */
public class Tabs {

	/**
	 * Version number of this program
	 *
	 * @since ostermillerutils 1.00.00
	 */
	public static final String version = "1.1";

	/**
	 * Locale specific strings displayed to the user.
	 *
	 * @since ostermillerutils 1.00.00
	 */
	 protected static ResourceBundle labels = ResourceBundle.getBundle("com.Ostermiller.util.Tabs",  Locale.getDefault());


	/**
	 * Can be passed instead of a spaces argument to use tabs instead.
	 *
	 * @since ostermillerutils 1.00.00
	 */
	public final static int TABS = -1;

	private enum TabsCmdLnOption {
		/** --help */
		HELP(new CmdLnOption(labels.getString("help.option")).setDescription( labels.getString("help.message"))),
		/** --version */
		VERSION(new CmdLnOption(labels.getString("version.option")).setDescription(labels.getString("version.message"))),
		/** --about */
		ABOUT(new CmdLnOption(labels.getString("about.option")).setDescription(labels.getString("about.message"))),
		/** --width */
		WIDTH(new CmdLnOption(labels.getString("width.option"), 'w').setDescription(labels.getString("w.message")).setRequiredArgument()),
		/** --guess */
		GUESS(new CmdLnOption(labels.getString("guess.option"), 'g').setDescription(labels.getString("g.message") + " (" + labels.getString("default") + ")")),
		/** --tabs */
		TABS(new CmdLnOption(labels.getString("tabs.option"), 't').setDescription(labels.getString("t.message"))),
		/** --spaces */
		SPACES(new CmdLnOption(labels.getString("spaces.option"), 's').setDescription(labels.getString("s.message") + " (" + labels.getString("default") + "=4)").setRequiredArgument()),
		/** --force */
		FORCE(new CmdLnOption(labels.getString("force.option"), 'f').setDescription(labels.getString("f.message"))),
		/** --noforce */
		NOFORCE(new CmdLnOption(labels.getString("noforce.option")).setDescription(labels.getString("noforce.message") + " (" + labels.getString("default") + ")")),
		/** --reallyverbose */
		REALLYVERBOSE(new CmdLnOption(labels.getString("reallyverbose.option"), 'V').setDescription(labels.getString("V.message"))),
		/** --verbose */
		VERBOSE(new CmdLnOption(labels.getString("verbose.option"), 'v').setDescription(labels.getString("v.message"))),
		/** --quiet */
		QUIET(new CmdLnOption(labels.getString("quiet.option"), 'q').setDescription(labels.getString("q.message") + " (" + labels.getString("default") + ")")),
		/** --reallyquiet */
		REALLYQUIET(new CmdLnOption(labels.getString("reallyquiet.option"), 'Q').setDescription(labels.getString("Q.message")));

		private CmdLnOption option;

		private TabsCmdLnOption(CmdLnOption option){
			option.setUserObject(this);
			this.option = option;
		}

		private CmdLnOption getCmdLineOption(){
			return option;
		}
	}

	/**
	 * Converts the tabs in files, or standard input.
	 * Run with --help argument for more information.
	 *
	 * @param args Command line arguments.
	 *
	 * @since ostermillerutils 1.00.00
	 */
	public static void main(String[] args){
		CmdLn commandLine = new CmdLn(
			args
		).setDescription(
			labels.getString("tabs") + labels.getString("purpose.message")
		);
		for (TabsCmdLnOption option: TabsCmdLnOption.values()){
			commandLine.addOption(option.getCmdLineOption());
		}
		int inputTabWidth = TABS;
		int outputTabWidth = 4;
		boolean force = false;
		boolean printMessages = false;
		boolean printExtraMessages = false;
		boolean printErrors = true;
		for(CmdLnResult result: commandLine.getResults()){
			switch((TabsCmdLnOption)result.getOption().getUserObject()){
				case HELP:{
					commandLine.printHelp();
					System.exit(0);
				} break;
				case VERSION:{
					// print out the version message
					System.out.println(MessageFormat.format(labels.getString("version"), (Object[])new String[] {version}));
					System.exit(0);
				} break;
				case ABOUT:{
					System.out.println(
						labels.getString("tabs") + " -- " + labels.getString("purpose.message") + "\n" +
						MessageFormat.format(labels.getString("copyright"), (Object[])new String[] {"2002-2007", "Stephen Ostermiller (http://ostermiller.org/contact.pl?regarding=Java+Utilities)"}) + "\n\n" +
						labels.getString("license")
					);
					System.exit(0);
				} break;
				case WIDTH:{
					try {
						inputTabWidth = Integer.parseInt(commandLine.getResult('w').getArgument());
					} catch (NumberFormatException x){
						inputTabWidth = -1;
					}
					if (inputTabWidth<1 || inputTabWidth>20){
						System.err.println(labels.getString("widtherror"));
						System.exit(1);
					}
				} break;
				case GUESS:{
					inputTabWidth = TABS;
				} break;
				case SPACES:{
					try {
						outputTabWidth = Integer.parseInt(commandLine.getResult('s').getArgument());
					} catch (NumberFormatException x){
						outputTabWidth = -1;
					}
					if (outputTabWidth<1 || outputTabWidth>20){
						System.err.println("widtherror");
						System.exit(1);
					}
				} break;
				case TABS:{
					outputTabWidth = TABS;
				} break;
				case FORCE:{
					force = true;
				} break;
				case NOFORCE:{
					force = false;
				} break;
				case REALLYVERBOSE:{
					printExtraMessages = true;
					printMessages = true;
					printErrors = true;
				} break;
				case VERBOSE:{
					printExtraMessages = false;
					printMessages = true;
					printErrors = true;
				} break;
				case QUIET:{
					printExtraMessages = false;
					printMessages = false;
					printErrors = true;
				} break;
				case REALLYQUIET:{
					printExtraMessages = false;
					printMessages = false;
					printErrors = false;
				} break;
			}
		}

		int exitCond = 0;
		boolean done = false;
		for (String argument: commandLine.getNonOptionArguments()){
			done = true;
			File source = new File(argument);
			if (!source.exists()){
				if(printErrors){
					System.err.println(MessageFormat.format(labels.getString("doesnotexist"), (Object[])new String[] {argument}));
				}
				exitCond = 1;
			} else if (!source.canRead()){
				if(printErrors){
					System.err.println(MessageFormat.format(labels.getString("cantread"), (Object[])new String[] {argument}));
				}
				exitCond = 1;
			} else if (!source.canWrite()){
				if(printErrors){
					System.err.println(MessageFormat.format(labels.getString("cantwrite"), (Object[])new String[] {argument}));
				}
				exitCond = 1;
			} else {
				try {
					if(convert (source, inputTabWidth, outputTabWidth, !force)){
						if (printMessages){
							System.out.println(MessageFormat.format(labels.getString("modified"), (Object[])new String[] {argument}));
						}
					} else {
						if (printExtraMessages){
							System.out.println(MessageFormat.format(labels.getString("alreadycorrect"), (Object[])new String[] {argument}));
						}
					}
				} catch (IOException x){
					if(printErrors){
						System.err.println(argument + ": " + x.getMessage());
					}
					exitCond = 1;
				}
			}
		}
		if (!done){
			if(inputTabWidth == TABS){
				System.err.println(labels.getString("stdinguess"));
				exitCond = 1;
			} else {
				try {
					convert (System.in, System.out, inputTabWidth, outputTabWidth, !force);
				} catch (IOException x){
					System.err.println(x.getMessage());
					exitCond = 1;
				}
			}
		}
		System.exit(exitCond);
	}

	private final static int DEFAULT_INPUT_TAB_WIDTH = 4;
	private final static int DEFAULT_INPUT_FILE_TAB_WIDTH = TABS;
	private final static int DEFAULT_OUTPUT_TAB_WIDTH = 4;

	private final static boolean DEFAULT_MODIFY_BINARY = false;

	/**
	 * Read form the input stream, changing the tabs at the beginning of each line
	 * to four spaces, write the result to the output stream.
	 *
	 * @param in stream that contains the text which needs line number conversion.
	 * @param out stream where converted text is written.
	 * @return true if the output was modified from the input, false if it is exactly the same
	 * @throws BinaryDataException if non-text data is encountered.
	 * @throws IOException if an input or output error occurs.
	 *
	 * @since ostermillerutils 1.00.00
	 */
	public static boolean convert(InputStream in, OutputStream out) throws IOException {
		return convert(in, out, DEFAULT_INPUT_TAB_WIDTH, DEFAULT_OUTPUT_TAB_WIDTH, DEFAULT_MODIFY_BINARY);
	}

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

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

	/**
	 * Read form the input stream, changing the tabs at the beginning of each line
	 * to the specified number of spaces or the other way around, write the result
	 * to the output stream.
	 *
	 * The current system's line separator is used.
	 *
	 * @param in stream that contains the text which needs line number conversion.
	 * @param out stream where converted text is written.
	 * @param inputTabWidth number of spaces used instead of a tab in the input.
	 * @param outputTabWidth TABS if tabs should be used, otherwise, number of spaces to use.
	 * @param binaryException throw an exception and abort the operation if binary data is encountered and binaryExcepion is false.
	 * @return true if the output was modified from the input, false if it is exactly the same.
	 * @throws BinaryDataException if non-text data is encountered.
	 * @throws IOException if an input or output error occurs.
	 *
	 * @since ostermillerutils 1.00.00
	 */
	public static boolean convert(InputStream in, OutputStream out, int inputTabWidth, int outputTabWidth, boolean binaryException) throws IOException {
		if ((inputTabWidth < 1 || inputTabWidth > 20) && inputTabWidth != TABS){
			throw new IllegalArgumentException(labels.getString("widtherror"));
		}
		if ((outputTabWidth < 1 || outputTabWidth > 20) && outputTabWidth != TABS){
			throw new IllegalArgumentException(labels.getString("widtherror"));
		}
		int state = STATE_INIT;
		int spaces = 0;
		int tabs = 0;
		int tabStops = 0;
		int extraSpaces = 0;
		boolean modified = false;

		byte[] buffer = new byte[BUFFER_SIZE];
		int read;
		while((read = in.read(buffer)) != -1){
			for (int i=0; i 0){
								// put tabs before spaces
								modified = true;
							}
							tabs++;
							tabStops++;
							extraSpaces = 0;
						} else {
							out.write(b);
						}
					} break;
					case '\r': case '\n': {
						out.write(b);
						spaces = 0;
						tabs = 0;
						tabStops = 0;
						extraSpaces = 0;
						state = STATE_INIT;
					} break;
					default: {
						if (state == STATE_INIT){
							if (outputTabWidth == TABS){
								for (int j=0; j mostTabs) mostTabs = tabs;
							if (spaces > mostSpaces) mostSpaces = spaces;
							spaces = 0;
							tabs = 0;
						}
					} break;
					default: {
						state = STATE_SOMETHING;
					} break;
				}
			}
		}
		for (int tabWidth=2; tabWidth<=20; tabWidth++){
			int mostCombined=0;
			for (int tabInd=0; tabInd <= mostTabs; tabInd++){
				for (int spaceInd=0; spaceInd <= mostSpaces; spaceInd++){
					int totInd = spaceInd + (tabInd * tabWidth);
					if (totInd < MAX_COMBINED){
						int numLines = data[spaceInd][tabInd];
						if (numLines > 0){
							if (mostCombined < totInd) mostCombined = totInd;
							spaceData[totInd] += numLines;
						}
					}
				}
			}
			boolean found = true;
			for(int combInd=0; found && combInd < mostCombined; combInd+=tabWidth){
				found = spaceData[combInd] > 0;
			}
			if (found) return tabWidth;
		}
		return 2;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy