Commit | Line | Data |
---|---|---|
1479465f GJ |
1 | /* |
2 | * dselect - Debian package maintenance user interface | |
3 | * pkgsublist.cc - status modification and recursive package list handling | |
4 | * | |
5 | * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk> | |
6 | * Copyright © 2007-2014 Guillem Jover <guillem@debian.org> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | |
20 | */ | |
21 | ||
22 | #include <config.h> | |
23 | #include <compat.h> | |
24 | ||
25 | #include <assert.h> | |
26 | #include <string.h> | |
27 | #include <stdio.h> | |
28 | ||
29 | #include <dpkg/i18n.h> | |
30 | #include <dpkg/dpkg.h> | |
31 | #include <dpkg/dpkg-db.h> | |
32 | ||
33 | #include "dselect.h" | |
34 | #include "bindings.h" | |
35 | ||
36 | void packagelist::add(pkginfo *pkg) { | |
37 | debug(dbg_general, "packagelist[%p]::add(pkginfo %s)", | |
38 | this, pkg_name(pkg, pnaw_always)); | |
39 | if (!recursive || // never add things to top level | |
40 | !pkg->clientdata || // don't add pure virtual packages | |
41 | pkg->clientdata->uprec) // don't add ones already in the recursive list | |
42 | return; | |
43 | debug(dbg_general, "packagelist[%p]::add(pkginfo %s) adding", | |
44 | this, pkg_name(pkg, pnaw_always)); | |
45 | perpackagestate *state= &datatable[nitems]; | |
46 | state->pkg= pkg; | |
47 | state->direct= state->original= pkg->clientdata->selected; | |
48 | state->suggested= state->selected= pkg->clientdata->selected; | |
49 | state->spriority= sp_inherit; state->dpriority= dp_none; | |
50 | state->uprec= pkg->clientdata; | |
51 | state->relations.init(); | |
52 | pkg->clientdata= state; | |
53 | table[nitems]= state; | |
54 | nitems++; | |
55 | } | |
56 | ||
57 | void | |
58 | packagelist::add(pkginfo *pkg, pkgwant nw) | |
59 | { | |
60 | debug(dbg_general, "packagelist[%p]::add(pkginfo %s, %s)", | |
61 | this, pkg_name(pkg, pnaw_always), wantstrings[nw]); | |
62 | add(pkg); if (!pkg->clientdata) return; | |
63 | pkg->clientdata->direct= nw; | |
64 | selpriority np; | |
65 | np= would_like_to_install(nw,pkg) ? sp_selecting : sp_deselecting; | |
66 | if (pkg->clientdata->spriority > np) return; | |
67 | debug(dbg_general, "packagelist[%p]::add(pkginfo %s, %s) setting", | |
68 | this, pkg_name(pkg, pnaw_always), wantstrings[nw]); | |
69 | pkg->clientdata->suggested= pkg->clientdata->selected= nw; | |
70 | pkg->clientdata->spriority= np; | |
71 | } | |
72 | ||
73 | void packagelist::add(pkginfo *pkg, const char *extrainfo, showpriority showimp) { | |
74 | debug(dbg_general, "packagelist[%p]::add(pkginfo %s, ..., showpriority %d)", | |
75 | this, pkg_name(pkg, pnaw_always), showimp); | |
76 | add(pkg); if (!pkg->clientdata) return; | |
77 | if (pkg->clientdata->dpriority < showimp) pkg->clientdata->dpriority= showimp; | |
78 | pkg->clientdata->relations(extrainfo); | |
79 | } | |
80 | ||
81 | bool | |
82 | packagelist::alreadydone(doneent **done, void *check) | |
83 | { | |
84 | doneent *search = *done; | |
85 | ||
86 | while (search && search->dep != check) | |
87 | search = search->next; | |
88 | if (search) | |
89 | return true; | |
90 | debug(dbg_general, "packagelist[%p]::alreadydone(%p, %p) new", | |
91 | this, done, check); | |
92 | search= new doneent; | |
93 | search->next= *done; | |
94 | search->dep= check; | |
95 | *done= search; | |
96 | return false; | |
97 | } | |
98 | ||
99 | void packagelist::addunavailable(deppossi *possi) { | |
100 | debug(dbg_general, "packagelist[%p]::addunavail(%p)", this, possi); | |
101 | ||
102 | if (!recursive) return; | |
103 | if (alreadydone(&unavdone,possi)) return; | |
104 | ||
105 | assert(possi->up->up->clientdata); | |
106 | assert(possi->up->up->clientdata->uprec); | |
107 | ||
108 | varbuf& vb= possi->up->up->clientdata->relations; | |
109 | vb(possi->ed->name); | |
110 | vb(_(" does not appear to be available\n")); | |
111 | } | |
112 | ||
113 | bool | |
114 | packagelist::add(dependency *depends, showpriority displayimportance) | |
115 | { | |
116 | debug(dbg_general, "packagelist[%p]::add(dependency[%p])", this, depends); | |
117 | ||
118 | if (alreadydone(&depsdone, depends)) | |
119 | return false; | |
120 | ||
121 | const char *comma= ""; | |
122 | varbuf depinfo; | |
123 | depinfo(depends->up->set->name); | |
124 | depinfo(' '); | |
125 | depinfo(gettext(relatestrings[depends->type])); | |
126 | depinfo(' '); | |
127 | deppossi *possi; | |
128 | for (possi=depends->list; | |
129 | possi; | |
130 | possi=possi->next, comma=(possi && possi->next ? ", " : _(" or "))) { | |
131 | depinfo(comma); | |
132 | depinfo(possi->ed->name); | |
133 | if (possi->verrel != DPKG_RELATION_NONE) { | |
134 | switch (possi->verrel) { | |
135 | case DPKG_RELATION_LE: | |
136 | depinfo(" (<= "); | |
137 | break; | |
138 | case DPKG_RELATION_GE: | |
139 | depinfo(" (>= "); | |
140 | break; | |
141 | case DPKG_RELATION_LT: | |
142 | depinfo(" (<< "); | |
143 | break; | |
144 | case DPKG_RELATION_GT: | |
145 | depinfo(" (>> "); | |
146 | break; | |
147 | case DPKG_RELATION_EQ: | |
148 | depinfo(" (= "); | |
149 | break; | |
150 | default: | |
151 | internerr("unknown dpkg_relation %d", possi->verrel); | |
152 | } | |
153 | depinfo(versiondescribe(&possi->version, vdew_nonambig)); | |
154 | depinfo(")"); | |
155 | } | |
156 | } | |
157 | depinfo('\n'); | |
158 | add(depends->up, depinfo.string(), displayimportance); | |
159 | for (possi=depends->list; possi; possi=possi->next) { | |
160 | add(&possi->ed->pkg, depinfo.string(), displayimportance); | |
161 | if (depends->type != dep_provides) { | |
162 | /* Providers are not relevant if we are looking at a provider | |
163 | * relationship already. */ | |
164 | deppossi *provider; | |
165 | for (provider = possi->ed->depended.available; | |
166 | provider; | |
167 | provider = provider->rev_next) { | |
168 | if (provider->up->type != dep_provides) continue; | |
169 | add(provider->up->up, depinfo.string(), displayimportance); | |
170 | add(provider->up,displayimportance); | |
171 | } | |
172 | } | |
173 | } | |
174 | return true; | |
175 | } | |
176 | ||
177 | void repeatedlydisplay(packagelist *sub, | |
178 | showpriority initial, | |
179 | packagelist *unredisplay) { | |
180 | pkginfo **newl; | |
181 | keybindings *kb; | |
182 | ||
183 | debug(dbg_general, "repeatedlydisplay(packagelist[%p])", sub); | |
184 | if (sub->resolvesuggest() != 0 && sub->deletelessimp_anyleft(initial)) { | |
185 | debug(dbg_general, "repeatedlydisplay(packagelist[%p]) once", sub); | |
186 | if (unredisplay) unredisplay->enddisplay(); | |
187 | for (;;) { | |
188 | /* Reset manual_install flag now that resolvesuggest() has seen it. */ | |
189 | manual_install = false; | |
190 | newl= sub->display(); | |
191 | if (!newl) break; | |
192 | debug(dbg_general, "repeatedlydisplay(packagelist[%p]) newl", sub); | |
193 | kb= sub->bindings; delete sub; | |
194 | sub= new packagelist(kb,newl); | |
195 | if (sub->resolvesuggest() <= 1) break; | |
196 | if (!sub->deletelessimp_anyleft(dp_must)) break; | |
197 | debug(dbg_general, "repeatedlydisplay(packagelist[%p]) again", sub); | |
198 | } | |
199 | if (unredisplay) unredisplay->startdisplay(); | |
200 | } | |
201 | debug(dbg_general, "repeatedlydisplay(packagelist[%p]) done", sub); | |
202 | delete sub; | |
203 | } | |
204 | ||
205 | int packagelist::deletelessimp_anyleft(showpriority than) { | |
206 | debug(dbg_general, "packagelist[%p]::dli_al(%d): nitems=%d", | |
207 | this, than, nitems); | |
208 | int insat, runthr; | |
209 | for (runthr=0, insat=0; | |
210 | runthr < nitems; | |
211 | runthr++) { | |
212 | if (table[runthr]->dpriority < than) { | |
213 | table[runthr]->free(recursive); | |
214 | } else { | |
215 | if (insat != runthr) table[insat]= table[runthr]; | |
216 | insat++; | |
217 | } | |
218 | } | |
219 | nitems= insat; | |
220 | debug(dbg_general, "packagelist[%p]::dli_al(%d) done; nitems=%d", | |
221 | this, than, nitems); | |
222 | return nitems; | |
223 | } |