2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
22 * (c) Copyright 2007-2008 by Intra2net AG
30 #include <cmath> // for round()
37 #include <boost/numeric/conversion/cast.hpp>
39 #include <stringfunc.hxx>
50 const std::string hexDigitsLower("0123456789abcdef");
51 const std::string hexDigitsUpper("0123456789ABCDEF");
56 char operator() (char c)
58 return std::toupper(c);
60 }; // eo struct UpperFunc
65 char operator() (char c)
67 return std::tolower(c);
69 }; // eo struct LowerFunc
72 } // eo namespace <anonymous>
77 * default list of Whitespaces (" \t\r\n");
79 const std::string Whitespaces = " \t\r\n";
82 * default list of lineendings ("\r\n");
84 const std::string LineEndings= "\r\n";
89 * @brief checks if a string begins with a given prefix.
90 * @param[in,out] str the string which is tested
91 * @param prefix the prefix which should be tested for.
92 * @return @a true iff the prefix is not empty and the string begins with that prefix.
94 bool has_prefix(const std::string& str, const std::string& prefix)
96 if (prefix.empty() || str.empty() || str.size() < prefix.size() )
100 return str.compare(0, prefix.size(), prefix) == 0;
101 } // eo has_prefix(const std::string&,const std::string&)
105 * @brief checks if a string ends with a given suffix.
106 * @param[in,out] str the string which is tested
107 * @param suffix the suffix which should be tested for.
108 * @return @a true iff the suffix is not empty and the string ends with that suffix.
110 bool has_suffix(const std::string& str, const std::string& suffix)
112 if (suffix.empty() || str.empty() || str.size() < suffix.size() )
116 return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
117 } // eo has_suffix(const std::string&,const std::string&)
121 * cut off characters from a given list from front and end of a string.
122 * @param[in,out] str the string which should be trimmed.
123 * @param charlist the list of characters to remove from beginning and end of string
124 * @return the result string.
126 std::string trim_mod(std::string& str, const std::string& charlist)
128 // first: trim the beginning:
129 std::string::size_type pos= str.find_first_not_of (charlist);
130 if (pos == std::string::npos)
132 // whole string consists of charlist (or is already empty)
138 // str starts with charlist
141 // now let's look at the tail:
142 pos= str.find_last_not_of(charlist) +1; // note: we already know there is at least one other char!
143 if ( pos < str.size() )
145 str.erase(pos, str.size()-pos);
148 } // eo trim_mod(std::string&,const std::string&)
153 * removes last character from a string when it is in a list of chars to be removed.
154 * @param[in,out] str the string.
155 * @param what the list of chars which will be tested for.
156 * @return the resulting string with last char removed (if applicable)
158 std::string chomp_mod(std::string& str, const std::string& what)
160 if (str.empty() || what.empty() )
164 if (what.find(str.at (str.size()-1) ) != std::string::npos)
166 str.erase(str.size() - 1);
169 } // eo chomp_mod(std::string&,const std::string&)
173 * @brief converts a string to lower case.
174 * @param[in,out] str the string to modify.
177 std::string to_lower_mod(std::string& str)
179 std::transform(str.begin(), str.end(), str.begin(), LowerFunc() );
181 } // eo to_lower_mod(std::string&)
185 * @brief converts a string to upper case.
186 * @param[in,out] str the string to modify.
189 std::string to_upper_mod(std::string& str)
191 std::transform( str.begin(), str.end(), str.begin(), UpperFunc() );
193 } // eo to_upper_mod(std::string&)
198 * cut off characters from a given list from front and end of a string.
199 * @param str the string which should be trimmed.
200 * @param charlist the list of characters to remove from beginning and end of string
201 * @return the result string.
203 std::string trim (const std::string& str, const std::string& charlist)
205 // first: trim the beginning:
206 std::string::size_type pos0= str.find_first_not_of(charlist);
207 if (pos0 == std::string::npos)
209 // whole string consists of charlist (or is already empty)
210 return std::string();
212 // now let's look at the end:
213 std::string::size_type pos1= str.find_last_not_of(charlist);
214 return str.substr(pos0, pos1 - pos0 + 1);
215 } // eo trim(const std:.string&,const std::string&)
219 * removes last character from a string when it is in a list of chars to be removed.
220 * @param str the string.
221 * @param what the list of chars which will be tested for.
222 * @return the resulting string with last char removed (if applicable)
224 std::string chomp (const std::string& str, const std::string& what)
226 if (str.empty() || what.empty() )
230 if (what.find(str.at (str.size()-1) ) != std::string::npos)
232 return str.substr(0, str.size()-1);
235 } // eo chomp(const std:.string&,const std::string&)
239 * @brief returns a lower case version of a given string.
240 * @param str the string
241 * @return the lower case version of the string
243 std::string to_lower (const std::string& str)
245 std::string result(str);
246 return to_lower_mod(result);
247 } // eo to_lower(const std::string&)
251 * @brief returns a upper case version of a given string.
252 * @param str the string
253 * @return the upper case version of the string
255 std::string to_upper(const std::string& str)
257 std::string result(str);
258 return to_upper_mod(result);
259 } // eo to_upper(const std::string&)
264 * @brief removes a given suffix from a string.
265 * @param str the string.
266 * @param suffix the suffix which should be removed if the string ends with it.
267 * @return the string without the suffix.
269 * If the string ends with the suffix, it is removed. If the the string doesn't end
270 * with the suffix the original string is returned.
272 std::string remove_suffix(const std::string& str, const std::string& suffix)
274 if (has_suffix(str,suffix) )
276 return str.substr(0, str.size()-suffix.size() );
279 } // eo remove_suffix(const std::string&,const std::string&)
284 * @brief removes a given prefix from a string.
285 * @param str the string.
286 * @param prefix the prefix which should be removed if the string begins with it.
287 * @return the string without the prefix.
289 * If the string begins with the prefix, it is removed. If the the string doesn't begin
290 * with the prefix the original string is returned.
292 std::string remove_prefix(const std::string& str, const std::string& prefix)
294 if (has_prefix(str,prefix) )
296 return str.substr( prefix.size() );
299 } // eo remove_prefix(const std::string&,const std::string&)
303 * split a string to key and value delimited by a given delimiter.
304 * The resulting key and value strings are trimmed (Whitespaces removed at beginning and end).
305 * @param str the string which should be splitted.
306 * @param[out] key the resulting key
307 * @param[out] value the resulting value
308 * @param delimiter the delimiter between key and value; default is '='.
309 * @return @a true if the split was successful.
312 const std::string& str,
317 std::string::size_type pos = str.find (delimiter);
318 if (pos == std::string::npos) return false;
319 key= str.substr(0,pos);
320 value= str.substr(pos+1);
324 } // eo pair_split(const std::string&,std::string&,std::string&,char)
328 * splits a string by given delimiter
330 * @param[in] str the string which should be splitted.
331 * @param[out] result the list resulting from splitting @a str.
332 * @param[in] delimiter the delimiter (word/phrase) at which @a str should be splitted.
333 * @param[in] omit_empty should empty parts not be stored?
334 * @param[in] trim_list list of characters the parts should be trimmed by.
335 * (empty string results in no trim)
338 const std::string& str,
339 std::list<std::string>& result,
340 const std::string& delimiter,
342 const std::string& trim_list
345 std::string::size_type pos, last_pos=0;
346 bool delimiter_found= false;
347 while ( last_pos < str.size() && last_pos != std::string::npos)
349 pos= str.find(delimiter, last_pos);
351 if (pos == std::string::npos)
353 part= str.substr(last_pos);
354 delimiter_found= false;
358 part= str.substr(last_pos, pos-last_pos);
359 delimiter_found=true;
361 if (pos != std::string::npos)
363 last_pos= pos+ delimiter.size();
367 last_pos= std::string::npos;
369 if (!trim_list.empty() ) trim_mod (part, trim_list);
370 if (omit_empty && part.empty() ) continue;
371 result.push_back( part );
373 // if the string ends with a delimiter we need to append an empty string if no omit_empty
375 // (this way we keep the split result consistent to a join operation)
376 if (delimiter_found && !omit_empty)
378 result.push_back("");
380 } // eo split_string(const std::string&,std::list< std::string >&,const std::string&,bool,const std::string&)
384 * splits a string by a given delimiter
385 * @param str the string which should be splitted.
386 * @param delimiter delimiter the delimiter (word/phrase) at which @a str should be splitted.
387 * @param[in] omit_empty should empty parts not be stored?
388 * @param[in] trim_list list of characters the parts should be trimmed by.
389 * (empty string results in no trim)
390 * @return the list resulting from splitting @a str.
392 std::list<std::string> split_string(
393 const std::string& str,
394 const std::string& delimiter,
396 const std::string& trim_list
399 std::list<std::string> result;
400 split_string(str, result, delimiter, omit_empty, trim_list);
402 } // eo split_string(const std::string&,const std::string&,bool,const std::string&)
406 * @brief joins a list of strings into a single string.
408 * This funtion is (basically) the reverse operation of @a split_string.
410 * @param parts the list of strings.
411 * @param delimiter the delimiter which is inserted between the strings.
412 * @return the joined string.
414 std::string join_string(
415 const std::list< std::string >& parts,
416 const std::string& delimiter
420 if (! parts.empty() )
422 std::list< std::string >::const_iterator it= parts.begin();
424 while ( ++it != parts.end() )
431 } // eo join_string(const std::list< std::string >&,const std::string&)
441 * @brief returns a hex string from a binary string.
442 * @param str the (binary) string
443 * @param upper_case_digits determine whether to use upper case characters for digits A-F.
444 * @return the string in hex notation.
446 std::string convert_binary_to_hex(
447 const std::string& str,
448 bool upper_case_digits
452 std::string hexDigits(upper_case_digits ? hexDigitsUpper : hexDigitsLower);
453 for ( std::string::const_iterator it= str.begin();
457 result.push_back( hexDigits[ ( (*it) >> 4) & 0x0f ] );
458 result.push_back( hexDigits[ (*it) & 0x0f ] );
461 } // eo convert_binary_to_hex(const std::string&,bool)
465 * @brief converts a hex digit string to binary string.
466 * @param str hex digit string
467 * @return the binary string.
469 * The hex digit string may contains white spaces or colons which are treated
470 * as delimiters between hex digit groups.
472 * @todo rework the handling of half nibbles (consistency)!
474 std::string convert_hex_to_binary(
475 const std::string& str
477 throw (std::runtime_error)
481 bool hasNibble= false;
482 bool lastWasWS= true;
483 for ( std::string::const_iterator it= str.begin();
487 std::string::size_type p = hexDigitsLower.find( *it );
488 if (p== std::string::npos)
490 p= hexDigitsUpper.find( *it );
492 if (p == std::string::npos)
494 if ( ( Whitespaces.find( *it ) != std::string::npos) // is it a whitespace?
495 or ( *it == ':') // or a colon?
498 // we treat that as a valid delimiter:
501 // 1 nibble before WS is treate as lower part:
510 if (p == std::string::npos )
512 throw runtime_error("illegal character in hex digit string: " + str);
526 //we already had a nibble, so a char is complete now:
527 result.push_back( c );
532 // this is the first nibble of a new char:
538 //well, there is one nibble left
539 // let's do some heuristics:
542 // if the preceeding character was a white space (or a colon)
543 // we treat the nibble as lower part:
544 //( this is consistent with shortened hex notations where leading zeros are not noted)
545 result.push_back( c );
549 // if it was part of a hex digit chain, we treat it as UPPER part (!!)
550 result.push_back( c << 4 );
554 } // eo convert_hex_to_binary(const std::string&)
557 } // eo namespace I2n
562 std::string iso_to_utf8(const std::string& isostring)
566 iconv_t i2utf8 = iconv_open("UTF-8", "ISO-8859-1");
568 if (iso_to_utf8 == (iconv_t)-1)
569 throw runtime_error("iconv can't convert from ISO-8859-1 to UTF-8");
571 size_t in_size=isostring.size();
572 size_t out_size=in_size*4;
574 char *buf = (char *)malloc(out_size+1);
576 throw runtime_error("out of memory for iconv buffer");
578 char *in = (char *)isostring.c_str();
580 iconv(i2utf8, &in, &in_size, &out, &out_size);
582 buf[isostring.size()*4-out_size]=0;
592 std::string utf8_to_iso(const std::string& utf8string)
596 iconv_t utf82iso = iconv_open("ISO-8859-1","UTF-8");
598 if (utf82iso == (iconv_t)-1)
599 throw runtime_error("iconv can't convert from UTF-8 to ISO-8859-1");
601 size_t in_size=utf8string.size();
602 size_t out_size=in_size;
604 char *buf = (char *)malloc(out_size+1);
606 throw runtime_error("out of memory for iconv buffer");
608 char *in = (char *)utf8string.c_str();
610 iconv(utf82iso, &in, &in_size, &out, &out_size);
612 buf[utf8string.size()-out_size]=0;
617 iconv_close(utf82iso);
622 wchar_t* utf8_to_wbuf(const std::string& utf8string)
624 iconv_t utf82wstr = iconv_open("UCS-4LE","UTF-8");
626 if (utf82wstr == (iconv_t)-1)
627 throw runtime_error("iconv can't convert from UTF-8 to UCS-4");
629 size_t in_size=utf8string.size();
630 size_t out_size= (in_size+1)*sizeof(wchar_t);
632 wchar_t *buf = (wchar_t *)malloc(out_size);
634 throw runtime_error("out of memory for iconv buffer");
636 char *in = (char *)utf8string.c_str();
637 char *out = (char*) buf;
638 if (iconv(utf82wstr, &in, &in_size, &out, &out_size) == (size_t)-1)
639 throw runtime_error("error converting char encodings");
641 buf[ ( (utf8string.size()+1)*sizeof(wchar_t)-out_size) /sizeof(wchar_t) ]=0;
643 iconv_close(utf82wstr);
648 std::string utf7imap_to_utf8(const std::string& utf7imapstring)
652 iconv_t utf7imap2utf8 = iconv_open("UTF-8","UTF-7-IMAP");
654 if (utf7imap2utf8 == (iconv_t)-1)
655 throw runtime_error("iconv can't convert from UTF-7-IMAP to UTF-8");
657 size_t in_size=utf7imapstring.size();
658 size_t out_size=in_size*4;
660 char *buf = (char *)malloc(out_size+1);
662 throw runtime_error("out of memory for iconv buffer");
664 char *in = (char *)utf7imapstring.c_str();
666 iconv(utf7imap2utf8, &in, &in_size, &out, &out_size);
668 buf[utf7imapstring.size()*4-out_size]=0;
673 iconv_close(utf7imap2utf8);
678 std::string utf8_to_utf7imap(const std::string& utf8string)
682 iconv_t utf82utf7imap = iconv_open("UTF-7-IMAP", "UTF-8");
684 if (utf82utf7imap == (iconv_t)-1)
685 throw runtime_error("iconv can't convert from UTF-7-IMAP to UTF-8");
687 // UTF-7 is base64 encoded, a buffer 10x as large
688 // as the utf-8 buffer should be enough. If not the string will be truncated.
689 size_t in_size=utf8string.size();
690 size_t out_size=in_size*10;
692 char *buf = (char *)malloc(out_size+1);
694 throw runtime_error("out of memory for iconv buffer");
696 char *in = (char *)utf8string.c_str();
698 iconv(utf82utf7imap, &in, &in_size, &out, &out_size);
700 buf[utf8string.size()*10-out_size]= 0;
705 iconv_close(utf82utf7imap);
710 // Tokenize string by (html) tags
711 void tokenize_by_tag(vector<pair<string,bool> > &tokenized, const std::string &input)
713 string::size_type pos, len = input.size();
714 bool inside_tag = false;
717 for (pos = 0; pos < len; pos++)
719 if (input[pos] == '<')
723 if (!current.empty() )
725 tokenized.push_back( make_pair(current, false) );
729 current += input[pos];
731 else if (input[pos] == '>' && inside_tag)
733 current += input[pos];
735 if (!current.empty() )
737 tokenized.push_back( make_pair(current, true) );
742 current += input[pos];
745 // String left over in buffer?
746 if (!current.empty() )
747 tokenized.push_back( make_pair(current, false) );
748 } // eo tokenize_by_tag
751 std::string strip_html_tags(const std::string &input)
753 // Pair first: string, second: isTag
754 vector<pair<string,bool> > tokenized;
755 tokenize_by_tag (tokenized, input);
758 vector<pair<string,bool> >::const_iterator token, tokens_end = tokenized.end();
759 for (token = tokenized.begin(); token != tokens_end; ++token)
761 output += token->first;
764 } // eo strip_html_tags
767 // Smart-encode HTML en
768 string smart_html_entities(const std::string &input)
770 // Pair first: string, second: isTag
771 vector<pair<string,bool> > tokenized;
772 tokenize_by_tag (tokenized, input);
775 vector<pair<string,bool> >::const_iterator token, tokens_end = tokenized.end();
776 for (token = tokenized.begin(); token != tokens_end; ++token)
778 // keep HTML tags as they are
780 output += token->first;
782 output += html_entities(token->first);
789 string::size_type find_8bit(const std::string &str)
791 string::size_type l=str.size();
792 for (string::size_type p=0; p < l; p++)
793 if (static_cast<unsigned char>(str[p]) > 127)
799 // encoded UTF-8 chars into HTML entities
800 string html_entities(std::string str)
803 replace_all (str, "&", "&");
804 replace_all (str, "<", "<");
805 replace_all (str, ">", ">");
806 replace_all (str, "\"", """);
807 replace_all (str, "'", "'");
808 replace_all (str, "/", "/");
811 replace_all (str, "\xC3\xA4", "ä");
812 replace_all (str, "\xC3\xB6", "ö");
813 replace_all (str, "\xC3\xBC", "ü");
814 replace_all (str, "\xC3\x84", "Ä");
815 replace_all (str, "\xC3\x96", "Ö");
816 replace_all (str, "\xC3\x9C", "Ü");
819 replace_all (str, "\xC3\x9F", "ß");
821 // conversion of remaining non-ASCII chars needed?
822 // just do if needed because of performance
823 if (find_8bit(str) != string::npos)
825 // convert to fixed-size encoding UTF-32
826 wchar_t* wbuf=utf8_to_wbuf(str);
827 ostringstream target;
829 // replace all non-ASCII chars with HTML representation
830 for (int p=0; wbuf[p] != 0; p++)
832 unsigned int c=wbuf[p];
835 target << static_cast<unsigned char>(c);
837 target << "&#" << c << ';';
846 } // eo html_entities(std::string)
848 // convert HTML entities to something that can be viewed on a basic text console (restricted to ASCII-7)
849 string html_entities_to_console(std::string str)
852 replace_all (str, "&", "&");
853 replace_all (str, "<", "<");
854 replace_all (str, ">", ">");
855 replace_all (str, """, "\"");
856 replace_all (str, "'", "'");
857 replace_all (str, "/", "/");
860 replace_all (str, "ä", "ae");
861 replace_all (str, "ö", "oe");
862 replace_all (str, "ü", "ue");
863 replace_all (str, "Ä", "Ae");
864 replace_all (str, "Ö", "Oe");
865 replace_all (str, "Ü", "Ue");
868 replace_all (str, "ß", "ss");
873 bool replace_all(string &base, const char *ist, const char *soll)
877 return replace_all(base,&i,&s);
880 bool replace_all(string &base, const string &ist, const char *soll)
883 return replace_all(base,&ist,&s);
886 bool replace_all(string &base, const string *ist, const string *soll)
888 return replace_all(base,*ist,*soll);
891 bool replace_all(string &base, const char *ist, const string *soll)
894 return replace_all(base,&i,soll);
897 bool replace_all(string &base, const string &ist, const string &soll)
899 bool found_ist = false;
900 string::size_type a=0;
903 throw runtime_error ("replace_all called with empty search string");
905 while ( (a=base.find(ist,a) ) != string::npos)
907 base.replace(a,ist.size(),soll);
916 * @brief replaces all characters that could be problematic or impose a security risk when being logged
917 * @param str the original string
918 * @param replace_with the character to replace the unsafe chars with
919 * @return a string that is safe to send to syslog or other logfiles
921 * All chars between 0x20 (space) and 0x7E (~) (including) are considered safe for logging.
922 * See e.g. RFC 5424, section 8.2 or the posix character class "printable".
923 * This eliminates all possible problems with NUL, control characters, 8 bit chars, UTF8.
926 std::string sanitize_for_logging(const std::string &str, const char replace_with)
928 std::string output=str;
930 const string::size_type len = output.size();
931 for (std::string::size_type p=0; p < len; p++)
932 if (output[p] < 0x20 || output[p] > 0x7E)
933 output[p]=replace_with;
939 string to_lower(const string &src)
943 string::size_type pos, end = dst.size();
944 for (pos = 0; pos < end; pos++)
945 dst[pos] = tolower(dst[pos]);
950 string to_upper(const string &src)
954 string::size_type pos, end = dst.size();
955 for (pos = 0; pos < end; pos++)
956 dst[pos] = toupper(dst[pos]);
962 const int MAX_UNIT_FORMAT_SYMBOLS = 6;
964 const string shortUnitFormatSymbols[MAX_UNIT_FORMAT_SYMBOLS] = {
973 const string longUnitFormatSymbols[MAX_UNIT_FORMAT_SYMBOLS] = {
975 i18n_noop(" KBytes"),
976 i18n_noop(" MBytes"),
977 i18n_noop(" GBytes"),
978 i18n_noop(" TBytes"),
983 long double rounding_upwards(
984 const long double number,
985 const int rounding_multiplier
988 long double rounded_number;
989 rounded_number = number * rounding_multiplier;
990 rounded_number += 0.5;
991 rounded_number = (int64_t) (rounded_number);
992 rounded_number = (long double) (rounded_number) / (long double) (rounding_multiplier);
994 return rounded_number;
998 string nice_unit_format(
1000 const UnitFormat format,
1004 // select the system of units (decimal or binary)
1006 if (base == UnitBase1000)
1015 long double size = input;
1017 // check the size of the input number to fit in the appropriate symbol
1019 while (size > multiple)
1021 size = size / multiple;
1024 // rollback to the previous values and stop the loop when cannot
1025 // represent the number length.
1026 if (sizecount >= MAX_UNIT_FORMAT_SYMBOLS)
1028 size = size * multiple;
1034 // round the input number "half up" to multiples of 10
1035 const int rounding_multiplier = 10;
1036 size = rounding_upwards(size, rounding_multiplier);
1038 // format the input number, placing the appropriate symbol
1040 out.setf (ios::fixed);
1041 if (format == ShortUnitFormat)
1044 out << size << i18n( shortUnitFormatSymbols[sizecount].c_str() );
1049 out << size << i18n( longUnitFormatSymbols[sizecount].c_str() );
1053 } // eo nice_unit_format(int input)
1056 string nice_unit_format(
1058 const UnitFormat format,
1062 // round as double and cast to int64_t
1063 // cast raised overflow error near max val of int64_t (~9.2e18, see unittest)
1064 int64_t input_casted_and_rounded =
1065 boost::numeric_cast<int64_t>( round(input) );
1068 return nice_unit_format( input_casted_and_rounded, format, base );
1069 } // eo nice_unit_format(double input)
1072 string escape(const string &s)
1075 string::size_type p;
1078 while ( (p=out.find_first_of("\"\\",p) ) !=out.npos)
1080 out.insert (p,"\\");
1085 while ( (p=out.find_first_of("\r",p) ) !=out.npos)
1087 out.replace (p,1,"\\r");
1092 while ( (p=out.find_first_of("\n",p) ) !=out.npos)
1094 out.replace (p,1,"\\n");
1101 } // eo scape(const std::string&)
1104 string descape(const string &s, int startpos, int &endpos)
1108 if (s.at(startpos) != '"')
1109 throw out_of_range("value not type escaped string");
1111 out=s.substr(startpos+1);
1112 string::size_type p=0;
1114 // search for the end of the string
1115 while ( (p=out.find("\"",p) ) !=out.npos)
1120 // the " might be escaped with a backslash
1121 while (e>=0 && out.at (e) =='\\')
1123 if (escaped == false)
1137 // we now have the end of the string
1138 out=out.substr(0,p);
1140 // tell calling prog about the endposition
1141 endpos=startpos+p+1;
1143 // descape all \ stuff inside the string now
1145 while ( (p=out.find_first_of("\\",p) ) !=out.npos)
1147 switch (out.at(p+1) )
1150 out.replace(p,2,"\r");
1153 out.replace(p,2,"\n");
1162 } // eo descape(const std::string&,int,int&)
1165 string escape_shellarg(const string &input)
1167 string output = "'";
1168 string::const_iterator it, it_end = input.end();
1169 for (it = input.begin(); it != it_end; ++it)