/*** * ==++== * * 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; }