#include #include #include #include #define TRUE 1 #define FALSE 0 #define BUFF_FILE 256 #define BUFF_LINE 2048 struct NODE { char filename[BUFF_FILE]; char lineNumber[10]; char line[BUFF_LINE]; struct NODE *next; }; int buildList(struct NODE **listHead) { /* * buildList() reads input from stdin (the resulting output of a grep call) * and generates a linked list of nodes. Each node contains the filename, * line number, and line of text of the match that grep specified. The * function returns a hitCount to main() so that the program knows * whether or not the input (grep's output) was valid. The line number is * not inserted into each node, but is available for testing purposes * should this be necessary. */ char filename[BUFF_FILE]; char lineNumber[4]; char line[BUFF_LINE]; int hitCount = 0; struct NODE *newNode = NULL; while (fscanf(stdin, "%256[^:]:%4[^:]:%2048[^\n]\n", filename, lineNumber, line) == 3) { newNode = (struct NODE *) malloc(sizeof(struct NODE)); strncpy(newNode->filename, filename, BUFF_FILE); strncpy(newNode->line, line, BUFF_LINE); newNode->next = *listHead; *listHead = newNode; hitCount++; } return hitCount; } int lineHunter (struct NODE **listHead, int hitCount, int lineNumberSwitch, int bannerSwitch) { /* * lineHunter() iterates through the nodes built in buildList() * and looks for lines in the given files that match the lines presented * in the nodes themselves. If it finds a match, it prints an '*' next * to the line that it finds. It only opens new files (files that haven't * been opened before) and then runs through the nodes a second time to * find matches to the lines being printed. */ char filename[BUFF_FILE]; char line[BUFF_LINE]; int tagBool; int lineCount; struct NODE *currentNode = *listHead; struct NODE *matchNode = NULL; FILE *grepFile = NULL; // If args specify banner then print it. if (bannerSwitch) { printf("\nTHERE ARE %d MATCHING LINES\n", hitCount); } // Iterate through filenames while (currentNode->next != NULL) { if (!(grepFile = fopen(currentNode->filename, "r"))) { fprintf(stderr, "rgpp: error: grep filename couldn't " "be opened -- check input.\n"); exit(1); } strcpy(filename, currentNode->filename); printf("\n====================%s\n", currentNode->filename); lineCount = 1; // While in the same file print file contents. while (fgets(line, BUFF_LINE, grepFile)) { // Strip the newline off of lines pulled from file. line[strlen(line) - 1] = '\0'; tagBool = FALSE; matchNode = *listHead; // Search through nodes to find match to line. while (matchNode != NULL) { if (strcmp(currentNode->filename, matchNode->filename) == 0 && strcmp(currentNode->lineNumber, matchNode->lineNumber) == 0 && strcmp(line, matchNode->line) == 0) { tagBool = TRUE; } matchNode = matchNode->next; } // Print tag if match was found in line. if (tagBool) { printf("* "); } else { printf(" "); } // If args specify line numbering, print them. if (lineNumberSwitch) { printf("%4d: ", lineCount); } // Print the line of text. printf("%s\n", line); lineCount++; } fclose(grepFile); // Search for next new file to open. while (strcmp(filename, currentNode->filename) == 0 && currentNode->next != NULL) { currentNode = currentNode->next; } } return 0; } int wordHunter (struct NODE **listHead, int lineNumberSwitch, int bannerSwitch, char *word) { /* * wordHunter() iterates through the nodes created in buildList() * and looks for lines in the given files that match the lines * specified by the nodes themselves. If a match is found (aka a line * is determined to contain matches according to grep) then the function * goes through the line in the node looking for matching words, printing * them in inverse video. */ char *matchWord[BUFF_FILE]; char filename[BUFF_FILE]; char line[BUFF_LINE]; int i; int j; int k; int hitCount = 0; int matchBool; int lineCount; struct NODE *currentNode = *listHead; struct NODE *matchNode = NULL; FILE *grepFile = NULL; // Print out the banner based on args. if (bannerSwitch) { // Iterate through files to find matches for hitCount while (currentNode != NULL) { i = 0; j = 0; // This while loop checks the string character by character for // matches to the given word. while (currentNode->line[i] != '\0') { if (word[j] == '\0') { j = 0; hitCount++; } else if (tolower(currentNode->line[i]) == tolower(word[j])) { j++; } else { j = 0; } i++; } currentNode = currentNode->next; } printf("\nTHERE ARE %d MATCHING WORDS\n", hitCount); } currentNode = *listHead; // Iterate through filenames while (currentNode->next != NULL) { if (!(grepFile = fopen(currentNode->filename, "r"))) { fprintf(stderr, "rgpp: error: grep filename couldn't be " "opened -- check input\n"); exit(1); } strcpy(filename, currentNode->filename); // Print out filename header. printf("\n=====================%s\n", currentNode->filename); lineCount = 1; // While in the same file, print file contents while (fgets(line, BUFF_LINE, grepFile)) { // Strip the newline off of lines pulled from file. line[strlen(line) - 1] = '\0'; // If the args specify line numbering, print them. if (lineNumberSwitch) { printf("%4d: ", lineCount); } // Find if line is a match in nodes. matchNode = *listHead; matchBool = FALSE; while (matchNode != NULL) { if (strcmp(line, matchNode->line) == 0) { matchBool = TRUE; } matchNode = matchNode->next; } // If the line isn't a match then print the line if (!matchBool) { printf("%s", line); } else { // Find and highlight the matching words in the node line. i = 0; j = 0; *matchWord = ""; // This while loop checks the string character by character for // matches to the given word. If a match is not found, the // characters are printed to output. If a match is found, it // is highlighted with inverse video and then printed. while (line[i] != '\0') { if (word[j] == '\0') { printf("\e[7m"); for (k = i - j; k < i; k++) { printf("%c", line[k]); } printf("\e[0m"); j = 0; } if (tolower(line[i]) == tolower(word[j])) { j++; } else { if (j != 0) { for (k = i - j; k <= i; k++) { printf("%c", line[k]); } j = 0; } else { printf("%c", line[i]); } } i++; } } lineCount++; printf("\n"); } fclose(grepFile); // Search for next file to open. while (strcmp(filename, currentNode->filename) == 0 && currentNode->next != NULL) { currentNode = currentNode->next; } } return 0; } int main(int argc, char *argv[]) { /* * main()'s soul purpose is to receive the command line arguments for rgpp * and then process them and make the necessary function calls to fulfill * the user's request. It also checks to make sure that return values are * valid from those functions. */ char word[BUFF_LINE]; int i = 1; int modeSwitch = -1; int lineNumberSwitch = 0; int bannerSwitch = 0; int hitCount = 0; struct NODE *list = NULL; // Check for minimum number of required args. if (strcmp(argv[1], "-l") != 0 && strcmp(argv[1], "-w") != 0) { fprintf(stderr, "rgpp: usage: rgpp [-l | -w word] {-n} {-b}\n"); exit(1); } // Read args, set variables based on switches and optional word. while(argv[i] != NULL) { if (!strcmp(argv[i], "-l")) { modeSwitch = 0; } else if (!strcmp(argv[i], "-w")) { modeSwitch = 1; strncpy(word, argv[i+1], BUFF_LINE); i++; } else if (!strcmp(argv[i], "-b")) { bannerSwitch = 1; } else if (!strcmp(argv[i], "-n")) { lineNumberSwitch = 1; } else { fprintf(stderr, "rgpp: usage: rgpp [-l | -w word] {-n} {-b}\n"); exit(1); } i++; } // Call buildList to read input and build linked list. hitCount = buildList(&list); if (hitCount == 0) { fprintf(stderr, "rgpp: error: no grep results found -- " "check grep input\n"); exit(1); } if (modeSwitch) { if (wordHunter(&list, lineNumberSwitch, bannerSwitch, word) != 0) { fprintf(stderr, "rgpp: error: no word matches --" " check grep input and word arg\n"); exit(1); } } else { if (lineHunter(&list, hitCount, lineNumberSwitch, bannerSwitch) != 0) { fprintf(stderr, "rgpp: error: no line matches --" " check grep input\n"); exit(1); } } // Free allocated memory. struct NODE *tmp; while (list != NULL) { tmp = list; list = list->next; free(tmp); } exit(0); }