| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| |
| #include "transformer.h" |
| #include <log4cxx/file.h> |
| #include <log4cxx/helpers/transcoder.h> |
| #include <apr_thread_proc.h> |
| #include <apr_pools.h> |
| #include <apr_file_io.h> |
| #include <apr_strings.h> |
| #include <assert.h> |
| #include <iostream> |
| |
| using namespace log4cxx; |
| using namespace log4cxx::helpers; |
| |
| #if !defined(APR_FOPEN_READ) |
| #define APR_FOPEN_READ APR_READ |
| #define APR_FOPEN_CREATE APR_CREATE |
| #define APR_FOPEN_WRITE APR_WRITE |
| #define APR_FOPEN_TRUNCATE APR_TRUNCATE |
| #define APR_FOPEN_APPEND APR_APPEND |
| #endif |
| |
| void Transformer::transform(const File& in, const File& out, |
| const std::vector<Filter *>& filters) |
| { |
| log4cxx::Filter::PatternList patterns; |
| for(std::vector<Filter*>::const_iterator iter = filters.begin(); |
| iter != filters.end(); |
| iter++) { |
| |
| const log4cxx::Filter::PatternList& thesePatterns = (*iter)->getPatterns(); |
| for (log4cxx::Filter::PatternList::const_iterator pattern = thesePatterns.begin(); |
| pattern != thesePatterns.end(); |
| pattern++) { |
| patterns.push_back(*pattern); |
| } |
| } |
| transform(in, out, patterns); |
| } |
| |
| void Transformer::transform(const File& in, const File& out, |
| const Filter& filter) |
| { |
| transform(in, out, filter.getPatterns()); |
| } |
| |
| |
| void Transformer::copyFile(const File& in, const File& out) { |
| Pool p; |
| apr_pool_t* pool = p.getAPRPool(); |
| |
| |
| // |
| // fairly naive file copy code |
| // |
| // |
| apr_file_t* child_out; |
| apr_int32_t flags = APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE; |
| apr_status_t stat = out.open(&child_out, flags, APR_OS_DEFAULT, p); |
| assert(stat == APR_SUCCESS); |
| |
| apr_file_t* in_file; |
| stat = in.open(&in_file, APR_FOPEN_READ, APR_OS_DEFAULT, p); |
| assert(stat == APR_SUCCESS); |
| apr_size_t bufsize = 32000; |
| void* buf = apr_palloc(pool, bufsize); |
| apr_size_t bytesRead = bufsize; |
| |
| while(stat == 0 && bytesRead == bufsize) { |
| stat = apr_file_read(in_file, buf, &bytesRead); |
| if (stat == 0 && bytesRead > 0) { |
| stat = apr_file_write(child_out, buf, &bytesRead); |
| assert(stat == APR_SUCCESS); |
| } |
| } |
| stat = apr_file_close(child_out); |
| assert(stat == APR_SUCCESS); |
| } |
| |
| void Transformer::createSedCommandFile(const std::string& regexName, |
| const log4cxx::Filter::PatternList& patterns, |
| apr_pool_t* pool) { |
| apr_file_t* regexFile; |
| apr_status_t stat = apr_file_open(®exFile, |
| regexName.c_str(), |
| APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE, APR_OS_DEFAULT, |
| pool); |
| assert(stat == APR_SUCCESS); |
| |
| std::string tmp; |
| for (log4cxx::Filter::PatternList::const_iterator iter = patterns.begin(); |
| iter != patterns.end(); |
| iter++) { |
| tmp = "sQ"; |
| tmp.append(iter->first); |
| tmp.append(1, 'Q'); |
| tmp.append(iter->second); |
| tmp.append("Qg\n"); |
| apr_file_puts(tmp.c_str(), regexFile); |
| } |
| apr_file_close(regexFile); |
| } |
| |
| void Transformer::transform(const File& in, const File& out, |
| const log4cxx::Filter::PatternList& patterns) |
| { |
| // |
| // if no patterns just copy the file |
| // |
| if (patterns.size() == 0) { |
| copyFile(in, out); |
| } else { |
| Pool p; |
| apr_pool_t* pool = p.getAPRPool(); |
| |
| // |
| // write the regex's to a temporary file since they |
| // may get mangled if passed as parameters |
| // |
| std::string regexName; |
| Transcoder::encode(in.getPath(), regexName); |
| regexName.append(".sed"); |
| createSedCommandFile(regexName, patterns, pool); |
| |
| |
| // |
| // prepare to launch sed |
| // |
| // |
| apr_procattr_t* attr = NULL; |
| apr_status_t stat = apr_procattr_create(&attr, pool); |
| assert(stat == APR_SUCCESS); |
| |
| stat = apr_procattr_io_set(attr, APR_NO_PIPE, APR_FULL_BLOCK, |
| APR_FULL_BLOCK); |
| assert(stat == APR_SUCCESS); |
| |
| // |
| // find the program on the path |
| // |
| stat = apr_procattr_cmdtype_set(attr, APR_PROGRAM_PATH); |
| assert(stat == APR_SUCCESS); |
| |
| // |
| // build the argument list |
| // using Q as regex separator on s command |
| // |
| const char** args = (const char**) |
| apr_palloc(pool, 5 * sizeof(*args)); |
| int i = 0; |
| |
| // |
| // not well documented |
| // but the first arg is a duplicate of the executable name |
| // |
| args[i++] = "sed"; |
| |
| |
| std::string regexArg("-f"); |
| regexArg.append(regexName); |
| args[i++] = apr_pstrdup(pool, regexArg.c_str()); |
| |
| // |
| // specify the input file |
| args[i++] = Transcoder::encode(in.getPath(), p); |
| args[i] = NULL; |
| |
| |
| |
| // |
| // set the output stream to the filtered file |
| // |
| apr_file_t* child_out; |
| apr_int32_t flags = APR_FOPEN_READ | APR_FOPEN_WRITE | |
| APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE; |
| stat = out.open(&child_out, flags, APR_OS_DEFAULT, p); |
| assert(stat == APR_SUCCESS); |
| |
| stat = apr_procattr_child_out_set(attr, child_out, NULL); |
| assert(stat == APR_SUCCESS); |
| |
| // |
| // redirect the child's error stream to this processes' error stream |
| // |
| apr_file_t* child_err; |
| stat = apr_file_open_stderr(&child_err, pool); |
| assert(stat == 0); |
| stat = apr_procattr_child_err_set(attr, child_err, NULL); |
| assert(stat == APR_SUCCESS); |
| |
| |
| |
| apr_proc_t pid; |
| stat = apr_proc_create(&pid,"sed", args, NULL, attr, pool); |
| if (stat != APR_SUCCESS) { |
| puts("Error invoking sed, sed must be on the path in order to run unit tests"); |
| } |
| assert(stat == APR_SUCCESS); |
| |
| apr_proc_wait(&pid, NULL, NULL, APR_WAIT); |
| stat = apr_file_close(child_out); |
| assert(stat == APR_SUCCESS); |
| } |
| |
| |
| } |