/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * jAstyle library includes in most of its parts translated C++ code originally * developed by Jim Pattee and Tal Davidson for the Artistic Style project. * * Copyright (C) 2009 by Hector Suarez Barenca http://barenca.net * Copyright (C) 2013 by Abrar Syed <sacabrarsyed@gmail.com> * Copyright (C) 2006-2008 by Jim Pattee <jimp03@email.com> * Copyright (C) 1998-2002 by Tal Davidson * <http://www.gnu.org/licenses/lgpl-3.0.html> * * This file is a part of jAstyle library - an indentation and * reformatting library for C, C++, C# and Java source files. * <http://jastyle.sourceforge.net> * * jAstyle is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * jAstyle 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with jAstyle. If not, see <http://www.gnu.org/licenses/>. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package decompsource.com.github.abrarsyed.jastyle; import java.io.*; import java.util.ArrayList; public class Main { private final static int EXIT_SUCCESS = 0; private final static int EXIT_FAILURE = -1; private final static String JASTYLE_VERSION = findVersion("version.txt"); private static boolean recursive = false; private static File optionsFile = null; public static ArrayList<String> errors = new ArrayList<String>(); private final static void printVersion() { System.out.println("\n jAstyle " + JASTYLE_VERSION); System.out.println(" Maintained by: AbrarSyed\n"); } private final static void printHelp() { printVersion(); printText("help.txt", new PrintWriter(System.out)); } private final static String findVersion(String filename) { StringWriter writer = new StringWriter(); printText(filename, new PrintWriter(writer)); return writer.toString(); } private final static void printText(String filename, PrintWriter out) { BufferedReader reader = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(filename))); String line; try { do { line = reader.readLine(); if (line != null) { out.println(line); } } while (line != null); out.flush(); reader.close(); } catch (IOException e) { e.printStackTrace(); } } // /** // * LINUX function to resolve wildcards and recurse into sub directories. // * The fileName vector is filled with the path and names of files to // process. // * // * @param directory The path of the directory to be processed. // * @param wildcard The wildcard to be processed (e.g. *.cpp). // * @param fileName An empty vector which will be filled with the path and // names of files to process. // */ // void getFileNames( String directory, String wildcard, List<String> // fileName) // { // dirent *entry; // entry from readdir() // stat statbuf; // entry from stat() // vector<String> subDirectory; // sub directories of this directory // // // errno is defined in <errno.h> and is set for errors in opendir, // readdir, or stat // errno = 0; // // DIR *dp = opendir(directory); // if (errno) // error("Cannot open directory", directory); // // // save the first fileName entry for this recursion // unsigned firstEntry = fileName.size(); // // // save files and sub directories // while ((entry = readdir(dp)) != null) // { // // get file status // String entryFilepath = directory + FILE_SEPARATOR + entry->d_name; // stat(entryFilepath, statbuf); // if (errno) // { // if (errno == EOVERFLOW) // file over 2 GB is OK // { // errno = 0; // continue; // } // perror("errno message"); // error("Error getting file status in directory", directory); // } // // skip hidden or read only // if (entry->d_name[0] == '.' || !(statbuf.st_mode & S_IWUSR)) // continue; // // if a sub directory and recursive, save sub directory // if (S_ISDIR(statbuf.st_mode) && isRecursive) // { // if (isPathExclued(entryFilepath)) // System.out.println("exclude " + // entryFilepath.substr(mainDirectoryLength)); // else // subDirectory.push_back(entryFilepath); // continue; // } // // // if a file, save file name // if (S_ISREG(statbuf.st_mode)) // { // // check exclude before wildcmp to avoid "unmatched exclude" error // boolean isExcluded = isPathExclued(entryFilepath); // // save file name if wildcard match // if (wildcmp(wildcard, entry->d_name)) // { // if (isExcluded) // System.out.println("exclude " + // entryFilepath.substr(mainDirectoryLength)); // else // fileName.push_back(entryFilepath); // } // } // } // closedir(dp); // // if (errno) // { // perror("errno message"); // error("Error reading directory", directory); // } // // // sort the current entries for fileName // if (firstEntry < fileName.size()) // sort(fileName[firstEntry], fileName[fileName.size()]); // // // recurse into sub directories // // if not doing recursive, subDirectory is empty // if (subDirectory.size() > 1) // sort(subDirectory.begin(), subDirectory.end()); // for (unsigned i = 0; i < subDirectory.size(); i++) // { // getFileNames(subDirectory[i], wildcard, fileName); // } // // return; // } // // // void preserveFileDate(String oldFileName, String newFileName) // { // stat stBuf; // boolean statErr = false; // if (stat (oldFileName, stBuf) == -1) // statErr = true; // else // { // utimbuf outBuf; // outBuf.actime = stBuf.st_atime; // // add 2 so 'make' will recoginze a change // // Visual Studio 2008 needs 2 // outBuf.modtime = stBuf.st_mtime + 2; // if (utime (newFileName, outBuf) == -1) // statErr = true; // } // if (statErr) // System.out.println(" Could not preserve file date"); // } // // process a command-line file path, including wildcards // void processFilePath(String filePath, ASFormatter formatter) // { // vector<String> fileName; // files to be processed including path // String targetDirectory; // path to the directory being processed // String targetFilename; // file name being processed // // // standardize the file separators // standardizePath(filePath); // // // separate directory and file name // size_t separator = filePath.find_last_of(FILE_SEPARATOR); // if (separator == -1) // { // // if no directory is present, use the currently active directory // targetDirectory = getCurrentDirectory(filePath); // targetFilename = filePath; // mainDirectoryLength = targetDirectory.length() + 1; // +1 includes // trailing separator // } // else // { // targetDirectory = filePath.substr(0, separator); // targetFilename = filePath.substr(separator+1); // mainDirectoryLength = targetDirectory.length() + 1; // +1 includes // trailing separator // } // // if (targetFilename.length() == 0) // error("Missing filename in", filePath); // // // check filename for wildcards // hasWildcard = false; // if (targetFilename.find_first_of( "*?") != -1) // hasWildcard = true; // // // clear exclude hits vector // for (size_t ix = 0; ix < excludeHitsVector.size(); ix++) // excludeHitsVector[ix] = false; // // // display directory name for wildcard processing // if (hasWildcard && ! isQuiet) // { // System.out.println("--------------------------------------------------"); // System.out.println("directory " + targetDirectory + FILE_SEPARATOR + // targetFilename; // } // // // create a vector of paths and file names to process // if (hasWildcard || isRecursive) // getFileNames(targetDirectory, targetFilename, fileName); // else // fileName.push_back(filePath); // // if (hasWildcard && ! isQuiet) // System.out.println("--------------------------------------------------"); // // // check for unprocessed excludes // boolean excludeErr = false; // for (size_t ix = 0; ix < excludeHitsVector.size(); ix++) // { // if (excludeHitsVector[ix] == false) // { // System.out.println("Unmatched exclude " + excludeVector[ix]); // excludeErr = true; // } // } // if (excludeErr) // exit(EXIT_FAILURE); // // // check if files were found (probably an input error if not) // if (fileName.size() == 0) // System.out.println("No file to process " + filePath); // // // loop thru fileName vector to format the files // for (size_t j = 0; j < fileName.size(); j++) // { // // format the file // boolean isFormatted = formatFile(fileName[j], formatter); // // // remove targetDirectory from filename if required // String displayName; // if (hasWildcard) // displayName = fileName[j].substr(targetDirectory.length() + 1); // else // displayName = fileName[j]; // // if (isFormatted) // { // filesFormatted++; // if (!isQuiet) // System.out.println("formatted " + displayName); // } // else // { // filesUnchanged++; // if (!isQuiet && !isFormattedOnly) // System.out.println("unchanged* " + displayName); // } // } // } // // , optionsVector, and fileOptionsVector // // rename a file and check for an error // void renameFile(String oldFileName, String newFileName, String errMsg) // { // rename(oldFileName, newFileName); // // if file still exists the remove needs more time - retry // if (errno == EEXIST) // { // errno = 0; // waitForRemove(newFileName); // rename(oldFileName, newFileName); // } // if (errno) // { // perror("errno message"); // error(errMsg, oldFileName); // } // } /** * Not supported options:<br> * <p/> * <p/> * <pre> * --suffix=#### * --suffix=none / -n * --exclude=#### * --errors-to-stdout / -X * --preserve-date / -Z * --verbose / -v * --formatted / -Q * --quiet / -q * </pre> * * @param cliArgs * @throws IOException */ public static void main(String[] cliArgs) throws IOException { // intial catch for no options if (cliArgs.length < 1) { printHelp(); System.exit(EXIT_SUCCESS); } System.out.println("Parsing options..."); // clear errors list. errors.clear(); // convert to list so we can add and remove stuff easily. ArrayList<String> args = convertList(cliArgs); // parse non-formatter stuff changes the args list too. ArrayList<String> filenames = parseConsoleOptions(args); ASFormatter formatter = new ASFormatter(); OptParser parser = new OptParser(formatter); // check options file first.. since they are overwrite by the other options. if (optionsFile != null) { // get the errors... ArrayList<String> parsedErrors = parser.parseOptionFile(optionsFile); // catch and output the IO error. if (parsedErrors == null) { errors.add("something went wrong reading options file : " + optionsFile); } // and add them to the actual errors list. for (String e : parsedErrors) { System.err.println(e + " is not a supported config file option, continuing..."); } } // now the normal options. for (String opt : args) { try { parser.parseOption(opt); } catch (MalformedOptionException e) { errors.add("option " + opt + " is not a valid option"); } } // grab the errors before anything special happens. if (errors.size() > 0) { for (String error : errors) { System.err.println(error); } System.exit(EXIT_FAILURE); } // now we make sure there are no conflicting messages. formatter.fixOptionVariableConflicts(); System.out.println("Parsing file names..."); // now we go through the filenames and parse them into files. ArrayList<File> files = parseFileNames(filenames, recursive); System.out.println("Formatting files."); // now we format the collected files boolean worked; for (File currFile : files) { System.out.println("Converting " + currFile.getAbsolutePath() + " ...\n"); worked = formatter.formatFile(currFile); if (!worked) { System.out.println("Error formatting file " + currFile.getAbsolutePath() + " ...\n"); } } System.out.println("Complete"); System.exit(EXIT_SUCCESS); } /** * This method parses the CommandLine options that have no bearing on the actual formatting, and will ONLY be parsed when coming from the command line. * The OptParser is reserved for only changing formatter options. * * @param args A list with all of the parsed options removed. leaving only things for the OptParser to go through. * @return A list of FileNames to be parsed into actual paths */ public static ArrayList<String> parseConsoleOptions(ArrayList<String> args) { ArrayList<String> filenames = new ArrayList<String>(); ArrayList<String> toRemove = new ArrayList<String>(); String temp; // used normal loop so I can remove elements for (String arg : args) { if (arg.startsWith("--")) { // LONG CLI options temp = arg.substring(2); if (temp.equals("recursive")) { recursive = true; } else if (temp.equals("version")) { printVersion(); System.exit(EXIT_SUCCESS); } else if (temp.equals("help")) { printHelp(); System.exit(EXIT_SUCCESS); } else if (temp.startsWith("options=")) { temp = temp.substring(8); if (temp.equals("none")) { optionsFile = null; } else { optionsFile = new File(temp); if (!optionsFile.exists()) { errors.add("the file " + temp + " could not be found."); } } } else { // other options that havent been parsed yet. continue; } toRemove.add(arg); } else if (arg.startsWith("-")) { if (arg.length() > 2) { // leave real error checking to the OptParser //errors.add(arg + " is not a supported command-line option."); continue; } // SHORT CLI options switch (arg.charAt(1)) { case 'r': case 'R': recursive = true; toRemove.add(arg); // only one that doesn't terminate the program. break; case 'V': printVersion(); System.exit(EXIT_SUCCESS); case 'h': case '?': printHelp(); System.exit(EXIT_SUCCESS); } } else { // isn't a short or a long. good to add as a file. filenames.add(arg); // remove these from the list so they arn't flagged in the OptParser. toRemove.add(arg); } } args.removeAll(toRemove); return filenames; } /** * Parses filenames and patterns into a list of existing files. * * @param filenames List of filenames to parse. * @param recursive Whether or not to search recursively * @return a list of existing files. */ private static ArrayList<File> parseFileNames(ArrayList<String> filenames, boolean recursive) { ArrayList<File> files = new ArrayList<File>(); FilenameFilter filter = null; File temp; String dir, name; // collect potential files for (String filepath : filenames) { int index = filepath.lastIndexOf(File.separatorChar); // no slash? directory is here. if (index < 0) { dir = "."; name = filepath; } else { // slash index is somehow larger than string??? this isnt possible..... if (index >= filepath.length()) { System.err.println("The filename " + filepath + " is invalid"); System.exit(EXIT_FAILURE); } // split the dir and the file name into different strings for parsing later dir = filepath.substring(0, index); name = filepath.substring(index + 1); } // filename with wildcard if (name.indexOf('*') != -1 || name.indexOf('?') != -1) { // set teh filter filter = new FileWildcardFilter(name); // set teh searching file to the directory temp = new File(dir); } // only possible with a trailing slash // pointing to a directory no? else if (name.isEmpty()) { temp = new File(dir); } // straight up filename else { temp = new File(dir, name); } // collect the files files.addAll(collectFiles(temp, filter, recursive)); // clear filter status. filter = null; } return files; } private static <T> ArrayList<T> convertList(T[] array) { ArrayList<T> list = new ArrayList<T>(); for (T obj : array) { list.add(obj); } return list; } /** * @param dir Directory to search in * @param filter Filter to apply to files. May be null to accept all the file names. * @param recurse If subdirectopries should be recursed through or not. * @return ArrayList of accepted files. Will never be null, only an empty list. */ public static ArrayList<File> collectFiles(File dir, FilenameFilter filter, boolean recurse) { ArrayList<File> files = new ArrayList<File>(); // check if supplied directory is a file itself. if (dir.isFile() && (filter == null || filter.accept(dir, dir.getName()))) { files.add(dir); return files; } // otherwise.. recurse and search for files. for (File file : dir.listFiles()) { // if its a file, AND ..... // if the filter is null, add it. // if filter accepts the file add it. if (file.isFile() && (filter == null || filter.accept(dir, file.getName()))) { files.add(file); } // its a directory and recursing is enabled.. recurse. if (file.isDirectory() && recurse) { files.addAll(collectFiles(file, filter, recurse)); } } return files; } }