file_differ.cpp

Go to the documentation of this file.
00001 #ifndef FILE_DIFFER_IMPLEMENTATION_FILE
00002 #define FILE_DIFFER_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *
00006 *  Name   : file_differ
00007 *  Author : Aaron Buchanan
00008 *
00009 *******************************************************************************
00010 * Copyright (c) 2002-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 #include "file_differ.h"
00019 
00020 #include <basis/convert_utf.h>
00021 #include <basis/istring.h>
00022 #include <basis/portable.h>
00023 
00024 #include <stdio.h> 
00025 
00026 #define BUFSIZE 4096 
00027 
00028 bool file_differ::diff_files(const istring &_file1, const istring &_file2, const istring &_options,
00029                              istring &_results, istring &_error)
00030 { 
00031     _results.reset();
00032 
00033 #ifdef __WIN32__
00034     // Set the bInheritHandle flag so pipe handles are inherited. 
00035     SECURITY_ATTRIBUTES saAttr; 
00036     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
00037     saAttr.bInheritHandle = true; 
00038     saAttr.lpSecurityDescriptor = NULL; 
00039     
00040     // The steps for redirecting child process's STDOUT: 
00041     //     1. Save current STDOUT, to be restored later. 
00042     //     2. Create anonymous pipe to be STDOUT for child process. 
00043     //     3. Set STDOUT of the parent process to be write handle to 
00044     //        the pipe, so it is inherited by the child process. 
00045     //     4. Create a noninheritable duplicate of the read handle and
00046     //        close the inheritable read handle. 
00047     
00048     // Save the handle to the current STDOUT. 
00049     HANDLE hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
00050     
00051     // Create a pipe for the child process's STDOUT. 
00052     HANDLE hChildStdoutRd, hChildStdoutWr;
00053     if( false == CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0) ) 
00054     {
00055         _error = "Stdout pipe creation failed";
00056         return false;
00057     }
00058     
00059     // Set a write handle to the pipe to be STDOUT. 
00060     if( false == SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr) )
00061     {
00062         _error = "Redirecting STDOUT failed";
00063         return false;
00064     }
00065     
00066     // Create noninheritable read handle and close the inheritable read handle. 
00067     HANDLE hChildStdoutRdDup;
00068     if( false == DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
00069                                  GetCurrentProcess(), &hChildStdoutRdDup , 0,
00070                                  false,
00071                                  DUPLICATE_SAME_ACCESS) )
00072     {
00073         _error = "DuplicateHandle failed";
00074         return false;
00075     }
00076     CloseHandle(hChildStdoutRd);
00077     
00078     // Now create the child process.
00079     // Set up members of the PROCESS_INFORMATION structure. 
00080     PROCESS_INFORMATION piProcInfo; 
00081     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
00082     
00083     // Set up members of the STARTUPINFO structure. 
00084     STARTUPINFO siStartInfo; 
00085     ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
00086     siStartInfo.cb = sizeof(STARTUPINFO); 
00087     // Note here the dwFlags should be STARTF_USESTDHANDLES, which is descripted in 
00088     // win32 API document, but this was omitted in MSDN sample
00089     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
00090     siStartInfo.hStdOutput = hChildStdoutWr;
00091     siStartInfo.hStdError = hChildStdoutWr;
00092     
00093     // Create the child process. 
00094     isprintf cmdline("diff %s %s %s", _options.s(), _file1.s(), _file2.s());
00095     if( !CreateProcess(NULL,          // app name
00096                        to_unicode_temp(cmdline),   // command line 
00097                        NULL,          // process security attributes 
00098                        NULL,          // primary thread security attributes 
00099                        true,          // handles are inherited 
00100                        CREATE_NO_WINDOW,    // creation flags 
00101                        NULL,          // use parent's environment 
00102                        NULL,          // use parent's current directory 
00103                        &siStartInfo,  // STARTUPINFO pointer 
00104                        &piProcInfo) ) // receives PROCESS_INFORMATION 
00105     {
00106         LPVOID lpMsgBuf;
00107         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
00108                       FORMAT_MESSAGE_IGNORE_INSERTS,
00109                       NULL,
00110                       GetLastError(),
00111                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00112                       (LPTSTR) &lpMsgBuf,
00113                       0,
00114                       NULL);
00115         _error = isprintf("Create process failed: %s", (LPCTSTR)lpMsgBuf);
00116         // Free the buffer.
00117         LocalFree( lpMsgBuf );
00118         return false;
00119     }
00120     
00121     // After process creation, restore the saved STDOUT. 
00122     if( false == SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout) )
00123     {
00124         _error = "Re-redirecting Stdout failed";
00125         return false;
00126     }
00127     
00128     // Close the write end of the pipe before reading from the 
00129     // read end of the pipe. 
00130     if( false == CloseHandle(hChildStdoutWr) ) 
00131     {
00132         _error = "Closing handle failed";
00133         return false;
00134     }
00135     
00136     // Read output from the child process, and save to the results string
00137     DWORD dwRead; 
00138     CHAR chBuf[BUFSIZE]; 
00139     HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
00140     for (;;) 
00141     { 
00142         chBuf[0] = '\0';
00143         if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE - 1, &dwRead, NULL) || dwRead == 0)
00144             break; 
00145         chBuf[dwRead] = '\0';
00146         _results += chBuf;
00147     } 
00148 #elif defined(__UNIX__)
00149 if (!_file1 || !_file2 || !_options || !_error) {}
00150   // hmmm: add support for calling diff here.
00151 #else
00152   // hmmm: add support for calling diff here.
00153 #endif
00154 
00155     return true;
00156 } 
00157 
00158 
00159 void file_differ::AddCRs(istring &_string)
00160 {
00161     const istring addin("\r");
00162     for( int i = 0; i < _string.length(); ++i )
00163     {
00164         if( ('\n' == _string[i]) && ((i == 0) || ('\r' != _string[i-1])) )
00165         {
00166             _string.insert(i, addin);
00167             ++i;
00168         }
00169     }
00170 }
00171 
00172 
00173 #endif //FILE_DIFFER_IMPLEMENTATION_FILE
00174 

Generated on Fri Nov 28 04:29:33 2008 for HOOPLE Libraries by  doxygen 1.5.1