/***
* ==++==
*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ==--==
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* searchfile.cpp - Simple cmd line application that uses a variety of streams features to search a file,
* store the results, and write results back to a new file.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include "cpprest/filestream.h"
#include "cpprest/containerstream.h"
#include "cpprest/producerconsumerstream.h"
using namespace utility;
using namespace concurrency::streams;
///
/// A convenient helper function to loop asychronously until a condition is met.
///
pplx::task _do_while_iteration(std::function(void)> func)
{
pplx::task_completion_event ev;
func().then([=](bool guard)
{
ev.set(guard);
});
return pplx::create_task(ev);
}
pplx::task _do_while_impl(std::function(void)> func)
{
return _do_while_iteration(func).then([=](bool guard) -> pplx::task
{
if(guard)
{
return ::_do_while_impl(func);
}
else
{
return pplx::task_from_result(false);
}
});
}
pplx::task do_while(std::function(void)> func)
{
return _do_while_impl(func).then([](bool){});
}
///
/// Structure used to store individual line results.
///
typedef std::vector matched_lines;
namespace Concurrency { namespace streams {
///
/// Parser implementation for 'matched_lines' type.
///
template
class type_parser
{
public:
static pplx::task parse(streambuf buffer)
{
basic_istream in(buffer);
auto lines = std::make_shared();
return do_while([=]()
{
container_buffer line;
return in.read_line(line).then([=](const size_t bytesRead)
{
if(bytesRead == 0 && in.is_eof())
{
return false;
}
else
{
lines->push_back(std::move(line.collection()));
return true;
}
});
}).then([=]()
{
return matched_lines(std::move(*lines));
});
}
};
}}
///
/// Function to create in data from a file and search for a given string writing all lines containing the string to memory_buffer.
///
static pplx::task find_matches_in_file(const string_t &fileName, const std::string &searchString, basic_ostream results)
{
return file_stream::open_istream(fileName).then([=](basic_istream inFile)
{
auto lineNumber = std::make_shared(1);
return ::do_while([=]()
{
container_buffer inLine;
return inFile.read_line(inLine).then([=](size_t bytesRead)
{
if(bytesRead == 0 && inFile.is_eof())
{
return pplx::task_from_result(false);
}
else if(inLine.collection().find(searchString) != std::string::npos)
{
results.print("line ");
results.print((*lineNumber)++);
return results.print(":").then([=](size_t)
{
container_buffer outLine(std::move(inLine.collection()));
return results.write(outLine, outLine.collection().size());
}).then([=](size_t)
{
return results.print("\r\n");
}).then([=](size_t)
{
return true;
});
}
else
{
++(*lineNumber);
return pplx::task_from_result(true);
}
});
}).then([=]()
{
// Close the file and results stream.
return inFile.close() && results.close();
});
});
}
///
/// Function to write out results from matched_lines type to file
///
static pplx::task write_matches_to_file(const string_t &fileName, matched_lines results)
{
// Create a shared pointer to the matched_lines structure to copying repeatedly.
auto sharedResults = std::make_shared(std::move(results));
return file_stream::open_ostream(fileName, std::ios::trunc).then([=](basic_ostream outFile)
{
auto currentIndex = std::make_shared(0);
return ::do_while([=]()
{
if(*currentIndex >= sharedResults->size())
{
return pplx::task_from_result(false);
}
container_buffer lineData((*sharedResults)[(*currentIndex)++]);
outFile.write(lineData, lineData.collection().size());
return outFile.print("\r\n").then([](size_t)
{
return true;
});
}).then([=]()
{
return outFile.close();
});
});
}
#ifdef _WIN32
int wmain(int argc, wchar_t *args[])
#else
int main(int argc, char *args[])
#endif
{
if(argc != 4)
{
printf("Usage: SearchFile.exe input_file search_string output_file\n");
return -1;
}
const string_t inFileName = args[1];
const std::string searchString = utility::conversions::to_utf8string(args[2]);
const string_t outFileName = args[3];
producer_consumer_buffer lineResultsBuffer;
// Find all matches in file.
basic_ostream outLineResults(lineResultsBuffer);
find_matches_in_file(inFileName, searchString, outLineResults)
// Write matches into custom data structure.
.then([&]()
{
basic_istream inLineResults(lineResultsBuffer);
return inLineResults.extract();
})
// Write out stored match data to a new file.
.then([&](matched_lines lines)
{
return write_matches_to_file(outFileName, std::move(lines));
})
// Wait for everything to complete.
.wait();
return 0;
}