Chris@629: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@629: 
Chris@629: /*
Chris@629:     Sonic Visualiser
Chris@629:     An audio file viewer and annotation editor.
Chris@629:     Centre for Digital Music, Queen Mary, University of London.
Chris@629:     
Chris@629:     This program is free software; you can redistribute it and/or
Chris@629:     modify it under the terms of the GNU General Public License as
Chris@629:     published by the Free Software Foundation; either version 2 of the
Chris@629:     License, or (at your option) any later version.  See the file
Chris@629:     COPYING included with this distribution for more information.
Chris@629: */
Chris@629: 
Chris@629: /*
Chris@629:    This is a modified version of a source file from the 
Chris@629:    Rosegarden MIDI and audio sequencer and notation editor.
Chris@629:    This file copyright 2000-2010 Chris Cannam.
Chris@629: */
Chris@629: 
Chris@629: #include "StringBits.h"
Chris@629: 
Chris@629: double
Chris@629: StringBits::stringToDoubleLocaleFree(QString s, bool *ok)
Chris@629: {
Chris@629:     int dp = 0;
Chris@629:     int sign = 1;
Chris@629:     int i = 0;
Chris@629:     double result = 0.0;
Chris@629:     int len = s.length();
Chris@629: 
Chris@629:     result = 0.0;
Chris@629: 
Chris@629:     if (ok) *ok = true;
Chris@629: 
Chris@629:     while (i < len && s[i].isSpace()) ++i;
Chris@629:     if (i < len && s[i] == '-') sign = -1;
Chris@629: 
Chris@629:     while (i < len) {
Chris@629: 
Chris@629: 	QChar c = s[i];
Chris@629: 
Chris@629:         if (c.isDigit()) {
Chris@629: 
Chris@629:             double d = c.digitValue();
Chris@629: 
Chris@629:             if (dp > 0) {
Chris@629:                 for (int p = dp; p > 0; --p) d /= 10.0;
Chris@629:                 ++dp;
Chris@629:             } else {
Chris@629:                 result *= 10.0;
Chris@629:             }
Chris@629: 
Chris@629:             result += d;
Chris@629: 
Chris@629:         } else if (c == '.') {
Chris@629: 
Chris@629:             dp = 1;
Chris@629: 
Chris@629:         } else if (ok) {
Chris@629:             *ok = false;
Chris@629:         }
Chris@629: 
Chris@629:         ++i;
Chris@629:     }
Chris@629: 
Chris@629:     return result * sign;
Chris@629: }
Chris@629:     
Chris@629: QStringList
Chris@629: StringBits::splitQuoted(QString s, QChar separator)
Chris@629: {
Chris@629:     QStringList tokens;
Chris@629:     QString tok;
Chris@629: 
Chris@629:     enum { sep, unq, q1, q2 } mode = sep;
Chris@629: 
Chris@629:     for (int i = 0; i < s.length(); ++i) {
Chris@629: 	
Chris@629: 	QChar c = s[i];
Chris@629: 
Chris@629: 	if (c == '\'') {
Chris@629: 	    switch (mode) {
Chris@629: 	    case sep: mode = q1; break;
Chris@629: 	    case unq: case q2: tok += c; break;
Chris@629: 	    case q1: mode = sep; tokens << tok; tok = ""; break;
Chris@629: 	    }
Chris@629: 
Chris@629: 	} else if (c == '"') {
Chris@629: 	    switch (mode) {
Chris@629: 	    case sep: mode = q2; break;
Chris@629: 	    case unq: case q1: tok += c; break;
Chris@629: 	    case q2: mode = sep; tokens << tok; tok = ""; break;
Chris@629: 	    }
Chris@629: 
Chris@629: 	} else if (c == separator || (separator == ' ' && c.isSpace())) {
Chris@629: 	    switch (mode) {
Chris@629: 	    case sep: if (separator != ' ') tokens << ""; break;
Chris@629: 	    case unq: mode = sep; tokens << tok; tok = ""; break;
Chris@629: 	    case q1: case q2: tok += c; break;
Chris@629: 	    }
Chris@629: 
Chris@629: 	} else if (c == '\\') {
Chris@629: 	    if (++i < s.length()) {
Chris@629: 		c = s[i];
Chris@629: 		switch (mode) {
Chris@629: 		case sep: mode = unq; tok += c; break;
Chris@629: 		default: tok += c; break;
Chris@629: 		}
Chris@629: 	    }
Chris@629: 
Chris@629: 	} else {
Chris@629: 	    switch (mode) {
Chris@629: 	    case sep: mode = unq; tok += c; break;
Chris@629: 	    default: tok += c; break;
Chris@629: 	    }
Chris@629: 	}
Chris@629:     }
Chris@629: 
Chris@629:     if (tok != "" || mode != sep) tokens << tok;
Chris@629:     return tokens;
Chris@629: }
Chris@629: 
Chris@629: /*
Chris@629: 
Chris@629: void testSplit()
Chris@629: {
Chris@629:     QStringList tests;
Chris@629:     tests << "a b c d";
Chris@629:     tests << "a \"b c\" d";
Chris@629:     tests << "a 'b c' d";
Chris@629:     tests << "a \"b c\\\" d\"";
Chris@629:     tests << "a 'b c\\' d'";
Chris@629:     tests << "a \"b c' d\"";
Chris@629:     tests << "a 'b c\" d'";
Chris@629:     tests << "aa 'bb cc\" dd'";
Chris@629:     tests << "a'a 'bb' \\\"cc\" dd\\\"";
Chris@629:     tests << "  a'a \\\'	 'bb'	 \'	\\\"cc\" ' dd\\\" '";
Chris@629: 
Chris@629:     for (int j = 0; j < tests.size(); ++j) {
Chris@629: 	cout << endl;
Chris@686: 	cout << tests[j] << endl;
Chris@629: 	cout << "->" << endl << "(";
Chris@629: 	QStringList l = splitQuoted(tests[j], ' ');
Chris@629: 	for (int i = 0; i < l.size(); ++i) {
Chris@629: 	    if (i > 0) cout << ";";
Chris@629: 	    cout << l[i].toStdString();
Chris@629: 	}
Chris@629: 	cout << ")" << endl;
Chris@629:     }
Chris@629: }
Chris@629: 
Chris@629: */
Chris@629: 
Chris@629: /* 
Chris@629:    Results:
Chris@629: 
Chris@629: a b c d
Chris@629: ->     
Chris@629: (a;b;c;d)
Chris@629: 
Chris@629: a "b c" d
Chris@629: ->       
Chris@629: (a;b c;d)
Chris@629: 
Chris@629: a 'b c' d
Chris@629: ->       
Chris@629: (a;b c;d)
Chris@629: 
Chris@629: a "b c\" d"
Chris@629: ->         
Chris@629: (a;b c" d) 
Chris@629: 
Chris@629: a 'b c\' d'
Chris@629: ->         
Chris@629: (a;b c' d) 
Chris@629: 
Chris@629: a "b c' d"
Chris@629: ->        
Chris@629: (a;b c' d)
Chris@629: 
Chris@629: a 'b c" d'
Chris@629: ->        
Chris@629: (a;b c" d)
Chris@629: 
Chris@629: aa 'bb cc" dd'
Chris@629: ->            
Chris@629: (aa;bb cc" dd)
Chris@629: 
Chris@629: a'a 'bb' \"cc" dd\"
Chris@629: ->                 
Chris@629: (a'a;bb;"cc";dd")  
Chris@629: 
Chris@629:   a'a \'         'bb'    '      \"cc" ' dd\" '
Chris@629: ->                                            
Chris@629: (a'a;';bb;      "cc" ;dd";)
Chris@629: 
Chris@629: */
Chris@629: 
Chris@629: QStringList
Chris@629: StringBits::split(QString line, QChar separator, bool quoted)
Chris@629: {
Chris@629:     if (quoted) {
Chris@629:         return splitQuoted(line, separator);
Chris@629:     } else {
Chris@629:         return line.split(separator,
Chris@629:                           separator == ' ' ? QString::SkipEmptyParts :
Chris@629:                           QString::KeepEmptyParts);
Chris@629:     }
Chris@629: }
Chris@629: