text.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <float.h>
00021 #include <ctype.h>
00022 #include <stdio.h>
00023 
00024 #include <vector>
00025 #include <string>
00026 #include <iostream>
00027 
00028 #include <archon/util/text.H>
00029 
00030 using namespace std;
00031 
00032 namespace Archon
00033 {
00034   namespace Utilities
00035   {
00036     namespace Text
00037     {
00038       string toString(void *v)
00039       {
00040         char buf[100];
00041         sprintf(buf, "%p", v);
00042         return buf;
00043       }
00044 
00045       string toString(bool v)
00046       {
00047         return v ? "true" : "false";
00048       }
00049 
00050       string toString(short v)
00051       {
00052         char buf[100];
00053         sprintf(buf, "%hd", v);
00054         return buf;
00055       }
00056 
00057       string toString(unsigned short v)
00058       {
00059         char buf[100];
00060         sprintf(buf, "%hu", v);
00061         return buf;
00062       }
00063 
00064       string toString(int v)
00065       {
00066         char buf[100];
00067         sprintf(buf, "%d", v);
00068         return buf;
00069       }
00070 
00071       string toString(unsigned v)
00072       {
00073         char buf[100];
00074         sprintf(buf, "%u", v);
00075         return buf;
00076       }
00077 
00078       string toString(long v)
00079       {
00080         char buf[100];
00081         sprintf(buf, "%ld", v);
00082         return buf;
00083       }
00084 
00085       string toString(unsigned long v)
00086       {
00087         char buf[100];
00088         sprintf(buf, "%lu", v);
00089         return buf;
00090       }
00091 
00092       string toString(float v)
00093       {
00094         char buf[100];
00095         sprintf(buf, "%g", static_cast<double>(v));
00096         return buf;
00097       }
00098 
00099       string toString(double v)
00100       {
00101         char buf[100];
00102         sprintf(buf, "%.10g", v);
00103         return buf;
00104       }
00105 
00106       string toString(long double v)
00107       {
00108         char buf[100];
00109         sprintf(buf, "%.15Lg", v);
00110         return buf;
00111       }
00112 
00113 
00114       bool isPrefixOf(string prefix, string s, bool ignoreCase)
00115       {
00116         return ignoreCase ?
00117           compareIgnoreCase(prefix, s.substr(0, prefix.size())) == 0 :
00118           s.compare(0, prefix.size(), prefix) == 0;
00119       }
00120 
00121       bool isSuffixOf(string suffix, string s, bool ignoreCase)
00122       {
00123         return s.size() >= suffix.size() &&
00124           (ignoreCase ?
00125            compareIgnoreCase(suffix, s.substr(s.size()-suffix.size())) == 0 :
00126            s.compare(s.size()-suffix.size(), string::npos, suffix) == 0);
00127       }
00128 
00129       string toLowerCase(string s)
00130       {
00131         string::iterator i = s.begin();
00132         while(i != s.end())
00133         {
00134           *i = static_cast<char>(tolower(*i));
00135           ++i;
00136         }
00137         return s;
00138       }
00139 
00140       string toUpperCase(string s)
00141       {
00142         string::iterator i = s.begin();
00143         while(i != s.end())
00144         {
00145           *i = static_cast<char>(toupper(*i));
00146           ++i;
00147         }
00148         return s;
00149       }
00150 
00151       string initCap(string s)
00152       {
00153         if(s.size())
00154           s[0] = static_cast<char>(toupper(s[0]));
00155         return s;
00156       }
00157 
00158       string trim(string s)
00159       {
00160         string::iterator i = s.begin();
00161         while(i != s.end() && isspace(static_cast<unsigned char>(*i))) ++i;
00162         string::iterator j = s.end();
00163         while(i != j && isspace(static_cast<unsigned char>(*(j-1)))) --j;
00164         return string(i, j);
00165       }
00166 
00167       string lineTrim(string s)
00168       {
00169         string::iterator i = s.begin();
00170         string::iterator f = i;
00171         while(i != s.end() && isspace(static_cast<unsigned char>(*i)))
00172         {
00173           char c = *i++;
00174           if(c == '\n' || c == '\r') f = i;
00175         }
00176         string::iterator j = s.end();
00177         while(i != j && isspace(static_cast<unsigned char>(*(j-1)))) --j;
00178         return i == j ? "" : string(f, j);
00179       }
00180 
00181       int compareIgnoreCase(const string &a, const string &b)
00182       {
00183         string::const_iterator i = a.begin();
00184         string::const_iterator j = b.begin();
00185         while(i != a.end() && j != b.end())
00186         {
00187           const int ca = toupper(static_cast<unsigned char>(*i));
00188           const int cb = toupper(static_cast<unsigned char>(*j));
00189           if(ca != cb) return ca - cb;
00190           ++i;
00191           ++j;
00192         }
00193         return a.size() - b.size();
00194       }
00195 
00196       string escapeNonprintable(const string &s)
00197       {
00198         string t;
00199         t+='"';
00200         t.reserve(s.size()+2);
00201         for(unsigned i=0; i<s.size(); ++i)
00202         {
00203           const int ch = static_cast<unsigned char>(s[i]);
00204           switch(ch)
00205           {
00206           case '\n': t+="\\n";  break;
00207           case '\t': t+="\\t";  break;
00208           case '\v': t+="\\v";  break;
00209           case '\b': t+="\\b";  break;
00210           case '\r': t+="\\r";  break;
00211           case '\f': t+="\\f";  break;
00212           case '\a': t+="\\a";  break;
00213           case '\\': t+="\\\\"; break;
00214           case '"' : t+="\\\""; break;
00215           default:
00216             if(ch <= 0x1f || ch >= 0x7f && ch <= 0xa0 || ch == 0xad)
00217             {
00218               char buffer[8];
00219               sprintf(buffer, "\\x%02x", ch);
00220               t+=buffer;
00221             }
00222             else t+=ch;
00223           }
00224         }
00225         t+='"';
00226         return t;
00227       }
00228 
00233       ustring escapeNonprintable(const ustring &s)
00234       {
00235         ustring t;
00236         t+='"';
00237         t.reserve(s.size()+2);
00238         for(unsigned i=0; i<s.size(); ++i)
00239         {
00240           const uchar ch = s[i];
00241           switch(ch)
00242           {
00243           case '\n': t+=Unicode::decodeUtf8("\\n");  break;
00244           case '\t': t+=Unicode::decodeUtf8("\\t");  break;
00245           case '\v': t+=Unicode::decodeUtf8("\\v");  break;
00246           case '\b': t+=Unicode::decodeUtf8("\\b");  break;
00247           case '\r': t+=Unicode::decodeUtf8("\\r");  break;
00248           case '\f': t+=Unicode::decodeUtf8("\\f");  break;
00249           case '\a': t+=Unicode::decodeUtf8("\\a");  break;
00250           case '\\': t+=Unicode::decodeUtf8("\\\\"); break;
00251           case '"' : t+=Unicode::decodeUtf8("\\\""); break;
00252           default:
00253             if(ch <= 0x1f || ch >= 0x7f && ch <= 0xa0 || ch == 0xad)
00254             {
00255               char buffer[8];
00256               sprintf(buffer, "\\x%02x", ch);
00257               t+=Unicode::decodeUtf8(buffer);
00258             }
00259             else t+=ch;
00260           }
00261         }
00262         t+='"';
00263         return t;
00264       }
00265 
00266       string format(string value, int width)
00267       {
00268         string buffer;
00269         StringTokenizer tokenizer(value, " \t\r\n", true);
00270 
00271         int position = 0; // Number of characters already put into the current line
00272         int pendingNewlines = 0; // Number of consecutive empty lines needing to be appended if something follows them
00273 
00274         while(tokenizer.hasMoreElements())
00275         {
00276           string word = tokenizer.nextToken();
00277 
00278           if(word == " " || word  == "\t" || word  == "\r") continue;
00279 
00280           if(word == "\n")
00281           {
00282             if(width < 0) continue;
00283             ++pendingNewlines;
00284             position = 0;
00285             continue;
00286           }
00287 
00288           if(pendingNewlines > 0)
00289           {
00290             for(int i=0; i<pendingNewlines; ++i) buffer += "\n";
00291             pendingNewlines = 0;
00292           }
00293 
00294           if(width > 0)
00295           {
00296             // Break line if next word exceeds max. width (never applies to the first word on a line)
00297             if(position > 0 && int(word.length()) + position >= width)
00298             {
00299               buffer += "\n";
00300               position = 0;
00301             }
00302 
00303             // Break word if it is wider than max. width (only applies to the first word on a line)
00304             while(position == 0 && int(word.length()) > width)
00305             {
00306               buffer += string(word, 0, width);
00307               buffer += "\n";
00308               word = string(word, width);
00309             }
00310           }
00311 
00312           if(position > 0)
00313           {
00314             buffer += " ";
00315             ++position;
00316           }
00317           buffer += word;
00318           position += word.length();
00319         }
00320 
00321         return buffer;
00322       }
00323 
00324       int width(string s)
00325       {
00326         int w = 0;
00327         unsigned p = 0;
00328         do
00329         {
00330           unsigned _p = s.find('\n', p);
00331           if(_p == string::npos) _p = s.length();
00332           int _w = _p - p;
00333           if(_w > w) w = _w;
00334           p = _p + 1;
00335         }
00336         while(p <= s.size());
00337         return w;
00338       }
00339 
00340       int height(string s)
00341       {
00342         int h = 0;
00343         unsigned p = 0;
00344         for(;;)
00345         {
00346           const unsigned _p = s.find('\n', p);
00347           if(_p == string::npos)
00348           {
00349             if(s.size() - p > 0) ++h;
00350             break;
00351           }
00352           ++h;
00353           p = _p + 1;
00354         }
00355 
00356         return h;
00357       }
00358 
00359       string extractLine(string s, int i)
00360       {
00361         if(i<0) return ""; // Actually we should throw an exception
00362         unsigned p = 0;
00363         while(i>0)
00364         {
00365           const unsigned _p = s.find('\n', p);
00366           if(_p == string::npos) return ""; // Actually we should throw an exception
00367           p = _p + 1;
00368           --i;
00369         }
00370         unsigned q = s.find('\n', p);
00371         if(q == string::npos) q = s.size();
00372         if(p == s.size()) return ""; // Actually we should throw an exception
00373         return s.substr(p, q-p);
00374       }
00375 
00376       string format(Table<string> &table, int maxTotalWidth, int columnSpacing, bool header)
00377       {
00378         if(!table.getRows()) return "";
00379 
00380         // Calculate column widths
00381         vector<int> columnWidths(table.getCols());
00382         for(int i=0; i<table.getRows(); ++i)
00383           for(int j=0; j<table.getCols(); ++j)
00384           {
00385             const int w = width(table(i, j));
00386             if(w > columnWidths[j]) columnWidths[j] = w;
00387           }
00388 
00389         // Calculate total width
00390         int totalWidth = 0;
00391         for(int i=0; i<table.getCols(); ++i)
00392         {
00393           totalWidth += columnWidths[i];
00394           if(i<table.getCols()-1) totalWidth += columnSpacing;
00395         }
00396 
00397         if(maxTotalWidth > 0 && totalWidth > maxTotalWidth)
00398         {
00399           // Calculate column excesses
00400           const int netWidth = maxTotalWidth - (table.getCols()-1) * columnSpacing;
00401           vector<double> excess(table.getCols());
00402           for(int i=0; i<table.getCols(); ++i)
00403             excess[i] = columnWidths[i] - netWidth * table.columnWidthFractions[i];
00404           while(totalWidth > maxTotalWidth)
00405           {
00406             // Find column with greatest excess
00407             double e = DBL_MIN;
00408             int j = -1;
00409             for(int i=0; i<table.getCols(); ++i)
00410               if(excess[i] > e) e = excess[j = i];
00411             // Reduce column with by one character
00412             if(columnWidths[j] > 1) --columnWidths[j];
00413             excess[j] -= 1;
00414             --totalWidth;
00415           }
00416 
00417           // Reformat cells
00418           for(int i=0; i<table.getRows(); ++i)
00419             for(int j=0; j<table.getCols(); ++j)
00420               table(i, j) = format(table(i, j), columnWidths[j]);
00421         }
00422 
00423         // Render table
00424         string buffer;
00425         for(int i=0; i<table.getRows(); ++i)
00426         {
00427           int h = 0;
00428           for(int j=0; j<table.getCols(); ++j)
00429           {
00430             int _h = height(table(i, j));
00431             if(_h > h) h = _h;
00432           }
00433 
00434           for(int l=0; l<h; ++l)
00435           {
00436             for(int j=0; j<table.getCols(); ++j)
00437             {
00438               string cellLine = extractLine(table(i, j), l);
00439               buffer += cellLine;
00440               if(j<table.getCols()-1)
00441               {
00442                 int w = cellLine.length();
00443                 while(w<columnWidths[j]+columnSpacing)
00444                 {
00445                   buffer += " ";
00446                   ++w;
00447                 }
00448               }
00449             }
00450 
00451             buffer += "\n";
00452           }
00453 
00454           if(header && i == 0)
00455           {
00456             for(int j=0; j<totalWidth; ++j) buffer += "-";
00457             buffer += "\n";
00458           }
00459         }
00460 
00461         return buffer;
00462       }
00463     }
00464   }
00465 }

Generated on Sun Jul 30 22:55:45 2006 for Archon by  doxygen 1.4.4