#include #include #include #include #include "tagz.h" #ifdef TAGZ_UNICODE #define _TX(X) L##X #define t_strdup wcsdup #define t_strlen wcslen #define t_strnicmp wcsnicmp #define t_atoi(x) wcstol(x,0,10) #define t_stricmp wcsicmp #define t_strstr wcsstr #define sprintf swprintf #else #define _TX(X) X #define t_strdup strdup #define t_strlen strlen #define t_strnicmp strnicmp #define t_atoi atoi #define t_stricmp stricmp #define t_strstr strstr #endif #define TABSIZE(x) (sizeof(x)/sizeof(x[0])) class T_String { private: T_CHAR * data; UINT size,used; public: T_String() {data=0;size=0;used=0;} void AddChar(T_CHAR c) { if (!data) { data=(T_CHAR*)malloc((size=512)*sizeof(T_CHAR)); used=0; } else if (size==used) { size<<=1; data=(T_CHAR*)realloc((char*)data,size*sizeof(T_CHAR)); } if (data) data[used++]=c; } void AddInt(int i) { T_CHAR foo[16]; sprintf(foo,_TX("%i"),i); AddString(foo); } void AddString(const T_CHAR * z) { while(*z) {AddChar(*z);z++;} } void AddString(T_String & s) { AddString(s.Peek()); } ~T_String() { if (data) free(data); } T_CHAR * GetBuf() { if (!data) return ::t_strdup(_TX("")); T_CHAR * r=(T_CHAR*)realloc(data,(used+1)*sizeof(T_CHAR)); r[used]=0; data=0; return r; } T_CHAR operator[](UINT i) { if (!data || i>=used) return 0; else return data[i]; } UINT Len() {return data ? used : 0;} void Reset() { if (data) {free(data);data=0;} } const T_CHAR * Peek() { AddChar(0); used--; return data; } T_CHAR * strdup() { return ::t_strdup(Peek()); } }; static int separator(T_CHAR x) { if (!x || x==' ') return 1; if (x=='\'' || x=='_') return 0; #ifdef TAGZ_UNICODE return !iswalnum(x); #else return !isalnum(x); #endif } static int sepcmp(T_CHAR* src,T_CHAR* val) { UINT l=t_strlen(val); return !t_strnicmp(src,val,l) && separator(src[l]); } static char roman_num[]= { 'I','V','X','L','C','D','M' }; static int is_roman(T_CHAR * ptr)/* could be more smart i think */ { if (ptr[0]==']' && ptr[1]=='[' && separator(ptr[2])) return 1; while(!separator(*ptr)) { UINT n; bool found=0; for(n=0;n'9') return 0; ptr++; } return 1; } typedef bool (*TEXTFUNC)(UINT n_src,T_CHAR **src,UINT*,T_String &out); #define MAKEFUNC(X) static bool X(UINT n_src,T_CHAR ** src,UINT *found_src,T_String &out) MAKEFUNC(If) { if (n_src!=3) return false; out.AddString(src[found_src[0] ? 1 : 2]); return true; } MAKEFUNC(If2) { if (n_src!=2) return false; out.AddString(src[found_src[0] ? 0 : 1]); return true; } MAKEFUNC(Iflonger) { if (n_src!=4) return false; out.AddString(src[(int)t_strlen(src[0])>t_atoi(src[1]) ? 2 : 3]); return true; } MAKEFUNC(Ifgreater) { if (n_src!=4) return false; out.AddString(src[t_atoi(src[0])>t_atoi(src[1]) ? 2 : 3]); return true; } MAKEFUNC(Upper) { if (n_src!=1) return false; T_CHAR * s=src[0]; while(*s) out.AddChar(toupper(*(s++))); return true; } MAKEFUNC(Lower) { if (n_src!=1) return false; T_CHAR * s=src[0]; while(*s) out.AddChar(tolower(*(s++))); return true; } MAKEFUNC(Pad) { if (n_src<2 || n_src>3) return false; T_CHAR *fill=_TX(" "); if (n_src==3 && src[2][0]) fill = src[2]; int num = t_atoi(src[1]); T_CHAR *p = src[0]; while (*p) { out.AddChar(*(p++)); num--; } UINT fl = t_strlen(fill); while (num>0) out.AddChar(fill[(--num)%fl]); return true; } MAKEFUNC(Cut) { if (n_src!=2) return false; UINT num = t_atoi(src[1]); T_CHAR *p = src[0]; while (*p && num>0) {out.AddChar(*(p++));num--;} return true; } MAKEFUNC(PadCut) { if (n_src<2 || n_src>3) return false; T_CHAR *fill = _TX(" "); if (n_src==3 && src[2][0]) fill = src[2]; int num = t_atoi(src[1]); T_CHAR *p = src[0]; while(*p && num>0) {out.AddChar(*(p++));num--;} UINT fl=t_strlen(fill); while (num>0) out.AddChar(fill[(--num)%fl]); return true; } /* abbr(string) */ /* abbr(string,len) */ MAKEFUNC(Abbr) { if (n_src==0 || n_src>2) return false; if (n_src==2 && (int)t_strlen(src[0])m) {m=l;ptr=src[n];} } if (ptr) out.AddString(ptr); return true; } MAKEFUNC(Shortest) { T_CHAR * ptr=0; UINT n,m=(UINT)(-1); for(n=0;n3) return false; int n1 = t_atoi(src[1]), n2; if (n_src == 3) n2 = t_atoi(src[2]); else n2 = n1; if (n1 < 1) n1=1; if (n2 >= n1) { n1--; n2--; while(n1<=n2 && src[0][n1]) out.AddChar(src[0][n1++]); } return true; } MAKEFUNC(Len) { if (n_src!=1) return false; out.AddInt(t_strlen(src[0])); return true; } MAKEFUNC(Add) { UINT n; int s=0; for (n=0;n m) m = t; } out.AddInt(m); return true; } MAKEFUNC(Min) { if (!n_src) return false; int m=t_atoi(src[0]); UINT n; for(n=1;ns2 || (*p!=',' && *p!=')')) {Error(_TX("internal error"));return;} T_CHAR bk=*p; *p=0; temp[nt]=_FMT(p1,&temp_f[nt]); nt++; *p=bk;; p1=p+1; p++; } *s1=0; UINT n; for (n=0; nf; ff=base->ff; fp=base->fp; spec=_spec; } public: FMT(const T_CHAR * p_spec,TAGFUNC _f,TAGFREEFUNC _ff,void * _fp) { found=0; org_spec=spec=t_strdup(p_spec); f=_f; ff=_ff; fp=_fp; } operator T_CHAR*() { run(); return str.GetBuf(); } ~FMT() { if (org_spec) free(org_spec); } }; extern "C" { UINT tagz_format(const T_CHAR * spec,TAGFUNC f,TAGFREEFUNC ff,void *fp,T_CHAR* out,UINT max) { T_CHAR * zz=tagz_format_r(spec,f,ff,fp); UINT r=0; while(r, eg. \"%artist%\"\n" "* $abbr(x) - inserts abbreviation of x, eg. \"$abbr(%album%)\" - will convert album name of \"Final Fantasy VI\" to \"FFVI\"\n" "* $abbr(x,y) - inserts abbreviation of x if x is longer than y characters; otherwise inserts full value of x, eg. \"$abbr(%album%,10)\"\n" "* $lower(x), $upper(x) - converts x to in lower/uppercase, eg. \"$upper(%title%)\"\n" "* $num(x,y) - displays x number and pads with zeros up to y characters (useful for track numbers), eg. $num(%tracknumber%,2)\n" "* $caps(x) - converts first letter in every word of x to uppercase, and all other letters to lowercase, eg. \"blah BLAH\" -> \"Blah Blah\"\n" "* $caps2(x) - similar to $caps, but leaves uppercase letters as they are, eg. \"blah BLAH\" -> \"Blah BLAH\"\n" "* $if(A,B,C) - if A contains at least one valid tag, displays B, otherwise displays C; eg. \"$if(%artist%,%artist%,unknown artist)\" will display artist name if present; otherwise will display \"unknown artist\"; note that \"$if(A,A,)\" is equivalent to \"[A]\" (see below)\n" "* $if2(A,B) - equals to $if(A,A,B)\n" "* $longest(A,B,C,....) - compares lengths of output strings produced by A,B,C... and displays the longest one, eg. \"$longest(%title%,%comment%)\" will display either title if it's longer than comment; otherwise it will display comment\n" "* $pad(x,y) - pads x with spaces up to y characters\n" "* $cut(x,y) - truncates x to y characters\n" "* $padcut(x,y) - pads x to y characters and truncates to y if longer\n" "* [ .... ] - displays contents of brackets only if at least one of fields referenced inside has been found, eg. \"%artist% - [%album% / ]%title%\" will hide [] block if album field is not present\n" "* \' (single quotation mark) - outputs raw text without parsing, eg, \'blah$blah%blah[][]\' will output the contained string and ignore all reserved characters (%,$,[,]) in it; you can use this feature to insert square brackets for an example.\n" "\n" "eg. \"[%artist% - ][$abbr(%album%,10)[ %tracknumber%] / ]%title%[ %streamtitle%]\"\n"; }