chiark / gitweb /
Abolish shared libdisorder; now we use a static one.
[disorder] / lib / trackname.c
1 /*
2  * This file is part of DisOrder
3  * Copyright (C) 2005, 2006, 2007 Richard Kettlewell
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21 #include <config.h>
22 #include "types.h"
23
24 #include <pcre.h>
25 #include <fnmatch.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "trackname.h"
30 #include "configuration.h"
31 #include "regsub.h"
32 #include "log.h"
33 #include "filepart.h"
34 #include "words.h"
35
36 const char *find_track_root(const char *track) {
37   int n;
38   size_t l, tl = strlen(track);
39
40   for(n = 0; n < config->collection.n; ++n) {
41     l = strlen(config->collection.s[n].root);
42     if(tl > l
43        && !strncmp(track, config->collection.s[n].root, l)
44        && track[l] == '/')
45       break;
46   }
47   if(n >= config->collection.n) {
48     error(0, "found track in no collection '%s'", track);
49     return 0;
50   }
51   return config->collection.s[n].root;
52 }
53
54 const char *track_rootless(const char *track) {
55   const char *root;
56
57   if(!(root = find_track_root(track))) return 0;
58   return track + strlen(root);
59 }
60
61 const char *trackname_part(const char *track,
62                            const char *context,
63                            const char *part) {
64   int n;
65   const char *replaced, *rootless;
66
67   assert(track != 0);
68   if(!strcmp(part, "path")) return track;
69   if(!strcmp(part, "ext")) return extension(track);
70   if((rootless = track_rootless(track))) track = rootless;
71   for(n = 0; n < config->namepart.n; ++n) {
72     if(!strcmp(config->namepart.s[n].part, part)
73        && fnmatch(config->namepart.s[n].context, context, 0) == 0) {
74       if((replaced = regsub(config->namepart.s[n].re,
75                             track,
76                             config->namepart.s[n].replace,
77                             config->namepart.s[n].reflags
78                             |REGSUB_MUST_MATCH
79                             |REGSUB_REPLACE)))
80         return replaced;
81     }
82   }
83   return "";
84 }
85
86 const char *trackname_transform(const char *type,
87                                 const char *subject,
88                                 const char *context) {
89   const char *replaced;
90   int n;
91   const struct transform *k;
92
93   for(n = 0; n < config->transform.n; ++n) {
94     k = &config->transform.t[n];
95     if(strcmp(k->type, type))
96       continue;
97     if(fnmatch(k->context, context, 0) != 0)
98       continue;
99     if((replaced = regsub(k->re, subject, k->replace, k->flags)))
100       subject = replaced;
101   }
102   return subject;
103 }
104
105 int compare_tracks(const char *sa, const char *sb,
106                    const char *da, const char *db,
107                    const char *ta, const char *tb) {
108   int c;
109
110   if((c = strcmp(casefold(sa), casefold(sb)))) return c;
111   if((c = strcmp(sa, sb))) return c;
112   if((c = strcmp(casefold(da), casefold(db)))) return c;
113   if((c = strcmp(da, db))) return c;
114   return compare_path(ta, tb);
115 }
116
117 int compare_path_raw(const unsigned char *ap, size_t an,
118                      const unsigned char *bp, size_t bn) {
119   while(an > 0 && bn > 0) {
120     if(*ap == *bp) {
121       ap++;
122       bp++;
123       an--;
124       bn--;
125     } else if(*ap == '/') {
126       return -1;                /* /a/b < /aa/ */
127     } else if(*bp == '/') {
128       return 1;                 /* /aa > /a/b */
129     } else
130       return *ap - *bp;
131   }
132   if(an > 0)
133     return 1;                   /* /a/b > /a and /ab > /a */
134   else if(bn > 0)
135     return -1;                  /* /a < /ab and /a < /a/b */
136   else
137     return 0;
138 }
139
140 /*
141 Local Variables:
142 c-basic-offset:2
143 comment-column:40
144 fill-column:79
145 End:
146 */