Commit 1412555e authored by Joachim Eibl's avatar Joachim Eibl

- parse preprocessor args and allow quoting via " or '

- check for incomplete conversion to unicode (possible for utf8-codec)


git-svn-id: https://kdiff3.svn.sourceforge.net/svnroot/kdiff3/trunk@116 c8aa9fed-2811-0410-8543-893ada326672
parent b7f8391d
......@@ -288,7 +288,12 @@ bool SourceData::isText()
{
return m_normalData.m_bIsText;
}
bool SourceData::isIncompleteConversion()
{
return m_normalData.m_bIncompleteConversion;
}
bool SourceData::isFromBuffer()
{
return !m_fileAccess.isValid();
......@@ -310,6 +315,7 @@ void SourceData::FileData::reset()
m_size = 0;
m_vSize = 0;
m_bIsText = true;
m_bIncompleteConversion = false;
m_eLineEndStyle = eLineEndStyleUndefined;
}
......@@ -416,6 +422,93 @@ QTextCodec* SourceData::detectEncoding( const QString& fileName, QTextCodec* pFa
return pFallbackCodec;
}
/* Split the command line into arguments.
* Normally split at white space separators except when quoting with " or '.
* Backslash is treated as meta character within single quotes ' only.
* Detect parsing errors like unclosed quotes.
* The first item in the list will be the command itself.
* Returns the error reasor as string or an empty string on success.
* Eg. >"1" "2"< => >1<, >2<
* Eg. >'\'\\'< => >'\< backslash is a meta character between single quotes
* Eg. > "\\" < => >\\< but not between double quotes
* Eg. >"c:\sed" 's/a/\' /g'< => >c:\sed<, >s/a/' /g<
*/
static QString getArguments( QString cmd, QString& program, QStringList& args )
{
program = QString();
args.clear();
for ( int i=0; i<cmd.length(); ++i )
{
while ( i<cmd.length() && cmd[i].isSpace() )
{
++i;
}
if ( cmd[i]=='"' || cmd[i]=='\'' ) // argument beginning with a quote
{
QChar quoteChar = cmd[i];
++i;
int argStart = i;
bool bSkip = false;
while ( i<cmd.length() && ( cmd[i]!=quoteChar || bSkip ) )
{
if ( bSkip )
{
bSkip = false;
if ( cmd[i]=='\\' || cmd[i]==quoteChar )
{
cmd.remove( i-1, 1 ); // remove the backslash '\'
continue;
}
}
else if ( cmd[i]=='\\' && quoteChar=='\'')
bSkip = true;
++i;
}
if ( i<cmd.length() )
{
args << cmd.mid( argStart, i-argStart );
if ( i+1<cmd.length() && !cmd[i+1].isSpace() )
return i18n("Expecting space after closing apostroph.");
}
else
return i18n("Not matching apostrophs.");
continue;
}
else
{
int argStart = i;
//bool bSkip = false;
while ( i<cmd.length() && ( !cmd[i].isSpace() /*|| bSkip*/ ) )
{
/*if ( bSkip )
{
bSkip = false;
if ( cmd[i]=='\\' || cmd[i]=='"' || cmd[i]=='\'' || cmd[i].isSpace() )
{
cmd.remove( i-1, 1 ); // remove the backslash '\'
continue;
}
}
else if ( cmd[i]=='\\' )
bSkip = true;
else */
if ( cmd[i]=='"' || cmd[i]=='\'' )
return i18n("Unexpected apostroph within argument.");
++i;
}
args << cmd.mid( argStart, i-argStart );
}
}
if ( args.isEmpty() )
return i18n("No program specified.");
else
{
program = args[0];
args.pop_front();
}
return QString();
}
void SourceData::readAndPreprocess( QTextCodec* pEncoding, bool bAutoDetectUnicode )
{
m_pEncoding = pEncoding;
......@@ -493,17 +586,25 @@ void SourceData::readAndPreprocess( QTextCodec* pEncoding, bool bAutoDetectUnico
QProcess ppProcess;
ppProcess.setStandardInputFile( fileNameInPP );
ppProcess.setStandardOutputFile( fileNameOut1 );
ppProcess.start( ppCmd );
ppProcess.waitForFinished(-1);
QString program;
QStringList args;
QString errorReason = getArguments(ppCmd, program, args);
if ( errorReason.isEmpty() )
{
ppProcess.start( program, args );
ppProcess.waitForFinished(-1);
}
else
errorReason = "\n("+errorReason+")";
//QString cmd = catCmd + " \"" + fileNameInPP + "\" | " + ppCmd + " >\"" + fileNameOut1+"\"";
//::system( encodeString(cmd) );
bool bSuccess = m_normalData.readFile( fileNameOut1 );
bool bSuccess = errorReason.isEmpty() && m_normalData.readFile( fileNameOut1 );
if ( fileInSize >0 && ( !bSuccess || m_normalData.m_size==0 ) )
{
KMessageBox::error(m_pOptionDialog,
i18n("Preprocessing possibly failed. Check this command:\n\n %1"
"\n\nThe preprocessing command will be disabled now."
).arg(ppCmd) );
).arg(ppCmd) + errorReason );
m_pOptionDialog->m_PreProcessorCmd = "";
m_normalData.readFile( fileNameIn1 );
pEncoding1 = m_pEncoding;
......@@ -533,17 +634,25 @@ void SourceData::readAndPreprocess( QTextCodec* pEncoding, bool bAutoDetectUnico
QProcess ppProcess;
ppProcess.setStandardInputFile( fileNameInPP );
ppProcess.setStandardOutputFile( fileNameOut2 );
ppProcess.start( ppCmd );
ppProcess.waitForFinished(-1);
QString program;
QStringList args;
QString errorReason = getArguments(ppCmd, program, args);
if ( errorReason.isEmpty() )
{
ppProcess.start( program, args );
ppProcess.waitForFinished(-1);
}
else
errorReason = "\n("+errorReason+")";
//QString cmd = catCmd + " \"" + fileNameInPP + "\" | " + ppCmd + " >\"" + fileNameOut2 + "\"";
//::system( encodeString(cmd) );
bool bSuccess = m_lmppData.readFile( fileNameOut2 );
bool bSuccess = errorReason.isEmpty() && m_lmppData.readFile( fileNameOut2 );
if ( FileAccess(fileNameIn2).size()>0 && ( !bSuccess || m_lmppData.m_size==0 ) )
{
KMessageBox::error(m_pOptionDialog,
i18n("The line-matching-preprocessing possibly failed. Check this command:\n\n %1"
"\n\nThe line-matching-preprocessing command will be disabled now."
).arg(ppCmd) );
).arg(ppCmd) + errorReason );
m_pOptionDialog->m_LineMatchingPreProcessorCmd = "";
m_lmppData.readFile( fileNameIn2 );
}
......@@ -654,6 +763,7 @@ void SourceData::FileData::preprocess( bool bPreserveCR, QTextCodec* pEncoding )
m_bIsText = true;
int lines = 1;
m_bIncompleteConversion = false;
for( i=0; i<ucSize; ++i )
{
if ( isLineOrBufEnd(p,i,ucSize) )
......@@ -664,6 +774,10 @@ void SourceData::FileData::preprocess( bool bPreserveCR, QTextCodec* pEncoding )
{
m_bIsText = false;
}
if ( p[i]==QChar::ReplacementCharacter )
{
m_bIncompleteConversion = true;
}
}
m_v.resize( lines+5 );
......
......@@ -263,6 +263,7 @@ public:
bool isEmpty(); // File was set
bool hasData(); // Data was readable
bool isText(); // is it pure text (vs. binary data)
bool isIncompleteConversion(); // true if some replacement characters were found
bool isFromBuffer(); // was it set via setData() (vs. setFileAccess() or setFilename())
void setData( const QString& data );
bool isValid(); // Either no file is specified or reading was successful
......@@ -286,7 +287,7 @@ private:
struct FileData
{
FileData(){ m_pBuf=0; m_size=0; m_vSize=0; m_bIsText=false; m_eLineEndStyle=eLineEndStyleUndefined; }
FileData(){ m_pBuf=0; m_size=0; m_vSize=0; m_bIsText=false; m_eLineEndStyle=eLineEndStyleUndefined; m_bIncompleteConversion=false;}
~FileData(){ reset(); }
const char* m_pBuf;
int m_size;
......@@ -294,6 +295,7 @@ private:
QString m_unicodeBuf;
std::vector<LineData> m_v;
bool m_bIsText;
bool m_bIncompleteConversion;
e_LineEndStyle m_eLineEndStyle;
bool readFile( const QString& filename );
bool writeFile( const QString& filename );
......
......@@ -59,7 +59,7 @@ void Merger::MergeData::update()
else if ( idx==1 && d.diff2 > 0 )
--d.diff2;
while( d.nofEquals == 0 && (idx==0 && d.diff1 == 0 || idx==1 && d.diff2 == 0)
while( d.nofEquals == 0 && ((idx==0 && d.diff1 == 0) || (idx==1 && d.diff2 == 0))
&& pDiffList!=0 && it != pDiffList->end() )
{
d = *it;
......
......@@ -552,6 +552,22 @@ void KDiff3App::init( bool bAuto, TotalDiffStatus* pTotalDiffStatus, bool bLoadF
"Note that the KDiff3-merge was not meant for binary data.\n"
"Continue at your own risk.") );
}
if ( m_sd1.isIncompleteConversion() || m_sd2.isIncompleteConversion() || m_sd3.isIncompleteConversion() )
{
QString files;
if ( m_sd1.isIncompleteConversion() )
files += "A";
if ( m_sd2.isIncompleteConversion() )
files += files.isEmpty() ? "B" : ", B";
if ( m_sd3.isIncompleteConversion() )
files += files.isEmpty() ? "C" : ", C";
KMessageBox::information( this, i18n(
"Some input characters could not be converted to valid unicode.\n"
"You might be using the wrong codec. (e.g. UTF-8 for non UTF-8 files).\n"
"Don't save the result if unsure. Continue at your own risk.\n"
"Affected input files are in %1.").arg(files) );
}
}
QTimer::singleShot( 10, this, SLOT(slotAfterFirstPaint()) );
......
#undef VERSION
#define VERSION "0.9.96d"
#define VERSION "0.9.96"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment