/ ************************************************************************ * * Purpose: * Author: M J Leslie * Date: 26-Oct-98 * ************************************************************************/ /* Known problems. Serious memory leaks not enough comments Has problems with vi swp files on Linux (so does normal grep). */ extern "C" { #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <ctype.h> #include <stdlib.h> #include <unistd.h> } #include <iostream.h> // DEBUG 1 == Debugging information is required. // DEBUG 0 == Debugging info is suppresed. #define DEBUG 0 class List { public: List() { Reset(); } ~List() { } void Add(int Number) { Add(Number, ':'); } void Add(int Number, char Prefix) { // Are we adding the first item in the list? if ( pFirstItem == 0 ) { // Yes. pFirstItem = new IntList; pCurrentItem = pFirstItem; } else { // No. Add the number to the end of the list. pCurrentItem->pNext = new IntList; pCurrentItem = pCurrentItem->pNext; } pCurrentItem->Item = Number; pCurrentItem->Prefix = Prefix; pCurrentItem->pNext = 0; } void PointToFirstEntry(void) { pCurrentItem = pFirstItem; } void Reset(void) { // This is going to cause seriuos memory leaks! pFirstItem = 0; pCurrentItem = 0; } int GetCurrentEntry(void) { // Check we have a valid Item. if (pCurrentItem) { return (pCurrentItem->Item); } else { // No Item. This could happen when the list is empty. return (0); } } int GetNextEntry(void) { // Is there another entry in the list? if ( pCurrentItem->pNext != 0 ) { // Yes. Give it to the caller. pCurrentItem = pCurrentItem->pNext; return (pCurrentItem->Item); } else { // No. return (0); } } char GetCurrentPrefix(void) { // pCurrentItem = pCurrentItem->pNext; return (pCurrentItem->Prefix); } char GetNextPrefix(void) { pCurrentItem = pCurrentItem->pNext; return (pCurrentItem->Prefix); } private: struct IntList { int Item; char Prefix; IntList *pNext; }; IntList *pFirstItem; IntList *pCurrentItem; }; class grep { public: // enum { LL = 512 } LineLength ; // ....................................................................... grep() // Constructor. { OFF = 0; ON = 1; LineNumbering = ON; LinesBefore = 2; LinesAfter = 2; LinesInFile = 0; pFileName = 0; SearchString = '\0'; InsensitiveSearch = OFF; } // ....................................................................... ~grep () // Distructor. { delete[] pFileName; } // ....................................................................... void BuildMatrix(void) { int Line = 0; int StartPos = 0; int EndPos = 0; int NextPos = 0; Debug("BuildMatrix"); FoundLines.PointToFirstEntry(); Line = FoundLines.GetCurrentEntry(); Debug(Line); // Loop until we run out of line numbers. while ( Line > 0 ) { // Find the first line to display. StartPos = Line - LinesBefore; if ( StartPos <= EndPos ) { StartPos = EndPos + 1; } while ( StartPos < Line ) { LineMatrix.Add(StartPos, ':'); Debug(StartPos, 's'); StartPos++; } LineMatrix.Add(Line, '*'); Debug(Line, '*'); EndPos = Line + LinesAfter; if ( EndPos > LinesInFile ) { EndPos = LinesInFile; } NextPos = FoundLines.GetNextEntry(); if ( NextPos > 0 && EndPos >= NextPos ) { EndPos = NextPos - 1; } Line++; while ( Line <= EndPos ) { LineMatrix.Add(Line, ':'); Debug(Line, 'e'); Line++; } Line = NextPos; Debug(Line); } } // ....................................................................... void CaseInsensitive(void) { InsensitiveSearch = ON; } // ....................................................................... void Diagnostic(void) { cout << endl << "Extra lines before the found line: " << LinesBefore << endl; if ( InsensitiveSearch ) { cout << "Search is: Case Insensitive." << endl; } else { cout << "Search is: Case Sensitive." << endl; } } // ....................................................................... int Exists(void) { // Have we got the file name? if ( pFileName == 0 ) { // No. return (0); } else { // Yes. Check the file exists. struct stat stat_p; /* 'stat_p' is a pointer to a structure * of type 'stat'. */ /* Get stats for file and place them in * the structure. */ if ( -1 == stat (pFileName, &stat_p) ) { // File name not found. return (0); } if(!S_ISREG(stat_p.st_mode)) { // This is not a regular file. It may be a directory. // Ignore it. return(0); } // File name is OK. return (1); } } // ....................................................................... void Name(char *pFN) { Debug("Name", pFN); pFileName = new char[strlen(pFN)+1]; strcpy(pFileName, pFN); } // ....................................................................... void NoLineNumbers(void) { LineNumbering = OFF; } // ....................................................................... void ProcessFile(void) { int Line; int PreviousLine= 0; char Prefix; int CurrentLine = 0; char Buffer[512]; int LineCount = 0; FILE *fp; Debug("ProcessFile"); cout << endl << "Search String is: " << SearchString << endl; cout << "File Name is: " << pFileName << endl; fp = fopen (pFileName, "r"); LineMatrix.PointToFirstEntry(); Line = LineMatrix.GetCurrentEntry(); Prefix = LineMatrix.GetCurrentPrefix(); while ( Line > 0 ) { do { fgets(Buffer, 512, fp); LineCount ++; } while ( LineCount < Line ); // Put in a seperator between blocks. if ( PreviousLine+1 < Line ) { Seperator(); } if ( LineNumbering ) { cout << Line << Prefix << " " << Buffer; } else { cout << Prefix << " " << Buffer; } PreviousLine = Line; Line = LineMatrix.GetNextEntry(); Prefix = LineMatrix.GetCurrentPrefix(); } Seperator(); fclose(fp); } // ....................................................................... void PutSearchString(char *String) { Debug("PutSearchString"); Debug(String); SearchString = new char[strlen(String)+1]; strcpy(SearchString, String); if ( InsensitiveSearch ) { // Yes. Convert the buffer to uppercase. Uppercase(SearchString); } } // ....................................................................... void Reset(void) { FoundLines.Reset(); LineMatrix.Reset(); } // ....................................................................... int ScanFile(void) { FILE *fp; char Buffer[512]; int LineCounter = 0; int Found = 0; // Number of lines that matched the search string. fp = fopen(pFileName, "r"); Debug ("ScanFile"); while ( !feof(fp) ) { LineCounter++; fgets(Buffer, 512, fp); // Check the Buffer was big enough. if (strlen(Buffer) == 512 -1 ) { cout << __FILE__ << ": Warning! Lines in " << pFileName << " exceed the max line length of " << 512 << endl; } // Are we doing a case insensitive search? if ( InsensitiveSearch ) { // Yes. Convert the buffer to uppercase. Uppercase(Buffer); } if ( strstr(Buffer, SearchString) ) { FoundLines.Add(LineCounter); Found++; } } fclose (fp); LinesInFile = LineCounter; return(Found); } // ....................................................................... void SetLines(int Lines) { SetLinesBefore(Lines); SetLinesAfter(Lines); } // ....................................................................... void SetLinesBefore(int Lines) { LinesBefore = Lines; } // ....................................................................... void SetLinesAfter(int Lines) { LinesAfter = Lines; } private: // Debugging methods. void Debug(char *Message) { if ( DEBUG ) { cout << "Debug: " << Message << endl; } } // ....................................................................... void Debug(int Value) { if ( DEBUG ) { cout << "Debug: " << Value << endl; } } // ....................................................................... void Debug(int Value, char Char) { if ( DEBUG ) { cout << "Debug: " << Char << " " << Value << endl; } } // ....................................................................... void Debug(char * Str, int Value) { if ( DEBUG ) { cout << "Debug: " << Str << " " << Value << endl; } } // ....................................................................... void Debug(char * Str1, char * Str2) { if ( DEBUG ) { cout << "Debug: " << Str1 << " " << Str2 << endl; } } // ....................................................................... // Seperate blocks of data. void Seperator(void) { cout << "------" << endl; } // ....................................................................... void Uppercase(char *String) { int Offset = 0; while ( String[Offset] != (char)NULL ) { String[Offset] = toupper(String[Offset]); Offset++; } } int LineNumbering; // ON = Line numbering required. int LinesBefore; int LinesAfter; int LinesInFile; // Number of lines in the file. int InsensitiveSearch; // ON = Case insensitive search required. char *pFileName; // File to be searched. char *SearchString; List FoundLines; // List of lines that contain the search string. List LineMatrix; // List of lines that will be displayed. // Handy variables to set boolean variables. int OFF; int ON; }; // Private functions. void Debug(char *Message); void Help(void); void ProcessTheCommandLine( int argc, char **Argv); // // Start point in the program. // main( int Argc, char **Argv) { ProcessTheCommandLine(Argc, Argv); } // ....................................................................... void Help(void) { cout << endl << " mgrep (Martins grep or Multi line grep) is an alternative to grep. " << endl << " The purpose is the same as grep in that it searches files " << endl << " looking for a supplied string. The difference is in the output, " << endl << " aswell as showing the line that contains the string, it also " << endl << " shows the lines around the found line." << endl; cout << endl << " When reading from stdin, mgrep works a little differently to grep." << endl << " grep will scan the data on stdin looking for the search string." << endl << " mgrep assumes it is being passed file names, therefore it attempts " << endl << " to open the files and search the contents. " << endl; cout << endl << " Please note that mgrep is slower than grep, this is because it " << endl << " performs two passes over the files being searched. " << endl; cout << endl << "Syntax:" << endl << endl; // cout << " mgrep [ -d -h -l n -b n -a n -s] string [filenames]" << endl; cout << " mgrep [ -d -h -l n -b n -a n ] string [filenames]" << endl; cout << "" << endl; cout << " -h --------- Display this help." << endl; cout << " -d --------- Basic diagnostic information is printed." << endl; cout << " -i --------- Case insensitive search." << endl; cout << " -n --------- No line numbering required." << endl; cout << " -l n ------- Number of lines to show either side of the found line." << endl; cout << " Default is 2." << endl; cout << " -b n ------- Number of lines to show before the found line." << endl; cout << " Default is 2." << endl; cout << " -a n ------- Number of lines to show after the found line." << endl; cout << " Default is 2." << endl; cout << " -s --------- Look for the list of files on STDIN." << endl; cout << " string ----- The string to search for." << endl; cout << " filenames -- List of files to search." << endl << endl; } // ....................................................................... void Debug(char *Message) { if ( DEBUG ) { cout << "Debug: " << Message << endl; } } // // Read the command line and act on its contents. // void ProcessTheCommandLine( int Argc, char **Argv) { grep File; int Flag = 'x'; int LookAtStdin = 0; int FirstFile = 1; int DiagnosticRequired = 0; Debug("ProcessTheCommandLine"); // Process the command line. for ( int Inc = 1; Inc < Argc; Inc++ ) { // Have we got a flag? if ( *(Argv[Inc]) == '-' ) { // Yes. Flag = *((Argv[Inc])+1); switch ( Flag ) { case 'd': // Diagnostics requested DiagnosticRequired = 1; break; case 'h': // Help requested Help(); exit(0); break; case 'i': // Case insensitive search File.CaseInsensitive(); break; case 'l': // Number of lines to show either side of the found line. Inc++; File.SetLines(atoi(Argv[Inc])); break; case 'n': File.NoLineNumbers(); break; case 'b': Inc++; File.SetLinesBefore(atoi(Argv[Inc])); break; case 'a': Inc++; File.SetLinesAfter(atoi(Argv[Inc])); break; case 's': LookAtStdin = 1; default: cout << Argv[Inc] << " is an invalid flag" << endl; } } else { // This is not a flag, it has to be // the search string or a file name. if ( FirstFile ) { // Assume the first word following // the flags is the search string. File.PutSearchString(Argv[Inc]); if ( DiagnosticRequired ) { File.Diagnostic(); } FirstFile = 0; } else { File.Name(Argv[Inc]); // ... If the file exists, // ... find and display the lines that contain // ... the search string. if ( !File.Exists() ) { // cout << "File " << Argv[Inc] << " not found. " << endl; } else { int Found = 0; Debug("File Found"); Found = File.ScanFile(); // Only proceed with this file if we found matching records. if (Found > 0) { File.BuildMatrix(); File.ProcessFile(); } File.Reset(); } } } } // Should we scan stdin for file names? // This is a bodge because I cant figure out how to do a non blocking // read on sdtin. if (LookAtStdin) { // Yes. char FileName[256]; // check we have a search string before looking in STDIN for filenames. if (FirstFile) { cout << __FILE__ << ": Search string not Supplied. " << endl; Help(); return; } // Disable buffering on stdin. This mean that stdin can be // read without special cmd line flags and fgets does not // lock up the program. char Buffer[BUFSIZ]; // setvbuf(stdin, Buffer); // Now check STDIN for file names. while (fgets(FileName, 256, stdin)) { FileName[strlen(FileName)-1] = '\0'; // cout << "stdin loop" << FileName << endl; File.Name(FileName); // ... If the file exists, // ... find and display the lines that contain // ... the search string. if ( !File.Exists() ) { // cout << "File " << FileName << " not found. " << endl; } else { int Found = 0; Debug("File Found"); Found = File.ScanFile(); // Only proceed with this file if we found matching records. if (Found > 0) { File.BuildMatrix(); File.ProcessFile(); } File.Reset(); } } } }
file: /Techref/language/ccpp/cppref/EXAMPLES/MGREP.CC, 19KB, , updated: 1998/10/27 13:57, local time: 2024/8/15 00:17,
18.222.3.220:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://techref.massmind.org/techref/language/ccpp/cppref/EXAMPLES/MGREP.CC"> language ccpp cppref EXAMPLES MGREP</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to techref.massmind.org! |
.