diff options
author | Tobias Klauser <tklauser@distanz.ch> | 2008-01-27 11:37:44 +0100 |
---|---|---|
committer | Tobias Klauser <tklauser@xenon.tklauser.home> | 2008-01-27 11:37:44 +0100 |
commit | 7e0f021a9aec35fd8e6725e87e3313b101d26f5e (patch) | |
tree | b1cacc4b24393f517aeb4610e9e1021f954307a8 /reference/CPLUSPLUS/EXAMPLES/MGREP.CC |
Initial import (2.0.2-6)2.0.2-6
Diffstat (limited to 'reference/CPLUSPLUS/EXAMPLES/MGREP.CC')
-rw-r--r-- | reference/CPLUSPLUS/EXAMPLES/MGREP.CC | 854 |
1 files changed, 854 insertions, 0 deletions
diff --git a/reference/CPLUSPLUS/EXAMPLES/MGREP.CC b/reference/CPLUSPLUS/EXAMPLES/MGREP.CC new file mode 100644 index 0000000..6052afd --- /dev/null +++ b/reference/CPLUSPLUS/EXAMPLES/MGREP.CC @@ -0,0 +1,854 @@ +/************************************************************************ + * + * 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(); + } + } + } +} + |