chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / dselect / pkgsublist.cc
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 }