1 /* vi:set ts=8 sts=8 sw=8:
2  *
3  * PMS  <<Practical Music Search>>
4  * Copyright (C) 2006-2010  Kim Tore Jensen
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *
20  * field.cpp - format a song using field variables
21  *
22  */
23 
24 #include "field.h"
25 #include "pms.h"
26 
27 using namespace std;
28 
29 
30 extern Pms *		pms;
31 
32 
33 
34 /*
35  * Evaluates a format string and returns readable text
36  */
format(Song * song,string fmt,unsigned int & printlen,colortable_fields * f,bool clean)37 string			Formatter::format(Song * song, string fmt, unsigned int & printlen, colortable_fields * f, bool clean)
38 {
39 	Item				val;
40 	int				i = 0, next = 0, last = 0;
41 	string				strval;
42 	string				condformat;
43 	string				tmp;
44 	unsigned int			tmpint;
45 
46 	condformat = evalconditionals(fmt);
47 	printlen = 0;
48 
49 	while (true)
50 	{
51 		val = nextitem(condformat, &i, &next);
52 		if (val == EINVALID)
53 		{
54 			//already added the last item. add rest of string
55 			tmp = condformat.substr(next);
56 			strval += tmp;
57 			printlen += tmp.size();
58 			break;
59 		}
60 
61 		//add all text between last item and this one
62 		strval += condformat.substr(last, i - last);
63 		printlen += i - last;
64 
65 		tmp = format(song, val, tmpint, f, clean);
66 		if (!tmp.empty())
67 		{
68 			strval += tmp;
69 			printlen += tmpint;
70 		}
71 		last = next;
72 		i = next;
73 	}
74 
75 	return strval;
76 }
77 
78 /*
79  * Returns a single field for use in e.g. searches, no printlen is returned
80  */
format(Song * song,Item i,bool clean)81 string			Formatter::format(Song * song, Item i, bool clean)
82 {
83 	unsigned int		in;
84 
85 	return format(song, i, in, NULL, clean);
86 }
87 
88 /*
89  * Formats a string with multiple items into a vector
90  * e.g  'artist title track' => FIELD_ARTIST, FIELD_ALBUM, FIELD_TRACK
91  */
multiformat_item(string s)92 vector<Item> *		Formatter::multiformat_item(string s)
93 {
94 	vector<string> *	split;
95 	vector<Item> *		v = new vector<Item>;
96 	unsigned int		i;
97 
98 	split = Pms::splitstr(s);
99 	if (split == NULL)
100 	{
101 		delete v;
102 		return NULL;
103 	}
104 
105 	for (i = 0; i < split->size(); i++)
106 	{
107 		v->push_back(field_to_item(split->at(i)));
108 	}
109 
110 	delete split;
111 	return v;
112 }
113 
114 /*
115  * Interprets a string value into a field type
116  */
field_to_item(string f)117 Item			Formatter::field_to_item(string f)
118 {
119 	/* All field types */
120 
121 	if (f == "")
122 		return LITERALPERCENT;
123 	else if (f == "num")
124 		return FIELD_NUM;
125 	else if (f == "file")
126 		return FIELD_FILE;
127 	else if (f == "artist")
128 		return FIELD_ARTIST;
129 	else if (f == "artistsort")
130 		return FIELD_ARTISTSORT;
131 	else if (f == "albumartist")
132 		return FIELD_ALBUMARTIST;
133 	else if (f == "albumartistsort")
134 		return FIELD_ALBUMARTISTSORT;
135 	else if (f == "title")
136 		return FIELD_TITLE;
137 	else if (f == "album")
138 		return FIELD_ALBUM;
139 	else if (f == "date")
140 		return FIELD_DATE;
141 	else if (f == "year")
142 		return FIELD_YEAR;
143 	else if (f == "track")
144 		return FIELD_TRACK;
145 	else if (f == "trackshort")
146 		return FIELD_TRACKSHORT;
147 	else if (f == "time")
148 		return FIELD_TIME;
149 	else if (f == "name")
150 		return FIELD_NAME;
151 	else if (f == "genre")
152 		return FIELD_GENRE;
153 	else if (f == "composer")
154 		return FIELD_COMPOSER;
155 	else if (f == "performer")
156 		return FIELD_PERFORMER;
157 	else if (f == "disc")
158 		return FIELD_COMMENT;
159 
160 	/* Conditionals */
161 	else if (f == "ifcursong")
162 		return COND_IFCURSONG;
163 	else if (f == "ifplaying")
164 		return COND_IFPLAYING;
165 	else if (f == "ifpaused")
166 		return COND_IFPAUSED;
167 	else if (f == "ifstopped")
168 		return COND_IFSTOPPED;
169 	else if (f == "else")
170 		return COND_ELSE;
171 	else if (f == "endif")
172 		return COND_ENDIF;
173 
174 	/* The rest */
175 
176 	else if (f == "repeat")
177 		return REPEAT;
178 	else if (f == "random")
179 		return RANDOM;
180 	else if (f == "manual")
181 		return MANUALPROGRESSION;
182 	else if (f == "mute")
183 		return MUTE;
184 	else if (f == "repeatshort")
185 		return REPEATSHORT;
186 	else if (f == "randomshort")
187 		return RANDOMSHORT;
188 	else if (f == "manualshort")
189 		return MANUALPROGRESSIONSHORT;
190 	else if (f == "muteshort")
191 		return MUTESHORT;
192 
193 	else if (f == "librarysize")
194 		return LIBRARYSIZE;
195 	else if (f == "listsize")
196 		return LISTSIZE;
197 	else if (f == "queuesize")
198 		return QUEUESIZE;
199 	else if (f == "livequeuesize")
200 		return LIVEQUEUESIZE;
201 
202 	else if (f == "bitrate")
203 		return BITRATE;
204 	else if (f == "samplerate")
205 		return SAMPLERATE;
206 	else if (f == "bits")
207 		return BITS;
208 	else if (f == "channels")
209 		return CHANNELS;
210 
211 	else if (f == "time_elapsed")
212 		return TIME_ELAPSED;
213 	else if (f == "time_remaining")
214 		return TIME_REMAINING;
215 	else if (f == "progressbar")
216 		return PROGRESSBAR;
217 	else if (f == "progresspercentage")
218 		return PROGRESSPERCENTAGE;
219 	else if (f == "playstate")
220 		return PLAYSTATE;
221 	else if (f == "volume")
222 		return VOLUME;
223 	else
224 		return EINVALID;
225 }
226 
227 /*
228  * Return the next Item starting at the given string index of the given format
229  * The index of the leading % ends up in i
230  * The index of the character after the item is stored in next
231  */
nextitem(string fmt,int * i,int * next)232 Item			Formatter::nextitem(string fmt, int *i, int *next)
233 {
234 	int				l;
235 
236 	if (*i >= fmt.size())
237 		return EINVALID;
238 
239 	//keep going until we get to a %
240 	while (fmt[*i] != '%')
241 	{
242 		if (++(*i) >= fmt.size())
243 			return EINVALID;
244 	}
245 
246 	//find number of chars before next %
247 	for (l = 0; fmt[*i + l + 1] != '%'; l++);
248 
249 	//set next to index past keyword and the following %
250 	*next = *i + l + 2;
251 
252 	return field_to_item(fmt.substr(*i + 1, l));
253 }
254 
255 /*
256  * Recursive function to return a format string which has had conditionals
257  * applied
258  */
evalconditionals(string fmt)259 string			Formatter::evalconditionals(string fmt)
260 {
261 	int				if_start = 0, if_next;
262 	int				else_start = -1, else_next = -1;
263 	int				endif_start = 0, endif_next;
264 	int				depth = 0;
265 	Item				item1, item2;
266 	bool				satisfied;
267 	string				before, after;
268 
269 	while (true)
270 	{
271 		item1 = nextitem(fmt, &if_start, &if_next);
272 		if (item1 == EINVALID)
273 			break;
274 
275 		switch(item1)
276 		{
277 			case COND_IFCURSONG:
278 			case COND_IFPLAYING:
279 			case COND_IFPAUSED:
280 			case COND_IFSTOPPED:
281 				//find matching endif
282 				endif_start = if_next;
283 				while (true)
284 				{
285 					item2 = nextitem(fmt, &endif_start, &endif_next);
286 					if (item2 == EINVALID)
287 						break;
288 
289 					switch(item2)
290 					{
291 						case COND_IFCURSONG:
292 						case COND_IFPLAYING:
293 						case COND_IFPAUSED:
294 						case COND_IFSTOPPED:
295 							depth++;
296 							break;
297 
298 						case COND_ELSE:
299 							if (depth == 0)
300 							{
301 								else_start = endif_start;
302 								else_next = endif_next;
303 							}
304 							break;
305 
306 						case COND_ENDIF:
307 							if (depth > 0)
308 							{
309 								depth--;
310 								break;
311 							}
312 							switch(item1)
313 							{
314 								case COND_IFCURSONG:
315 									satisfied = pms->cursong() ? true : false;
316 									break;
317 
318 								case COND_IFPLAYING:
319 									satisfied = pms->comm->status()->state == MPD_STATUS_STATE_PLAY;
320 									break;
321 
322 								case COND_IFPAUSED:
323 									satisfied = pms->comm->status()->state == MPD_STATUS_STATE_PAUSE;
324 									break;
325 
326 								case COND_IFSTOPPED:
327 									satisfied = pms->comm->status()->state == MPD_STATUS_STATE_STOP;
328 									break;
329 
330 								default:
331 									//shouldn't be here
332 									pms->log(MSG_DEBUG, 0, "error: didn't know how to evaluate condition. assuming true\n");
333 									satisfied = true;
334 									break;
335 							}
336 							before = fmt.substr(0, if_start);
337 							after = evalconditionals(fmt.substr(endif_next));
338 							if (satisfied)
339 								return before + evalconditionals(fmt.substr(if_next, (else_start == -1 ? endif_start : else_start) - if_next)) + after;
340 							return before + (else_start == -1 ? "" : evalconditionals(fmt.substr(else_next, endif_start - else_next))) + after;
341 
342 						default:
343 							//ignore other items
344 							break;
345 					}
346 					endif_start = endif_next;
347 				}
348 				pms->log(MSG_DEBUG, 0, "error: no matching endif\n");
349 				return "";
350 
351 			case COND_ELSE:
352 				pms->log(MSG_DEBUG, 0, "error: found else before if\n");
353 				return "";
354 
355 			case COND_ENDIF:
356 				pms->log(MSG_DEBUG, 0, "error: found endif before if\n");
357 				return "";
358 
359 			default:
360 				break;
361 		}
362 		if_start = if_next;
363 	}
364 
365 	//no conditionals
366 	return fmt;
367 }
368 
369 /*
370  * Evaluate a topbar keyword
371  */
format(Song * song,Item keyword,unsigned int & printlen,colortable_fields * f,bool clean)372 string			Formatter::format(Song * song, Item keyword, unsigned int & printlen, colortable_fields * f, bool clean)
373 {
374 	char			s[30];
375 	int			tmpint;
376 	string			retstr;
377 	string			tmp;
378 	unsigned int		pint, progress;
379 	Songlist *		list;
380 	color *			c;
381 	long			playmode;
382 	long			repeatmode;
383 
384 	c = getcolor(keyword, f);
385 	playmode = pms->options->get_long("playmode");
386 	repeatmode = pms->options->get_long("repeat");
387 
388 	retstr = "";
389 	switch(keyword)
390 	{
391 		/* Field types */
392 
393 		case FIELD_NUM:
394 			if (!song) return retstr;
395 			retstr = Pms::tostring(song->pos);
396 			break;
397 
398 		case FIELD_FILE:
399 			if (!song) return retstr;
400 			retstr = song->file;
401 			break;
402 
403 		case FIELD_ARTIST:
404 			if (!song) return retstr;
405 			retstr = song->artist;
406 			if (clean) break;
407 
408 			if (!retstr.size())
409 				retstr = song->albumartist;
410 			if (!retstr.size())
411 				retstr = "<Unknown artist>";
412 			break;
413 
414 		case FIELD_ALBUMARTIST:
415 			if (!song) return retstr;
416 			retstr = song->albumartist;
417 			if (clean) break;
418 
419 			if (!retstr.size())
420 				retstr = song->artist;
421 			if (!retstr.size())
422 				retstr = "<Unknown artist>";
423 			break;
424 
425 		case FIELD_ARTISTSORT:
426 			if (!song) return retstr;
427 			retstr = song->artistsort;
428 			if (clean) break;
429 
430 			if (!retstr.size())
431 				retstr = song->artist;
432 			if (!retstr.size())
433 				retstr = "<Unknown artist>";
434 			break;
435 
436 		case FIELD_ALBUMARTISTSORT:
437 			if (!song) return retstr;
438 			retstr = song->albumartistsort;
439 			if (clean) break;
440 
441 			if (!retstr.size())
442 				retstr = song->albumartist;
443 			if (!retstr.size())
444 				retstr = "<Unknown artist>";
445 			break;
446 
447 		case FIELD_TITLE:
448 			if (!song) return retstr;
449 			retstr = song->title;
450 			if (clean) break;
451 
452 			if (!retstr.size())
453 				retstr = song->name;
454 			if (!retstr.size())
455 				retstr = song->file;
456 			break;
457 
458 		case FIELD_ALBUM:
459 			if (!song) return retstr;
460 			retstr = song->album;
461 			if (clean) break;
462 
463 			if (!retstr.size())
464 				retstr = "<Unknown album>";
465 			break;
466 
467 		case FIELD_DATE:
468 			if (!song) return retstr;
469 			retstr = song->date;
470 			if (clean) break;
471 
472 			if (!retstr.size())
473 				retstr = "----";
474 			break;
475 
476 		case FIELD_YEAR:
477 			if (!song) return retstr;
478 			retstr = song->year;
479 			if (clean) break;
480 
481 			if (!retstr.size())
482 				retstr = "----";
483 			break;
484 
485 		case FIELD_TRACK:
486 			if (!song) return retstr;
487 			retstr = song->track;
488 			break;
489 
490 		case FIELD_TRACKSHORT:
491 			if (!song) return retstr;
492 			retstr = song->trackshort;
493 			break;
494 
495 		case FIELD_TIME:
496 			if (!song) return retstr;
497 			if (clean)
498 				retstr = Pms::tostring(song->time);
499 			else
500 				retstr = Pms::timeformat(song->time);
501 			break;
502 
503 		case FIELD_NAME:
504 			if (!song) return retstr;
505 			retstr = song->name;
506 			break;
507 
508 		case FIELD_GENRE:
509 			if (!song) return retstr;
510 			retstr = song->genre;
511 			break;
512 
513 		case FIELD_COMPOSER:
514 			if (!song) return retstr;
515 			retstr = song->composer;
516 			break;
517 
518 		case FIELD_PERFORMER:
519 			if (!song) return retstr;
520 			retstr = song->performer;
521 			break;
522 
523 		case FIELD_DISC:
524 			if (!song) return retstr;
525 			retstr = song->disc;
526 			break;
527 
528 
529 		/* Times */
530 
531 		case TIME_ELAPSED:
532 			if (!pms->comm || !pms->comm->status()) return "";
533 
534 			retstr = Pms::timeformat(pms->comm->status()->time_elapsed);
535 
536 			break;
537 
538 		case TIME_REMAINING:
539 			if (!pms->comm || !pms->comm->status()) return "";
540 
541 			retstr = Pms::timeformat(pms->comm->status()->time_total - pms->comm->status()->time_elapsed);
542 
543 			break;
544 
545 		case PROGRESSPERCENTAGE:
546 			if (!pms->disp || !pms->comm || !pms->comm->status() || pms->comm->status()->time_total == 0)
547 				retstr = "0";
548 			else
549 			{
550 				tmpint = pms->comm->status()->time_elapsed * 100 / pms->comm->status()->time_total;
551 				retstr = Pms::tostring(tmpint);
552 			}
553 			break;
554 
555 		/* Widgets */
556 
557 		case PROGRESSBAR:
558 			if (!pms->disp || !pms->comm || !pms->comm->status() || pms->comm->status()->time_total == 0) return "";
559 
560 			retstr.clear();
561 			progress = pms->comm->status()->time_elapsed * pms->disp->topbar->bwidth() / pms->comm->status()->time_total;
562 			for (pint = 0; pint < progress; pint++)
563 			{
564 				retstr += "=";
565 			}
566 			retstr += ">";
567 			break;
568 
569 		/* Status items */
570 
571 		case REPEAT:
572 			switch(repeatmode)
573 			{
574 				case REPEAT_NONE:
575 					retstr = "no";
576 					break;
577 				case REPEAT_ONE:
578 					retstr = "one";
579 					break;
580 				case REPEAT_LIST:
581 					retstr = "yes";
582 					break;
583 				default:
584 					retstr = "unknown";
585 					break;
586 			}
587 			break;
588 
589 		case RANDOM:
590 			switch(playmode)
591 			{
592 				case PLAYMODE_LINEAR:
593 					retstr = "no";
594 					break;
595 				case PLAYMODE_RANDOM:
596 					retstr = "yes";
597 					break;
598 				default:
599 					retstr = "unknown";
600 					break;
601 			}
602 			break;
603 
604 		case MANUALPROGRESSION:
605 			if (playmode == PLAYMODE_MANUAL)
606 				retstr = "yes";
607 			else
608 				retstr = "no";
609 			break;
610 
611 		case MUTE:
612 			if (!pms->comm) return "";
613 			if (pms->comm->muted())
614 				retstr = "yes";
615 			else
616 				retstr = "no";
617 			break;
618 
619 		case REPEATSHORT:
620 			switch(repeatmode)
621 			{
622 				default:
623 				case REPEAT_NONE:
624 					retstr = "-";
625 					break;
626 				case REPEAT_ONE:
627 					retstr = "r";
628 					break;
629 				case REPEAT_LIST:
630 					retstr = "R";
631 					break;
632 			}
633 			break;
634 
635 		case RANDOMSHORT:
636 			switch(playmode)
637 			{
638 				default:
639 				case PLAYMODE_LINEAR:
640 					retstr = "-";
641 					break;
642 				case PLAYMODE_RANDOM:
643 					retstr = "S";
644 					break;
645 			}
646 			break;
647 
648 		case MANUALPROGRESSIONSHORT:
649 			if (playmode == PLAYMODE_MANUAL)
650 				retstr = "1";
651 			else
652 				retstr = "-";
653 			break;
654 
655 		case MUTESHORT:
656 			if (!pms->comm) return "-";
657 			if (pms->comm->muted())
658 				retstr = "M";
659 			else
660 				retstr = "-";
661 			break;
662 
663 		case LIBRARYSIZE:
664 			if (!pms->comm || !pms->comm->library()) return "";
665 
666 			list = pms->comm->library();
667 			sprintf(s, "%d %s (%s)", list->size(),
668 					Pms::pluralformat(list->size()).c_str(),
669 					Pms::timeformat(list->length).c_str());
670 
671 			retstr = s;
672 			break;
673 
674 		case LISTSIZE:
675 			if (!pms->disp || !pms->disp->actwin()) return "";
676 
677 			list = pms->disp->actwin()->plist();
678 			if (list)
679 			{
680 				if (list->selection.size > 0)
681 				{
682 					if (list->filtercount() == 0)
683 					{
684 						sprintf(s, "%ld/%d %s (%s)", static_cast<unsigned long>(list->selection.size),
685 								list->size(),
686 								Pms::pluralformat(list->size()).c_str(),
687 								Pms::timeformat(list->selection.length).c_str());
688 					}
689 					else
690 					{
691 						sprintf(s, "%ld/%d/%d %s (%s)", static_cast<unsigned long>(list->selection.size),
692 								list->size(),
693 								list->realsize(),
694 								Pms::pluralformat(list->realsize()).c_str(),
695 								Pms::timeformat(list->selection.length).c_str());
696 					}
697 				}
698 				else
699 				{
700 					if (list->filtercount() == 0)
701 					{
702 						sprintf(s, "%d %s (%s)", list->size(),
703 								Pms::pluralformat(list->size()).c_str(),
704 								Pms::timeformat(list->length).c_str());
705 					}
706 					else
707 					{
708 						sprintf(s, "%d/%d %s (%s)",
709 								list->size(),
710 								list->realsize(),
711 								Pms::pluralformat(list->realsize()).c_str(),
712 								Pms::timeformat(list->selection.length).c_str());
713 					}
714 				}
715 
716 			}
717 			else
718 			{
719 				sprintf(s, "Total of %d items", pms->disp->actwin()->size());
720 			}
721 
722 			retstr = s;
723 			break;
724 
725 		case QUEUESIZE:
726 			if (!pms->comm || !pms->comm->playlist()) return "";
727 
728 			tmpint = pms->comm->playlist()->qnumber();
729 			retstr = Pms::tostring(tmpint);
730 			retstr += " " + Pms::pluralformat(tmpint) + " (" + Pms::timeformat(pms->comm->playlist()->qlength()) + ")";
731 			break;
732 
733 		case LIVEQUEUESIZE:
734 			if (!pms->comm || !pms->comm->status() || !pms->comm->playlist()) return "";
735 
736 			if (pms->comm->playlist()->size() == 0)
737 			{
738 				retstr = "0 songs (0:00)";
739 				break;
740 			}
741 
742 			switch (pms->comm->status()->state)
743 			{
744 				case MPD_STATUS_STATE_PLAY:
745 				case MPD_STATUS_STATE_PAUSE:
746 					tmp = Pms::timeformat(pms->comm->playlist()->qlength() + pms->comm->status()->time_total - pms->comm->status()->time_elapsed);
747 					tmpint = pms->comm->playlist()->qnumber() + 1;
748 					break;
749 				default:
750 					if (pms->cursong())
751 					{
752 						tmpint = pms->comm->playlist()->qnumber() + 1;
753 						tmp = Pms::timeformat(pms->comm->playlist()->qlength() + pms->cursong()->time);
754 						break;
755 					}
756 					tmpint = pms->comm->playlist()->qnumber();
757 					tmp = Pms::timeformat(pms->comm->playlist()->qlength());
758 					break;
759 			}
760 			retstr = Pms::tostring(tmpint);
761 			retstr += " " + Pms::pluralformat(tmpint) + " (" + tmp + ")";
762 			break;
763 
764 		case PLAYSTATE:
765 			if (!pms->comm || !pms->comm->status()) return "";
766 
767 			switch (pms->comm->status()->state)
768 			{
769 				default:
770 				case MPD_STATUS_STATE_UNKNOWN:
771 					retstr = pms->options->get_string("status_unknown");
772 					break;
773 				case MPD_STATUS_STATE_STOP:
774 					retstr = pms->options->get_string("status_stop");
775 					break;
776 				case MPD_STATUS_STATE_PLAY:
777 					retstr = pms->options->get_string("status_play");
778 					break;
779 				case MPD_STATUS_STATE_PAUSE:
780 					retstr = pms->options->get_string("status_pause");
781 					break;
782 			}
783 			break;
784 
785 		case VOLUME:
786 			if (!pms->comm || !pms->comm->status()) return "";
787 
788 			retstr = Pms::tostring(pms->comm->status()->volume);
789 			break;
790 
791 		case BITRATE:
792 			if (!pms->comm) return "";
793 
794 			retstr = Pms::tostring(pms->comm->status()->bitrate);
795 			break;
796 
797 		case SAMPLERATE:
798 			if (!pms->comm) return "";
799 
800 			retstr = Pms::tostring(static_cast<long>(pms->comm->status()->samplerate));
801 			break;
802 
803 		case BITS:
804 			if (!pms->comm) return "";
805 
806 			retstr = Pms::tostring(pms->comm->status()->bits);
807 			break;
808 
809 		case CHANNELS:
810 			if (!pms->comm) return "";
811 
812 			retstr = Pms::tostring(pms->comm->status()->channels);
813 			break;
814 
815 		case LITERALPERCENT:
816 			retstr = "%";
817 			break;
818 
819 		case EINVALID:
820 		default:
821 			return "";
822 	}
823 
824 	// real length of returned string (not including colour codes)
825 	printlen = retstr.size();
826 
827 	// escape any percent signs by doubling them
828 	retstr = Pms::formtext(retstr);
829 
830 	/* Format string with colors */
831 	if (c != NULL)
832 	{
833 		return "%" + Pms::tostring(c->pair()) + "%" + retstr + "%/" + Pms::tostring(c->pair()) + "%";
834 	}
835 
836 	return retstr;
837 }
838 
getcolor(Item i,colortable_fields * f)839 color *			Formatter::getcolor(Item i, colortable_fields * f)
840 {
841 	color *		c = NULL;
842 
843 	if (!f)
844 		return NULL;
845 
846 	switch(i)
847 	{
848 		case FIELD_NUM:
849 			c = f->num;
850 			break;
851 
852 		case FIELD_FILE:
853 			c = f->file;
854 			break;
855 
856 		case FIELD_ARTIST:
857 			c = f->artist;
858 			break;
859 
860 		case FIELD_ALBUMARTIST:
861 			c = f->albumartist;
862 			break;
863 
864 		case FIELD_ARTISTSORT:
865 			c = f->artistsort;
866 			break;
867 
868 		case FIELD_ALBUMARTISTSORT:
869 			c = f->albumartistsort;
870 			break;
871 
872 		case FIELD_TITLE:
873 			c = f->title;
874 			break;
875 
876 		case FIELD_ALBUM:
877 			c = f->album;
878 			break;
879 
880 		case FIELD_DATE:
881 			c = f->date;
882 			break;
883 
884 		case FIELD_YEAR:
885 			c = f->year;
886 			break;
887 
888 		case FIELD_TRACK:
889 			c = f->track;
890 			break;
891 
892 		case FIELD_TRACKSHORT:
893 			c = f->trackshort;
894 			break;
895 
896 		case FIELD_TIME:
897 			c = f->time;
898 			break;
899 
900 		case FIELD_NAME:
901 			c = f->name;
902 			break;
903 
904 		case FIELD_GENRE:
905 			c = f->genre;
906 			break;
907 
908 		case FIELD_COMPOSER:
909 			c = f->composer;
910 			break;
911 
912 		case FIELD_PERFORMER:
913 			c = f->performer;
914 			break;
915 
916 		case FIELD_DISC:
917 			c = f->disc;
918 			break;
919 
920 		case TIME_ELAPSED:
921 			c = pms->options->colors->topbar.time_elapsed;
922 			break;
923 
924 		case TIME_REMAINING:
925 			c = pms->options->colors->topbar.time_remaining;
926 			break;
927 
928 		case PROGRESSPERCENTAGE:
929 			c = pms->options->colors->topbar.progresspercentage;
930 			break;
931 
932 		case PROGRESSBAR:
933 			c = pms->options->colors->topbar.progressbar;
934 			break;
935 
936 		case REPEAT:
937 			c = pms->options->colors->topbar.repeat;
938 			break;
939 
940 		case RANDOM:
941 			c = pms->options->colors->topbar.random;
942 			break;
943 
944 		case MANUALPROGRESSION:
945 			c = pms->options->colors->topbar.manualprogression;
946 			break;
947 
948 		case MUTE:
949 			c = pms->options->colors->topbar.mute;
950 			break;
951 
952 		case REPEATSHORT:
953 			c = pms->options->colors->topbar.repeatshort;
954 			break;
955 
956 		case RANDOMSHORT:
957 			c = pms->options->colors->topbar.randomshort;
958 			break;
959 
960 		case MANUALPROGRESSIONSHORT:
961 			c = pms->options->colors->topbar.manualprogressionshort;
962 			break;
963 
964 		case MUTESHORT:
965 			c = pms->options->colors->topbar.muteshort;
966 			break;
967 
968 		case LIBRARYSIZE:
969 			c = pms->options->colors->topbar.librarysize;
970 			break;
971 
972 		case LISTSIZE:
973 			c = pms->options->colors->topbar.listsize;
974 			break;
975 
976 		case QUEUESIZE:
977 			c = pms->options->colors->topbar.queuesize;
978 			break;
979 
980 		case LIVEQUEUESIZE:
981 			c = pms->options->colors->topbar.livequeuesize;
982 			break;
983 
984 		case PLAYSTATE:
985 			c = pms->options->colors->topbar.playstate;
986 			break;
987 
988 		case VOLUME:
989 			c = pms->options->colors->topbar.volume;
990 			break;
991 
992 		case BITRATE:
993 			c = pms->options->colors->topbar.bitrate;
994 			break;
995 
996 		case SAMPLERATE:
997 			c = pms->options->colors->topbar.samplerate;
998 			break;
999 
1000 		case BITS:
1001 			c = pms->options->colors->topbar.bits;
1002 			break;
1003 
1004 		case CHANNELS:
1005 			c = pms->options->colors->topbar.channels;
1006 			break;
1007 
1008 		case LITERALPERCENT:
1009 			c = pms->options->colors->topbar.standard;
1010 			break;
1011 
1012 		default:
1013 			break;
1014 	}
1015 
1016 	return c;
1017 }
1018 
1019 /*
1020  * Converts an Item to a match field
1021  */
item_to_match(Item i)1022 long			Formatter::item_to_match(Item i)
1023 {
1024 	long		l;
1025 
1026 	switch(i)
1027 	{
1028 		case FIELD_ARTIST:
1029 			l = MATCH_ARTIST;
1030 			break;
1031 
1032 		case FIELD_ARTISTSORT:
1033 			l = MATCH_ARTISTSORT;
1034 			break;
1035 
1036 		case FIELD_ALBUMARTIST:
1037 			l = MATCH_ALBUMARTIST;
1038 			break;
1039 
1040 		case FIELD_ALBUMARTISTSORT:
1041 			l = MATCH_ALBUMARTISTSORT;
1042 			break;
1043 
1044 		case FIELD_TITLE:
1045 			l = MATCH_TITLE;
1046 			break;
1047 
1048 		case FIELD_ALBUM:
1049 			l = MATCH_ALBUM;
1050 			break;
1051 
1052 		case FIELD_TRACK:
1053 		case FIELD_TRACKSHORT:
1054 			/* only match the short one so we don't get every track
1055 			 * of an album marked up as xx/14 when searching for
1056 			 * track 14s */
1057 			l = MATCH_TRACKSHORT;
1058 			break;
1059 
1060 		case FIELD_TIME:
1061 			l = MATCH_TIME;
1062 			break;
1063 
1064 		case FIELD_DATE:
1065 			l = MATCH_DATE;
1066 			break;
1067 
1068 		case FIELD_YEAR:
1069 			l = MATCH_YEAR;
1070 			break;
1071 
1072 		case FIELD_GENRE:
1073 			l = MATCH_GENRE;
1074 			break;
1075 
1076 		case FIELD_COMPOSER:
1077 			l = MATCH_COMPOSER;
1078 			break;
1079 
1080 		case FIELD_PERFORMER:
1081 			l = MATCH_PERFORMER;
1082 			break;
1083 
1084 		case FIELD_DISC:
1085 			l = MATCH_DISC;
1086 			break;
1087 
1088 		default:
1089 			return MATCH_FAILED;
1090 	}
1091 
1092 	return l;
1093 }
1094 
1095