stringutil.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file stringutil.cpp
00013 ** \version $Id: stringutil.cpp 3735 2009-04-28 20:28:01Z edmanm $
00014 ** \brief Common string manipulation functions
00015 */
00016 
00017 #include "stringutil.h"
00018 
00019 #include <QCoreApplication>
00020 #include <QApplication>
00021 
00022 
00023 /** Create a QStringList from the array of C-style strings. */
00024 QStringList
00025 char_array_to_stringlist(char **arr, int len)
00026 {
00027   QStringList list;
00028   for (int i = 0; i < len; i++) {
00029     list << QString(arr[i]);
00030   }
00031   return list;
00032 }
00033 
00034 /** Conditionally assigns errmsg to str if str is not null and returns false.
00035  * This is a seemingly pointless function, but it saves some messiness in
00036  * methods whose QString *errmsg parameter is optional. */
00037 bool
00038 err(QString *str, const QString &errmsg)
00039 {
00040   if (str) {
00041     *str = errmsg;
00042   }
00043   return false;
00044 }
00045 
00046 /** Ensures all characters in str are in validChars. If a character appears
00047  * in str but not in validChars, it will be removed and the resulting
00048  * string returned. */
00049 QString
00050 ensure_valid_chars(const QString &str, const QString &validChars)
00051 {
00052   QString out = str;
00053   for (int i = 0; i < str.length(); i++) {
00054     QChar c = str.at(i);
00055     if (validChars.indexOf(c) < 0) {
00056       out.remove(c);
00057     }
00058   }
00059   return out;
00060 }
00061 
00062 /** Scrubs an email address by replacing "@" with " at " and "." with " dot ". */
00063 QString
00064 scrub_email_addr(const QString &email)
00065 {
00066   QString scrubbed = email;
00067   scrubbed = scrubbed.replace("@", " at ");
00068   scrubbed = scrubbed.replace(".", " dot ");
00069   return scrubbed;
00070 }
00071 
00072 /** Wraps <b>str</b> at <b>width</b> characters wide, using <b>sep</b> as the
00073  * word separator (" ", for example), and placing the line ending <b>le</b> at
00074  * the end of each line, except the last. */
00075 QString
00076 string_wrap(const QString &str, int width,
00077             const QString &sep, const QString &le)
00078 {
00079   QString wrapped;
00080   int pos, nextsep, wordlen, n;
00081   int seplen = sep.length();
00082  
00083   if (str.length() < width) {
00084     return str;
00085   }
00086 
00087   pos = 0; 
00088   n = width;
00089   while (pos < str.length()) {
00090     /* Get the length of a "word" */
00091     nextsep = str.indexOf(sep, pos);
00092     if (nextsep < 0) {
00093       nextsep = str.length();
00094     }
00095     wordlen = nextsep-pos;
00096 
00097     /* Check if there is room for the word on this line */
00098     if (wordlen > n) {
00099       /* Create a new line */
00100       wrapped.append(le);
00101       n = width;
00102     }
00103 
00104     /* Add the word to the current line */
00105     wrapped.append(str.mid(pos, wordlen+seplen));
00106     n = n - wordlen - seplen;
00107     pos += wordlen + seplen;
00108   }
00109   return wrapped.trimmed();
00110 }
00111 
00112 /** Encodes the bytes in <b>buf</b> as an uppercase hexadecimal string and
00113  * returns the result. This function is derived from base16_encode() in Tor's
00114  * util.c. See LICENSE for details on Tor's license. */
00115 QString
00116 base16_encode(const QByteArray &buf)
00117 {
00118   QString hex;
00119   for (int i = 0; i < buf.size(); i++) {
00120     hex += "0123456789ABCDEF"[((quint8)buf[i]) >>  4];
00121     hex += "0123456789ABCDEF"[((quint8)buf[i]) & 0xf];
00122   }
00123   return hex;
00124 }
00125 
00126 /** Given a string <b>str</b>, this function returns a quoted string with all
00127  * '"' and '\' characters escaped with a single '\'. */
00128 QString
00129 string_escape(const QString &str)
00130 {
00131   QString out;
00132   out.append("\"");
00133   for (int i = 0; i < str.length(); i++) {
00134     if (str[i] == '\"' || str[i] == '\\')
00135       out.append('\\');
00136     out.append(str[i]);
00137   }
00138   out.append("\"");
00139   return out;
00140 }
00141 
00142 /** Given a quoted string <b>str</b>, this function returns an unquoted,
00143  * unescaped string. <b>str</b> must start and end with an unescaped quote. */
00144 QString
00145 string_unescape(const QString &str, bool *ok)
00146 {
00147   QString out;
00148  
00149   /* The string must start and end with an unescaped dquote */
00150   if (str.length() < 2 || !str.startsWith("\"") || !str.endsWith("\"") ||
00151       (str.endsWith("\\\"") && !str.endsWith("\\\\\""))) {
00152     if (ok)
00153       *ok = false;
00154     return QString();
00155   }
00156   for (int i = 1; i < str.length()-1; i++) {
00157     if (str[i] == '\\')
00158       i++;
00159     out.append(str[i]);
00160   }
00161   if (ok)
00162     *ok = true;
00163   return out;
00164 }
00165 
00166 /** Parses a series of space-separated key[=value|="value"] tokens from
00167  * <b>str</b> and returns the mappings in a QHash. If <b>str</b> was unable
00168  * to be parsed, <b>ok</b> is set to false. */
00169 QHash<QString,QString>
00170 string_parse_keyvals(const QString &str, bool *ok)
00171 {
00172   int i, len;
00173   bool tmp_ok;
00174   QHash<QString,QString> keyvals;
00175   
00176   i = 0;
00177   len = str.length();
00178   while (i < len && str[i].isSpace())
00179     i++; /* Skip initial whitespace */
00180   while (i < len) {
00181     QString key, val;
00182     
00183     while (i < len && !str[i].isSpace() && str[i] != '=')
00184       key.append(str[i++]);
00185       
00186     if (i < len && str[i] == '=') {
00187       if (++i < len && str[i] == '\"') {
00188         /* The value is wrapped in quotes */
00189         val.append(str[i]);
00190         while (++i < len) {
00191           val.append(str[i]);
00192           if (str[i] == '\\') {
00193             if (++i == len)
00194               goto error;
00195             val.append(str[i]);
00196           } else if (str[i] == '\"') {
00197             i++;
00198             break;
00199           } 
00200         }
00201         val = string_unescape(val, &tmp_ok);
00202         if (!tmp_ok)
00203           goto error;
00204         keyvals.insert(key, val);
00205       } else {
00206         /* The value was not wrapped in quotes */
00207         while (i < len && !str[i].isSpace())
00208           val.append(str[i++]);
00209         keyvals.insert(key, val);
00210       }
00211     } else {
00212       /* The key had no value */
00213       keyvals.insert(key, QString(""));
00214     }
00215     while (i < len && str[i].isSpace())
00216       i++;
00217   }
00218   if (ok)
00219     *ok = true;
00220   return keyvals;
00221 
00222 error:
00223   if (ok)
00224     *ok = false;
00225   return QHash<QString,QString>();
00226 }
00227 
00228 /** Parses a series of command line arguments from <b>str</b>. If <b>str</b>
00229  * was unable to be parsed, <b>ok</b> is set to false. */
00230 QStringList
00231 string_parse_arguments(const QString &str, bool *ok)
00232 {
00233   QStringList args;
00234   int i, len;
00235   bool tmp_ok;
00236 
00237   i = 0;
00238   len = str.length();
00239   while (i < len && str[i].isSpace())
00240     i++; /* Skip initial whitespace */
00241   while (i < len) {
00242     QString arg;
00243     
00244     if (str[i] == '\"') {
00245       /* The value is wrapped in quotes */
00246       arg.append(str[i]);
00247       while (++i < len) {
00248         arg.append(str[i]);
00249         if (str[i] == '\\') {
00250           if (++i == len)
00251             goto error;
00252           arg.append(str[i]);
00253         } else if (str[i] == '\"') {
00254           i++;
00255           break;
00256         } 
00257       }
00258       arg = string_unescape(arg, &tmp_ok);
00259       if (!tmp_ok)
00260         goto error;
00261       args << arg;
00262     } else {
00263       /* The value was not wrapped in quotes */
00264       while (i < len && !str[i].isSpace())
00265         arg.append(str[i++]);
00266       args << arg;
00267     }
00268     while (i < len && str[i].isSpace())
00269       i++;
00270   }
00271 
00272   if (ok)
00273     *ok = true;
00274   return args;
00275 
00276 error:
00277   if (ok)
00278     *ok = false;
00279   return QStringList();
00280 }
00281 
00282 /** Formats the list of command line arguments in <b>args</b> as a string.
00283  * Arguments that contain ' ', '\', or '"' tokens will be escaped and
00284  * wrapped in double quotes. */
00285 QString
00286 string_format_arguments(const QStringList &args)
00287 {
00288   QStringList out;
00289   foreach (QString arg, args) {
00290     if (arg.contains("\"") || arg.contains("\\") || arg.contains(" "))
00291       out << string_escape(arg);
00292     else 
00293       out << arg;
00294   }
00295   return out.join(" ");
00296 }
00297 
00298 /** Returns true if <b>str</b> is a valid hexademical string. Returns false
00299  * otherwise. */
00300 bool
00301 string_is_hex(const QString &str)
00302 {
00303   for (int i = 0; i < str.length(); i++) {
00304     char c = str[i].toUpper().toAscii();
00305     if ((c < 'A' || c > 'F') && (c < '0' || c > '9'))
00306       return false;
00307   }
00308   return true;
00309 }
00310 
00311 /** Returns a human-readable description of the time elapsed given by
00312  * <b>seconds</b>, broken down into days, hours, minutes and seconds. */
00313 QString
00314 string_format_uptime(quint64 seconds)
00315 {
00316   QString uptime;
00317   int secs  = (seconds % 60);
00318   int mins  = (seconds / 60 % 60);
00319   int hours = (seconds / 3600 % 24);
00320   int days  = (seconds / 86400);
00321 
00322   if (days)
00323     uptime += qApp->translate("stringutil.h", "%1 days ").arg(days);
00324   if (hours)
00325     uptime += qApp->translate("stringutil.h", "%1 hours ").arg(hours);
00326   if (mins)
00327     uptime += qApp->translate("stringutil.h", "%1 mins ").arg(mins);
00328   if (secs)
00329     uptime += qApp->translate("stringutil.h", "%1 secs").arg(secs);
00330 
00331   return uptime;
00332 }
00333 
00334 /** Returns a string representation of <b>date</b> formatted according to
00335  * "yyyy-MM-dd HH:mm:ss". */
00336 QString
00337 string_format_datetime(const QDateTime &date)
00338 {
00339   return date.toString("yyyy-MM-dd HH:mm:ss");
00340 }
00341 
00342 /** Returns a string representation of <b>bytes</b> with the appropriate
00343  * suffix of either "B/s", "KB/s", "MB/s" or "GB/s". */
00344 QString
00345 string_format_bandwidth(quint64 bytes)
00346 {
00347   if (bytes < 1024)
00348     return qApp->translate("stringutil.h", "%1 B/s").arg(bytes);
00349   if (bytes < 1048576)
00350     return qApp->translate("stringutil.h", "%1 KB/s").arg(bytes/1024.0, 0, 'f', 2);
00351   if (bytes < 1073741824)
00352     return qApp->translate("stringutil.h", "%1 MB/s").arg(bytes/1048576.0, 0, 'f', 2);
00353 
00354   return qApp->translate("stringutil.h", "%1 GB/s").arg(bytes/1073741824.0, 0, 'f', 2);
00355 }
00356 
Generated on Mon Aug 30 22:58:55 2010 for Vidalia by  doxygen 1.6.3