Skip to content

feature grep #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: feature_antlr
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
plugins {
java
application
}

application {
mainClass.set("parser.Bash")
}

tasks.named<JavaExec>("run") {
standardInput = System.`in`
}

group = "org.example"
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStorePath=wrapper/dists
12 changes: 12 additions & 0 deletions greptest
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
123
3324
hello
hello
fsdfsd
sdfsdf
qwer
qwerty
HELLOWORLD
dsfsdf
sdfdsf
HELLO
6 changes: 6 additions & 0 deletions greptest1
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
123
3324
hello
hello1
123
3324
4 changes: 2 additions & 2 deletions src/main/java/bntler/WordOrStringVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public String visitDqstr(BashParser.DqstrContext ctx) {
String noQuotes = dqstr.substring(1, dqstr.length() - 1);

for (Map.Entry<String, String> entry : Environment.values.entrySet()) {
if (noQuotes.contains("$"+entry.getKey())) {
noQuotes = noQuotes.replace("$"+entry.getKey(), entry.getValue());
if (noQuotes.contains("$" + entry.getKey())) {
noQuotes = noQuotes.replace("$" + entry.getKey(), entry.getValue());
}
}
return noQuotes;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/builtins/Echo.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static String execute(BashCommand command, @Nullable String stdin) {

int i = 1;
boolean flag = true;
if (!command.parts().isEmpty() && command.parts().get(i).equals("-n")) {
if (command.parts().size() > 1 && command.parts().get(i).equals("-n")) {
i++;
flag = false;
}
Expand Down
131 changes: 131 additions & 0 deletions src/main/java/builtins/Grep.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package builtins;

import bntler.BashCommand;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;

//lazy javadoc
//-i - ignore case
//-w - complete word
//-A - after context

public class Grep {

private static final int STATE_INITIAL = 0;
private static final int STATE_DASH_A_WORDS_COMPLETED = 1;
private static final int STATE_HAVE_MORE_WORDS_AFTER_DASH_A = 2;

public static String execute(BashCommand command, @Nullable String stdin) {

boolean ignoreCase = false;
int linesAfterMatch = 0;
boolean exactMatch = false;

int i = 1;
while (i < command.parts().size()) {
String arg = command.parts().get(i);
if (!arg.startsWith("-")) {
break;
}

switch (arg) {
case "-i" -> ignoreCase = true;
case "-w" -> exactMatch = true;
case "-A" -> {
if (i + 1 < command.parts().size()) {
String number = command.parts().get(i + 1);
try {
linesAfterMatch = Integer.parseInt(number);
i++;
} catch (NumberFormatException e) {
return "Invalid Argument\n";
}
} else {
return "Invalid Argument\n";
}
}
default -> {
return "Unsupported parameter\n";
}
}
i++;
}

if (i == command.parts().size()) {
return "usage: grep [-w] [-A num] [-i] <pattern> <filenames...>\n";
}

String lookingFor = command.parts().get(i);
i++;

try {
StringBuilder grepWhat = new StringBuilder();

if (i == command.parts().size()) {
for (String s : stdin.split("\n")) {
if (getMatch(s, lookingFor, ignoreCase, exactMatch)) {
grepWhat.append(s).append("\n");
}
}
} else if (i == command.parts().size() - 1) {
String filename = command.parts().get(i);
searchFile(grepWhat, filename, lookingFor, linesAfterMatch, ignoreCase, exactMatch, false);
} else {
while (i < command.parts().size()) {
String filename = command.parts().get(i);
searchFile(grepWhat, filename, lookingFor, linesAfterMatch, ignoreCase, exactMatch, true);
i++;
}
}
return grepWhat.toString();
} catch (IOException e) {
return e.getMessage();
}
}


private static void searchFile(StringBuilder builder, String filename, String pattern, int linesAfterMatch, boolean ignoreCase, boolean exactMatch, boolean multiFile) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(filename));
String line;
int linesToPrint = 0;
int stateForDoubleDash = STATE_INITIAL;
while ((line = br.readLine()) != null) {
boolean matched = getMatch(line, pattern, ignoreCase, exactMatch);
if (matched) {
if (stateForDoubleDash == STATE_HAVE_MORE_WORDS_AFTER_DASH_A) {
builder.append("--").append("\n");
stateForDoubleDash = STATE_INITIAL;
}
linesToPrint = linesAfterMatch;
if (multiFile) {
builder.append(filename).append(":");
}
builder.append(line).append("\n");
} else if (linesToPrint > 0) {
builder.append(line).append("\n");
linesToPrint--;
if (linesToPrint == 0) {
stateForDoubleDash = STATE_DASH_A_WORDS_COMPLETED;
}
} else if (stateForDoubleDash == STATE_DASH_A_WORDS_COMPLETED) {
stateForDoubleDash = STATE_HAVE_MORE_WORDS_AFTER_DASH_A;
}
}
}

private static boolean getMatch(String line, String pattern, boolean ignoreCase, boolean exactMatch) {
if (ignoreCase) {
line = line.toLowerCase();
pattern = pattern.toLowerCase();
}
if (exactMatch) {
return Arrays.asList(line.toLowerCase().split(" ")).contains(pattern);
} else {
return line.contains(pattern);
}
}
}
1 change: 0 additions & 1 deletion src/main/java/builtins/Wc.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package builtins;

import bntler.BashCommand;
import parser.Bash;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/parser/Bash.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@ public static String runExternal(String source) {
var rootNodeGood = new PipelineVisitor().visit(rootNode);
String result;
try {
result = interpreter.interpret(rootNodeGood);
return interpreter.interpret(rootNodeGood);
} catch (Exception e) {
// e.printStackTrace(); for debug
result = e + "\n";
return e.getMessage() + "\n";
}
return result;
}
}
9 changes: 4 additions & 5 deletions src/main/java/parser/Interpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import bntler.BashCommand;
import bntler.BashNode;
import bntler.BashPipeline;
import builtins.Cat;
import builtins.Echo;
import builtins.Pwd;
import builtins.Wc;
import builtins.*;

import java.io.BufferedReader;
import java.io.InputStreamReader;
Expand Down Expand Up @@ -46,7 +43,9 @@ public String visitCommand(BashCommand command) throws Exception {
case "cat" -> {
return Cat.execute(command, result);
}

case "grep" -> {
return Grep.execute(command, result);
}
default -> {
String strCommand = String.join(" ", command.parts());
return executeCommand(strCommand);
Expand Down
8 changes: 4 additions & 4 deletions src/test/java/parser/BashTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ public void testSimpleCat() {

@Test
public void randomCommand() {
String expected = "java.io.IOException: Cannot run program \"rrandom\": error=2, No such file or directory\n";
String expected = "Cannot run program \"rrandom\": error=2, No such file or directory\n";
String actual = Bash.runExternal("rrandom");
assertEquals(expected, actual);
}

@Test
public void testSimpleVariable() {
String expected = "java.io.IOException: Cannot run program \"rrandom\": error=2, No such file or directory\n";
String expected = "Cannot run program \"rrandom\": error=2, No such file or directory\n";
Bash.runExternal("a=rrandom");
String actual = Bash.runExternal("$a");
assertEquals(expected, actual);
Expand All @@ -72,15 +72,15 @@ public void testSimpleDString() {

@Test
public void testSimpleVariableWithDString() {
String expected = "java.io.IOException: Cannot run program \"rrandom\": error=2, No such file or directory\n";
String expected = "Cannot run program \"rrandom\": error=2, No such file or directory\n";
Bash.runExternal("a=rrandom");
String actual = Bash.runExternal("\"$a\"");
assertEquals(expected, actual);
}

@Test
public void testSimpleVariableWithSString() {
String expected = "java.io.IOException: Cannot run program \"$a\": error=2, No such file or directory\n";
String expected = "Cannot run program \"$a\": error=2, No such file or directory\n";
Bash.runExternal("a=rrandom");
String actual = Bash.runExternal("'$a'");
assertEquals(expected, actual);
Expand Down
93 changes: 93 additions & 0 deletions src/test/java/parser/GrepTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package parser;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class GrepTest {

@Test
public void testSimpleGrep() {
String expected = "hello\nhello1\n";
String actual = Bash.runExternal("grep hello greptest1");
assertEquals(expected, actual);
}

@Test
public void testWGrep() {
String expected = "hello\n";
String actual = Bash.runExternal("grep -w hello greptest1");
assertEquals(expected, actual);
}

@Test
public void testA2WGrep() {
String expected = "hello\nhello1\n123\n";
String actual = Bash.runExternal("grep -A 2 -w hello greptest1");
assertEquals(expected, actual);

String actual1 = Bash.runExternal("grep -w -A 2 hello greptest1");
assertEquals(expected, actual1);
}

@Test
public void testIGrep() {
String expected = "hello\nhello\nHELLOWORLD\nHELLO\n";
String actual = Bash.runExternal("grep -i hello greptest");
assertEquals(expected, actual);
}

@Test
public void testIA2Grep() {
String expected = """
hello
hello
fsdfsd
sdfsdf
--
HELLOWORLD
dsfsdf
sdfdsf
HELLO
""";
String actual = Bash.runExternal("grep -i -A 2 hello greptest");
assertEquals(expected, actual);
}

@Test
public void testIA2WGrep() {
String expected = """
hello
hello
fsdfsd
sdfsdf
--
HELLO
""";
String actual = Bash.runExternal("grep -i -w -A 2 hello greptest");
assertEquals(expected, actual);
}

@Test
public void testPipe() {
String expected = """
hello
hello
""";
String actual = Bash.runExternal("cat greptest | grep hello");
assertEquals(expected, actual);
}


@Test
public void multiFile() {
String expected = """
greptest:hello
greptest:hello
greptest1:hello
greptest1:hello1
""";
String actual = Bash.runExternal("grep hello greptest greptest1");
assertEquals(expected, actual);
}
}