001package org.unix4j.unix.head;
002
003import java.io.File;
004import java.util.Arrays;
005import java.util.List;
006
007import org.unix4j.command.AbstractCommand;
008import org.unix4j.context.ExecutionContext;
009import org.unix4j.io.FileInput;
010import org.unix4j.io.Input;
011import org.unix4j.line.Line;
012import org.unix4j.line.SimpleLine;
013import org.unix4j.processor.DefaultInputProcessor;
014import org.unix4j.processor.InputProcessor;
015import org.unix4j.processor.LineProcessor;
016import org.unix4j.processor.MultipleInputLineProcessor;
017import org.unix4j.processor.RedirectInputLineProcessor;
018import org.unix4j.unix.Head;
019import org.unix4j.util.FileUtil;
020
021/**
022 * Implementation of the {@link Head head} command.
023 */
024class HeadCommand extends AbstractCommand<HeadArguments> {
025        public HeadCommand(HeadArguments arguments) {
026                super(Head.NAME, arguments);
027                if (arguments.isCountSet() && arguments.getCount() < 0) {
028                        throw new IllegalArgumentException("count cannot be negative: " + arguments);
029                }
030        }
031
032        @Override
033        public LineProcessor execute(ExecutionContext context, final LineProcessor output) {
034                final HeadArguments args = getArguments(context);
035                
036                //input from file(s)?
037                if (args.isFilesSet()) {
038                        final List<FileInput> inputs = FileInput.multiple(args.getFiles());
039                        return getFileInputProcessor(inputs, context, output, args);
040                } else if (args.isPathsSet()) {
041                        final List<File> files = FileUtil.expandFiles(context.getCurrentDirectory(), args.getPaths());
042                        final List<FileInput> inputs = FileInput.multiple(files);
043                        return getFileInputProcessor(inputs, context, output, args);
044                } else if (args.isInputsSet()) {
045                        final List<Input> inputs = Arrays.asList(args.getInputs());
046                        return getFileInputProcessor(inputs, context, output, args);
047                }
048                
049                //read from standard input
050                return getStandardInputProcessor(context, output, args);
051        }
052        
053        private AbstractHeadProcessor getStandardInputProcessor(ExecutionContext context, LineProcessor output, HeadArguments args) {
054                if (args.isChars()) {
055                        //count chars
056                        return new HeadCharsProcessor(this, context, output);
057                } else {
058                        //count lines
059                        return new HeadLinesProcessor(this, context, output);
060                }
061        }
062        
063        private LineProcessor getFileInputProcessor(List<? extends Input> inputs, final ExecutionContext context, final LineProcessor output, HeadArguments args) {
064                final AbstractHeadProcessor headProcessor = getStandardInputProcessor(context, output, args);
065                if (inputs.size() <= 1 || args.isSuppressHeaders()) {
066                        return new RedirectInputLineProcessor(inputs, headProcessor);
067                } else {
068                        //write header line per file
069                        final InputProcessor inputProcessor = new DefaultInputProcessor() {
070                                private boolean firstFile = true;
071                                @Override
072                                public void begin(Input input, LineProcessor standardInputProcessor) {
073                                        if (firstFile) {
074                                                firstFile = false;
075                                        } else {
076                                                output.processLine(Line.EMPTY_LINE);
077                                        }
078                                        final String fileInfo = input instanceof FileInput ? ((FileInput)input).getFileInfo(context.getCurrentDirectory()) : input.toString();
079                                        output.processLine(new SimpleLine("==> " + fileInfo + " <=="));
080                                }
081
082                @Override
083                public void finish(Input input, LineProcessor output) {
084                    super.finish(input, output);
085                    headProcessor.resetCounter();
086                }
087            };
088                        return new MultipleInputLineProcessor(inputs, inputProcessor, headProcessor);
089                }
090        }
091}