chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / dselect / pkgcmds.cc
1 /*
2  * dselect - Debian package maintenance user interface
3  * pkgcmds.cc - package list keyboard commands
4  *
5  * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6  * Copyright © 2008-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 <string.h>
26 #include <stdio.h>
27
28 #include <dpkg/dpkg.h>
29 #include <dpkg/dpkg-db.h>
30
31 #include "dselect.h"
32 #include "pkglist.h"
33
34 bool
35 packagelist::affectedmatches(struct pkginfo *pkg, struct pkginfo *comparewith) {
36   switch (statsortorder) {
37   case sso_avail:
38     if (comparewith->clientdata->ssavail != pkg->clientdata->ssavail)
39       return false;
40     break;
41   case sso_state:
42     if (comparewith->clientdata->ssstate != pkg->clientdata->ssstate)
43       return false;
44     break;
45   case sso_unsorted:
46     break;
47   default:
48     internerr("unknown statsortorder %d", statsortorder);
49   }
50   if (comparewith->priority != PKG_PRIO_UNSET &&
51       (comparewith->priority != pkg->priority ||
52        (comparewith->priority == PKG_PRIO_OTHER &&
53         strcasecmp(comparewith->otherpriority, pkg->otherpriority))))
54     return false;
55   if (comparewith->section &&
56       strcasecmp(comparewith->section,
57                  pkg->section ?
58                  pkg->section : ""))
59     return false;
60   return true;
61 }
62
63 void packagelist::affectedrange(int *startp, int *endp) {
64   if (table[cursorline]->pkg->set->name) {
65     *startp= cursorline;
66     *endp= cursorline+1;
67     return;
68   }
69   int index = cursorline;
70   while (index < nitems && !table[index]->pkg->set->name)
71     index++;
72   if (index >= nitems) {
73     *startp= *endp= cursorline;
74     return;
75   }
76   *startp= index;
77   while (index < nitems && affectedmatches(table[index]->pkg,table[cursorline]->pkg))
78     index++;
79   *endp= index;
80 }
81
82 void packagelist::movecursorafter(int ncursor) {
83   if (ncursor >= nitems) ncursor= nitems-1;
84   topofscreen += ncursor-cursorline;
85   if (topofscreen > nitems - list_height) topofscreen= nitems - list_height;
86   if (topofscreen < 0) topofscreen= 0;
87   setcursor(ncursor);
88   refreshlist(); redrawthisstate();
89 }
90
91 pkgwant
92 packagelist::reallywant(pkgwant nwarg, struct perpackagestate *pkgstate)
93 {
94   if (nwarg != PKG_WANT_SENTINEL)
95     return nwarg;
96   pkgstatus status = pkgstate->pkg->status;
97   if (status == PKG_STAT_NOTINSTALLED)
98     return PKG_WANT_PURGE;
99   if (status == PKG_STAT_CONFIGFILES)
100     return PKG_WANT_DEINSTALL;
101   return PKG_WANT_INSTALL;
102 }
103
104 void
105 packagelist::setwant(pkgwant nwarg)
106 {
107   int index, top, bot;
108   pkgwant nw;
109
110   if (modstatdb_get_status() == msdbrw_readonly) {
111     beep();
112     return;
113   }
114
115   if (recursive) {
116     redrawitemsrange(cursorline,cursorline+1);
117     table[cursorline]->selected= reallywant(nwarg,table[cursorline]);
118     redraw1item(cursorline);
119     top= cursorline;
120     bot= cursorline+1;
121   } else {
122     packagelist *sub = new packagelist(bindings, nullptr);
123
124     affectedrange(&top,&bot);
125     for (index= top; index < bot; index++) {
126       if (!table[index]->pkg->set->name)
127         continue;
128       nw= reallywant(nwarg,table[index]);
129       if (table[index]->selected == nw ||
130           (table[index]->selected == PKG_WANT_PURGE &&
131            nw == PKG_WANT_DEINSTALL))
132         continue;
133       sub->add(table[index]->pkg,nw);
134     }
135
136     repeatedlydisplay(sub,dp_may,this);
137     for (index=top; index < bot; index++)
138       redraw1item(index);
139   }
140   movecursorafter(bot);
141 }
142
143 bool manual_install = false;
144
145 void packagelist::kd_select()   {
146         manual_install = true;
147         setwant(PKG_WANT_INSTALL);
148         manual_install = false;
149 }
150 void packagelist::kd_hold()     { setwant(PKG_WANT_HOLD);      }
151 void packagelist::kd_deselect() { setwant(PKG_WANT_DEINSTALL); }
152 void packagelist::kd_unhold()   { setwant(PKG_WANT_SENTINEL);  }
153 void packagelist::kd_purge()    { setwant(PKG_WANT_PURGE);     }
154
155 int
156 would_like_to_install(pkgwant wantvalue, pkginfo *pkg)
157 {
158   /* Returns: 1 for yes, 0 for no, -1 for if they want to preserve an error condition. */
159   debug(dbg_general, "would_like_to_install(%d, %s) status %d",
160         wantvalue, pkg_name(pkg, pnaw_always), pkg->status);
161
162   if (wantvalue == PKG_WANT_INSTALL)
163     return 1;
164   if (wantvalue != PKG_WANT_HOLD)
165     return 0;
166   if (pkg->status == PKG_STAT_INSTALLED)
167     return 1;
168   if (pkg->status == PKG_STAT_NOTINSTALLED ||
169       pkg->status == PKG_STAT_CONFIGFILES)
170     return 0;
171   return -1;
172 }
173
174 const char *packagelist::itemname(int index) {
175   return table[index]->pkg->set->name;
176 }
177
178 void packagelist::kd_swapstatorder() {
179   if (sortorder == so_unsorted) return;
180   switch (statsortorder) {
181   case sso_avail:     statsortorder= sso_state;     break;
182   case sso_state:     statsortorder= sso_unsorted;  break;
183   case sso_unsorted:  statsortorder= sso_avail;     break;
184   default:
185     internerr("unknown statsort %d", statsortorder);
186   }
187   resortredisplay();
188 }
189
190 void packagelist::kd_swaporder() {
191   switch (sortorder) {
192   case so_priority:  sortorder= so_section;   break;
193   case so_section:   sortorder= so_alpha;     break;
194   case so_alpha:     sortorder= so_priority;  break;
195   case so_unsorted:                           return;
196   default:
197     internerr("unknown sort %d", sortorder);
198   }
199   resortredisplay();
200 }
201
202 void packagelist::resortredisplay() {
203   const char *oldname = table[cursorline]->pkg->set->name;
204   sortmakeheads();
205   int newcursor;
206   newcursor= 0;
207   if (oldname) {
208     int index;
209     for (index=0; index<nitems; index++) {
210       if (table[index]->pkg->set->name &&
211           strcasecmp(oldname, table[index]->pkg->set->name) == 0) {
212         newcursor= index;
213         break;
214       }
215     }
216   }
217   topofscreen= newcursor-1;
218   if (topofscreen > nitems - list_height) topofscreen= nitems-list_height;
219   if (topofscreen < 0) topofscreen= 0;
220   setwidths();
221   redrawtitle();
222   redrawcolheads();
223   ldrawnstart= ldrawnend= -1;
224   cursorline= -1;
225   setcursor(newcursor);
226   refreshlist();
227 }
228
229 void
230 packagelist::kd_archdisplay()
231 {
232   switch (archdisplayopt) {
233   case ado_both:
234     archdisplayopt = ado_none;
235     break;
236   case ado_none:
237     archdisplayopt = ado_available;
238     break;
239   case ado_available:
240     archdisplayopt = ado_both;
241     break;
242   default:
243     internerr("unknown archdisplayopt %d", archdisplayopt);
244   }
245   setwidths();
246   leftofscreen = 0;
247   ldrawnstart = ldrawnend = -1;
248   redrawtitle();
249   redrawcolheads();
250   redrawitemsrange(topofscreen, min(topofscreen + list_height, nitems));
251   refreshlist();
252 }
253
254 void packagelist::kd_versiondisplay() {
255   switch (versiondisplayopt) {
256   case vdo_both:       versiondisplayopt= vdo_none;       break;
257   case vdo_none:       versiondisplayopt= vdo_available;  break;
258   case vdo_available:  versiondisplayopt= vdo_both;       break;
259   default:
260     internerr("unknown versiondisplayopt %d", versiondisplayopt);
261   }
262   setwidths();
263   leftofscreen= 0;
264   ldrawnstart= ldrawnend= -1;
265   redrawtitle();
266   redrawcolheads();
267   redrawitemsrange(topofscreen, min(topofscreen + list_height, nitems));
268   refreshlist();
269 }
270
271 void packagelist::kd_verbose() {
272   verbose= !verbose;
273   setwidths();
274   leftofscreen= 0;
275   ldrawnstart= ldrawnend= -1;
276   redrawtitle();
277   redrawcolheads();
278   redrawitemsrange(topofscreen, min(topofscreen + list_height, nitems));
279   refreshlist();
280 }
281
282 void packagelist::kd_quit_noop() { }
283
284 void packagelist::kd_revert_abort() {
285   int index;
286   for (index=0; index<nitems; index++) {
287     if (table[index]->pkg->set->name)
288       table[index]->selected= table[index]->original;
289     ldrawnstart= ldrawnend= -1;
290   }
291   refreshlist(); redrawthisstate();
292 }
293
294 void packagelist::kd_revertdirect() {
295   int index;
296   for (index=0; index<nitems; index++) {
297     if (table[index]->pkg->set->name)
298       table[index]->selected= table[index]->direct;
299     ldrawnstart= ldrawnend= -1;
300   }
301   refreshlist(); redrawthisstate();
302 }
303
304 void packagelist::kd_revertsuggest() {
305   int index;
306   for (index=0; index<nitems; index++) {
307     if (table[index]->pkg->set->name)
308       table[index]->selected= table[index]->suggested;
309     ldrawnstart= ldrawnend= -1;
310   }
311   refreshlist(); redrawthisstate();
312 }
313
314 void
315 packagelist::kd_revertinstalled()
316 {
317   int i;
318
319   for (i = 0; i < nitems; i++) {
320     if (table[i]->pkg->set->name)
321       table[i]->selected = reallywant(PKG_WANT_SENTINEL, table[i]);
322     ldrawnstart = ldrawnend = -1;
323   }
324
325   refreshlist();
326   redrawthisstate();
327 }
328
329 /* FIXME: configurable purge/deselect */
330
331 void packagelist::kd_toggleinfo() {
332   showinfo= (showinfo+2) % 3;
333   setheights();
334   if (cursorline >= topofscreen+list_height) topofscreen += list_height;
335   if (topofscreen > nitems - list_height) topofscreen= nitems-list_height;
336   if (topofscreen < 0) topofscreen= 0;
337   infotopofscreen= 0;
338   redraw1item(cursorline);
339   refreshlist();
340   redrawthisstate();
341   redrawinfo();
342 }
343
344 void packagelist::kd_info() {
345   if (!showinfo) {
346     showinfo= 2; kd_toggleinfo();
347   } else {
348     currentinfo++;
349     infotopofscreen=0;
350     redrawinfo();
351   }
352 }