|
|
|
/*
|
|
|
|
*
|
|
|
|
* $Id: k3bpatternparser.cpp 619556 2007-01-03 17:38:12Z trueg $
|
|
|
|
* Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
|
|
|
|
* Copyright (C) 2004-2005 Jakob Petsovits <jpetso@gmx.at>
|
|
|
|
*
|
|
|
|
* This file is part of the K3b project.
|
|
|
|
* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
* See the file "COPYING" for the exact licensing terms.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "k3bpatternparser.h"
|
|
|
|
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <tqvaluestack.h>
|
|
|
|
|
|
|
|
#include <kglobal.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
|
|
|
|
|
|
|
|
TQString K3bPatternParser::parsePattern( const K3bCddbResultEntry& entry,
|
|
|
|
unsigned int trackNumber,
|
|
|
|
const TQString& pattern,
|
|
|
|
bool replace,
|
|
|
|
const TQString& replaceString )
|
|
|
|
{
|
|
|
|
if( entry.titles.count() < trackNumber )
|
|
|
|
return "";
|
|
|
|
|
|
|
|
TQString dir, s;
|
|
|
|
char c = ' '; // contains the character representation of a special string
|
|
|
|
unsigned int len; // length of the current special string
|
|
|
|
|
|
|
|
|
|
|
|
for( unsigned int i = 0; i < pattern.length(); ++i ) {
|
|
|
|
|
|
|
|
if( pattern[i] == '%' ) {
|
|
|
|
|
|
|
|
if( i + 1 < pattern.length() ) {
|
|
|
|
len = 2;
|
|
|
|
|
|
|
|
if( pattern[i+1] != '{' ) { // strings like %a
|
|
|
|
c = pattern[i+1];
|
|
|
|
}
|
|
|
|
else if( i + 3 >= pattern.length() ) { // too short to contain a %{*} string
|
|
|
|
c = ' ';
|
|
|
|
}
|
|
|
|
else { // long enough to contain %{*}
|
|
|
|
|
|
|
|
if( pattern[i+3] == '}' ) { // strings like %{a}
|
|
|
|
c = pattern[i+2];
|
|
|
|
len = 4;
|
|
|
|
}
|
|
|
|
else { // strings like %{artist}, or anything like %{*
|
|
|
|
|
|
|
|
while( i + len - 1 < pattern.length() ) {
|
|
|
|
++len;
|
|
|
|
|
|
|
|
if( pattern[i + len - 1] == '%' ) { // don't touch other special strings
|
|
|
|
c = ' ';
|
|
|
|
--len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if( pattern[i + len - 1] == '}' ) {
|
|
|
|
s = pattern.mid( i + 2, len - 3 );
|
|
|
|
|
|
|
|
if( s == "title" ) {
|
|
|
|
c = TITLE;
|
|
|
|
}
|
|
|
|
else if( s == "artist" ) {
|
|
|
|
c = ARTIST;
|
|
|
|
}
|
|
|
|
else if( s == "number" ) {
|
|
|
|
c = NUMBER;
|
|
|
|
}
|
|
|
|
else if( s == "comment" ) {
|
|
|
|
c = COMMENT;
|
|
|
|
}
|
|
|
|
else if( s == "year" ) {
|
|
|
|
c = YEAR;
|
|
|
|
}
|
|
|
|
else if( s == "genre" ) {
|
|
|
|
c = GENRE;
|
|
|
|
}
|
|
|
|
else if( s == "albumtitle" ) {
|
|
|
|
c = ALBUMTITLE;
|
|
|
|
}
|
|
|
|
else if( s == "albumartist" ) {
|
|
|
|
c = ALBUMARTIST;
|
|
|
|
}
|
|
|
|
else if( s == "albumcomment" ) {
|
|
|
|
c = ALBUMCOMMENT;
|
|
|
|
}
|
|
|
|
else if( s == "date" ) {
|
|
|
|
c = DATE;
|
|
|
|
}
|
|
|
|
else { // no valid pattern in here, don't replace anything
|
|
|
|
c = ' ';
|
|
|
|
}
|
|
|
|
break; // finished parsing %{* string
|
|
|
|
}
|
|
|
|
} // end of while(...)
|
|
|
|
|
|
|
|
} // end of %{* strings
|
|
|
|
|
|
|
|
} // end of if( long enough to contain %{*} )
|
|
|
|
|
|
|
|
switch( c ) {
|
|
|
|
case ARTIST:
|
|
|
|
s = entry.artists[trackNumber-1];
|
|
|
|
s.replace( '/', '_' );
|
|
|
|
s.replace( '*', '_' );
|
|
|
|
s.replace( '}', '*' ); // for conditional inclusion
|
|
|
|
dir.append( s.isEmpty()
|
|
|
|
? i18n("unknown") + TQString(" %1").arg(trackNumber)
|
|
|
|
: s );
|
|
|
|
break;
|
|
|
|
case TITLE:
|
|
|
|
s = entry.titles[trackNumber-1];
|
|
|
|
s.replace( '/', '_' );
|
|
|
|
s.replace( '*', '_' );
|
|
|
|
s.replace( '}', '*' );
|
|
|
|
dir.append( s.isEmpty()
|
|
|
|
? i18n("Track %1").arg(trackNumber)
|
|
|
|
: s );
|
|
|
|
break;
|
|
|
|
case NUMBER:
|
|
|
|
dir.append( TQString::number(trackNumber).rightJustify( 2, '0' ) );
|
|
|
|
break;
|
|
|
|
case YEAR:
|
|
|
|
dir.append( TQString::number( entry.year ) );
|
|
|
|
break;
|
|
|
|
case COMMENT:
|
|
|
|
s = entry.extInfos[trackNumber-1];
|
|
|
|
s.replace( '/', '_' );
|
|
|
|
s.replace( '*', '_' );
|
|
|
|
s.replace( '}', '*' );
|
|
|
|
dir.append( s );
|
|
|
|
break;
|
|
|
|
case GENRE:
|
|
|
|
s = ( entry.genre.isEmpty() ? entry.category : entry.genre );
|
|
|
|
s.replace( '/', '_' );
|
|
|
|
s.replace( '*', '_' );
|
|
|
|
s.replace( '}', '*' );
|
|
|
|
dir.append( s );
|
|
|
|
break;
|
|
|
|
case ALBUMARTIST:
|
|
|
|
dir.append( entry.cdArtist.isEmpty()
|
|
|
|
? i18n("unknown") : entry.cdArtist );
|
|
|
|
break;
|
|
|
|
case ALBUMTITLE:
|
|
|
|
s = entry.cdTitle;
|
|
|
|
s.replace( '/', '_' );
|
|
|
|
s.replace( '*', '_' );
|
|
|
|
s.replace( '}', '*' );
|
|
|
|
dir.append( s.isEmpty()
|
|
|
|
? i18n("unknown") : s );
|
|
|
|
break;
|
|
|
|
case ALBUMCOMMENT:
|
|
|
|
s = entry.cdExtInfo;
|
|
|
|
s.replace( '/', '_' );
|
|
|
|
s.replace( '*', '_' );
|
|
|
|
s.replace( '}', '*' );
|
|
|
|
dir.append( s ); // I think it makes more sense to allow empty comments
|
|
|
|
break;
|
|
|
|
case DATE:
|
|
|
|
dir.append( KGlobal::locale()->formatDate( TQDate::currentDate() ) );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dir.append( pattern.mid(i, len) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i += len - 1;
|
|
|
|
}
|
|
|
|
else { // end of pattern
|
|
|
|
dir.append( "%" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dir.append( pattern[i] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// /* delete line comment to comment out
|
|
|
|
// the following part: Conditional Inclusion
|
|
|
|
|
|
|
|
TQValueStack<int> offsetStack;
|
|
|
|
TQString inclusion;
|
|
|
|
bool isIncluded;
|
|
|
|
|
|
|
|
static TQRegExp conditionrx( "^[@|!][atyegrmx](?:='.*')?\\{" );
|
|
|
|
conditionrx.setMinimal( TRUE );
|
|
|
|
|
|
|
|
for( unsigned int i = 0; i < dir.length(); ++i ) {
|
|
|
|
|
|
|
|
offsetStack.push(
|
|
|
|
conditionrx.search(dir, i, TQRegExp::CaretAtOffset) );
|
|
|
|
|
|
|
|
if( offsetStack.top() == -1 ) {
|
|
|
|
offsetStack.pop();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
i += conditionrx.matchedLength() - 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( dir[i] == '}' && !offsetStack.isEmpty() ) {
|
|
|
|
|
|
|
|
int offset = offsetStack.pop();
|
|
|
|
int length = i - offset + 1;
|
|
|
|
|
|
|
|
switch( (TQChar) dir[offset+1] ) {
|
|
|
|
case ARTIST:
|
|
|
|
s = entry.artists[trackNumber-1];
|
|
|
|
break;
|
|
|
|
case TITLE:
|
|
|
|
s = entry.titles[trackNumber-1];
|
|
|
|
break;
|
|
|
|
case NUMBER:
|
|
|
|
s = TQString::number( trackNumber );
|
|
|
|
break;
|
|
|
|
case YEAR:
|
|
|
|
s = TQString::number( entry.year );
|
|
|
|
break;
|
|
|
|
case COMMENT:
|
|
|
|
s = entry.extInfos[trackNumber-1];
|
|
|
|
break;
|
|
|
|
case GENRE:
|
|
|
|
s = ( entry.genre.isEmpty() ? entry.category : entry.genre );
|
|
|
|
break;
|
|
|
|
case ALBUMARTIST:
|
|
|
|
s = entry.cdArtist;
|
|
|
|
break;
|
|
|
|
case ALBUMTITLE:
|
|
|
|
s = entry.cdTitle;
|
|
|
|
break;
|
|
|
|
case ALBUMCOMMENT:
|
|
|
|
s = entry.cdExtInfo;
|
|
|
|
break;
|
|
|
|
case DATE:
|
|
|
|
s = KGlobal::locale()->formatDate( TQDate::currentDate() );
|
|
|
|
break;
|
|
|
|
default: // we must never get here,
|
|
|
|
break; // all choices should be covered
|
|
|
|
}
|
|
|
|
|
|
|
|
if( dir[offset+2] == '{' ) { // no string matching, e.g. ?y{text}
|
|
|
|
switch( (TQChar) dir[offset+1] ) {
|
|
|
|
case YEAR:
|
|
|
|
isIncluded = (s != "0");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
isIncluded = !s.isEmpty();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
inclusion = dir.mid( offset + 3, length - 4 );
|
|
|
|
}
|
|
|
|
else { // with string matching, e.g. ?y='2004'{text}
|
|
|
|
|
|
|
|
// Be aware that there might be ' in the condition text
|
|
|
|
int endOfCondition = dir.find( '{', offset+4 )-1;
|
|
|
|
TQString condition = dir.mid( offset+4,
|
|
|
|
endOfCondition - (offset+4) );
|
|
|
|
|
|
|
|
isIncluded = (s == condition);
|
|
|
|
inclusion = dir.mid( endOfCondition+2,
|
|
|
|
i - (endOfCondition+2) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( dir[offset] == '!' )
|
|
|
|
isIncluded = !isIncluded;
|
|
|
|
// Leave it when it's '@'.
|
|
|
|
|
|
|
|
dir.replace( offset, length, ( isIncluded ? inclusion : TQString("") ) );
|
|
|
|
|
|
|
|
if( isIncluded == TRUE )
|
|
|
|
i -= length - inclusion.length();
|
|
|
|
else
|
|
|
|
i = offset - 1; // start next loop at offset
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
} // end of replace (at closing bracket '}')
|
|
|
|
|
|
|
|
} // end of conditional inclusion for(...)
|
|
|
|
|
|
|
|
// end of Conditional Inclusion */
|
|
|
|
|
|
|
|
|
|
|
|
dir.replace( '*', '}' ); // bring the brackets back, if there were any
|
|
|
|
|
|
|
|
if( replace )
|
|
|
|
dir.replace( TQRegExp( "\\s" ), replaceString );
|
|
|
|
|
|
|
|
return dir;
|
|
|
|
}
|