I am trying to modify some code that was written in lecture to develop a program that simulates rgrep. The aim of the project is to search a directory's files for a string and output the line it occured on. The problem I'm having is I'm not sure what to put in the ifstream to open of the files in the directory. This is what I have so far:

 /*
 * Purpose: This program lists the occurences of a user-specified string. In addition
            all occurences of the string will be counted and their occurences totaled
            along with the number of files that contain the string.
 * Date: Apr 08, 2012
 */

#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>     // ctime_s()
#include <io.h>          // _findfirst, etc.
using namespace std;
vector<string> wordsFound;

vector<string> scan( string const& keyword, string const& filespec, string startDir, bool isRecursive )
{
    intptr_t hFile;
    _finddata_t fd;
    string line;
    unsigned lineCount = 0;
    //vector<string> wordsFound;

    // fix directory name
    if( !startDir.empty() )
    {
        char last = startDir.back();
        if( last != '/' && last != '\\' && last != ':' )
            startDir += '/';
    }
    string findPath = startDir + filespec;
    hFile = _findfirst( findPath.c_str(), &fd );

    ifstream in(  );

    while( getline( in, line ) ) {
        ++lineCount;
        if( line.find( keyword ) != string::npos ){
            //++keywordCount;
            wordsFound.push_back(line);
            //cout << lineCount << "\t" << line << '\n';
        }
    }

    if( (hFile = _findfirst( findPath.c_str(), &fd )) == -1L )
    {
        cout << "No " << filespec << " files in current directory." << endl;
        return wordsFound;
    }

    do {
        if( isRecursive &&
            (fd.attrib & _A_SUBDIR) &&
            fd.name != string(".") &&
            fd.name != string("..") )
        {
            string subDir = startDir + fd.name ;
            scan( keyword, filespec, subDir, isRecursive );1
        }
    } while( _findnext( hFile, &fd ) == 0 );

    _findclose( hFile );
    return wordsFound;
}


int main( int argc, char *argv[] ) {
    locale here("");
    cout.imbue( here );

    vector<string> args;
    for( int i = 0; i < argc; ++i )
        args.push_back( argv[i] );

    string keyword, inputFile, line;
    unsigned lineCount = 0;


    //if only the string is provided
    if ( args.size() == 1 ) {
        cin >> keyword;
        scan( keyword, "*.*", "..", false );
        cout << wordsFound.size() << endl;
        /*for( unsigned i = 0; i < wordsFound.size(); ++i ) {
            cout << wordsFound[i] << endl;
        }*/
    }
}

Any help is appreciated.

ifstream in( );

line 36: Inside the parenthese you put the full path to the filename. But you have that line in the wrong place

do
{
    if( !fd.attrib & _A_SUBDIR )
    {
        ifstream in(findPath+fd.name);
        while( getline(in, line))
        {
           // blabla
        }
     }
} while( _findnext() );

)

Thanks for the help. What arguments would I put in the findnext?
while( _findnext() );

I got it to run doing:

    hFile = _findfirst( findPath.c_str(), &fd );

    do {
        if ( (!fd.attrib & _A_SUBDIR) ) {
            ifstream in( findPath+fd.name );

            while( getline( in, line ) ) {
                ++lineCount;
                if( line.find( keyword ) != string::npos ) {
                    //++keywordCount;
                    wordsFound.push_back(line);
                    //cout << lineCount << "\t" << line << '\n';
                }
            }
        }
    } while ( _findnext( hFile, &fd ) == 0 );

But I keep getting a 0 for the size of the vector when I output later which means it's not finding anything
Any suggestions?

Edited 4 Years Ago by Jorox03: Fixed code block

findPath+fd.name );

