]> git.saurik.com Git - apt.git/blob - apt-pkg/versionmatch.cc
45cdb117e4a63d2fc282e545a002194145671e8a
[apt.git] / apt-pkg / versionmatch.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: versionmatch.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
4 /* ######################################################################
5
6 Version Matching
7
8 This module takes a matching string and a type and locates the version
9 record that satisfies the constraint described by the matching string.
10
11 ##################################################################### */
12 /*}}}*/
13 // Include Files /*{{{*/
14 #ifdef __GNUG__
15 #pragma implementation "apt-pkg/versionmatch.h"
16 #endif
17 #include <apt-pkg/versionmatch.h>
18
19 #include <apt-pkg/strutl.h>
20 #include <apt-pkg/error.h>
21
22 #include <stdio.h>
23 /*}}}*/
24
25 // VersionMatch::pkgVersionMatch - Constructor /*{{{*/
26 // ---------------------------------------------------------------------
27 /* Break up the data string according to the selected type */
28 pkgVersionMatch::pkgVersionMatch(string Data,MatchType Type) : Type(Type)
29 {
30 if (Type == None || Data.length() < 1)
31 return;
32
33 // Cut up the version representation
34 if (Type == Version)
35 {
36 if (Data.end()[-1] == '*')
37 {
38 VerPrefixMatch = true;
39 VerStr = string(Data.begin(),Data.end()-1);
40 }
41 else
42 VerStr = Data;
43 return;
44 }
45
46 if (Type == Release)
47 {
48 // All empty = match all
49 if (Data == "*")
50 return;
51
52 // Are we a simple specification?
53 const char *I = Data.begin();
54 for (; I < Data.end() && *I != '='; I++);
55 if (I == Data.end())
56 {
57 // Temporary
58 if (isdigit(Data[0]))
59 RelVerStr = Data;
60 else
61 RelArchive = Data;
62
63 if (RelVerStr.end()[-1] == '*')
64 {
65 RelVerPrefixMatch = true;
66 RelVerStr = string(RelVerStr.begin(),RelVerStr.end()-1);
67 }
68 return;
69 }
70
71 char Spec[300];
72 char *Fragments[20];
73 snprintf(Spec,sizeof(Spec),"%s",Data.c_str());
74 if (TokSplitString(',',Spec,Fragments,
75 sizeof(Fragments)/sizeof(Fragments[0])) == false)
76 {
77 Type = None;
78 return;
79 }
80
81 for (unsigned J = 0; Fragments[J] != 0; J++)
82 {
83 if (strlen(Fragments[J]) < 3)
84 continue;
85
86 if (stringcasecmp(Fragments[J],Fragments[J]+2,"v=") == 0)
87 RelVerStr = Fragments[J]+2;
88 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"o=") == 0)
89 RelOrigin = Fragments[J]+2;
90 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"a=") == 0)
91 RelArchive = Fragments[J]+2;
92 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"l=") == 0)
93 RelLabel = Fragments[J]+2;
94 else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0)
95 RelComponent = Fragments[J]+2;
96 }
97
98 if (RelVerStr.end()[-1] == '*')
99 {
100 RelVerPrefixMatch = true;
101 RelVerStr = string(RelVerStr.begin(),RelVerStr.end()-1);
102 }
103 return;
104 }
105
106 if (Type == Origin)
107 {
108 OrSite = Data;
109 return;
110 }
111 }
112 /*}}}*/
113 // VersionMatch::MatchVer - Match a version string with prefixing /*{{{*/
114 // ---------------------------------------------------------------------
115 /* */
116 bool pkgVersionMatch::MatchVer(const char *A,string B,bool Prefix)
117 {
118 const char *Ab = A;
119 const char *Ae = Ab + strlen(A);
120
121 // Strings are not a compatible size.
122 if ((unsigned)(Ae - Ab) != B.length() && Prefix == false ||
123 (unsigned)(Ae - Ab) < B.length())
124 return false;
125
126 // Match (leading?)
127 if (stringcasecmp(B.begin(),B.end(),
128 Ab,Ab + B.length()) == 0)
129 return true;
130
131 return false;
132 }
133 /*}}}*/
134 // VersionMatch::Find - Locate the best match for the select type /*{{{*/
135 // ---------------------------------------------------------------------
136 /* */
137 pkgCache::VerIterator pkgVersionMatch::Find(pkgCache::PkgIterator Pkg)
138 {
139 pkgCache::VerIterator Ver = Pkg.VersionList();
140 for (; Ver.end() == false; Ver++)
141 {
142 if (Type == Version)
143 {
144 if (MatchVer(Ver.VerStr(),VerStr,VerPrefixMatch) == true)
145 return Ver;
146 continue;
147 }
148
149 for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; VF++)
150 if (FileMatch(VF.File()) == true)
151 return Ver;
152 }
153
154 // This will be Ended by now.
155 return Ver;
156 }
157 /*}}}*/
158 // VersionMatch::FileMatch - Match against an index file /*{{{*/
159 // ---------------------------------------------------------------------
160 /* This matcher checks against the release file and the origin location
161 to see if the constraints are met. */
162 bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File)
163 {
164 if (Type == Release)
165 {
166 /* cout << RelVerStr << ',' << RelOrigin << ',' << RelArchive << ',' << RelLabel << endl;
167 cout << File.Version() << ',' << File.Origin() << ',' << File.Archive() << ',' << File.Label() << endl;
168 */
169 if (RelVerStr.empty() == true && RelOrigin.empty() == true &&
170 RelArchive.empty() == true && RelLabel.empty() == true &&
171 RelComponent.empty() == true)
172 return false;
173
174 if (RelVerStr.empty() == false)
175 if (File->Version == 0 ||
176 MatchVer(File.Version(),RelVerStr,RelVerPrefixMatch) == false)
177 return false;
178 if (RelOrigin.empty() == false)
179 if (File->Origin == 0 ||
180 stringcasecmp(RelOrigin,File.Origin()) != 0)
181 return false;
182 if (RelArchive.empty() == false)
183 {
184 if (File->Archive == 0 ||
185 stringcasecmp(RelArchive,File.Archive()) != 0)
186 return false;
187 }
188 if (RelLabel.empty() == false)
189 if (File->Label == 0 ||
190 stringcasecmp(RelLabel,File.Label()) != 0)
191 return false;
192 if (RelComponent.empty() == false)
193 if (File->Component == 0 ||
194 stringcasecmp(RelLabel,File.Component()) != 0)
195 return false;
196 return true;
197 }
198
199 if (Type == Origin)
200 {
201 if (OrSite.empty() == false)
202 if (File->Site == 0 ||
203 OrSite != File.Site())
204 return false;
205 return true;
206 }
207
208 return false;
209 }
210 /*}}}*/