kio Library API Documentation

kshellcompletion.cpp

00001 /* This file is part of the KDE libraries
00002     Copyright (C) 2000 David Smith <dsmith@algonet.se>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to
00016     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017     Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #include <stdlib.h>
00021 #include <kdebug.h>
00022 #include <qstring.h>
00023 #include <qstringlist.h>
00024 #include <qregexp.h>
00025 #include <kcompletion.h>
00026 
00027 #include "kshellcompletion.h"
00028 
00029 class KShellCompletionPrivate
00030 {
00031 };
00032 
00033 KShellCompletion::KShellCompletion() : KURLCompletion()
00034 {
00035         m_word_break_char = ' ';
00036         m_quote_char1 = '\"';
00037         m_quote_char2 = '\'';
00038         m_escape_char = '\\';
00039 }
00040 
00041 /*
00042  * makeCompletion()
00043  *
00044  * Entry point for file name completion 
00045  */
00046 QString KShellCompletion::makeCompletion(const QString &text)
00047 {
00048         // Split text at the last unquoted space 
00049         //
00050         splitText(text, m_text_start, m_text_compl);
00051         
00052         // Remove quotes from the text to be completed
00053         //
00054         QString tmp = unquote(m_text_compl);
00055         m_text_compl = tmp;
00056 
00057         // Do exe-completion if there was no unquoted space
00058         //
00059         bool is_exe_completion = true;
00060         
00061         for ( uint i = 0; i < m_text_start.length(); i++ ) {
00062                 if ( m_text_start[i] != m_word_break_char ) {
00063                         is_exe_completion = false;
00064                         break;
00065                 }
00066         }
00067         
00068         Mode mode = (is_exe_completion ? ExeCompletion : FileCompletion );
00069 
00070         setMode(mode);
00071 
00072         // Make completion on the last part of text
00073         //
00074         return KURLCompletion::makeCompletion( m_text_compl );
00075 }
00076 
00077 /*
00078  * postProcessMatch, postProcessMatches
00079  *
00080  * Called by KCompletion before emitting match() and matches()
00081  *
00082  * Add add the part of the text that was not completed
00083  * Add quotes when needed 
00084  */
00085 void KShellCompletion::postProcessMatch( QString *match ) const
00086 {
00087         //kDebugInfo("KShellCompletion::postProcessMatch() in: '%s'",
00088         //      match->latin1());
00089 
00090         KURLCompletion::postProcessMatch( match );
00091 
00092         if ( match->isNull() )
00093                 return;
00094                 
00095         if ( match->right(1) == QChar('/') )
00096                 quoteText( match, false, true ); // don't quote the trailing '/'
00097         else
00098                 quoteText( match, false, false ); // quote the whole text
00099         
00100         match->prepend( m_text_start );
00101 
00102         //kDebugInfo("KShellCompletion::postProcessMatch() ut: '%s'",
00103         //      match->latin1());
00104 }
00105 
00106 void KShellCompletion::postProcessMatches( QStringList *matches ) const
00107 {
00108         KURLCompletion::postProcessMatches( matches );
00109 
00110         for ( QStringList::Iterator it = matches->begin();
00111                   it != matches->end(); it++ )
00112         {
00113                 if ( (*it) != QString::null ) {
00114                         if ( (*it).right(1) == QChar('/') )
00115                                 quoteText( &(*it), false, true ); // don't quote trailing '/'
00116                         else
00117                                 quoteText( &(*it), false, false ); // quote the whole text
00118 
00119                         (*it).prepend( m_text_start );
00120                 }
00121         }
00122 }
00123 
00124 void KShellCompletion::postProcessMatches( KCompletionMatches *matches ) const
00125 {
00126         KURLCompletion::postProcessMatches( matches );
00127 
00128         for ( KCompletionMatches::Iterator it = matches->begin();
00129                   it != matches->end(); it++ )
00130         {
00131                 if ( (*it).value() != QString::null ) {
00132                         if ( (*it).value().right(1) == QChar('/') )
00133                                 quoteText( &(*it).value(), false, true ); // don't quote trailing '/'
00134                         else
00135                                 quoteText( &(*it).value(), false, false ); // quote the whole text
00136 
00137                         (*it).value().prepend( m_text_start );
00138                 }
00139         }
00140 }
00141 
00142 /*
00143  * splitText
00144  *
00145  * Split text at the last unquoted space 
00146  *
00147  * text_start = [out] text at the left, including the space
00148  * text_compl = [out] text at the right
00149  */
00150 void KShellCompletion::splitText(const QString &text, QString &text_start, 
00151                 QString &text_compl) const
00152 {
00153         bool in_quote = false;
00154         bool escaped = false;
00155         QChar p_last_quote_char;
00156         int last_unquoted_space = -1;
00157         int end_space_len = 0;
00158         
00159         for (uint pos = 0; pos < text.length(); pos++) {
00160                 
00161                 end_space_len = 0;
00162                 
00163                 if ( escaped ) {
00164                         escaped = false;
00165                 }
00166                 else if ( in_quote && text[pos] == p_last_quote_char ) {
00167                         in_quote = false;
00168                 }
00169                 else if ( !in_quote && text[pos] == m_quote_char1 ) {
00170                         p_last_quote_char = m_quote_char1;
00171                         in_quote = true;
00172                 }
00173                 else if ( !in_quote && text[pos] == m_quote_char2 ) {
00174                         p_last_quote_char = m_quote_char2;
00175                         in_quote = true;
00176                 }
00177                 else if ( text[pos] == m_escape_char ) {
00178                         escaped = true;
00179                 }
00180                 else if ( !in_quote && text[pos] == m_word_break_char ) {
00181 
00182                         end_space_len = 1;
00183                         
00184                         while ( pos+1 < text.length() && text[pos+1] == m_word_break_char ) {
00185                                 end_space_len++;
00186                                 pos++;
00187                         }
00188 
00189                         if ( pos+1 == text.length() ) 
00190                                 break; 
00191 
00192                         last_unquoted_space = pos;
00193                 }
00194         }
00195 
00196         text_start = text.left( last_unquoted_space + 1 );
00197 
00198         // the last part without trailing blanks
00199         text_compl = text.mid( last_unquoted_space + 1 ); 
00200 
00201 //      text_compl = text.mid( last_unquoted_space + 1, 
00202 //                                                 text.length() - end_space_len - (last_unquoted_space + 1) );
00203 
00204         //kDebugInfo("split right = '%s'", text_compl.latin1());
00205 }
00206 
00207 /*
00208  * quoteText()
00209  *
00210  * Add quotations to 'text' if needed or if 'force' = true
00211  * Returns true if quotes were added
00212  *
00213  * skip_last => ignore the last charachter (we add a space or '/' to all filenames)
00214  */
00215 bool KShellCompletion::quoteText(QString *text, bool force, bool skip_last) const
00216 {
00217         int pos = 0;
00218 
00219         if ( !force ) {
00220                 pos = text->find( m_word_break_char );
00221                 if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
00222         }
00223 
00224         if ( !force && pos == -1 ) {
00225                 pos = text->find( m_quote_char1 );
00226                 if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
00227         }
00228 
00229         if ( !force && pos == -1 ) {
00230                 pos = text->find( m_quote_char2 );
00231                 if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
00232         }
00233 
00234         if ( !force && pos == -1 ) {
00235                 pos = text->find( m_escape_char );
00236                 if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
00237         }
00238 
00239         if ( force || (pos >= 0) ) {
00240 
00241                 // Escape \ in the string
00242                 text->replace( QRegExp( m_escape_char ),
00243                                QString( m_escape_char ) + m_escape_char );
00244 
00245                 // Escape " in the string
00246                 text->replace( QRegExp( m_quote_char1 ),
00247                                QString( m_escape_char ) + m_quote_char1 );
00248 
00249                 // " at the beginning
00250                 text->insert( 0, m_quote_char1 );
00251 
00252                 // " at the end
00253                 if ( skip_last )
00254                         text->insert( text->length()-1, m_quote_char1 );
00255                 else
00256                         text->insert( text->length(), m_quote_char1 );
00257 
00258                 return true;
00259         }
00260 
00261         return false;
00262 }
00263  
00264 /*
00265  * unquote
00266  *
00267  * Remove quotes and return the result in a new string
00268  *
00269  */
00270 QString KShellCompletion::unquote(const QString &text) const
00271 {
00272         bool in_quote = false;
00273         bool escaped = false;
00274         QChar p_last_quote_char;
00275         QString result;
00276 
00277         for (uint pos = 0; pos < text.length(); pos++) {
00278 
00279                 if ( escaped ) {
00280                         escaped = false;
00281                         result.insert( result.length(), text[pos] );
00282                 }
00283                 else if ( in_quote && text[pos] == p_last_quote_char ) {
00284                         in_quote = false;
00285                 }
00286                 else if ( !in_quote && text[pos] == m_quote_char1 ) {
00287                         p_last_quote_char = m_quote_char1;
00288                         in_quote = true;
00289                 }
00290                 else if ( !in_quote && text[pos] == m_quote_char2 ) {
00291                         p_last_quote_char = m_quote_char2;
00292                         in_quote = true;
00293                 }
00294                 else if ( text[pos] == m_escape_char ) {
00295                         escaped = true;
00296                         result.insert( result.length(), text[pos] );
00297                 }
00298                 else {
00299                         result.insert( result.length(), text[pos] );
00300                 }
00301 
00302         }
00303 
00304         return result;
00305 }
00306 
00307 void KShellCompletion::virtual_hook( int id, void* data )
00308 { KURLCompletion::virtual_hook( id, data ); }
00309 
00310 #include "kshellcompletion.moc"
00311 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:21 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001