Line 5: Check the value of findPath, does it contain a trailing / or \ ? If not then you need to put one there. Also check if the file was opened: if( in.is_open() ) {

I've changed my approach to search for the files and then search for the term inside the file. The problem I'm having now is I can't transfer over the complete file path into main() from scan() becuase it just transfers ".\" which isn't an actual path when I go to open the ifstream. Is there any way to tranfer the full path name so I can open it properly? This is what I have so far:

/*
 * Purpose: This program lists the occurences of a user-specified string. In addition
            all occurences of the string will be counted and their occurences totaled
            along with the number of files that contain the string.
 * Date: Apr 08, 2012
 */

#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>     // ctime_s()
#include <io.h>          // _findfirst, etc.
using namespace std;
vector<string> filesFound;

vector<string> scan( string const& filespec, string startDir, bool isRecursive )
{
    intptr_t hFile;
    _finddata_t fd;

    // fix directory name
    if( !startDir.empty() )
    {
        char last = startDir.back();
        if( last != '/' && last != '\\' && last != ':' )
            startDir += '/';
    }
    string findPath = startDir + filespec;
    string fullPath = findPath + "\\";


    if( (hFile = _findfirst( findPath.c_str(), &fd )) == -1L )
    {
        cout << "No " << filespec << " files in current directory." << endl;
        return filesFound;
    }

    do {
        if( isRecursive &&
            (fd.attrib & _A_SUBDIR) &&
            fd.name != string(".") &&
            fd.name != string("..") )
        {
            string subDir = startDir + fd.name ;
            scan( filespec, subDir, isRecursive );
        }
            filesFound.push_back( fullPath + fd.name );
    } while( _findnext( hFile, &fd ) == 0 );

    _findclose( hFile );
    return filesFound;
}

int main( int argc, char *argv[] ) {
    locale here("");
    cout.imbue( here );

    vector<string> args;
    for( int i = 0; i < argc; ++i )
        args.push_back( argv[i] );

    string keyword, inputFile, line;
    unsigned lineCount = 0;


    //if only the string is provided
    if ( args.size() == 1 ) {
        cin >> keyword;
        scan( "*.*", "..", false );

        for( unsigned i = 0; i < filesFound.size(); ++i ) {

            cout << i << endl;
                ifstream in( filesFound[i].c_str() );

                if( !in ) {
                    cout << "Could not open: " << filesFound[i] << endl;
                    continue;
                } else {
                    while( getline( in,line ) ) {
                        ++lineCount;
                        if( line.find( keyword ) != string::npos ){
                            //++keywordCount;
                            cout << lineCount << "\t" << line << '\n' << endl;
                        }//end if
                    }//end while
                }
        }//end for
    }
}

The first thing I noticed while stepping (debugging) through your program is that you are pushing "." and ".." as well as other folder names onto the vector of files (see line 49). If the file is a folder then you don't want to do that.

Instead of main() passsing ".." to scan(), have main() call _getcwd() to get the current working directory and pass that to scan().

Then in scan(), the value of fullPath should just be the same as the parameter startDir

Here is the complete program I tested. Notice that I commented out a few things in main() that you may want to put back in. I didn't know what it was for su I just commented it out

#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>     // ctime_s()
#include <io.h>          // _findfirst, etc.
#include <direct.h>
using namespace std;
vector<string> filesFound;

vector<string> scan( string const& filespec, string startDir, bool isRecursive )
{
    intptr_t hFile;
    _finddata_t fd;

    // fix directory name
    if( !startDir.empty() )
    {
        char last = startDir.back();
        if( last != '/' && last != '\\' && last != ':' )
            startDir += '/';
    }
    string findPath = startDir + filespec;
    string fullPath = startDir; //findPath + "\\";


    if( (hFile = _findfirst( findPath.c_str(), &fd )) == -1L )
    {
        cout << "No " << filespec << " files in current directory." << endl;
        return filesFound;
    }

    do {
        if( isRecursive &&
            (fd.attrib & _A_SUBDIR) &&
            fd.name != string(".") &&
            fd.name != string("..") )
        {
            string subDir = startDir + fd.name ;
            scan( filespec, subDir, isRecursive );
        }
        else if(!(fd.attrib & _A_SUBDIR))
        {
            filesFound.push_back( fullPath + fd.name );
        }
    } while( _findnext( hFile, &fd ) == 0 );

    _findclose( hFile );
    return filesFound;
}

int main( int argc, char *argv[] ) {
#if 0
    locale here("");
    cout.imbue( here );

    vector<string> args;
    for( int i = 0; i < argc; ++i )
        args.push_back( argv[i] );
#endif
    char path[_MAX_PATH] = {0};
    string keyword, inputFile, line;
    unsigned lineCount = 0;
    //if only the string is provided
//    if ( args.size() == 1 ) {
//        cin >> keyword;
       _getcwd(path, sizeof(path));
        scan( "*.*", path, false );

        for( unsigned i = 0; i < filesFound.size(); ++i ) {


                ifstream in( filesFound[i].c_str() );

                if( !in ) {
                    cout << "Could not open: " << filesFound[i] << endl;
                    continue;
                } else {
                    while( getline( in,line ) ) {
                        ++lineCount;
                        if( line.find( keyword ) != string::npos ){
                            //++keywordCount;
                            cout << lineCount << "\t" << line << '\n' << endl;
                        }//end if
                    }//end while
                }
        }//end for
//    }
}

Thanks! That's all I needed, now I can finally get started on the rest of the program

This question has already been answered. Start a new discussion instead.