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