/*
* FAPG
*/
-#define VERSION "0.34"
+#define VERSION "0.35"
/*
* FAPG means Fast Audio Playlist Generator.
* It is a tool to generate list of audio files (Wav, MP3, Ogg, etc)
#define MP3_BASE 1024
#define OGG_BASE 1024*10
-#define MAX 1024*200 /* 200ko for ID3 with JPEG images in it */
-
-int debug=0;
-int format=0; /* 0 = m3u ; 1 = pls ; 2 = html ; 3 = rss */
-char *genrelist=NULL;
-unsigned char *prefix="";
-unsigned char *base="";
-unsigned char *dir="";
-unsigned char *hostname="fritzserver.de";
-unsigned char *referal="http://www.explaining.text.org/select.php?title=";
-int recursive=0;
-int avoidhlinked=0;
-int separator='/';
-int skip=0;
-int windows=0;
-unsigned char *eol="\n";
+#define MAX 1024*200 /* 200ko for ID3 with JPEG images in it */
+
+int debug = 0;
+int format = 0; /* 0 = m3u ; 1 = pls ; 2 = html ; 3 = rss */
+char *genrelist = NULL;
+unsigned char *prefix = "";
+unsigned char *base = "";
+unsigned char *dir = "";
+unsigned char *hostname = "fritzserver.de";
+// unsigned char *referal="/usr/local/bin/fapg-rss.sh";
+unsigned char *referal = NULL;
+//int windows=0;
+int recursive = 0;
+int avoidhlinked = 0;
+int separator = '/';
+unsigned char *eol = "\n";
unsigned char buffer[MAX];
-int counter=0;
+int counter = 0;
unsigned char artist[1024];
unsigned char title[1024];
unsigned char genrebuf[1024];
-unsigned char genre=0;
+unsigned char genre = 0;
int duration;
+#define MP2ENC 1
+#define MP3ENC 2
+#define MPCENC 3
+#define MPPENC 4
+#define OGGENC 5
+#define WAVENC 6
+
+char *magic[] = { NULL,
+ "audio/mpeg", "audio/mpeg",
+ "audio/mpeg", "audio/mpeg",
+ "audio/ogg-vorbis", "audio/x-wav",
+ NULL
+};
+
+unsigned char unix2dos[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 70, 35, 36, 37, 38, 39, 40, 41, 82, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 84, 59, 36, 61, 65, 71,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 36, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 36, 125, 126, 127,
+ 199, 252, 233, 226, 228, 224, 229, 231,
+ 234, 235, 232, 239, 238, 236, 196, 197,
+ 201, 230, 198, 244, 246, 242, 251, 249,
+ 255, 214, 220, 248, 163, 216, 215, 131,
+ 225, 237, 243, 250, 241, 209, 170, 186,
+ 191, 174, 172, 189, 188, 161, 171, 187,
+ 166, 166, 166, 166, 166, 193, 194, 192,
+ 169, 166, 166, 43, 43, 162, 165, 43,
+ 43, 45, 45, 43, 45, 43, 227, 195,
+ 43, 43, 45, 45, 166, 45, 43, 164,
+ 240, 208, 202, 203, 200, 105, 205, 206,
+ 207, 43, 43, 166, 220, 166, 204, 175,
+ 211, 223, 212, 210, 245, 213, 181, 254,
+ 222, 218, 219, 217, 253, 221, 175, 180,
+ 173, 177, 61, 190, 182, 167, 247, 184,
+ 176, 168, 183, 185, 179, 178, 166, 160
+};
-unsigned char unix2dos[256]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,70,35,36,37,38,39,40,41,82,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,84,59,36,61,65,71,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,36,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,36,125,126,127,199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,201,230,198,244,246,242,251,249,255,214,220,248,163,216,215,131,225,237,243,250,241,209,170,186,191,174,172,189,188,161,171,187,166,166,166,166,166,193,194,192,169,166,166,43,43,162,165,43,43,45,45,43,45,43,227,195,43,43,45,45,166,45,43,164,240,208,202,203,200,105,205,206,207,43,43,166,220,166,204,175,211,223,212,210,245,213,181,254,222,218,219,217,253,221,175,180,173,177,61,190,182,167,247,184,176,168,183,185,179,178,166,160};
+unsigned char *basemap;
+unsigned char *winorunix;
+unsigned char one2one[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255
+}; /* identical mapping */
+
+unsigned char noand[256] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 43, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255
+}; /* only '&' is mapped to '+' */
+
+unsigned char *iso2web[256] = {
+ "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
+ "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f",
+ "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
+ "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f",
+ "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27",
+ "%28", "%29", "%2a", "+", ",", "-", ".", "/",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", ":", ";", "%3c", "=", "%3e", "%3f",
+ "@", "A", "B", "C", "D", "E", "F", "G",
+ "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "%5B", "\\", "%5D", "^", "_",
+ "`", "a", "b", "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l", "m", "n", "o",
+ "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "%7b", "|", "%7d", "~", "%7f",
+ "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
+ "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f",
+ "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
+ "%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f",
+ "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
+ "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af",
+ "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7",
+ "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf",
+ "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
+ "%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf",
+ "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
+ "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df",
+ "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7",
+ "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef",
+ "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
+ "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff"
+};
void usage()
{
- fprintf(stderr,"Usage >> fapg [-b|--backslash] [-d|--debug] [-f|--format=m3u|pls|html|rss] [-g|--genre=#:#:...] [-n|--nohardlink] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-x|--exclude=#:#:...] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...]\n");
- exit(1);
+ fprintf(stderr,
+ "Usage >> fapg [-b|--backslash] [-d|--debug] [-f|--format=m3u|pls|html|rss] [-g|--genre=#:#:...] [-n|--nohardlink] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-c|--command=<intern|....>] [-x|--exclude=#:#:...] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...]\n");
+ exit(1);
}
-const char*reflink(const char*title)
+#define mywebputchar(x) { fputs(iso2web[(unsigned char)winorunix[(unsigned char)x]], stdout); }
+#define myputchar(x) { putchar(basemap[(unsigned char)winorunix[(unsigned char)x]]); }
+
+void mywebputstr(const char *c)
{
- int i=0;
- static char *buffer;
- buffer=malloc(strlen(title)+strlen(referal)+2);
- strcpy(buffer,referal);
- strcat(buffer,title);
- for(i=strlen(referal);i<strlen(buffer);i++)
- {
- switch(buffer[i])
- {
- case ' ': buffer[i]='+'; break;
- default: ;
- }
- }
- return(buffer);
+ while(*c != 0) {
+ mywebputchar(*c);
+ c++;
+ }
}
-void parse_options(int argc,char **argv)
+void myputstr(const char *c)
{
- static char const short_options[]="bdf:g:lo:np:rwx:";
- static struct option long_options[]=
- {
- {"backslash",no_argument,NULL,'b'},
- {"debug",no_argument,NULL,'d'},
- {"format",required_argument,NULL,'f'},
- {"genre",required_argument,NULL,'g'},
- {"nohardlink",no_argument,NULL,'n'},
- {"output",required_argument,NULL,'o'},
- {"prefix",required_argument,NULL,'p'},
- {"recursive",no_argument,NULL,'r'},
- {"windows",no_argument,NULL,'w'},
- {"exclude",required_argument,NULL,'x'}
- };
- int c;
- int option_index=0;
- while ((c=getopt_long(argc,argv,short_options,long_options,&option_index))!=-1)
- {
- switch(c)
- {
- case 'b':
- separator='\\';
- break;
- case 'd':
- debug=1;
- break;
- case 'f':
- if (strcmp(optarg,"m3u")==0) format=0; else
- if (strcmp(optarg,"pls")==0) format=1; else
- if (strcmp(optarg,"html")==0) format=2; else
- if (strcmp(optarg,"rss")==0) format=3; else
- usage();
- break;
- case 'g':
- if (genrelist==NULL) genrelist=calloc(257,sizeof(char)); /* allow multiple includes/excludes */
- if (genrelist==NULL) { fprintf(stderr,"Error >> unable to allocate cleared memory\n"); exit(2); }
- else
- {
- int n=0;
- while (n<strlen(optarg))
- {
- if (debug) fprintf(stderr,"Debug >> genrelist entry activting : %d\n",atoi(&optarg[n]));
- genrelist[atoi(&optarg[n])]=1;
- while (isdigit(optarg[n++]));
- }
- }
- break;
- case 'n':
- avoidhlinked=1;
- break;
- case 'o':
- close(1);
- if (fopen(optarg,"w")==NULL) { fprintf(stderr,"Error >> unable to open output file : %s\n",optarg); exit(2); }
- break;
- case 'p':
- prefix=malloc(strlen(optarg)+1);
- strcpy(prefix,optarg);
- base=malloc(strlen(prefix)+1);
- strcpy(base,prefix);
- dir=strchr(base,'/');
- if( (dir!=NULL) && (dir[1]=='/') ) dir=strchr(dir+2,'/');
- if (dir!=NULL) *dir++=0; else dir="";
- /* if prefix is a weblink, base is the baselink, dir is the path */
- break;
- case 'r':
- recursive=1;
- break;
- case 'w':
- windows=1;
- eol="\r\n";
- break;
- case 'x':
- if (genrelist==NULL) /* allow multiple includes/excludes - not recommended (confusing) but possible */
- {
- int n=0;
- genrelist=calloc(257,sizeof(char));
- while (n<256) genrelist[n++]=1;
- }
- if (genrelist==NULL) { fprintf(stderr,"Error >> unable to allocate cleared memory\n"); exit(2); }
- else
- {
- int n=0;
- while (n<strlen(optarg))
- {
- if (debug) fprintf(stderr,"Debug >> genrelist entry activting : %d\n",atoi(&optarg[n]));
- genrelist[atoi(&optarg[n])]=0;
- while (isdigit(optarg[n++]));
- }
- }
- break;
- default:
- usage();
+ while(*c != 0) {
+ myputchar(*c);
+ c++;
+ /* remove multiple slashes "//" when parsing a directory ending with a "/" */
+ while(*c == '/' && c[1] == '/')
+ c++;
}
- }
- /* hostname = getenv("HOSTNAME"); */
- if (genrelist==NULL)
- {
- genrelist=calloc(257,sizeof(char));
- if (genrelist==NULL) { fprintf(stderr,"Error >> unable to allocate cleared memory\n"); exit(2); }
- else
- {
- int n=0;
- while (n<256) genrelist[n++]=1;
+}
+
+void print_webpath(const char *path)
+{
+ const char *c = path;
+
+ printf(prefix); /* we must not modify this part */
+ if(*c == '.' && c[1] == '/') { /* remove leading "./" when parsing current directory */
+ c += 2;
+ /* maybe there follow many slashes */
+ while(*c == '/')
+ c++;
+ }
+ for(; *c != '\0'; c++) {
+ mywebputchar(*c);
+ /* remove multiple "//" when parsing a directory ending with a "/" */
+ while(*c == '/' && c[1] == '/')
+ c++;
}
- }
}
-void parse_mp3(unsigned char *file)
+void print_path(const char *path)
{
- int bitrates[2][3][15]=
- {{{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448},
- {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384},
- {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}},
- {{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256},
- {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160},
- {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}}};
- FILE *fic;
- unsigned char *c;
- int lus;
-
- genre=0;
- genrebuf[0]=0;
- if (debug) fprintf(stderr,"Debug >> parsing mp3 : %s\n",file);
-
- /* read header */
- if ((fic=fopen(file,"r"))==NULL) { fprintf(stderr,"Warning >> can't open file : %s\n",file); return; }
- lus=fread(buffer,1,MP3_BASE,fic);
- c=buffer;
-
- /* try ID3v2 */
- if (buffer[0]=='I' && buffer[1]=='D' && buffer[2]=='3')
- {
- int size;
- int version;
- version=*(buffer+3);
- if (version<2 || version>4)
- fprintf(stderr,"Warning >> ID3 v2.%d not implemented ! trying anyway : %s\n",version,file);
- if (*(buffer+5)!=0)
- fprintf(stderr,"Warning >> specials headers not implemented (%d) ! trying anyway : %s\n",*(buffer+5),file);
- c=buffer+6;
- size=(*c<<21)+(*(c+1)<<14)+(*(c+2)<<7)+(*(c+3));
- /* read more header */
- if (size+lus>MAX)
- {
- lus+=fread(buffer+lus,1,MAX-lus,fic);
- fprintf(stderr,"Warning >> ID3 header is huge (%d bytes) ! trying anyway : %s\n",size,file);
+ const char *c = path;
+ printf(prefix);
+ /* skip leading "./" when parsing current directory */
+ if(*c == '.' && *(c + 1) == '/') {
+ c += 2;
+ /* maybe there follow more slashes */
+ while(*c == '/')
+ c++;
}
+ myputstr(c);
+}
+
+void print_pathtail(const char *path)
+{
+ const char *c;
+ c = strrchr(path, separator);
+ if(c != NULL)
+ c++;
else
- lus+=fread(buffer+lus,1,size,fic);
- if (size>lus) size=lus;
- c+=4;
- if (version==2) while (c<buffer+size)
- {
- int size=(*(c+3)<<16)+(*(c+4)<<8)+(*(c+5));
- if (*c==0) break;
- if (strncmp(c,"TT2",3)==0)
- {
- strncpy(title,c+7,size-1);
- title[size-1]='\0';
- }
- if (strncmp(c,"TP1",3)==0)
- {
- strncpy(artist,c+7,size-1);
- artist[size-1]='\0';
- }
- if (strncmp(c,"TCO",3)==0)
- {
- /* strncpy(genrebuf,c+7,size-1);*/
- /* genrebuf[size-1]='\0'; */
- /* genre=atoi(&genrebuf[1]); */
- genre=atoi(c+8);
- }
- c+=size+6;
- }
- if (version==3 || version==4) while (c<buffer+size)
- {
- int size=(*(c+4)<<24)+(*(c+5)<<16)+(*(c+6)<<8)+(*(c+7));
- if (*c==0) break;
- if (strncmp(c,"TIT2",4)==0)
- {
- strncpy(title,c+11,size-1);
- title[size-1]='\0';
- }
- if (strncmp(c,"TPE1",4)==0)
- {
- strncpy(artist,c+11,size-1);
- artist[size-1]='\0';
- }
- if (strncmp(c,"TCON",4)==0)
- {
- /* strncpy(genrebuf,c+11,size-1); */
- /* genrebuf[size-1]='\0'; */
- /* genre=atoi(&genrebuf[1]); */
- genre=atoi(c+12);
- }
- c+=size+10;
- }
- }
-
- while (c<buffer+lus-10)
- {
- if (*c==0xFF && (*(c+1)&0xF0)==0xF0)
- {
- int version;
- int lay;
- int bitrate_index;
- int bitrate;
- version=2-(*(c+1)>>3&1);
- lay=4-(*(c+1)>>1&3);
- bitrate_index=*(c+2)>>4&0xF;
- if (version>=1 && version<=2 && lay-1>=0 && lay-1<=2 && bitrate_index>=0 && bitrate_index<=14)
- bitrate=bitrates[version-1][lay-1][bitrate_index];
- else
- bitrate=0;
- if (bitrate!=0)
- {
- fseek(fic,0,SEEK_END);
- duration=(ftell(fic)+buffer-c)/125/bitrate;
- }
- else
- duration=0;
- break;
- }
- c++;
- }
-
- /* try ID3v1 */
- if (strlen(artist)==0 && strlen(title)==0)
- {
- fseek(fic,-128,SEEK_END);
- lus=fread(buffer,1,128,fic);
- if (lus==128 && buffer[0]=='T' && buffer[1]=='A' && buffer[2]=='G')
- {
- strncpy(title,buffer+3,30);
- title[30]='\0';
- c=title+29;
- while (c>title && *c==' ') *(c--)='\0';
- strncpy(artist,buffer+33,30);
- artist[30]='\0';
- c=artist+29;
- while (c>artist && *c==' ') *(c--)='\0';
- /* strncpy(album,buffer+65,30); */
- /* strncpy(year,buffer+97,4); */
- /* strncpy(comment,buffer+101,30); */
- /* strncpy(genrebuf,buffer+127,1); genre[1]=0; */
- genre=buffer[127];
- }
- }
-
- fclose(fic);
-}
+ c = path;
+ myputstr(c);
+}
-void parse_ogg(unsigned char *file)
+void noreferal(const char *path, const char *artist, const char *title)
{
- FILE *fic;
- unsigned char *c;
- int lus;
- int sample_rate;
- int samples;
-
- if (debug) fprintf(stderr,"Debug >> parsing ogg : %s\n",file);
-
- /* read header */
- if ((fic=fopen(file,"r"))==NULL) { fprintf(stderr,"Warning >> can't open file : %s\n",file); return; }
- lus=fread(buffer,1,OGG_BASE,fic);
-
- /* try Ogg */
- if (buffer[0]!='O' && buffer[1]!='g' && buffer[2]!='g')
- {
- fprintf(stderr,"Warning >> not a Ogg header : %s\n",file);
+ printf("\t\t<description><![CDATA[<h4>");
+ myputstr(artist);
+ printf("</h4><h5>");
+ myputstr(title);
+ printf("</h5><a href=\"");
+ print_webpath(path);
+ printf
+ ("\"><br><br>Direct Link to Audiofile</a><br>]]></description>%s",
+ eol);
+}
+
+void reference(const char *title)
+{
+ FILE *pipe = NULL;
+ static char command[2048], buffer[1024];
+ int buflen = 8192;
+
+ buflen = strlen(title) + strlen(referal) + 3;
+ assert((buflen < 2046));
+ strcpy(command, referal);
+ buflen = strlen(command);
+ command[buflen] = ' ';
+ command[buflen + 1] = '"';
+ command[buflen + 2] = 0;
+ strcat(command, title);
+ buflen = strlen(command);
+ command[buflen] = '"';
+ command[buflen + 1] = 0;
+ if(debug)
+ fprintf(stderr, "Debug >> processing command: %s\n", command);
+ pipe = popen(command, "r");
+ if(pipe == NULL) {
+ fprintf(stderr, "Warning >> can't open pipe >%s< !\n", command);
+ free(command);
+ return;
+ }
+ fgets(buffer, 1020, pipe);
+ while(!feof(pipe)) {
+ fputs(buffer, stdout);
+ fgets(buffer, 1020, pipe);
+ }
+ pclose(pipe);
return;
- }
-
- c=buffer+0x28;
- sample_rate=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24);
-
- while (c<buffer+lus-10)
- {
- int size;
- if (strncasecmp(c,"TITLE=",6)==0)
- {
- size=*(c-4)+(*(c-3)<<8)+(*(c-2)<<16)+(*(c-1)<<24);
- strncpy(title,c+6,size-6);
- title[size-6]='\0';
- c+=size;
- }
- if (strncasecmp(c,"ARTIST=",7)==0)
- {
- size=*(c-4)+(*(c-3)<<8)+(*(c-2)<<16)+(*(c-1)<<24);
- strncpy(artist,c+7,size-7);
- artist[size-7]='\0';
- c+=size;
- }
- if (strncasecmp(c,"GENRE=",6)==0)
- {
- static int i=0;
- size=*(c-4)+(*(c-3)<<8)+(*(c-2)<<16)+(*(c-1)<<24);
- strncpy(genrebuf,c+6,size-6);
- genrebuf[size-6]='\0';
- c+=size;
- for(i=0;i<ID3_NR_OF_V1_GENRES;i++)
- {
- if (strcasecmp(ID3_v1_genre_description[i],genrebuf)==0)
- {
- genre=i;
- break;
+}
+
+void parse_options(int argc, char **argv)
+{
+ static char const short_options[] = "c:bdf:g:lo:np:ruwx:";
+ static struct option long_options[] = {
+ {"backslash", no_argument, NULL, 'b'},
+ {"command", required_argument, NULL, 'b'},
+ {"debug", no_argument, NULL, 'd'},
+ {"format", required_argument, NULL, 'f'},
+ {"genre", required_argument, NULL, 'g'},
+ {"nohardlink", no_argument, NULL, 'n'},
+ {"output", required_argument, NULL, 'o'},
+ {"prefix", required_argument, NULL, 'p'},
+ {"recursive", no_argument, NULL, 'r'},
+ {"windows", no_argument, NULL, 'w'},
+ {"exclude", required_argument, NULL, 'x'}
+ };
+ int c;
+ int option_index = 0;
+ while((c =
+ getopt_long(argc, argv, short_options, long_options,
+ &option_index)) != -1) {
+ switch (c) {
+ case 'b':
+ separator = '\\';
+ noand['/'] = '\\';
+ break;
+ case 'c':
+ if(strncmp(optarg, "intern", 6) == 0)
+ referal = NULL;
+ else
+ referal = strdup(optarg);
+ break;
+ case 'd':
+ debug = 1 - debug;
+ break;
+ case 'f':
+ if(strcmp(optarg, "m3u") == 0)
+ format = 0;
+ else if(strcmp(optarg, "pls") == 0)
+ format = 1;
+ else if(strcmp(optarg, "html") == 0)
+ format = 2;
+ else if(strcmp(optarg, "rss") == 0)
+ format = 3;
+ else
+ usage();
+ break;
+ case 'g':
+ if(genrelist == NULL)
+ genrelist = calloc(257, sizeof(char)); /* allow multiple includes/excludes */
+ if(genrelist == NULL) {
+ fprintf(stderr,
+ "Error >> unable to allocate cleared memory\n");
+ exit(2);
+ } else {
+ unsigned int n = 0;
+ while(n < strlen(optarg)) {
+ if(debug)
+ fprintf(stderr,
+ "Debug >> genrelist entry activting : %d\n",
+ atoi(&optarg[n]));
+ genrelist[atoi(&optarg[n])] = 1;
+ while(isdigit(optarg[n++]));
+ }
+ }
+ break;
+ case 'n':
+ avoidhlinked = 1;
+ break;
+ case 'o':
+ close(1);
+ if(fopen(optarg, "w") == NULL) {
+ fprintf(stderr,
+ "Error >> unable to open output file : %s\n",
+ optarg);
+ exit(2);
+ }
+ break;
+ case 'p':
+ prefix = malloc(strlen(optarg) + 1);
+ strcpy(prefix, optarg);
+ base = malloc(strlen(prefix) + 1);
+ strcpy(base, prefix);
+ dir = strchr(base, '/');
+ if((dir != NULL) && (dir[1] == '/'))
+ dir = strchr(dir + 2, '/');
+ if(dir != NULL)
+ *dir++ = 0;
+ else
+ dir = "";
+ /* if prefix is a weblink, base is the baselink, dir is the path */
+ break;
+ case 'r':
+ recursive = 1;
+ break;
+ case 'u':
+ winorunix = one2one;
+ eol = "\n";
+ break;
+ case 'w':
+ winorunix = unix2dos;
+ eol = "\r\n";
+ break;
+ case 'x':
+ if(genrelist == NULL) { /* allow multiple includes/excludes - not recommended (confusing) but possible */
+ int n = 0;
+ genrelist = calloc(257, sizeof(char));
+ while(n < 256)
+ genrelist[n++] = 1;
+ }
+ if(genrelist == NULL) {
+ fprintf(stderr,
+ "Error >> unable to allocate cleared memory\n");
+ exit(2);
+ } else {
+ unsigned int n = 0;
+ while(n < strlen(optarg)) {
+ if(debug)
+ fprintf(stderr,
+ "Debug >> genrelist entry activting : %d\n",
+ atoi(&optarg[n]));
+ genrelist[atoi(&optarg[n])] = 0;
+ while(isdigit(optarg[n++]));
+ }
+ }
+ break;
+ default:
+ usage();
+ }
+ }
+ /* hostname = getenv("HOSTNAME"); */
+ if(genrelist == NULL) {
+ genrelist = calloc(257, sizeof(char));
+ if(genrelist == NULL) {
+ fprintf(stderr,
+ "Error >> unable to allocate cleared memory\n");
+ exit(2);
+ } else {
+ int n = 0;
+ while(n < 256)
+ genrelist[n++] = 1;
}
- if (i==ID3_NR_OF_V1_GENRES) genre=0;
- }
- }
- c++;
- }
-
- fseek(fic,-OGG_BASE,SEEK_END);
- lus=fread(buffer,1,OGG_BASE,fic);
- c=buffer+lus-1;
- while (strncmp(c,"OggS",4)!=0 && c>buffer) c--;
- if (c!=buffer)
- {
- c+=6;
- samples=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24);
- duration=samples/sample_rate;
- }
-
- fclose(fic);
+ }
}
-void parse_mpc(unsigned char *file)
+void parse_mp3(unsigned char *file)
{
- FILE *fic;
- unsigned char *c;
- int lus;
- int sample_rates[4]={44100,48000,37800,32000};
- int frame_count;
- int size,items;
- int i;
-
- if (debug) fprintf(stderr,"Debug >> parsing mpc : %s\n",file);
-
- /* read header */
- if ((fic=fopen(file,"r"))==NULL) { fprintf(stderr,"Warning >> can't open file : %s\n",file); return; }
- lus=fread(buffer,1,12,fic);
-
- /* try Musepack */
- if (buffer[0]!='M' && buffer[1]!='P' && buffer[2]!='+')
- {
- fprintf(stderr,"Warning >> not a Musepack header : %s\n",file);
- return;
- }
-
- /* only version 7 */
- if (buffer[3]!=7)
- {
- fprintf(stderr,"Warning >> only Musepack SV7 supported : %s\n",file);
- return;
- }
-
- /* duration */
- c=buffer+4;
- frame_count=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24);
- c+=5;
- duration=frame_count*1152/sample_rates[*c&3];
-
- /* try APETAGEX footer */
- fseek(fic,-32,SEEK_END);
- lus=fread(buffer,1,32,fic);
- if (lus==32 && strncmp(buffer,"APETAGEX",8)==0)
- {
- c=buffer+12;
- size=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24);
- size+=32;
- c+=4;
- items=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24);
- fseek(fic,-size,SEEK_END);
- lus=fread(buffer,1,size,fic);
- if (lus==size && strncmp(buffer,"APETAGEX",8)==0)
- {
- c=buffer+32;
- while (items--)
- {
- size=(*c)+(*(c+1)<<8)+(*(c+2)<<16)+(*(c+3)<<24);
- c+=8;
- if (strcasecmp(c,"TITLE")==0)
- {
- strncpy(title,c+6,size);
- title[size]='\0';
+ int bitrates[2][3][15] =
+ { {{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384,
+ 416, 448},
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,
+ 384},
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256,
+ 320}},
+ {{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}}
+ };
+ FILE *fic;
+ unsigned char *c;
+ int lus;
+
+ genre = 0;
+ genrebuf[0] = 0;
+ if(debug)
+ fprintf(stderr, "Debug >> parsing mp3 : %s\n", file);
+
+ /* read header */
+ if((fic = fopen(file, "r")) == NULL) {
+ fprintf(stderr, "Warning >> can't open file : %s\n", file);
+ return;
+ }
+ lus = fread(buffer, 1, MP3_BASE, fic);
+ c = buffer;
+
+ /* try ID3v2 */
+ if(buffer[0] == 'I' && buffer[1] == 'D' && buffer[2] == '3') {
+ int size;
+ int version;
+ version = *(buffer + 3);
+ if(version < 2 || version > 4)
+ fprintf(stderr,
+ "Warning >> ID3 v2.%d not implemented ! trying anyway : %s\n",
+ version, file);
+ if(*(buffer + 5) != 0)
+ fprintf(stderr,
+ "Warning >> specials headers not implemented (%d) ! trying anyway : %s\n",
+ *(buffer + 5), file);
+ c = buffer + 6;
+ size =
+ (*c << 21) + (*(c + 1) << 14) + (*(c + 2) << 7) + (*(c + 3));
+ /* read more header */
+ if(size + lus > MAX) {
+ lus += fread(buffer + lus, 1, MAX - lus, fic);
+ fprintf(stderr,
+ "Warning >> ID3 header is huge (%d bytes) ! trying anyway : %s\n",
+ size, file);
+ } else
+ lus += fread(buffer + lus, 1, size, fic);
+ if(size > lus)
+ size = lus;
+ c += 4;
+ if(version == 2)
+ while(c < buffer + size) {
+ int size = (*(c + 3) << 16) + (*(c + 4) << 8) + (*(c + 5));
+ if(*c == 0)
+ break;
+ if(strncmp(c, "TT2", 3) == 0) {
+ strncpy(title, c + 7, size - 1);
+ title[size - 1] = '\0';
+ }
+ if(strncmp(c, "TP1", 3) == 0) {
+ strncpy(artist, c + 7, size - 1);
+ artist[size - 1] = '\0';
+ }
+ if(strncmp(c, "TCO", 3) == 0) {
+ /* strncpy(genrebuf,c+7,size-1); */
+ /* genrebuf[size-1]='\0'; */
+ /* genre=atoi(&genrebuf[1]); */
+ genre = atoi(c + 8);
+ }
+ c += size + 6;
+ }
+ if(version == 3 || version == 4)
+ while(c < buffer + size) {
+ int size =
+ (*(c + 4) << 24) + (*(c + 5) << 16) + (*(c + 6) << 8) +
+ (*(c + 7));
+ if(*c == 0)
+ break;
+ if(strncmp(c, "TIT2", 4) == 0) {
+ strncpy(title, c + 11, size - 1);
+ title[size - 1] = '\0';
+ }
+ if(strncmp(c, "TPE1", 4) == 0) {
+ strncpy(artist, c + 11, size - 1);
+ artist[size - 1] = '\0';
+ }
+ if(strncmp(c, "TCON", 4) == 0) {
+ /* strncpy(genrebuf,c+11,size-1); */
+ /* genrebuf[size-1]='\0'; */
+ /* genre=atoi(&genrebuf[1]); */
+ genre = atoi(c + 12);
+ }
+ c += size + 10;
+ }
+ }
+
+ while(c < buffer + lus - 10) {
+ if(*c == 0xFF && (*(c + 1) & 0xF0) == 0xF0) {
+ int version;
+ int lay;
+ int bitrate_index;
+ int bitrate;
+ version = 2 - (*(c + 1) >> 3 & 1);
+ lay = 4 - (*(c + 1) >> 1 & 3);
+ bitrate_index = *(c + 2) >> 4 & 0xF;
+ if(version >= 1 && version <= 2 && lay - 1 >= 0 && lay - 1 <= 2
+ && bitrate_index >= 0 && bitrate_index <= 14)
+ bitrate = bitrates[version - 1][lay - 1][bitrate_index];
+ else
+ bitrate = 0;
+ if(bitrate != 0) {
+ fseek(fic, 0, SEEK_END);
+ duration = (ftell(fic) + buffer - c) / 125 / bitrate;
+ } else
+ duration = 0;
+ break;
}
- if (strcasecmp(c,"ARTIST")==0)
- {
- strncpy(artist,c+7,size);
- artist[size]='\0';
+ c++;
+ }
+
+ /* try ID3v1 */
+ if(strlen(artist) == 0 && strlen(title) == 0) {
+ fseek(fic, -128, SEEK_END);
+ lus = fread(buffer, 1, 128, fic);
+ if(lus == 128 && buffer[0] == 'T' && buffer[1] == 'A'
+ && buffer[2] == 'G') {
+ strncpy(title, buffer + 3, 30);
+ title[30] = '\0';
+ c = title + 29;
+ while(c > title && *c == ' ')
+ *(c--) = '\0';
+ strncpy(artist, buffer + 33, 30);
+ artist[30] = '\0';
+ c = artist + 29;
+ while(c > artist && *c == ' ')
+ *(c--) = '\0';
+ /* strncpy(album,buffer+65,30); */
+ /* strncpy(year,buffer+97,4); */
+ /* strncpy(comment,buffer+101,30); */
+ /* strncpy(genrebuf,buffer+127,1); genre[1]=0; */
+ genre = buffer[127];
}
- if (strcasecmp(c,"GENRE")==0)
- {
- for(i=0;i<ID3_NR_OF_V1_GENRES;i++)
- {
- strncpy(genrebuf,c+6,size);
- genrebuf[size]='\0';
- if (strcasecmp(ID3_v1_genre_description[i],genrebuf)==0)
- {
- genre=i;
- break;
+ }
+
+ fclose(fic);
+}
+
+void parse_ogg(unsigned char *file)
+{
+ FILE *fic;
+ unsigned char *c;
+ int lus;
+ int sample_rate;
+ int samples;
+
+ if(debug)
+ fprintf(stderr, "Debug >> parsing ogg : %s\n", file);
+
+ /* read header */
+ if((fic = fopen(file, "r")) == NULL) {
+ fprintf(stderr, "Warning >> can't open file : %s\n", file);
+ return;
+ }
+ lus = fread(buffer, 1, OGG_BASE, fic);
+
+ /* try Ogg */
+ if(buffer[0] != 'O' && buffer[1] != 'g' && buffer[2] != 'g') {
+ fprintf(stderr, "Warning >> not a Ogg header : %s\n", file);
+ return;
+ }
+
+ c = buffer + 0x28;
+ sample_rate =
+ (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24);
+
+ while(c < buffer + lus - 10) {
+ int size;
+ if(strncasecmp(c, "TITLE=", 6) == 0) {
+ size =
+ *(c - 4) + (*(c - 3) << 8) + (*(c - 2) << 16) +
+ (*(c - 1) << 24);
+ strncpy(title, c + 6, size - 6);
+ title[size - 6] = '\0';
+ c += size;
+ }
+ if(strncasecmp(c, "ARTIST=", 7) == 0) {
+ size =
+ *(c - 4) + (*(c - 3) << 8) + (*(c - 2) << 16) +
+ (*(c - 1) << 24);
+ strncpy(artist, c + 7, size - 7);
+ artist[size - 7] = '\0';
+ c += size;
+ }
+ if(strncasecmp(c, "GENRE=", 6) == 0) {
+ static int i = 0;
+ size =
+ *(c - 4) + (*(c - 3) << 8) + (*(c - 2) << 16) +
+ (*(c - 1) << 24);
+ strncpy(genrebuf, c + 6, size - 6);
+ genrebuf[size - 6] = '\0';
+ c += size;
+ for(i = 0; i < ID3_NR_OF_V1_GENRES; i++) {
+ if(strcasecmp(ID3_v1_genre_description[i], genrebuf) == 0) {
+ genre = i;
+ break;
+ }
+ if(i == ID3_NR_OF_V1_GENRES)
+ genre = 0;
+ }
+ }
+ c++;
+ }
+
+ fseek(fic, -OGG_BASE, SEEK_END);
+ lus = fread(buffer, 1, OGG_BASE, fic);
+ c = buffer + lus - 1;
+ while(strncmp(c, "OggS", 4) != 0 && c > buffer)
+ c--;
+ if(c != buffer) {
+ c += 6;
+ samples =
+ (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24);
+ duration = samples / sample_rate;
+ }
+
+ fclose(fic);
+}
+
+
+void parse_mpc(unsigned char *file)
+{
+ FILE *fic;
+ unsigned char *c;
+ int lus;
+ int sample_rates[4] = { 44100, 48000, 37800, 32000 };
+ int frame_count;
+ int size, items;
+ int i;
+
+ if(debug)
+ fprintf(stderr, "Debug >> parsing mpc : %s\n", file);
+
+ /* read header */
+ if((fic = fopen(file, "r")) == NULL) {
+ fprintf(stderr, "Warning >> can't open file : %s\n", file);
+ return;
+ }
+ lus = fread(buffer, 1, 12, fic);
+
+ /* try Musepack */
+ if(buffer[0] != 'M' && buffer[1] != 'P' && buffer[2] != '+') {
+ fprintf(stderr, "Warning >> not a Musepack header : %s\n", file);
+ return;
+ }
+
+ /* only version 7 */
+ if(buffer[3] != 7) {
+ fprintf(stderr, "Warning >> only Musepack SV7 supported : %s\n",
+ file);
+ return;
+ }
+
+ /* duration */
+ c = buffer + 4;
+ frame_count =
+ (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24);
+ c += 5;
+ duration = frame_count * 1152 / sample_rates[*c & 3];
+
+ /* try APETAGEX footer */
+ fseek(fic, -32, SEEK_END);
+ lus = fread(buffer, 1, 32, fic);
+ if(lus == 32 && strncmp(buffer, "APETAGEX", 8) == 0) {
+ c = buffer + 12;
+ size =
+ (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24);
+ size += 32;
+ c += 4;
+ items =
+ (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) + (*(c + 3) << 24);
+ fseek(fic, -size, SEEK_END);
+ lus = fread(buffer, 1, size, fic);
+ if(lus == size && strncmp(buffer, "APETAGEX", 8) == 0) {
+ c = buffer + 32;
+ while(items--) {
+ size =
+ (*c) + (*(c + 1) << 8) + (*(c + 2) << 16) +
+ (*(c + 3) << 24);
+ c += 8;
+ if(strcasecmp(c, "TITLE") == 0) {
+ strncpy(title, c + 6, size);
+ title[size] = '\0';
+ }
+ if(strcasecmp(c, "ARTIST") == 0) {
+ strncpy(artist, c + 7, size);
+ artist[size] = '\0';
+ }
+ if(strcasecmp(c, "GENRE") == 0) {
+ for(i = 0; i < ID3_NR_OF_V1_GENRES; i++) {
+ strncpy(genrebuf, c + 6, size);
+ genrebuf[size] = '\0';
+ if(strcasecmp
+ (ID3_v1_genre_description[i], genrebuf) == 0) {
+ genre = i;
+ break;
+ }
+ if(i == ID3_NR_OF_V1_GENRES)
+ genre = 0;
+ }
+ }
+ c += strlen(c) + 1 + size;
}
- if (i==ID3_NR_OF_V1_GENRES) genre=0;
- }
}
- c+=strlen(c)+1+size;
- }
}
- }
- fclose(fic);
+ fclose(fic);
}
#define FSN 32
#define regbit_qry(x,y) ( x[( (y) / sizeof(INOTYP) )] & 1<<( (y) % sizeof(INOTYP) ) )
#define regbit_set(x,y) ( x[( (y) / sizeof(INOTYP) )] |= 1<<( (y) % sizeof(INOTYP) ) )
-int hlink_check(struct stat*info)
+int hlink_check(struct stat *info)
{
- /*
- * for speed this subroutine should only be called
- * - if the file has more than one hardlink
- * - if the file is a resolved softlink
- */
- /* the persistent variables */
- static INOTYP *list[FSN];
- static dev_t name[FSN];
- /* some temporary variables */
- int fsn, is_registered=0;
-
- /* assertions - in case parameters are lowered for less memory usage */
- assert(fsn<FSN);
- assert((info->st_ino)/sizeof(INOTYP)<MAXINO);
-
- /* search which internal registration number is used for this filesystem */
- for( fsn=0; (name[fsn]!=(info->st_dev)) && (name[fsn]!=0) ; fsn++);
-
- /* if file system is not registered yet, do it and leave */
- if( name[fsn] == 0 )
- {
- name[fsn] = (info->st_dev);
- /* provide space for the bitmap that maps the inodes of this file system */
- list[fsn] = (INOTYP*)calloc(MAXINO,sizeof(INOTYP));
- /* no comparison is needed in empty lists ... return */
- if(debug) fprintf(stderr, "Debug >> Linked >> Init List %04x @mem %04lx\n", (int)name[fsn], (long)&list[fsn] );
- } else
- {
- /* this looks more complicated than it really is */
- /* the idea is very simple:
- * provide a bitmap that maps all inodes of a file system
- * to mark all files that have already been visited.
- * If it is already visited, do not add it to the playlist
- */
/*
- * The difficulty is as follows:
- * struct inode_bitmap { char registered:1; } bitmap[1<<MAXINO];
- * would be byte-aligned and would allocate at least eight times the needed space.
- * Feel free to change the definitions that are involved here, if you know better.
+ * for speed this subroutine should only be called
+ * - if the file has more than one hardlink
+ * - if the file is a resolved softlink
*/
- if( regbit_qry( list[fsn], (info->st_ino) ) ) is_registered=1;
- else regbit_set( list[fsn], (info->st_ino) );
- /*
- * the debug expression is more complicated then the working stuff
- */
- if(debug)
- fprintf(stderr, "Debug >> Linked >> DEV %04x INO %06x => "
- "list[%02x][%04x] = %04x & %04x --> %s registered\n",
- (int)info->st_dev, (int)info->st_ino, fsn, (int)((info->st_ino)/sizeof(INOTYP)),
- (int)list[fsn][(info->st_ino)/sizeof(INOTYP)],
- 1<<((info->st_ino)%sizeof(INOTYP)), is_registered?"Already":"Not" );
- }
- return is_registered;
+ /* the persistent variables */
+ static INOTYP *list[FSN];
+ static dev_t name[FSN];
+ /* some temporary variables */
+ int fsn, is_registered = 0;
+
+ /* assertions - in case parameters are lowered for less memory usage */
+ assert(fsn < FSN);
+ assert((info->st_ino) / sizeof(INOTYP) < MAXINO);
+
+ /* search which internal registration number is used for this filesystem */
+ for(fsn = 0; (name[fsn] != (info->st_dev)) && (name[fsn] != 0); fsn++);
+
+ /* if file system is not registered yet, do it and leave */
+ if(name[fsn] == 0) {
+ name[fsn] = (info->st_dev);
+ /* provide space for the bitmap that maps the inodes of this file system */
+ list[fsn] = (INOTYP *) calloc(MAXINO, sizeof(INOTYP));
+ /* no comparison is needed in empty lists ... return */
+ if(debug)
+ fprintf(stderr,
+ "Debug >> Linked >> Init List %04x @mem %04lx\n",
+ (int)name[fsn], (long)&list[fsn]);
+ } else {
+ /* this looks more complicated than it really is */
+ /* the idea is very simple:
+ * provide a bitmap that maps all inodes of a file system
+ * to mark all files that have already been visited.
+ * If it is already visited, do not add it to the playlist
+ */
+ /*
+ * The difficulty is as follows:
+ * struct inode_bitmap { char registered:1; } bitmap[1<<MAXINO];
+ * would be byte-aligned and would allocate at least eight times the needed space.
+ * Feel free to change the definitions that are involved here, if you know better.
+ */
+ if(regbit_qry(list[fsn], (info->st_ino)))
+ is_registered = 1;
+ else
+ regbit_set(list[fsn], (info->st_ino));
+ /*
+ * the debug expression is more complicated then the working stuff
+ */
+ if(debug)
+ fprintf(stderr, "Debug >> Linked >> DEV %04x INO %06x => "
+ "list[%02x][%04x] = %04x & %04x --> %s registered\n",
+ (int)info->st_dev, (int)info->st_ino, fsn,
+ (int)((info->st_ino) / sizeof(INOTYP)),
+ (int)list[fsn][(info->st_ino) / sizeof(INOTYP)],
+ 1 << ((info->st_ino) % sizeof(INOTYP)),
+ is_registered ? "Already" : "Not");
+ }
+ return is_registered;
}
void parse_file(unsigned char *newpath)
{
- unsigned char *c;
- unsigned char ext[5];
- int j;
-
- void print_faketitle()
- {
- c=newpath+strlen(newpath);
- while (c>newpath && *c!='/') c--;
- while (c<newpath+strlen(newpath)-5)
- {
- c++;
- if (*c=='_') putchar(' '); else if (windows) putchar(unix2dos[*c]); else putchar(*c);
- }
- }
-
- void print_path()
- {
- char last=0;
- printf(prefix);
- c=newpath+skip;
- /* remove leading "./" when parsing current directory */
- if (*c=='.' && *(c+1)=='/') { c+=2; last='/'; }
- for (;*c!='\0';c++)
- {
- /* remove double "//" when parsing a directory ending with a "/" */
- if (last=='/' && *c=='/') continue;
- last=*c;
- if (*c=='/') putchar(separator); else if (windows) putchar(unix2dos[*c]); else putchar(*c);
- }
- }
-
- for (j=0;j<5;j++) ext[j]=tolower(newpath[strlen(newpath)-4+j]);
- artist[0]='\0';
- title[0]='\0';
- duration=-2;
- if (strcmp(".mp2",ext)==0) { duration=-1; parse_mp3(newpath); }
- if (strcmp(".mp3",ext)==0) { duration=-1; parse_mp3(newpath); }
- if (strcmp(".mpc",ext)==0) { duration=-1; parse_mpc(newpath); }
- if (strcmp(".mp+",ext)==0) { duration=-1; parse_mpc(newpath); }
- if (strcmp(".ogg",ext)==0) { duration=-1; parse_ogg(newpath); }
- if (strcmp(".wav",ext)==0) { duration=-1; /* parse_wav(newpath); */ }
-
- if (duration!=-2 && genrelist[genre]) /* is it an audio file ? */
- {
+ unsigned char ext[5];
+ int j, encoding = 0;
+
+ for(j = 0; j < 5; j++)
+ ext[j] = tolower(newpath[strlen(newpath) - 4 + j]);
+ artist[0] = '\0';
+ title[0] = '\0';
+ duration = -2;
+ if(strcmp(".mp2", ext) == 0) {
+ duration = -1;
+ parse_mp3(newpath);
+ encoding = MP2ENC;
+ }
+ if(strcmp(".mp3", ext) == 0) {
+ duration = -1;
+ parse_mp3(newpath);
+ encoding = MP3ENC;
+ }
+ if(strcmp(".mpc", ext) == 0) {
+ duration = -1;
+ parse_mpc(newpath);
+ encoding = MPCENC;
+ }
+ if(strcmp(".mp+", ext) == 0) {
+ duration = -1;
+ parse_mpc(newpath);
+ encoding = MPPENC;
+ }
+ if(strcmp(".ogg", ext) == 0) {
+ duration = -1;
+ parse_ogg(newpath);
+ encoding = OGGENC;
+ }
+ if(strcmp(".wav", ext) == 0) {
+ duration = -1; /* parse_wav(newpath); */
+ encoding = WAVENC;
+ }
+ /* faketitle() */
+ if((strlen(artist) == 0) && (strlen(title) == 0)) {
+ // there are no tag infos read
+ // use file name to state substitute it
+ char *c = strrchr(newpath, separator);
+ strcpy(artist, ++c);
+ // arbitrarily use the first '-'
+ // to separate artist and title
+ c = strchr(artist, '-');
+ if(c != NULL) { // if trenner found, divide file name
+ *c = '\0';
+ strcpy(title, ++c);
+ c = strrchr(title, '.');
+ if(c != NULL)
+ *c = '\0';
+ } else { // no trenner found, assume
+ // no artist, only title
+ strcpy(title, artist);
+ artist[0] = '\0';
+ }
+ // replace underscores by spaces
+ for(c = artist; (c = strchr(c, '_')) != NULL; c++)
+ *c = ' ';
+ for(c = title; (c = strchr(c, '_')) != NULL; c++)
+ *c = ' ';
+ }
+ /* faketitle() end */
+
+ if(duration != -2 && genrelist[genre]) { /* is it an audio file ? */
counter++;
- switch (format)
- {
- case 0:
- if (duration!=-1)
- {
- printf("#EXTINF:%d,",duration);
- if (strlen(artist)==0 && strlen(title)==0) print_faketitle();
- else printf("%s - %s",artist,title);
- printf("%s",eol);
+ switch (format) {
+ case 0:
+ if(duration != -1) {
+ printf("#EXTINF:%d,%s - %s%s", duration, artist, title,
+ eol);
}
- print_path();
- printf("%s",eol);
+ print_path(newpath);
+ printf("%s", eol);
break;
- case 1:
- printf("File%d=",counter);
- print_path();
- printf("%s",eol);
- printf("Title%d=",counter);
- if (strlen(artist)==0 && strlen(title)==0) print_faketitle();
- else printf("%s - %s",artist,title);
- printf("%s",eol);
- if (duration!=-1) printf("Length%d=%d%s",counter,duration,eol);
+ case 1:
+ printf("File%d=", counter);
+ print_path(newpath);
+ printf("%sTitle%d=%s - %s%s", eol, counter, artist, title,
+ eol);
+ if(duration != -1)
+ printf("Length%d=%d%s", counter, duration, eol);
break;
- case 2:
- printf("<tr><td>%d</td><td>%s</td><td>%s</td><td>",counter,artist,title);
- if (duration==-1) printf("?"); else printf("%d:%s%d",duration/60,duration%60<10?"0":"",duration%60);
- printf("</td></tr>%s",eol);
+ case 2:
+ printf("<tr><td>%d</td><td>%s</td><td>%s</td><td>", counter,
+ artist, title);
+ if(duration == -1)
+ printf("?</td></tr>%s", eol);
+ else
+ printf("%d:%s%d</td></tr>%s", duration / 60,
+ duration % 60 < 10 ? "0" : "", duration % 60, eol);
break;
- case 3:
- if (duration!=-1)
- { time_t zeit;
- time(&zeit);
- char timebuffer[256];
- strftime(timebuffer,255, "%a %d %b %Y %T %Z", localtime(&zeit) ); /* ctime() had a trailing CR */
- printf("\t<item>%s",eol);
- if (strlen(artist)==0 && strlen(title)==0)
- {
- /* find a better solution for this */
- printf("\t\t<author>%s</author>%s\t\t<title>%s</title>%s",newpath,eol, newpath,eol );
- }
- else printf("\t\t<author>%s</author>%s\t\t<title>%s</title>%s",artist,eol, title,eol );
- /* you might want to add more into description --> look for a smart, not a fast program */
- printf("\t\t<description><![CDATA[<h4>%s</h4><h5>%s</h5><a href=\"",title,artist);
- print_path();
- printf("\">Direct Link to Audiofile</a><br>]]></description>%s",eol);
-#if 1
- printf("\t\t<link>%s</link>%s",reflink(title),eol);
-#endif
- printf("\t\t<pubDate>%s</pubDate>%s",timebuffer,eol);
- printf("\t\t<enclosure url=\"");
- print_path();
- printf("\" length=\"%d\" type=\"audio/mpeg\"/>%s\t\t<guid>",duration, eol);
- print_path();
- printf("</guid>%s",eol );
- printf("\t\t<itunes:duration>%d:%d:%d</itunes:duration>%s",duration/3600,(duration/60)%60,duration%60,eol);
- printf("\t\t<itunes:author>%s</itunes:author>%s", artist, eol);
- printf("\t</item>%s",eol );
+ case 3:
+ if(duration != -1) {
+ struct stat infos;
+ char timebuffer[256];
+
+ if(stat(newpath, &infos) != 0) {
+ fprintf(stderr, "Warning >> can't stat entry : %s\n",
+ newpath);
+ return;
+ }
+ strftime(timebuffer, 255, "%a %d %b %Y %T %z", localtime(&(infos.st_mtime))); /* ctime() had a trailing CR */
+ printf("\t<item>%s", eol);
+ printf("\t\t<author>");
+ myputstr(artist);
+ printf("</author>%s\t\t<title>", eol);
+ myputstr(title);
+ printf("</title>%s", eol);
+
+ if(referal == NULL) {
+ noreferal(newpath, artist, title);
+ } else
+ reference(newpath);
+ printf("\t\t<pubDate>%s</pubDate>%s\t\t<enclosure url=\"",
+ timebuffer, eol);
+ print_webpath(newpath);
+ printf("\" length=\"%d\" type=\"%s\"/>%s\t\t<guid>",
+ (int)infos.st_size, magic[encoding], eol);
+ print_pathtail(newpath);
+ printf("</guid>%s", eol);
+ if(duration > 3599)
+ printf
+ ("\t\t<itunes:duration>%d:%02d:%02d</itunes:duration>%s",
+ duration / 3600, (duration / 60) % 60,
+ duration % 60, eol);
+ else
+ printf
+ ("\t\t<itunes:duration>%d:%02d</itunes:duration>%s",
+ duration / 60, duration % 60, eol);
+ if(strlen(artist) != 0) {
+ printf("\t\t<itunes:author>");
+ myputstr(artist);
+ printf("</itunes:author>%s", eol);
+ }
+ printf("\t</item>%s", eol);
}
break;
}
- }
+ }
}
void parse_directory(unsigned char *path)
{
- int i,n;
- struct dirent **namelist;
- unsigned char newpath[PATH_MAX];
- struct stat infos;
-
- if (debug)
- fprintf(stderr,"Debug >> parsing directory : %s\n",path);
- if (stat(path,&infos)!=0)
- {
- fprintf(stderr,"Warning >> can't stat entry : %s\n",path);
- return;
- }
- /* check if it is a filename */
- if (S_ISREG(infos.st_mode) || S_ISLNK(infos.st_mode))
- {
- parse_file(path);
- return;
- }
- /* must be a directory - or something unusable like pipe, socket, etc */
- if ((n=scandir(path,&namelist,0,alphasort))<0)
- {
- fprintf(stderr,"Warning >> can't open directory : %s\n",path);
- return;
- }
- for (i=0;i<n;i++)
- {
- sprintf(newpath,"%s/%s",path,namelist[i]->d_name);
-
- if (stat(newpath,&infos)!=0)
- {
- fprintf(stderr,"Warning >> can't stat entry : %s\n",newpath);
- continue;
- }
- if (recursive && S_ISDIR(infos.st_mode)
- && strcmp(namelist[i]->d_name,".")!=0
- && strcmp(namelist[i]->d_name,"..")!=0) parse_directory(newpath);
- /* hlink_check() might be applied more selective ... avoidhlink is only a simple prereq */
- if (S_ISREG(infos.st_mode) && ! ( avoidhlinked && hlink_check(&infos) ) )
- {
- parse_file(newpath);
- }
- free(namelist[i]);
- }
- free(namelist);
+ int i, n;
+ struct dirent **namelist;
+ unsigned char newpath[PATH_MAX];
+ struct stat infos;
+
+ if(debug)
+ fprintf(stderr, "Debug >> parsing directory : %s\n", path);
+ if(stat(path, &infos) != 0) {
+ fprintf(stderr, "Warning >> can't stat entry : %s\n", path);
+ return;
+ }
+ /* check if it is a filename */
+ if(S_ISREG(infos.st_mode) || S_ISLNK(infos.st_mode)) {
+ parse_file(path);
+ return;
+ }
+ /* must be a directory - or something unusable like pipe, socket, etc */
+ if((n = scandir(path, &namelist, 0, alphasort)) < 0) {
+ fprintf(stderr, "Warning >> can't open directory : %s\n", path);
+ return;
+ }
+ for(i = 0; i < n; i++) {
+ sprintf(newpath, "%s/%s", path, namelist[i]->d_name);
+
+ if(stat(newpath, &infos) != 0) {
+ fprintf(stderr, "Warning >> can't stat entry : %s\n", newpath);
+ continue;
+ }
+ if(recursive && S_ISDIR(infos.st_mode)
+ && strcmp(namelist[i]->d_name, ".") != 0
+ && strcmp(namelist[i]->d_name, "..") != 0)
+ parse_directory(newpath);
+ /* hlink_check() might be applied more selective ... avoidhlink is only a simple prereq */
+ if(S_ISREG(infos.st_mode)
+ && !(avoidhlinked && hlink_check(&infos))) {
+ parse_file(newpath);
+ }
+ free(namelist[i]);
+ }
+ free(namelist);
}
-int main(int argc,char **argv)
+int main(int argc, char **argv)
{
- parse_options(argc,argv);
- if (optind==argc) usage();
- switch (format)
- {
+ winorunix = one2one;
+ basemap = one2one;
+ parse_options(argc, argv);
+ if(optind == argc)
+ usage();
+ switch (format) {
case 0:
- printf("#EXTM3U%s",eol);
- break;
+ printf("#EXTM3U%s", eol);
+ break;
case 1:
- printf("[playlist]%s",eol);
- break;
+ printf("[playlist]%s", eol);
+ break;
case 2:
- printf("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">%s%s<html>%s%s<head>%s<title>Playlist generated by FAPG " VERSION "</title>%s<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />%s<style type=\"text/css\">%s<!--%s%sbody,td,tr {%s font-family: Verdana, Arial, Helvetica, sans-serif;%s font-size: 12px;%s color: #000000;%s}%s%sbody {%s background: #ffffff;%s}%s%sth {%s text-align: center;%s background: #ffcccc;%s padding-left: 15px;%s padding-right: 15px;%s border: 1px #dd8888 solid;%s}%s%std {%s text-align: center;%s background: #eeeeee;%s padding-left: 15px;%s padding-right: 15px;%s border: 1px #cccccc solid;%s}%s%sh1 {%s font-size: 25px;%s}%s%sp {%s font-size: 10px;%s}%s%sa {%s color: #993333;%s text-decoration: none;%s}%s%sa:hover {%s text-decoration: underline;%s}%s%s-->%s</style>%s</head>%s%s<body>%s%s<h1>Playlist</h1>%s%s<table>%s<tr><th>Entry</th><th>Artist</th><th>Title</th><th>Length</th></tr>%s",eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol);
- break;
+ printf
+ ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">%s%s<html>%s%s<head>%s<title>Playlist generated by FAPG "
+ VERSION
+ "</title>%s<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />%s<style type=\"text/css\">%s<!--%s%sbody,td,tr {%s font-family: Verdana, Arial, Helvetica, sans-serif;%s font-size: 12px;%s color: #000000;%s}%s%sbody {%s background: #ffffff;%s}%s%sth {%s text-align: center;%s background: #ffcccc;%s padding-left: 15px;%s padding-right: 15px;%s border: 1px #dd8888 solid;%s}%s%std {%s text-align: center;%s background: #eeeeee;%s padding-left: 15px;%s padding-right: 15px;%s border: 1px #cccccc solid;%s}%s%sh1 {%s font-size: 25px;%s}%s%sp {%s font-size: 10px;%s}%s%sa {%s color: #993333;%s text-decoration: none;%s}%s%sa:hover {%s text-decoration: underline;%s}%s%s-->%s</style>%s</head>%s%s<body>%s%s<h1>Playlist</h1>%s%s<table>%s<tr><th>Entry</th><th>Artist</th><th>Title</th><th>Length</th></tr>%s",
+ eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol,
+ eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol,
+ eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol,
+ eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol,
+ eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol,
+ eol, eol, eol);
+ break;
case 3:
- { time_t zeit;
- time(&zeit);
- char timebuffer[256];
- strftime(timebuffer,255, "%a %d %b %Y %T %Z", localtime(&zeit) );
- printf("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>%s<!-- generator=\"FAPG " VERSION " -->%s<rss xmlns:itunes=\"http://www.itunes.com/DTDs/Podcast-1.0.dtd\" version=\"2.0\">%s <channel>%s\t<title>%s - %s</title>%s\t<description>Directory Tree %s</description>%s\t<link>%s</link>%s\t<itunes:image href=\"%s/rss/podcast.jpg\"/>%s\t<lastBuildDate>%s</lastBuildDate>%s\t<generator>FAPG " VERSION "</generator>%s\t<image>%s\t\t<url>%s/podcast.jpg</url>%s\t\t<title>Server Logo</title>%s\t\t<link>%s</link>%s\t\t<description>Feed provided by FAPG. Click to visit.</description>%s\t</image>%s\t<itunes:owner>%s\t\t<itunes:name>Admin %s</itunes:name>%s\t\t<itunes:email>podcast@%s</itunes:email>%s\t</itunes:owner>%s\t<category>Various</category>%s\t<itunes:subtitle>Directory Tree %s</itunes:subtitle>%s\t<itunes:author>%s</itunes:author>%s\t<copyright>unknown</copyright>%s\t<language>%s</language>%s\t<itunes:explicit>No</itunes:explicit>%s\t<ttl>1800</ttl>%s",eol,eol,eol,eol,hostname,dir,eol,prefix,eol,base,eol,prefix,eol,timebuffer,eol,eol,eol,base,eol,eol,base,eol,eol,eol,eol,base,eol,hostname,eol,eol,eol,dir,eol,getenv("LOGNAME"),eol,eol,getenv("LANG"),eol,eol,eol);
- }
- break;
- }
- for (;optind<argc;optind++)
- {
-#if 0
- /* activating skip means that all given path components are stripped */
- /* in consequence a list of subdirs is always mapped to the same prefix */
- /* a recommended workaround is to move to the desired subdir and avoid absolute directories in the list */
- if (strlen(prefix)!=0) skip=strlen(argv[optind]);
-#endif
- parse_directory(argv[optind]);
- }
- switch(format)
- {
+ {
+ time_t zeit;
+ char timebuffer[256];
+ time(&zeit);
+ strftime(timebuffer, 255, "%a %d %b %Y %T %z",
+ localtime(&zeit));
+ printf
+ ("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>%s<!-- generator=\"FAPG "
+ VERSION
+ " -->%s<rss xmlns:itunes=\"http://www.itunes.com/DTDs/Podcast-1.0.dtd\" version=\"2.0\">%s <channel>%s\t<title>%s - %s - %s</title>%s\t<description>Directory Tree %s</description>%s\t<link>%s</link>%s\t<itunes:image href=\"%s/xml/podcast.jpg\"/>%s\t<lastBuildDate>%s</lastBuildDate>%s\t<generator>FAPG "
+ VERSION
+ "</generator>%s\t<image>%s\t\t<url>%s/podcast.jpg</url>%s\t\t<title>Server Logo</title>%s\t\t<link>%s</link>%s\t\t<description>Feed provided by FAPG. Click to visit.</description>%s\t</image>%s\t<itunes:owner>%s\t\t<itunes:name>Admin %s</itunes:name>%s\t\t<itunes:email>podcast@%s</itunes:email>%s\t</itunes:owner>%s\t<category>Various</category>%s\t<itunes:subtitle>Directory Tree %s</itunes:subtitle>%s\t<itunes:author>%s</itunes:author>%s\t<copyright>unknown</copyright>%s\t<language>%s</language>%s\t<itunes:explicit>No</itunes:explicit>%s\t<ttl>1800</ttl>%s",
+ eol, eol, eol, eol, hostname, dir, argv[optind], eol,
+ prefix, eol, base, eol, prefix, eol, timebuffer, eol, eol,
+ eol, base, eol, eol, base, eol, eol, eol, eol, base, eol,
+ hostname, eol, eol, eol, dir, eol, getenv("LOGNAME"), eol,
+ eol, getenv("LANG"), eol, eol, eol);
+ unix2dos[38] = 43; // I never made an rss feed work with '&' in it
+ basemap = noand;
+ }
+ break;
+ }
+ for(; optind < argc; optind++) {
+ parse_directory(argv[optind]);
+ }
+ switch (format) {
case 1:
- printf("NumberOfEntries=%d%sVersion=2%s",counter,eol,eol);
- break;
+ printf("NumberOfEntries=%d%sVersion=2%s", counter, eol, eol);
+ break;
case 2:
- printf("</table>%s%s<p>Playlist generated by <a href=\"http://royale.zerezo.com/fapg/\">FAPG " VERSION "</a></p>%s%s</body>%s%s</html>",eol,eol,eol,eol,eol,eol);
- break;
+ printf
+ ("</table>%s%s<p>Playlist generated by <a href=\"http://royale.zerezo.com/fapg/\">FAPG "
+ VERSION "</a></p>%s%s</body>%s%s</html>", eol, eol, eol, eol,
+ eol, eol);
+ break;
case 3:
- printf(" </channel>%s</rss>%s",eol,eol);
- break;
- }
- if (genrelist) free(genrelist);
- exit(0);
+ printf(" </channel>%s</rss>%s", eol, eol);
+ break;
+ }
+ if(genrelist)
+ free(genrelist);
+ exit(0);
}