Package org.jnode.command.file

Source Code of org.jnode.command.file.TailCommand

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library 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 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.command.file;

import org.jnode.shell.AbstractCommand;
import org.jnode.shell.syntax.Argument;
import org.jnode.shell.syntax.FlagArgument;
import org.jnode.shell.syntax.FileArgument;
import org.jnode.shell.syntax.IntegerArgument;
import org.jnode.shell.syntax.StringArgument;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;

/**
* TODO add follow support
* TODO add support for -c +<int> on stdin
*
* @author chris boertien
*/
public class TailCommand extends AbstractCommand {
   
    private static final String help_files = "Print the last 10 lines of each file to stdout, with multiple files a " +
                                             "header giving the file name is printed. With no file, or if file is - " +
                                             "read standard in.";
    private static final String help_bytes = "output the last <int> bytes, or output from +<int> bytes into the file " +
                                             "to the end.";
    private static final String help_follow = "keep the file open, outputing data as the file grows.";
    private static final String help_follow_retry = "same as -f --retry";
    private static final String help_lines = "Output the last <int> lines instead of, or +<int> to start printing " +
                                             "from that line";
    private static final String help_unchanged = "with -f, reopen the file when the size has not change for <int> " +
                                                 "iterations to see if it has be unlinked or renamed Default is 5";
    @SuppressWarnings("unused")
    private static final String help_pid = "with -f, terminate after process PID does (how?)";
    private static final String help_sleep = "with -f, sleep for <int> seconds between iterations. Default is 1";
    private static final String help_quiet = "never output headers giving file names";
    private static final String help_verbose = "always output headers giving file names";
    private static final String help_retry = "keep trying to open a file even if it is inaccessible at the start, or " +
                                             "if it becomes inaccessible.";
   
    private final FileArgument Files;
    private final StringArgument Bytes;
    private final StringArgument Lines;
    // FIXME this has to be able to handle -f --follow and --folow=<file>
    private final FlagArgument Follow;
    private final FlagArgument FollowR;
    private final IntegerArgument MaxUnchanged;
    private final IntegerArgument Sleep;
    private final FlagArgument Retry;
    private final FlagArgument Quiet;
    private final FlagArgument Verbose;
    // TODO This might work as thread id, since we dont have process ids
    //private final IntegerArgument PID = new IntegerArgument("pid", Argument.OPTIONAL, help_pid);
   
    private PrintWriter err;
   
    private int count;
    @SuppressWarnings("unused")
    private int sleep;
    @SuppressWarnings("unused")
    private int unchanged;
    private boolean headers;
    private boolean useLines;
    private boolean reverse;
    private boolean follow;
    @SuppressWarnings("unused")
    private boolean retry;
    private boolean first = true;
   
    public TailCommand() {
        super("Print the tail end of a list of files, or stdin.");
        Files        = new FileArgument("files", Argument.OPTIONAL | Argument.MULTIPLE, help_files);
        Bytes        = new StringArgument("bytes", Argument.EXISTING | Argument.OPTIONAL, help_bytes);
        Lines        = new StringArgument("lines", Argument.EXISTING | Argument.OPTIONAL, help_lines);
        Follow       = new FlagArgument("follow", Argument.OPTIONAL, help_follow);
        FollowR      = new FlagArgument("followr", Argument.OPTIONAL, help_follow_retry);
        MaxUnchanged = new IntegerArgument("unchanged", Argument.OPTIONAL, help_unchanged);
        Sleep        = new IntegerArgument("sleep", Argument.OPTIONAL, help_sleep);
        Retry        = new FlagArgument("retry", Argument.OPTIONAL, help_retry);
        Quiet        = new FlagArgument("quiet", Argument.OPTIONAL, help_quiet);
        Verbose      = new FlagArgument("verbose", Argument.OPTIONAL, help_verbose);
        registerArguments(Files, Bytes, Lines, Follow, Retry, FollowR, MaxUnchanged, Sleep, Quiet, Verbose);
    }
   
