001package org.unix4j.unix.grep;
002
003import org.unix4j.command.AbstractCommand;
004import org.unix4j.context.ExecutionContext;
005import org.unix4j.io.FileInput;
006import org.unix4j.io.Input;
007import org.unix4j.io.NullInput;
008import org.unix4j.processor.DefaultInputProcessor;
009import org.unix4j.processor.InputLineProcessor;
010import org.unix4j.processor.InputProcessor;
011import org.unix4j.processor.LineProcessor;
012import org.unix4j.processor.MultipleInputLineProcessor;
013import org.unix4j.unix.Grep;
014import org.unix4j.util.FileUtil;
015
016import java.io.File;
017import java.util.Arrays;
018import java.util.List;
019
020/**
021 * Implementation of the {@link Grep grep} command.
022 */
023class GrepCommand extends AbstractCommand<GrepArguments> {
024        public GrepCommand(GrepArguments arguments) {
025                super(Grep.NAME, arguments);
026        }
027
028        @Override
029        public LineProcessor execute(ExecutionContext context, LineProcessor output) {
030                final GrepArguments args = getArguments(context);
031
032                //from file?
033                if (args.isFilesSet()) {
034                        final List<FileInput> inputs = FileInput.multiple(args.getFiles());
035                        return getFileInputProcessor(inputs, context, output, args);
036                } else if (args.isPathsSet()) {
037                        final List<File> files = FileUtil.expandFiles(context.getCurrentDirectory(), args.getPaths());
038                        final List<FileInput> inputs = FileInput.multiple(files);
039                        return getFileInputProcessor(inputs, context, output, args);
040                } else if (args.isInputsSet()) {
041                        final List<Input> inputs = Arrays.asList(args.getInputs());
042                        return getFileInputProcessor(inputs, context, output, args);
043                }
044
045                //from standard input
046                return getStandardInputProcessor(context, output, args);
047        }
048
049        private LineMatcher getMatcher(GrepArguments args) {
050                final LineMatcher matcher;
051                if (args.isFixedStrings()) {
052                        if (args.isWholeLine()) {
053                                matcher = args.isIgnoreCase() ? new FixedStringMatcher.WholeLineIgnoreCase(args) : new FixedStringMatcher.WholeLine(args);
054                        } else {
055                                matcher = args.isIgnoreCase() ? new FixedStringMatcher.IgnoreCase(args) : new FixedStringMatcher.Standard(args);
056                        }
057                } else {
058                        matcher = new RegexpMatcher(args);
059                }
060                return args.isInvertMatch() ? new InvertedMatcher(matcher) : matcher;
061        }
062
063        private LineProcessor getStandardInputProcessor(ExecutionContext context, LineProcessor output, GrepArguments args) {
064                final LineMatcher matcher = getMatcher(args);
065                if (args.isCount()) {
066                        return new CountMatchingLinesInputProcessor(this, context, output, matcher);
067                } else if (args.isMatchingFiles()) {
068                        return new WriteFilesWithMatchingLinesProcessor(this, context, output, matcher);
069                } else if (args.isLineNumber()) {
070                        return new WriteMatchingLinesWithLineNumberProcessor(this, context, output, matcher);
071                }
072                return new WriteMatchingLinesProcessor(this, context, output, matcher);
073        }
074
075        private LineProcessor getFileInputProcessor(List<? extends Input> inputs, ExecutionContext context, LineProcessor output, GrepArguments args) {
076                switch (inputs.size()) {
077                        case 0:
078                                return getInputProcessor(NullInput.INSTANCE, context, output, args);
079                        case 1:
080                                return getInputProcessor(inputs.get(0), context, output, args);
081                        default:
082                                return getMultipleFilesInputProcessor(inputs, context, output, args);
083                }
084        }
085
086        private LineProcessor getInputProcessor(Input input, ExecutionContext context, LineProcessor output, GrepArguments args) {
087                if (args.isCount()) {
088                        final LineMatcher matcher = getMatcher(args);
089                        final LineProcessor lineProcessor = new CountMatchingLinesProcessor(this, context, output, matcher);
090                        return new InputLineProcessor(input, new DefaultInputProcessor(), lineProcessor);
091                } else if (args.isMatchingFiles()) {
092                        final LineMatcher matcher = getMatcher(args);
093                        final InputProcessor inputProcessor = new WriteFilesWithMatchingLinesProcessor(this, context, output, matcher);
094                        return new InputLineProcessor(input, inputProcessor, output);
095                } else if (args.isLineNumber()) {
096                        final LineMatcher matcher = getMatcher(args);
097                        final LineProcessor lineProcessor = new WriteMatchingLinesWithLineNumberProcessor(this, context, output, matcher);
098                        return new InputLineProcessor(input, new DefaultInputProcessor(), lineProcessor);
099                } else {
100                        final LineMatcher matcher = getMatcher(args);
101                        final LineProcessor lineProcessor = new WriteMatchingLinesProcessor(this, context, output, matcher);
102                        return new InputLineProcessor(input, new DefaultInputProcessor(), lineProcessor);
103                }
104        }
105
106        private LineProcessor getMultipleFilesInputProcessor(List<? extends Input> inputs, ExecutionContext context, LineProcessor output, GrepArguments args) {
107                if (args.isCount()) {
108                        final LineMatcher matcher = getMatcher(args);
109                        final InputProcessor inputProcessor = new CountMatchingLinesInputProcessor(this, context, output, matcher);
110                        return new MultipleInputLineProcessor(inputs, inputProcessor, output);
111                } else if (args.isMatchingFiles()) {
112                        final LineMatcher matcher = getMatcher(args);
113                        final InputProcessor inputProcessor = new WriteFilesWithMatchingLinesProcessor(this, context, output, matcher);
114                        return new MultipleInputLineProcessor(inputs, inputProcessor, output);
115                } else if (args.isLineNumber()) {
116                        final LineMatcher matcher = getMatcher(args);
117                        final LineProcessor inputProcessor = new WriteMatchingLinesProcessor(this, context, output, matcher);
118                        return new MultipleInputLineProcessor(inputs,
119                                        new WriteMatchingLinesInputProcessor(this, context, matcher), inputProcessor);
120                } else {
121                        final LineMatcher matcher = getMatcher(args);
122                        final InputProcessor inputProcessor = new WriteMatchingLinesInputProcessor(this, context, matcher);
123                        return new MultipleInputLineProcessor(inputs, inputProcessor, output);
124                }
125        }
126}