--- xmms-1.2.7/Input/vorbis/vorbis.c	Mon Mar  4 21:56:45 2002
+++ xmms-1.2.7/Input/vorbis/vorbis.y	Wed Sep  4 23:16:53 2002
@@ -1,3 +1,4 @@
+%{
 /*
  * Copyright (C) Tony Arcieri <bascule@inferno.tusculum.edu>
  * Copyright (C) 2001  Haavard Kvaalen <havardk@xmms.org>
@@ -29,6 +30,7 @@
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <pthread.h>
 #include <glib.h>
 #include <gtk/gtk.h>
@@ -112,6 +114,199 @@
 static gboolean output_error;
 	
 
+#define YYSTYPE char *
+#define YYPARSE_PARAM p
+#define YYLEX_PARAM p
+
+static char *dupcat (char *a, char *b);
+static char *tag_lookup (vorbis_comment *comment, char *name);
+
+static int yylex();
+static int yyerror();
+
+struct parser {
+	char *title;
+	char *lineptr;
+	vorbis_comment *comment;
+};
+
+%}
+
+%token TAG
+%token LITERAL
+
+%token IF "$if("
+%token LOWER "$lower("
+%token UPPER "$upper("
+%token CAPS "$caps("
+%token NUM "$num("
+
+%token_table 
+
+%pure_parser
+
+%%
+
+
+
+title:
+	multi { ((struct parser *)p)->title=$1; }
+;
+
+part:  { $$=NULL; }
+       | TAG { $$=tag_lookup(((struct parser *)p)->comment,$1); }
+       | LITERAL
+       | '[' ifdef ']' { $$=$2?$2:g_strdup(""); }
+       | "$if(" ifdef ',' multi ',' multi ')'
+		{
+			if ($2) { 
+				$$=$4; g_free($6);
+			} else { 
+				$$=$6; g_free($4);
+			}
+			g_free($2);
+		}
+       | "$num(" part ',' part ')'
+		{
+			if ($2 && $4)
+				$$=g_strdup_printf("%0*d", atoi($4), atoi($2));
+			else
+				$$=NULL;
+			g_free($2);
+			g_free($4);
+		}
+       | "$upper(" multi ')'
+		{
+			$$=$2;
+			if ($2)
+				while (*$2) {
+					*$2=toupper(*$2);
+					$2++;
+				}
+		}
+       | "$lower(" multi ')'
+		{
+			$$=$2;
+			if ($2)
+				while (*$2) {
+					*$2=tolower(*$2);
+					$2++;
+				}
+		}
+       | "$caps(" multi ')'
+		{
+			int wasalpha=0; 
+			$$=$2;
+			if ($2)
+				while (*$2) {
+					if (isalpha(*$2))
+						*$2=wasalpha++?tolower(*$2):toupper(*$2); 
+					else
+						wasalpha=0; 
+					$2++;
+				}
+		}
+       | "$caps2(" multi ')'
+		{
+			int wasalpha=0; 
+			$$=$2;
+			if ($2)
+				while (*$2) {
+					if (isalpha(*$2))
+						*$2=wasalpha++?*$2:toupper(*$2); 
+					else
+						wasalpha=0; 
+					$2++;
+				}
+		}
+
+multi: part
+       | multi part { $$=dupcat($1,$2); }
+
+ifdef: { $$=g_strdup("");}
+       | ifdef part
+		{ 
+			//printf("ifdef: '%s' '%s'\n",$1,$2);
+			if ($1 && $2)
+				$$=dupcat($1,$2);
+			else {
+				$$=NULL;
+				g_free($1);
+				g_free($2);
+			}
+		}
+
+%%
+
+static char *dupcat (char *a, char *b)
+{
+	int len;
+	char *s, *t, *x=a, *y=b;
+
+	if (!a)
+		return b;
+	if (!b)
+		return a;
+	len = strlen(a)+strlen(b);
+
+	t = s = g_malloc(len+1);
+	while ((*t++=*a++));
+	t--;
+	while ((*t++=*b++));
+
+	g_free(x);
+	g_free(y);
+
+	return s;
+}
+
+static char *tag_lookup (vorbis_comment *comment, char *name)
+{
+	return convert_from_utf8(vorbis_comment_query(comment, name, 0));
+}
+
+int yylex(char **lvalp, struct parser *p)
+{
+	char **lineptr=&(((struct parser *)p)->lineptr);
+	int c=*(*lineptr)++;
+	int i;
+
+	if (c == '%') {
+		char *tmp=*lineptr;
+		do {
+			(*lineptr)++;
+		} while (**lineptr && **lineptr!='%');
+		*lvalp = g_strndup (tmp, *lineptr-tmp);
+		(*lineptr)++;
+		return TAG;
+	}
+	if (c == '\'') {
+		char *tmp=*lineptr;
+		do {
+			(*lineptr)++;
+		} while (**lineptr && **lineptr!='\'');
+		*lvalp = g_strndup (tmp, *lineptr-tmp);
+		(*lineptr)++;
+		return LITERAL;
+	}		
+
+	for (i = 0; i < YYNTOKENS; i++) {
+		if (yytname[i] != 0
+		    && yytname[i][0] == '"'
+		    && !strncmp (yytname[i] + 1, *lineptr-1, strlen (yytname[i])-2)) {
+			*lineptr+=strlen(yytname[i])-3;
+			return yytoknum[i];
+		}
+	}
+
+	return c;
+}
+
+int yyerror()
+{
+	return 0;
+}
+
 InputPlugin *get_iplugin_info(void)
 {
 	vorbis_ip.description = g_strdup_printf(_("Ogg Vorbis Player %s"), VERSION);
@@ -538,37 +733,52 @@
 	vorbis_comment *comment;
 	TitleInput *input;
 
-	XMMS_NEW_TITLEINPUT(input);
+	if (!vorbis_cfg.tag_override) {
+
+		XMMS_NEW_TITLEINPUT(input);
 	
-	input->file_name = g_basename(fn);
-	input->file_ext = extname(fn);
-	input->file_path = fn;
+		input->file_name = g_basename(fn);
+		input->file_ext = extname(fn);
+		input->file_path = fn;
+		if ((comment = ov_comment(vorbisfile, -1)) != NULL)
+		{
+			input->track_name = convert_from_utf8(vorbis_comment_query(comment, "title", 0));
+			input->performer = convert_from_utf8(vorbis_comment_query(comment, "artist", 0));
+			input->album_name = convert_from_utf8(vorbis_comment_query(comment, "album", 0));
+			if ((tmp = vorbis_comment_query(comment, "tracknumber", 0)) != NULL)
+				input->track_number = atoi(tmp);
+			input->date = convert_from_utf8(vorbis_comment_query(comment, "date", 0));
+			input->genre = convert_from_utf8(vorbis_comment_query(comment, "genre", 0));
+			/* "" = user comment */
+			input->comment = convert_from_utf8(vorbis_comment_query(comment, "", 0));
+		}
+		
+		displaytitle = xmms_get_titlestring(vorbis_cfg.tag_override ?
+						    vorbis_cfg.tag_format :
+						    xmms_get_gentitle_format(), input);
+		g_free(input->track_name);
+		g_free(input->performer);
+		g_free(input->album_name);
+		g_free(input->date);
+		g_free(input->genre);
+		g_free(input->comment);
+		g_free(input);
+		
+	} else {
+		if ((comment = ov_comment(vorbisfile, -1)) != NULL) {
+			struct parser p={
+				NULL,
+				vorbis_cfg.tag_format,
+				comment
+			};
+			/* yydebug=1; */
 
-	if ((comment = ov_comment(vorbisfile, -1)) != NULL)
-	{
-		input->track_name = convert_from_utf8(vorbis_comment_query(comment, "title", 0));
-		input->performer = convert_from_utf8(vorbis_comment_query(comment, "artist", 0));
-		input->album_name = convert_from_utf8(vorbis_comment_query(comment, "album", 0));
-		if ((tmp = vorbis_comment_query(comment, "tracknumber", 0)) != NULL)
-			input->track_number = atoi(tmp);
-		input->date = convert_from_utf8(vorbis_comment_query(comment, "date", 0));
-		input->genre = convert_from_utf8(vorbis_comment_query(comment, "genre", 0));
-		/* "" = user comment */
-		input->comment = convert_from_utf8(vorbis_comment_query(comment, "", 0));
-	}
-
-	displaytitle = xmms_get_titlestring(vorbis_cfg.tag_override ?
-					    vorbis_cfg.tag_format :
-					    xmms_get_gentitle_format(), input);
-	g_free(input->track_name);
-	g_free(input->performer);
-	g_free(input->album_name);
-	g_free(input->date);
-	g_free(input->genre);
-	g_free(input->comment);
-	g_free(input);
+			displaytitle = yyparse(&p)?strdup(_("Syntax error")):p.title;
+		}
+	}
 
-	if (!displaytitle) {
+	if (!displaytitle || !*displaytitle) {
+		g_free(displaytitle);
 		if (!vorbis_is_streaming)
 			displaytitle = g_strdup_printf("%s", g_basename(fn));
 		else