    public void execute() {
        File[] files;
        err       = getError().getPrintWriter();
        headers   = getHeaders();
        useLines  = getCountType();
        count     = getCount();
        reverse   = getReversed();
        follow    = Follow.isSet() || FollowR.isSet();
        retry     = Retry.isSet()  || FollowR.isSet();
        sleep     = Sleep.isSet() ? Sleep.getValue() : 1;
        unchanged = MaxUnchanged.isSet() ? MaxUnchanged.getValue() : 5;
       
        if (follow) {
            err.println("Follow not supported yet");
            exit(1);
        }
       
        if (!Files.isSet()) {
            files = new File[1];
            files[0] = new File("-");
        } else {
            files = Files.getValues();
        }
       
        try {
            for (File file : files) {
                printHeader(file.getPath());
                if (!file.getName().equals("-")) {
                    if (useLines) {
                        printFileLines(file);
                    } else {
                        printFileBytes(file);
                    }
                } else {
                    if (useLines) {
                        printStdinLines();
                    } else {
                        printStdinBytes();
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            exit(1);
        }
    }
   
    private void printStdinLines() {
        try {
            printLines(new LineNumberReader(new InputStreamReader(getInput().getInputStream())));
        } catch (IOException ex) {
            err.println(ex);
        }
    }
   
    private void printStdinBytes() {
        try {
            printBytes(getInput().getInputStream(), -1);
        } catch (IOException ex) {
            err.println(ex);
        }
    }
   
    private void printFileLines(File file) {
        LineNumberReader reader = null;
        try {
            reader = new LineNumberReader(new FileReader(file));
            printLines(reader);
        } catch (IOException ex) {
            err.println(ex);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException _) {
                    // ignore
                }
            }
        }
    }
   
    private void printFileBytes(File file) {
        InputStream in = null;
        try {
            in = new FileInputStream(file);
            printBytes(in, (int) file.length());
        } catch (IOException ex) {
            err.println(ex);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException _) {
                    // ignore
                }
            }
        }
    }
   
    private void printLines(LineNumberReader reader) throws IOException {
        PrintWriter out = getOutput().getPrintWriter();
        String line;
        if (reverse) {
            int n = count;
            while (--n > 0 && reader.readLine() != null) {
                // no-op
            }
            while ((line = reader.readLine()) != null) {
                out.println(line);
            }
        } else {
            List<String> lines = new ArrayList<String>();
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
           
            int n = Math.max(0, lines.size() - count);
            for (; n < lines.size(); n++) {
                out.println(lines.get(n));
            }
        }
    }
   
    private void printBytes(InputStream in, int size) throws IOException {
        OutputStream out = getOutput().getOutputStream();
        byte[] buffer;
        int len;
        int bufsize = 8 * 1024;
       
        if (reverse) {
            in.skip(count + 1);
        } else if (size != -1) {
            in.skip(Math.max(0, size - count));
        } else {
            throw new UnsupportedOperationException("Cannot do -count byte reads on stdin yet");
        }
       
        buffer = new byte[bufsize];
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
    }
   
    private void printHeader(String name) {
        PrintWriter out = getOutput().getPrintWriter();
        if (headers) {
            if (!first) {
                out.println();
            }
            first = false;
            if (name.equals("-")) {
                out.println("==> standard input <==");
            } else {
                out.println("==> " + name + " <==");
            }
        }
    }
   
    private boolean getHeaders() {
        if (Quiet.isSet()) {
            return false;
        } else if (Verbose.isSet()) {
            return true;
        } else {
            return headers = Files.isSet() && Files.getValues().length > 1;
        }
    }
   
    private boolean getCountType() {
        return !Bytes.isSet();
    }
   
    private int getCount() {
        int count = 10;
        if (Bytes.isSet()) {
            count = parseInt(Bytes.getValue());
        }
        if (Lines.isSet()) {
            count = parseInt(Lines.getValue());
        }
        return count < 0 ? 10 : count;
    }
   
    private boolean getReversed() {
        if (Bytes.isSet()) {
            return Bytes.getValue().charAt(0) == '+';
        } else if (Lines.isSet()) {
            return Lines.getValue().charAt(0) == '+';
        }
        return false;
    }

    private int parseInt(String s) {
        if (s.charAt(0) == '+' || s.charAt(0) == '-') {
            s = s.substring(1);
        }
        try {
            return Integer.parseInt(s);
        } catch (NumberFormatException ex) {
            return -1;
        }
    }
}
TOP

Related Classes of org.jnode.command.file.TailCommand

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.