]> cygwin.com Git - cygwin-apps/setup.git/blame - choose.cc
2001-11-30 Robert Collins <rbtcollins@hotmail.com>
[cygwin-apps/setup.git] / choose.cc
CommitLineData
23c9e63c 1/*
3467d79f 2 * Copyright (c) 2000, 2001 Red Hat, Inc.
23c9e63c
DD
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by DJ Delorie <dj@cygnus.com>
13 *
14 */
15
16/* The purpose of this file is to let the user choose which packages
17 to install, and which versions of the package when more than one
18 version is provided. The "trust" level serves as an indication as
19 to which version should be the default choice. At the moment, all
20 we do is compare with previously installed packages to skip any
21 that are already installed (by setting the action to ACTION_SAME).
22 While the "trust" stuff is supported, it's not really implemented
23 yet. We always prefer the "current" option. In the future, this
24 file might have a user dialog added to let the user choose to not
25 install packages, or to install packages that aren't installed by
26 default. */
27
4bb38dfa
RC
28#if 0
29static const char *cvsid =
f557695e 30 "\n%%% $Id$\n";
4bb38dfa 31#endif
8507f105 32
23c9e63c
DD
33#include "win32.h"
34#include <stdio.h>
713bbe5f 35#include <stdlib.h>
60c632b3 36#include <io.h>
713bbe5f
DD
37#include <ctype.h>
38
23c9e63c
DD
39#include "dialog.h"
40#include "resource.h"
41#include "state.h"
42#include "ini.h"
43#include "concat.h"
44#include "msg.h"
89b1a15b 45#include "log.h"
4a83b7b0 46#include "find.h"
fb087b80 47#include "filemanip.h"
b24c88b3 48#include "io_stream.h"
8f53e82a 49#include "choose.h"
7b606ae5 50#include "category.h"
23c9e63c 51
7939f6d1
RC
52#include "package_db.h"
53#include "package_meta.h"
fa0c0d10 54#include "package_version.h"
7939f6d1 55
60c632b3
CV
56#include "port.h"
57
ee411d77
CF
58#define alloca __builtin_alloca
59
60c632b3 60#define HMARGIN 10
3b9077d4
DD
61#define ROW_MARGIN 5
62#define ICON_MARGIN 4
08f8c762 63#define NEW_COL_SIZE_SLOP (ICON_MARGIN + 11)
3b9077d4
DD
64
65#define CHECK_SIZE 11
713bbe5f 66
713bbe5f
DD
67static int initialized = 0;
68
713bbe5f
DD
69static int scroll_ulc_x, scroll_ulc_y;
70
42bf5b92 71static HWND lv, nextbutton, choose_inst_text;
713bbe5f
DD
72static TEXTMETRIC tm;
73static int header_height;
74static HANDLE sysfont;
75static int row_height;
3b9077d4 76static HANDLE bm_spin, bm_rtarrow, bm_checkyes, bm_checkno, bm_checkna;
713bbe5f 77static HDC bitmap_dc;
8f53e82a 78static view *chooser = NULL;
06560feb 79static trusts deftrust = TRUST_UNKNOWN;
8f53e82a
RC
80
81static struct _header pkg_headers[] = {
f557695e
RC
82 {"Current", 7, 0, 0},
83 {"New", 3, 0, 0},
84 {"Src?", 4, 0, 0},
85 {"Category", 8, 0, 0},
86 {"Package", 7, 0, 0},
87 {0, 0, 0, 0}
8f53e82a 88};
713bbe5f 89
8f53e82a 90static struct _header cat_headers[] = {
f557695e
RC
91 {"Category", 8, 0, 0},
92 {"Current", 7, 0, 0},
93 {"New", 3, 0, 0},
94 {"Src?", 4, 0, 0},
95 {"Package", 7, 0, 0},
96 {0, 0, 0, 0}
713bbe5f
DD
97};
98
4fe323f9 99static int add_required (packagemeta & pkg, size_t depth = 0);
8f53e82a
RC
100static void set_view_mode (HWND h, views mode);
101
bb849dbd 102#define pkgtrustp(pkg,t) (packageversion *)(t==TRUST_PREV ? pkg->prev : t == TRUST_CURR ? pkg->curr : pkg->exp)
6a748750 103
68b27c12 104/* Set the next action given a current action. */
c46a33a9 105static void
bb849dbd 106set_action (packagemeta * pkg)
c46a33a9 107{
bb849dbd
RC
108/* actions are the following:
109
110 for install modes (from net/local)
111 for each version:
112 install this version
113 install the source for this version
114 and a boolean flag - force install to allow reinstallation, or bypassing requirements
115 globally:
116 install the source for the current version.
117
118 to uninstall a package, the desired version is set to NULL;
119
120 for mirroring modes (download only)
121 for each version
122 download this version
123 download source for this version
124
125 these are represented by the following:
126 the desired pointer in the packagemetadata indicated which version we are operating on.
127 if we are operating on the installed version, reinstall is a valid option.
128 for the selected version, forceinstall means Do an install no matter what, and
129 srcpicked means download the source.
130
131 The default action for any installed package is to install the 'curr version'
132 if it is not already installed.
133
134 The default action for any non-installed package is to do nothing.
135
136 To achieve a no-op, set desired==installed, and if (installed) set forceinstall=0 and
137 srcpicked = 0;
138
139 Iteration through versions should follow the following rules:
140 selected radio button (prev/curr/test) (show as reinstall if that is the
141 current version) ->source only (only if the package is installed) ->oldest version....skip version of radio button...
142 newest version->uninstall->no-op->selected radio button.
143
144 If any state cannot be set (ie because (say) no prev entry exists for a package
145 simply progress to the next option.
146
147 */
148
149 /* We were set to uninstall the package */
150 if (!pkg->desired && pkg->installed)
3467d79f 151 {
bb849dbd
RC
152 /* No-op - keep whatever we've got */
153 pkg->desired = pkg->installed;
154 if (pkg->desired)
155 {
156 pkg->desired->binpicked = 0;
157 pkg->desired->srcpicked = 0;
158 }
159 return;
90d14922 160 }
bb849dbd
RC
161 else if (pkg->desired == pkg->installed
162 && (!pkg->installed
163 || !(pkg->installed->binpicked || pkg->installed->srcpicked)))
164 /* Install the default trust version - this is a 'reinstall' for installed
165 * packages */
166 {
167 pkg->desired = NULL;
168 /* No-op */
169 pkg->desired = pkgtrustp (pkg, deftrust);
170 if (pkg->desired)
171 {
172 pkg->desired->binpicked = 1;
d4a4527d 173 return;
bb849dbd
RC
174 }
175 }
176 /* are we currently on the radio button selection and installed */
177 if (pkg->desired == pkgtrustp (pkg, deftrust) && pkg->installed &&
4fe323f9
RC
178 (!pkg->desired || pkg->desired->binpicked)
179 && (pkg->desired->src.Cached () || pkg->desired->src.sites.number ()))
bb849dbd 180 {
bb849dbd
RC
181 /* source only this file */
182 pkg->desired = pkg->installed;
183 pkg->desired->binpicked = 0;
184 pkg->desired->srcpicked = 1;
185 return;
186 }
187 /* are we currently on source only or on the radio button but not installed */
188 else if ((pkg->desired == pkg->installed && pkg->installed
189 && pkg->installed->srcpicked) ||
190 pkg->desired == pkgtrustp (pkg, deftrust))
191 {
192 /* move onto the loop through versions */
193 pkg->desired = pkg->versions.getnth (1);
194 if (pkg->desired == pkgtrustp (pkg, deftrust))
195 pkg->desired =
196 pkg->versions.number () > 1 ? pkg->versions.getnth (2) : NULL;
197 if (pkg->desired)
d4a4527d 198 {
bb849dbd
RC
199 pkg->desired->binpicked = 1;
200 pkg->desired->srcpicked = 0;
1fb09149 201 }
bb849dbd
RC
202 return;
203 }
204 else
205 {
206 /* preserve the src tick box */
207 int source = pkg->desired->srcpicked;
208 /* bump the version selected, skipping the radio button trust along the way */
209 size_t n;
210 for (n = 1;
211 n <= pkg->versions.number ()
212 && pkg->desired != pkg->versions.getnth (n); n++);
213 /* n points at pkg->desired */
214 n++;
215 if (n <= pkg->versions.number ())
1fb09149 216 {
bb849dbd
RC
217 if (pkgtrustp (pkg, deftrust) == pkg->versions.getnth (n))
218 n++;
219 if (n <= pkg->versions.number ())
1fb09149 220 {
bb849dbd
RC
221 pkg->desired = pkg->versions.getnth (n);
222 pkg->desired->srcpicked = source;
1fb09149
CF
223 return;
224 }
225 }
bb849dbd
RC
226 /* went past the end - uninstall the package */
227 pkg->desired = NULL;
228 }
c46a33a9 229}
713bbe5f 230
8f53e82a 231static int
bb849dbd 232add_required (packagemeta & pkg, size_t depth = 0)
8f53e82a
RC
233{
234 Dependency *dp;
bb849dbd 235 packagemeta *required;
8f53e82a 236 int changed = 0;
bb849dbd
RC
237 if (!pkg.desired
238 || (pkg.desired != pkg.installed && !pkg.desired->binpicked))
239 /* uninstall || source only */
240 return 0;
241
242 dp = pkg.desired->required;
243 packagedb db;
244 /* cheap test for too much recursion */
4fe323f9 245 if (depth > 5)
bb849dbd 246 return 0;
8f53e82a
RC
247 while (dp)
248 {
bb849dbd 249 if ((required = db.getpackagebyname (dp->package)) == NULL)
1fb09149 250 {
f557695e 251 dp = dp->next;
bb849dbd 252 changed++;
1fb09149
CF
253 continue;
254 }
bb849dbd 255 if (!required->desired)
d4a4527d 256 {
bb849dbd
RC
257 /* it's set to uninstall */
258 set_action (required);
d4a4527d 259 }
bb849dbd
RC
260 else if (required->desired != required->installed
261 && !required->desired->binpicked)
262 {
263 /* it's set to change to a different version source only */
264 required->desired->binpicked = 1;
265 }
266 /* does this requirement have requirements? */
267 changed += add_required (*required, depth + 1);
f557695e 268 dp = dp->next;
8f53e82a
RC
269 }
270 return changed;
271}
272
68b27c12 273/* Return an appropriate caption given the current action. */
bb849dbd
RC
274char const *
275choose_caption (packagemeta * pkg)
c46a33a9 276{
bb849dbd
RC
277 if (!pkg->desired && pkg->installed)
278 return "Uninstall";
279 else if (!pkg->desired)
280 return "Skip";
281 else if (pkg->desired == pkg->installed && pkg->desired->binpicked)
282 return source == IDC_SOURCE_DOWNLOAD ? "Retrieve" : "Reinstall";
283 else if (pkg->desired == pkg->installed && pkg->desired->srcpicked)
284 /* FIXME: Redo source should come up if the tarball is already present locally */
285 return "Source";
286 else if (pkg->desired == pkg->installed) /* and neither src nor bin */
287 return "Keep";
288 else
289 return pkg->desired->Canonical_version ();
c46a33a9 290}
713bbe5f
DD
291
292static void
293paint (HWND hwnd)
23c9e63c 294{
713bbe5f
DD
295 HDC hdc;
296 PAINTSTRUCT ps;
4bb38dfa 297 int x, y, i, ii;
23c9e63c 298
713bbe5f 299 hdc = BeginPaint (hwnd, &ps);
23c9e63c 300
713bbe5f 301 SelectObject (hdc, sysfont);
fb087b80 302 SetBkColor (hdc, GetSysColor (COLOR_WINDOW));
9eeb0e83 303 SetTextColor (hdc, GetSysColor (COLOR_WINDOWTEXT));
23c9e63c 304
713bbe5f
DD
305 RECT cr;
306 GetClientRect (hwnd, &cr);
307
308 POINT p;
309
310 x = cr.left - scroll_ulc_x;
311 y = cr.top - scroll_ulc_y + header_height;
312
313
f557695e 314 for (i = 0; i <= chooser->last_col; i++)
23c9e63c 315 {
2dada532
CF
316 TextOut (hdc, x + chooser->headers[i].x, 3, chooser->headers[i].text,
317 chooser->headers[i].slen);
f557695e 318 MoveToEx (hdc, x + chooser->headers[i].x, header_height - 3, &p);
2dada532 319 LineTo (hdc, x + chooser->headers[i].x + chooser->headers[i].width,
f557695e 320 header_height - 3);
713bbe5f
DD
321 }
322
f557695e
RC
323 IntersectClipRect (hdc, cr.left, cr.top + header_height, cr.right,
324 cr.bottom);
713bbe5f 325
8f53e82a 326 for (ii = 0; ii < chooser->nlines; ii++)
f557695e
RC
327 chooser->lines[ii].paint (hdc, x, y, ii,
328 (chooser->get_view_mode () ==
329 VIEW_CATEGORY) ? 0 : 1);
5f48f258 330
8f53e82a 331 if (chooser->nlines == 0)
5f48f258 332 {
4bb38dfa 333 static const char *msg = "Nothing to Install/Update";
60c632b3 334 if (source == IDC_SOURCE_DOWNLOAD)
47f8d8b3 335 msg = "Nothing to Download";
5f48f258
DD
336 TextOut (hdc, HMARGIN, header_height, msg, strlen (msg));
337 }
fb087b80 338
713bbe5f
DD
339 EndPaint (hwnd, &ps);
340}
341
342static void
343scroll_common (HWND hwnd, int which, int *var, int code)
344{
713bbe5f
DD
345 SCROLLINFO si;
346 si.cbSize = sizeof (si);
347 si.fMask = SIF_ALL;
348 GetScrollInfo (hwnd, which, &si);
349
350 switch (code)
23c9e63c 351 {
713bbe5f
DD
352 case SB_THUMBTRACK:
353 si.nPos = si.nTrackPos;
354 break;
355 case SB_THUMBPOSITION:
356 break;
357 case SB_BOTTOM:
358 si.nPos = si.nMax;
359 break;
360 case SB_TOP:
361 si.nPos = 0;
362 break;
363 case SB_LINEDOWN:
364 si.nPos += row_height;
365 break;
366 case SB_LINEUP:
367 si.nPos -= row_height;
368 break;
369 case SB_PAGEDOWN:
f557695e 370 si.nPos += si.nPage * 9 / 10;
713bbe5f
DD
371 break;
372 case SB_PAGEUP:
f557695e 373 si.nPos -= si.nPage * 9 / 10;
713bbe5f
DD
374 break;
375 }
376
f557695e 377 if ((int) si.nPos < 0)
713bbe5f 378 si.nPos = 0;
4bb38dfa 379 if (si.nPos + si.nPage > (unsigned int) si.nMax)
713bbe5f
DD
380 si.nPos = si.nMax - si.nPage;
381
382 si.fMask = SIF_POS;
383 SetScrollInfo (hwnd, which, &si, TRUE);
384
385 int ox = scroll_ulc_x;
386 int oy = scroll_ulc_y;
387 *var = si.nPos;
388
389 RECT cr, sr;
390 GetClientRect (hwnd, &cr);
391 sr = cr;
392 sr.top += header_height;
393 ScrollWindow (hwnd, ox - scroll_ulc_x, oy - scroll_ulc_y, &sr, &sr);
394 sr.bottom = sr.top;
395 sr.top = cr.top;
396 ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr);
397}
398
399static LRESULT CALLBACK
400list_vscroll (HWND hwnd, HWND hctl, UINT code, int pos)
401{
402 scroll_common (hwnd, SB_VERT, &scroll_ulc_y, code);
2399c54d 403 return 0;
713bbe5f
DD
404}
405
406static LRESULT CALLBACK
407list_hscroll (HWND hwnd, HWND hctl, UINT code, int pos)
408{
409 scroll_common (hwnd, SB_HORZ, &scroll_ulc_x, code);
2399c54d 410 return 0;
713bbe5f
DD
411}
412
413static LRESULT CALLBACK
414list_click (HWND hwnd, BOOL dblclk, int x, int y, UINT hitCode)
415{
f557695e 416 int row, refresh;
713bbe5f 417
8f53e82a 418 if (chooser->nlines == 0)
8cfbc487
DD
419 return 0;
420
713bbe5f
DD
421 if (y < header_height)
422 return 0;
423 x += scroll_ulc_x;
424 y += scroll_ulc_y - header_height;
425
f557695e 426 row = (y + ROW_MARGIN / 2) / row_height;
713bbe5f 427
42a99ed1 428 if (row < 0 || row >= chooser->nlines)
713bbe5f
DD
429 return 0;
430
42a99ed1 431 refresh = chooser->click (row, x);
f557695e 432
8f53e82a
RC
433 if (refresh)
434 {
435 RECT r;
436 GetClientRect (lv, &r);
437 SCROLLINFO si;
438 memset (&si, 0, sizeof (si));
439 si.cbSize = sizeof (si);
f557695e 440 si.fMask = SIF_ALL; /* SIF_RANGE was giving strange behaviour */
8f53e82a 441 si.nMin = 0;
713bbe5f 442
8f53e82a
RC
443 si.nMax = chooser->nlines * row_height;
444 si.nPage = r.bottom - header_height;
42a99ed1
RC
445
446 /* if we are under the minimum display count ,
447 * set the offset to 0
448 */
4bb38dfa 449 if ((unsigned int) si.nMax <= si.nPage)
42a99ed1 450 scroll_ulc_y = 0;
8f53e82a 451 si.nPos = scroll_ulc_y;
42a99ed1 452
8f53e82a 453 SetScrollInfo (lv, SB_VERT, &si, TRUE);
3b9077d4 454
8f53e82a 455 InvalidateRect (lv, &r, TRUE);
713bbe5f 456
8f53e82a
RC
457 }
458 else
459 {
460 RECT rect;
461 rect.left = chooser->headers[chooser->new_col].x - scroll_ulc_x;
462 rect.right = chooser->headers[chooser->src_col + 1].x - scroll_ulc_x;
42a99ed1 463 rect.top = header_height + row * row_height - scroll_ulc_y;
8f53e82a
RC
464 rect.bottom = rect.top + row_height;
465 InvalidateRect (hwnd, &rect, TRUE);
466 }
2399c54d 467 return 0;
713bbe5f
DD
468}
469
470static LRESULT CALLBACK
471listview_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
472{
6a748750
CF
473 switch (message)
474 {
475 case WM_HSCROLL:
476 return HANDLE_WM_HSCROLL (hwnd, wParam, lParam, list_hscroll);
477 case WM_VSCROLL:
478 return HANDLE_WM_VSCROLL (hwnd, wParam, lParam, list_vscroll);
479 case WM_LBUTTONDOWN:
480 return HANDLE_WM_LBUTTONDOWN (hwnd, wParam, lParam, list_click);
481 case WM_PAINT:
482 paint (hwnd);
483 return 0;
484 default:
485 return DefWindowProc (hwnd, message, wParam, lParam);
486 }
713bbe5f
DD
487}
488
489static void
490register_windows (HINSTANCE hinst)
491{
492 WNDCLASSEX wcex;
493 static int done = 0;
494
495 if (done)
496 return;
497 done = 1;
498
499 memset (&wcex, 0, sizeof (wcex));
500 wcex.cbSize = sizeof (WNDCLASSEX);
501 wcex.style = CS_HREDRAW | CS_VREDRAW;
502 wcex.lpfnWndProc = listview_proc;
503 wcex.hInstance = hinst;
504 wcex.hIcon = LoadIcon (0, IDI_APPLICATION);
505 wcex.hCursor = LoadCursor (0, IDC_ARROW);
6a748750 506 wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
713bbe5f
DD
507 wcex.lpszClassName = "listview";
508
509 RegisterClassEx (&wcex);
510}
511
512static void
4bb38dfa 513note_width (struct _header *hdrs, HDC dc, const char *string, int addend,
f557695e 514 int column)
713bbe5f
DD
515{
516 if (!string)
517 return;
518 SIZE s;
519 GetTextExtentPoint32 (dc, string, strlen (string), &s);
8f53e82a
RC
520 if (hdrs[column].width < s.cx + addend)
521 hdrs[column].width = s.cx + addend;
713bbe5f
DD
522}
523
60c632b3
CV
524static void
525set_existence ()
526{
bb849dbd
RC
527 /* FIXME:
528 iterate through the package list, and delete packages that are
529 * Not installed
530 * have no mirror site
531 and then do the same for categories with no packages.
532 */
713bbe5f
DD
533}
534
8f53e82a
RC
535static void
536fill_missing_category ()
537{
7b606ae5 538 packagedb db;
bb849dbd
RC
539 for (packagemeta * pkg = db.getfirstpackage (); pkg;
540 pkg = db.getnextpackage ())
4fe323f9
RC
541 if (!pkg->Categories.number ())
542 pkg->add_category (db.categories.registerbykey ("Misc"));
3467d79f
CF
543}
544
713bbe5f 545static void
c46a33a9 546default_trust (HWND h, trusts trust)
713bbe5f 547{
06560feb 548 deftrust = trust;
bb849dbd
RC
549 packagedb db;
550 for (packagemeta * pkg = db.getfirstpackage (); pkg;
551 pkg = db.getnextpackage ())
552 {
4fe323f9
RC
553 if (pkg->installed
554 || pkg->Categories.getbykey (db.categories.registerbykey ("Base"))
555 || pkg->Categories.getbykey (db.categories.registerbykey ("Misc")))
bb849dbd
RC
556 {
557 pkg->desired = pkgtrustp (pkg, trust);
558 if (pkg->desired)
559 {
560 pkg->desired->binpicked =
561 pkg->desired == pkg->installed ? 0 : 1;
562 pkg->desired->srcpicked = 0;
563 }
564 }
565 else
566 pkg->desired = 0;
567 }
713bbe5f
DD
568 RECT r;
569 GetClientRect (h, &r);
570 InvalidateRect (h, &r, TRUE);
571 if (nextbutton)
572 SetFocus (nextbutton);
573}
574
8f53e82a 575void
bb849dbd 576pick_line::set_line (packagemeta * _pkg)
8f53e82a
RC
577{
578 pkg = _pkg;
579 cat = NULL;
580}
581
582void
f557695e 583pick_line::set_line (Category * _cat)
8f53e82a
RC
584{
585 cat = _cat;
586 pkg = NULL;
587}
588
589void
590pick_line::paint (HDC hdc, int x, int y, int row, int show_cat)
591{
592 int r = y + row * row_height;
593 int by = r + tm.tmHeight - 11;
594 if (pkg)
595 {
596 if (pkg->installed)
1fb09149
CF
597 {
598 TextOut (hdc, x + chooser->headers[chooser->current_col].x, r,
bb849dbd
RC
599 pkg->installed->Canonical_version (),
600 strlen (pkg->installed->Canonical_version ()));
1fb09149
CF
601 SelectObject (bitmap_dc, bm_rtarrow);
602 BitBlt (hdc, x + chooser->headers[chooser->current_col].x
f557695e
RC
603 + chooser->headers[0].width + ICON_MARGIN / 2
604 + HMARGIN / 2, by, 11, 11, bitmap_dc, 0, 0, SRCCOPY);
1fb09149 605 }
8f53e82a
RC
606
607 const char *s = choose_caption (pkg);
2dada532 608 TextOut (hdc, x + chooser->headers[chooser->new_col].x
f557695e 609 + NEW_COL_SIZE_SLOP, r, s, strlen (s));
8f53e82a
RC
610 SelectObject (bitmap_dc, bm_spin);
611 BitBlt (hdc, x + chooser->headers[chooser->new_col].x, by, 11, 11,
1fb09149 612 bitmap_dc, 0, 0, SRCCOPY);
8f53e82a
RC
613
614 HANDLE check_bm;
bb849dbd
RC
615 if ( /* uninstall */ !pkg->desired ||
616 /* source only */ (!pkg->desired->binpicked
617 && pkg->desired->srcpicked) ||
618 /* when no source mirror available */
619 !pkg->desired->src.sites.number ())
1fb09149 620 check_bm = bm_checkna;
bb849dbd 621 else if (pkg->desired->srcpicked)
1fb09149 622 check_bm = bm_checkyes;
8f53e82a 623 else
1fb09149 624 check_bm = bm_checkno;
8f53e82a
RC
625
626 SelectObject (bitmap_dc, check_bm);
627 BitBlt (hdc, x + chooser->headers[chooser->src_col].x, by, 11, 11,
1fb09149 628 bitmap_dc, 0, 0, SRCCOPY);
8f53e82a 629
2dada532 630 /* shows "first" category - do we want to show any? */
4fe323f9 631 if (pkg->Categories.number () && show_cat)
2dada532 632 TextOut (hdc, x + chooser->headers[chooser->cat_col].x, r,
4fe323f9
RC
633 pkg->Categories.getnth (1)->key.name,
634 strlen (pkg->Categories.getnth (1)->key.name));
8f53e82a 635
bb849dbd 636 if (!pkg->SDesc ())
1fb09149 637 s = pkg->name;
308d6f3e
CF
638 else
639 {
640 static char buf[512];
f557695e
RC
641 strcpy (buf, pkg->name);
642 strcat (buf, ": ");
bb849dbd 643 strcat (buf, pkg->SDesc ());
308d6f3e
CF
644 s = buf;
645 }
f557695e
RC
646 TextOut (hdc, x + chooser->headers[chooser->pkg_col].x, r, s,
647 strlen (s));
8f53e82a
RC
648 }
649 else if (cat)
2dada532
CF
650 TextOut (hdc, x + chooser->headers[chooser->cat_col].x, r, cat->name,
651 strlen (cat->name));
8f53e82a
RC
652}
653
654int
655pick_line::click (int x)
656{
657 if (pkg)
658 {
bb849dbd 659 if (pkg->desired && pkg->desired->src.sites.number ()
f557695e
RC
660 && x >= chooser->headers[chooser->src_col].x - HMARGIN / 2
661 && x <= chooser->headers[chooser->src_col + 1].x - HMARGIN / 2)
bb849dbd 662 pkg->desired->srcpicked ^= 1;
8f53e82a 663
3467d79f 664 if (x >= chooser->headers[chooser->new_col].x - (HMARGIN / 2)
f557695e 665 && x <= chooser->headers[chooser->new_col + 1].x - HMARGIN / 2)
3467d79f 666 {
bb849dbd 667 set_action (pkg);
3467d79f 668 /* Add any packages that are needed by this package */
bb849dbd 669 return add_required (*pkg);
3467d79f 670 }
8f53e82a
RC
671 }
672 else if (cat)
673 {
674 /* handle the catalog being clicked ... does this belong up a level.. ? */
675 }
f557695e 676
8f53e82a
RC
677 return 0;
678}
679
680_view::_view (views _mode, HDC dc)
681{
682 lines = NULL;
683 nlines = 0;
684 view_mode = VIEW_PACKAGE;
685 set_headers ();
686 init_headers (dc);
687 view_mode = VIEW_CATEGORY;
688 set_headers ();
689 init_headers (dc);
690
691 view_mode = _mode;
692 set_headers ();
693}
694
695void
696_view::set_view_mode (views _mode)
697{
698 if (_mode == NVIEW)
f557695e 699 view_mode = VIEW_PACKAGE_FULL;
8f53e82a
RC
700 else
701 view_mode = _mode;
702 set_headers ();
703}
704
4bb38dfa 705const char *
8f53e82a
RC
706_view::mode_caption ()
707{
708 switch (view_mode)
709 {
f557695e
RC
710 case VIEW_UNKNOWN:
711 return "";
712 case VIEW_PACKAGE_FULL:
713 return "Full";
714 case VIEW_PACKAGE:
715 return "Partial";
716 case VIEW_CATEGORY:
717 return "Category";
718 default:
719 return "";
8f53e82a
RC
720 }
721}
722
723void
724_view::set_headers (void)
725{
726 switch (view_mode)
727 {
728 case VIEW_UNKNOWN:
729 return;
f557695e
RC
730 case VIEW_PACKAGE_FULL:
731 case VIEW_PACKAGE:
8f53e82a
RC
732 headers = pkg_headers;
733 current_col = 0;
734 new_col = 1;
735 src_col = 2;
736 cat_col = 3;
737 pkg_col = 4;
738 last_col = 4;
739 break;
740 case VIEW_CATEGORY:
741 headers = cat_headers;
742 current_col = 1;
743 new_col = 2;
744 src_col = 3;
745 cat_col = 0;
746 pkg_col = 4;
747 last_col = 4;
748 default:
749 return;
750 }
751}
752
753void
754_view::init_headers (HDC dc)
713bbe5f 755{
c46a33a9 756 int i;
c46a33a9 757
8f53e82a
RC
758 for (i = 0; headers[i].text; i++)
759 headers[i].width = 0;
c46a33a9 760
8f53e82a
RC
761 for (i = 0; headers[i].text; i++)
762 note_width (headers, dc, headers[i].text, 0, i);
bb849dbd
RC
763 packagedb db;
764 for (packagemeta * pkg = db.getfirstpackage (); pkg;
765 pkg = db.getnextpackage ())
8f53e82a
RC
766 {
767 if (pkg->installed)
1fb09149 768 {
bb849dbd
RC
769 note_width (headers, dc, pkg->installed->Canonical_version (), 0,
770 current_col);
771 note_width (headers, dc, pkg->installed->Canonical_version (),
772 NEW_COL_SIZE_SLOP, new_col);
1fb09149 773 }
bb849dbd
RC
774 for (size_t n = 1; n <= pkg->versions.number (); n++)
775 note_width (headers, dc,
776 pkg->versions.getnth (n)->Canonical_version (),
777 NEW_COL_SIZE_SLOP, new_col);
4fe323f9
RC
778 for (size_t n = 1; n <= db.categories.number (); n++)
779 note_width (headers, dc, db.categories.getnth (n)->name, 0, cat_col);
bb849dbd 780 if (!pkg->SDesc ())
f557695e
RC
781 note_width (headers, dc, pkg->name, 0, pkg_col);
782 else
783 {
784 static char buf[512];
785 strcpy (buf, pkg->name);
786 strcat (buf, ": ");
bb849dbd 787 strcat (buf, pkg->SDesc ());
f557695e
RC
788 note_width (headers, dc, buf, 0, pkg_col);
789 }
8f53e82a
RC
790 }
791 note_width (headers, dc, "keep", NEW_COL_SIZE_SLOP, new_col);
792 note_width (headers, dc, "uninstall", NEW_COL_SIZE_SLOP, new_col);
793
f557695e
RC
794 headers[0].x = HMARGIN / 2;
795 for (i = 1; i <= last_col; i++)
796 headers[i].x = headers[i - 1].x + headers[i - 1].width + ((i == new_col) ?
797 NEW_COL_SIZE_SLOP
798 : 0) + HMARGIN;
8f53e82a
RC
799}
800
801void
bb849dbd 802_view::insert_pkg (packagemeta & pkg)
8f53e82a
RC
803{
804 pick_line line;
bb849dbd 805 line.set_line (&pkg);
7b606ae5 806 packagedb db;
8f53e82a
RC
807 if (view_mode != VIEW_CATEGORY)
808 {
809 if (lines == NULL)
1fb09149 810 {
7b606ae5 811 lines =
bb849dbd 812 (pick_line *) calloc (db.npackages () +
4fe323f9 813 db.categories.number (),
7b606ae5 814 sizeof (pick_line));
8f53e82a
RC
815 nlines = 0;
816 insert_at (0, line);
1fb09149 817 }
8f53e82a
RC
818 else
819 insert_under (0, line);
820 }
821 else
822 {
823// assert (lines); /* protect against a coding change in future */
4fe323f9 824 for (size_t x = 1; x <= pkg.Categories.number (); x++)
8f53e82a 825 {
4fe323f9 826 Category & cat = pkg.Categories.getnth (x)->key;
8f53e82a
RC
827 /* insert the package under this category in the list. If this category is not
828 visible, add it */
f557695e 829 int n = 0;
8f53e82a
RC
830 while (n < nlines)
831 {
832 /* this should be a generic call to list_sort_cmp */
833 if (lines[n].get_category ()
4fe323f9 834 && !strcasecmp (cat.name, lines[n].get_category ()->name))
3bcf85be 835 {
8f53e82a 836 insert_under (n, line);
3bcf85be
RC
837 n = nlines;
838 }
8f53e82a
RC
839 n++;
840 }
841 if (n == nlines)
842 {
843 /* the category wasn't visible - insert at the end */
4fe323f9 844 insert_category (&cat, CATEGORY_COLLAPSED);
8f53e82a
RC
845 insert_pkg (pkg);
846 }
847 }
848 }
849}
850
851void
f557695e 852_view::insert_category (Category * cat, int collapsed)
8f53e82a
RC
853{
854 pick_line line;
855 line.set_line (cat);
856 if (lines == NULL)
857 {
7b606ae5 858 packagedb db;
f557695e 859 lines =
4fe323f9 860 (pick_line *) malloc ((db.npackages () + db.categories.number ())
bb849dbd 861 * sizeof (pick_line));
7b606ae5 862 memset (lines, '\0',
bb849dbd 863 (db.npackages () +
4fe323f9 864 db.categories.number ()) * sizeof (pick_line));
8f53e82a
RC
865 nlines = 0;
866 insert_at (0, line);
867 if (!collapsed)
f557695e
RC
868 for (CategoryPackage * catpkg = cat->packages; catpkg;
869 catpkg = catpkg->next)
4fe323f9 870 insert_pkg (*catpkg->pkg);
8f53e82a
RC
871 }
872 else
873 {
f557695e 874 int n = 0;
8f53e82a 875 while (n < nlines)
1fb09149
CF
876 {
877 /* this should be a generic call to list_sort_cmp */
878 if (lines[n].get_category ()
879 && strcasecmp (cat->name, lines[n].get_category ()->name) < 0)
880 {
8f53e82a
RC
881 insert_at (n, line);
882 if (!collapsed)
f557695e
RC
883 for (CategoryPackage * catpkg = cat->packages; catpkg;
884 catpkg = catpkg->next)
4fe323f9 885 insert_pkg (*catpkg->pkg);
1fb09149
CF
886 n = nlines;
887 }
888 else if (lines[n].get_category () == cat)
889 n = nlines;
890 n++;
8f53e82a 891
1fb09149 892 }
8f53e82a 893 if (n == nlines)
1fb09149
CF
894 {
895 /* insert at the end */
8f53e82a
RC
896 insert_at (n, line);
897 if (!collapsed)
f557695e
RC
898 for (CategoryPackage * catpkg = cat->packages; catpkg;
899 catpkg = catpkg->next)
4fe323f9 900 insert_pkg (*catpkg->pkg);
1fb09149 901 }
8f53e82a
RC
902 }
903}
904
905/* insert a new line at line n */
906void
907_view::insert_at (int n, pick_line line)
908{
909 if (n < 0 || n > nlines)
910 return;
911 memmove (&lines[n + 1], &lines[n], (nlines - n) * sizeof (pick_line));
912 lines[n] = line;
913 nlines++;
914}
915
916/* insert a new line in the chooser, at the next depth in from linen */
917void
918_view::insert_under (int linen, pick_line line)
919{
920 int n;
921 /* special case - empty view */
922 if (nlines == 0)
923 {
924 insert_at (0, line);
925 return;
926 }
f97a1ece
RC
927 /* perhaps these two are equivalent. FIXME: check for potential insert_under (0,.. calls */
928 else if (linen > nlines)
929 {
930 insert_at (nlines, line);
931 return;
932 }
8f53e82a
RC
933 /* part 1 - find the appropriate bucket beginning */
934 if (lines[linen].get_category ())
935 {
936 n = linen + 1;
937 }
938 else if (lines[linen].get_pkg ())
939 {
940 n = linen;
941 /* walk up to the beginning of the bucket */
942 while (n > 0 && lines[n - 1].get_pkg ())
943 n--;
944 }
f97a1ece
RC
945 else
946 {
947 /* nlines != 0 and lines[linen] is not a category or a package! */
948 return;
949 }
8f53e82a
RC
950 /* part 2 - insert in sorted order in the bucket */
951 while (n < nlines)
952 {
953 if (lines[n].get_category () || (lines[n].get_pkg ()
f557695e 954 && strcasecmp (line.get_pkg ()->name,
03a6c5b1
RC
955 lines[n].
956 get_pkg ()->name) < 0))
8f53e82a
RC
957 {
958 insert_at (n, line);
959 n = nlines;
960 }
961 else if (lines[n].get_pkg () == line.get_pkg ())
962 {
963 n = nlines;
964 }
965 n++;
966 }
967 if (n == nlines)
968 {
969 /* insert at the end of this bucket */
970 insert_at (n, line);
971 }
972}
973
974void
975_view::clear_view (void)
976{
977 nlines = 0;
978}
979
980static views
f557695e 981viewsplusplus (views theview)
8f53e82a
RC
982{
983 switch (theview)
984 {
f557695e
RC
985 case VIEW_UNKNOWN:
986 return VIEW_PACKAGE_FULL;
987 case VIEW_PACKAGE_FULL:
988 return VIEW_PACKAGE;
989 case VIEW_PACKAGE:
990 return VIEW_CATEGORY;
991 case VIEW_CATEGORY:
992 return NVIEW;
993 default:
994 return VIEW_UNKNOWN;
8f53e82a
RC
995 }
996}
997
998int
999_view::click (int row, int x)
1000{
1001 if (row > nlines)
1002 return 0;
1003 if (lines[row].get_pkg ())
1004 return lines[row].click (x);
1005 else
1006 {
1007 /* if we are the last line or the next line is a category too, expand */
f557695e 1008 if (row == (nlines - 1) || lines[row + 1].get_category ())
8f53e82a
RC
1009 {
1010 int count = nlines;
f557695e
RC
1011 for (CategoryPackage * catpkg =
1012 lines[row].get_category ()->packages; catpkg;
1013 catpkg = catpkg->next)
8f53e82a 1014 {
4fe323f9 1015 packagemeta & pkg = *catpkg->pkg;
8f53e82a
RC
1016 int n = row + 1;
1017 pick_line line;
bb849dbd 1018 line.set_line (&pkg);
8f53e82a
RC
1019 /* this is a nasty hack. It will go away when the hierarchy is coded */
1020 while (n < nlines)
1fb09149 1021 {
8f53e82a 1022 if (lines[n].get_category () || (lines[n].get_pkg ()
bb849dbd 1023 && strcasecmp (pkg.name,
b24c88b3
RC
1024 lines
1025 [n].get_pkg
1026 ()->name) <
1027 0))
8f53e82a
RC
1028 {
1029 insert_at (n, line);
1030 n = nlines;
1031 }
bb849dbd 1032 else if (lines[n].get_pkg () == &pkg)
8f53e82a
RC
1033 {
1034 n = nlines;
1035 }
1036 n++;
1037 }
1038 if (n == nlines)
1039 {
1040 /* insert at the end of this category */
1041 insert_at (n, line);
f557695e 1042 n = nlines + 1;
8f53e82a
RC
1043 }
1044 }
1045 return nlines - count;
1046 }
1047 else
1048 /* contract */
1049 {
1050 int count = 0, n = row + 1;
f557695e 1051 while (n < nlines & !lines[n].get_category ())
8f53e82a 1052 {
f557695e
RC
1053 memmove (&lines[n], &lines[n + 1],
1054 (nlines - n) * sizeof (pick_line));
8f53e82a
RC
1055 nlines--;
1056 count++;
1057 }
42a99ed1 1058 return -count;
8f53e82a
RC
1059 }
1060 }
1061}
1062
1063
1064static void
1065set_view_mode (HWND h, views mode)
1066{
8f53e82a
RC
1067 chooser->set_view_mode (mode);
1068
1069 chooser->clear_view ();
bb849dbd 1070 packagedb db;
8f53e82a
RC
1071 switch (chooser->get_view_mode ())
1072 {
1073 case VIEW_PACKAGE:
bb849dbd
RC
1074 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1075 pkg = db.getnextpackage ())
4fe323f9
RC
1076 if ((!pkg->desired && pkg->installed)
1077 || (pkg->desired
1078 && (pkg->desired->srcpicked || pkg->desired->binpicked)))
bb849dbd 1079 chooser->insert_pkg (*pkg);
8f53e82a
RC
1080 break;
1081 case VIEW_PACKAGE_FULL:
bb849dbd
RC
1082 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1083 pkg = db.getnextpackage ())
1084 chooser->insert_pkg (*pkg);
8f53e82a
RC
1085 break;
1086 case VIEW_CATEGORY:
bb849dbd 1087 /* start collapsed. TODO: make this a chooser flag */
4fe323f9
RC
1088 for (size_t n = 1; n <= db.categories.number (); n++)
1089 chooser->insert_category (db.categories.getnth (n),
1090 CATEGORY_COLLAPSED);
8f53e82a
RC
1091 break;
1092 default:
1093 break;
1094 }
1095
713bbe5f
DD
1096 RECT r;
1097 GetClientRect (h, &r);
1098 SCROLLINFO si;
1099 memset (&si, 0, sizeof (si));
1100 si.cbSize = sizeof (si);
1101 si.fMask = SIF_ALL;
1102 si.nMin = 0;
f557695e
RC
1103 si.nMax =
1104 chooser->headers[chooser->last_col].x +
1105 chooser->headers[chooser->last_col].width + HMARGIN;
713bbe5f
DD
1106 si.nPage = r.right;
1107 SetScrollInfo (h, SB_HORZ, &si, TRUE);
1108
8f53e82a 1109 si.nMax = chooser->nlines * row_height;
713bbe5f
DD
1110 si.nPage = r.bottom - header_height;
1111 SetScrollInfo (h, SB_VERT, &si, TRUE);
1112
1113 scroll_ulc_x = scroll_ulc_y = 0;
1114
1115 InvalidateRect (h, &r, TRUE);
1116
1117 if (nextbutton)
1118 SetFocus (nextbutton);
1119}
1120
713bbe5f 1121static void
f557695e 1122create_listview (HWND dlg, RECT * r)
713bbe5f 1123{
713bbe5f 1124 lv = CreateWindowEx (WS_EX_CLIENTEDGE,
47f8d8b3
CF
1125 "listview",
1126 "listviewwindow",
1127 WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
1128 r->left, r->top,
f557695e 1129 r->right - r->left + 1, r->bottom - r->top + 1,
47f8d8b3 1130 dlg,
f557695e
RC
1131 (HMENU) MAKEINTRESOURCE (IDC_CHOOSE_LIST),
1132 hinstance, 0);
713bbe5f 1133 ShowWindow (lv, SW_SHOW);
713bbe5f
DD
1134 HDC dc = GetDC (lv);
1135 sysfont = GetStockObject (DEFAULT_GUI_FONT);
1136 SelectObject (dc, sysfont);
1137 GetTextMetrics (dc, &tm);
1138 header_height = tm.tmHeight + 5 + 3;
1139
1140 bitmap_dc = CreateCompatibleDC (dc);
1141
1142 row_height = (tm.tmHeight + tm.tmExternalLeading + ROW_MARGIN);
1143 int irh = tm.tmExternalLeading + tm.tmDescent + 11 + ROW_MARGIN;
1144 if (row_height < irh)
1145 row_height = irh;
1146
8f53e82a 1147 chooser = new (view) (VIEW_CATEGORY, dc);
713bbe5f 1148
713bbe5f 1149 default_trust (lv, TRUST_CURR);
9307254d 1150 set_view_mode (lv, VIEW_CATEGORY);
f557695e 1151 if (!SetDlgItemText (dlg, IDC_CHOOSE_VIEWCAPTION, chooser->mode_caption ()))
b24c88b3
RC
1152 log (LOG_BABBLE, "Failed to set View button caption %ld",
1153 GetLastError ());
bb849dbd
RC
1154 packagedb db;
1155 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1156 pkg = db.getnextpackage ())
1157 add_required (*pkg);
1158 /* FIXME: do we need to init the desired fields ? */
60c632b3
CV
1159 static int ta[] = { IDC_CHOOSE_CURR, 0 };
1160 rbset (dlg, ta, IDC_CHOOSE_CURR);
d07591a3
DD
1161
1162 ReleaseDC (lv, dc);
713bbe5f
DD
1163}
1164
1165static BOOL
1166dialog_cmd (HWND h, int id, HWND hwndctl, UINT code)
1167{
bb849dbd 1168 packagedb db;
713bbe5f
DD
1169 switch (id)
1170 {
713bbe5f
DD
1171 case IDC_CHOOSE_PREV:
1172 default_trust (lv, TRUST_PREV);
bb849dbd
RC
1173 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1174 pkg = db.getnextpackage ())
1175 add_required (*pkg);
8f53e82a 1176 set_view_mode (lv, chooser->get_view_mode ());
713bbe5f
DD
1177 break;
1178 case IDC_CHOOSE_CURR:
1179 default_trust (lv, TRUST_CURR);
bb849dbd
RC
1180 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1181 pkg = db.getnextpackage ())
1182 add_required (*pkg);
8f53e82a 1183 set_view_mode (lv, chooser->get_view_mode ());
713bbe5f
DD
1184 break;
1185 case IDC_CHOOSE_EXP:
1186 default_trust (lv, TRUST_TEST);
bb849dbd
RC
1187 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1188 pkg = db.getnextpackage ())
1189 add_required (*pkg);
8f53e82a 1190 set_view_mode (lv, chooser->get_view_mode ());
713bbe5f 1191 break;
8f53e82a
RC
1192 case IDC_CHOOSE_VIEW:
1193 set_view_mode (lv, viewsplusplus (chooser->get_view_mode ()));
f557695e
RC
1194 if (!SetDlgItemText
1195 (h, IDC_CHOOSE_VIEWCAPTION, chooser->mode_caption ()))
4bb38dfa 1196 log (LOG_BABBLE, "Failed to set View button caption %ld",
f557695e 1197 GetLastError ());
713bbe5f
DD
1198 break;
1199
1200 case IDOK:
1201 if (source == IDC_SOURCE_CWD)
47f8d8b3 1202 NEXT (IDD_S_INSTALL);
713bbe5f 1203 else
47f8d8b3 1204 NEXT (IDD_S_DOWNLOAD);
713bbe5f
DD
1205 break;
1206
1207 case IDC_BACK:
1208 initialized = 0;
1209 if (source == IDC_SOURCE_CWD)
45c2d7d3 1210 NEXT (IDD_LOCAL_DIR);
713bbe5f 1211 else
47f8d8b3 1212 NEXT (IDD_SITE);
713bbe5f
DD
1213 break;
1214
1215 case IDCANCEL:
1216 NEXT (0);
1217 break;
1218 }
4bb38dfa 1219 return 0;
713bbe5f 1220}
23c9e63c 1221
713bbe5f 1222static void
f557695e 1223GetParentRect (HWND parent, HWND child, RECT * r)
713bbe5f
DD
1224{
1225 POINT p;
1226 GetWindowRect (child, r);
1227 p.x = r->left;
1228 p.y = r->top;
1229 ScreenToClient (parent, &p);
1230 r->left = p.x;
1231 r->top = p.y;
1232 p.x = r->right;
1233 p.y = r->bottom;
1234 ScreenToClient (parent, &p);
1235 r->right = p.x;
1236 r->bottom = p.y;
1237}
1238
1239static BOOL CALLBACK
1240dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
1241{
713bbe5f
DD
1242 HWND frame;
1243 RECT r;
1244 switch (message)
1245 {
1246 case WM_INITDIALOG:
1247 nextbutton = GetDlgItem (h, IDOK);
1248 frame = GetDlgItem (h, IDC_LISTVIEW_POS);
f557695e 1249 choose_inst_text = GetDlgItem (h, IDC_CHOOSE_INST_TEXT);
42bf5b92 1250 if (source == IDC_SOURCE_DOWNLOAD)
47f8d8b3 1251 SetWindowText (choose_inst_text, "Select packages to download ");
42bf5b92 1252 else
47f8d8b3 1253 SetWindowText (choose_inst_text, "Select packages to install ");
713bbe5f
DD
1254 GetParentRect (h, frame, &r);
1255 r.top += 2;
1256 r.bottom -= 2;
1257 create_listview (h, &r);
1258#if 0
1259 load_dialog (h);
1260#endif
42a99ed1 1261 return TRUE;
713bbe5f
DD
1262 case WM_COMMAND:
1263 return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd);
1264 }
1265 return FALSE;
1266}
1267
c46a33a9
CF
1268char *
1269base (const char *s)
5f48f258
DD
1270{
1271 if (!s)
1272 return 0;
c46a33a9 1273 const char *rv = s;
5f48f258
DD
1274 while (*s)
1275 {
1276 if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
47f8d8b3 1277 rv = s + 1;
5f48f258
DD
1278 s++;
1279 }
c46a33a9 1280 return (char *) rv;
fb087b80
CF
1281}
1282
1283int
1284find_tar_ext (const char *path)
1285{
03a6c5b1 1286 char *end = strchr (path, '\0');
b24c88b3
RC
1287 /* check in longest first order */
1288 char *ext = strstr (path, ".tar.bz2");
1289 if (ext)
03a6c5b1 1290 return (end - ext) == 8 ? ext - path : 0;
b24c88b3 1291 if ((ext = strstr (path, ".tar.gz")));
03a6c5b1 1292 return (end - ext) == 7 ? ext - path : 0;
b24c88b3 1293 if ((ext = strstr (path, ".tar")));
03a6c5b1 1294 return (end - ext) == 4 ? ext - path : 0;
60c632b3 1295}
5f48f258 1296
68b27c12 1297/* Parse a filename into package, version, and extension components. */
85b43844 1298int
f557695e 1299parse_filename (const char *in_fn, fileparse & f)
4a83b7b0 1300{
85b43844
CF
1301 char *p, *ver;
1302 char fn[strlen (in_fn) + 1];
fb087b80 1303
85b43844
CF
1304 strcpy (fn, in_fn);
1305 int n = find_tar_ext (fn);
fb087b80 1306
85b43844
CF
1307 if (!n)
1308 return 0;
fb087b80 1309
85b43844
CF
1310 strcpy (f.tail, fn + n);
1311 fn[n] = '\0';
1312 f.pkg[0] = f.what[0] = '\0';
1313 p = base (fn);
1314 for (ver = p; *ver; ver++)
1315 if (*ver == '-' || *ver == '_')
1316 if (isdigit (ver[1]))
1317 {
1318 *ver++ = 0;
1319 strcpy (f.pkg, p);
1320 break;
1321 }
1322 else if (strcasecmp (ver, "-src") == 0 ||
1323 strcasecmp (ver, "-patch") == 0)
1324 {
1325 *ver++ = 0;
1326 strcpy (f.pkg, p);
1327 strcpy (f.what, strlwr (ver));
1328 strcpy (f.pkgtar, p);
1329 strcat (f.pkgtar, f.tail);
1330 ver = strchr (ver, '\0');
1331 break;
1332 }
fb087b80 1333
85b43844
CF
1334 if (!f.pkg[0])
1335 strcpy (f.pkg, p);
fb087b80 1336
85b43844 1337 if (!f.what[0])
60c632b3 1338 {
3a8276de 1339 int n;
85b43844
CF
1340 p = strchr (ver, '\0');
1341 strcpy (f.pkgtar, in_fn);
1342 if ((p -= 4) >= ver && strcasecmp (p, "-src") == 0)
3a8276de 1343 n = 4;
85b43844 1344 else if ((p -= 2) >= ver && strcasecmp (p, "-patch") == 0)
3a8276de
CF
1345 n = 6;
1346 else
1347 n = 0;
1348 if (n)
47f8d8b3 1349 {
3a8276de 1350 strcpy (f.what, p + 1);
85b43844 1351 *p = '\0';
3a8276de 1352 p = f.pkgtar + (p - fn) + n;
c29ee141 1353 memmove (p - n, p, strlen (p));
47f8d8b3 1354 }
60c632b3 1355 }
85b43844
CF
1356
1357 strcpy (f.ver, *ver ? ver : "0.0");
1358 return 1;
1359}
1360
1b13eeec
CF
1361/* Find out where to put existing tar file in local directory in
1362 known package array. */
85b43844
CF
1363static void
1364scan2 (char *path, unsigned int size)
1365{
bb849dbd 1366 packagemeta *pkg;
85b43844
CF
1367 fileparse f;
1368
1369 if (!parse_filename (path, f))
1370 return;
1371
2dada532 1372 if (f.what[0] != '\0' && f.what[0] != 's')
85b43844
CF
1373 return;
1374
bb849dbd
RC
1375 packagedb db;
1376 pkg = db.getpackagebyname (f.pkg);
c46a33a9 1377 if (pkg == NULL)
85b43844
CF
1378 return;
1379
1b13eeec 1380 /* Scan existing package list looking for a match between a known
bb849dbd 1381 package and a tar archive on disk.
1b13eeec
CF
1382 While scanning, keep track of appropriate "holes" in the trust
1383 table where a tar file could be put if no known entry
1384 exists.
1385
bb849dbd
RC
1386 We have 4 specific insertion points and one generic point.
1387 The generic point is in versioned order in the package version array.
1388 The specific points are
1389 *installed
1390 *prev
1391 *curr
1392 *exp.
1393
1394 if the version number matches a version in the db,
1395 we simply add this as a mirror source to that version.
1396 If it matches no version, we add a new version to the db.
1397
1398 Lastly if the version number does not matche one of installed/prev/current/exp
1399 AND we had to create a new version entry
1400 we apply the following heuristic:
1401 if there is no exp, we link this in exp.
1402 If there is an exp and this is higher, we link this in exp, and
1403 if there is no curr, bump what was in exp to curr. If there was a curr, we leave it be.
1404 if this is lower than exp, and there is no curr, link as curr. If there is a curr, leave it be.
1405 If this is lower than curr, and there is no prev, link as prev, if there is a prev, leave it be.
1406
1407 Whilst this logic is potentially wrong from time to time, it guarantees that
1408 setup.ini defined stability won't be altered unintentially. An alternative is to
1409 mark setup.ini defined prev/curr/exp packages as such, when this algorithm, can
1410 get smarter.
1411
1b13eeec
CF
1412 So, if setup.ini knows that ash-20010425-1.tar.gz is the current
1413 version and there is an ash-20010426-1.tar.gz in the current directory,
1414 the 20010426 version will be placed in the "test" slot, assuming that
1415 there is no test version listed in setup.ini. */
1416
bb849dbd
RC
1417 int added = 0;
1418 for (size_t n = 1; n <= pkg->versions.number (); n++)
80429b97 1419 {
bb849dbd 1420 if (!strcasecmp (f.ver, pkg->versions.getnth (n)->Canonical_version ()))
d4a4527d 1421 {
bb849dbd
RC
1422 /* FIXME: Add a mirror entry */
1423 added = 1;
d4a4527d
RC
1424 }
1425 }
bb849dbd 1426 if (!added)
d4a4527d 1427 {
bb849dbd
RC
1428 /* FIXME: Add a new version */
1429
1430 /* And now the hole finder */
1431#if 0
1432 if (!pkg->exp)
1433 pkg->exp = thenewver;
1434 else if (strcasecmp (f.ver, pkg->versions[n]->Canonicalversion ()) < 0)
1435 /* try curr */
1436 if (!pkg->curr)
1437 pkg->curr = thenewver;
1438 else if (strcasecmp (f.ver, pkg->versions[n]->Canonicalversion ()) <
1439 0)
1440 /* try prev */
1441 if (!pkg->prev)
1442 pkg->prev = thenewver;
1443#endif
d4a4527d 1444 }
bb849dbd 1445
4a83b7b0
DD
1446}
1447
1448static void
1449scan_downloaded_files ()
1450{
1451 find (".", scan2);
1452}
1453
3ae6c15c 1454_Info::_Info (const char *_install, const char *_version, int _install_size,
f557695e 1455 const char *_source, int _source_size)
3ae6c15c
CF
1456{
1457 memset (this, 0, sizeof (*this));
1458 install = strdup (_install);
1459 version = strdup (_version);
1460 install_size = _install_size;
86202506 1461 if (_source)
3ae6c15c 1462 {
86202506 1463 source = strdup (_source);
3ae6c15c
CF
1464 source_size = _source_size;
1465 }
1466}
1467
1b1b33ac
DD
1468int
1469package_sort (const void *va, const void *vb)
1470{
bb849dbd
RC
1471 packagemeta *a = (packagemeta *) va;
1472 packagemeta *b = (packagemeta *) vb;
8f53e82a 1473 return strcasecmp (a->name, b->name);
1b1b33ac
DD
1474}
1475
713bbe5f
DD
1476void
1477do_choose (HINSTANCE h)
1478{
c46a33a9 1479 int rv;
713bbe5f
DD
1480
1481 nextbutton = 0;
1482 bm_spin = LoadImage (h, MAKEINTRESOURCE (IDB_SPIN), IMAGE_BITMAP, 0, 0, 0);
f557695e 1483 bm_rtarrow = LoadImage (h, MAKEINTRESOURCE (IDB_RTARROW), IMAGE_BITMAP,
1fb09149 1484 0, 0, 0);
713bbe5f 1485
26a27c14 1486 bm_checkyes = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_YES), IMAGE_BITMAP,
1fb09149 1487 0, 0, 0);
26a27c14 1488 bm_checkno = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_NO), IMAGE_BITMAP,
f557695e 1489 0, 0, 0);
26a27c14 1490 bm_checkna = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_NA), IMAGE_BITMAP,
f557695e 1491 0, 0, 0);
3b9077d4 1492
713bbe5f
DD
1493 register_windows (h);
1494
60c632b3 1495 if (source == IDC_SOURCE_DOWNLOAD || source == IDC_SOURCE_CWD)
4a83b7b0 1496 scan_downloaded_files ();
fb087b80 1497
60c632b3 1498 set_existence ();
8f53e82a 1499 fill_missing_category ();
713bbe5f
DD
1500
1501 rv = DialogBox (h, MAKEINTRESOURCE (IDD_CHOOSE), 0, dialog_proc);
1502 if (rv == -1)
1503 fatal (IDS_DIALOG_FAILED);
1504
89b1a15b 1505 log (LOG_BABBLE, "Chooser results...");
bb849dbd
RC
1506 packagedb db;
1507 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1508 pkg = db.getnextpackage ())
89b1a15b 1509 {
bb849dbd
RC
1510// static const char *infos[] = { "nada", "prev", "curr", "test" };
1511 const char *trust = ((pkg->desired == pkg->prev) ? "prev"
1512 : (pkg->desired == pkg->curr) ? "curr"
1513 : (pkg->desired == pkg->exp) ? "test" : "unknown");
c46a33a9 1514 const char *action = choose_caption (pkg);
bb849dbd
RC
1515 const char *installed =
1516 pkg->installed ? pkg->installed->Canonical_version () : "none";
1517
1518 log (LOG_BABBLE, "[%s] action=%s trust=%s installed=%s"
2dada532 1519 " src?=%s",
bb849dbd
RC
1520 pkg->name, action, trust, installed,
1521 pkg->desired && pkg->desired->srcpicked ? "yes" : "no");
4fe323f9 1522 if (pkg->Categories.number ())
2dada532
CF
1523 {
1524 /* List categories the package belongs to */
f557695e 1525 int categories_len = 0;
4fe323f9
RC
1526 for (size_t n = 1; n <= pkg->Categories.number (); n++)
1527 categories_len +=
1528 strlen (pkg->Categories.getnth (n)->key.name) + 2;
2dada532
CF
1529
1530 if (categories_len > 0)
1531 {
4bb38dfa 1532 char *categories = (char *) malloc (categories_len);
4fe323f9
RC
1533 strcpy (categories, pkg->Categories.getnth (1)->key.name);
1534 for (size_t n = 2; n <= pkg->Categories.number (); n++)
1535 {
1536 strcat (categories, ", ");
1537 strcat (categories, pkg->Categories.getnth (n)->key.name);
1538 }
2dada532
CF
1539 log (LOG_BABBLE, " categories=%s", categories);
1540 free (categories);
1541 }
1542 }
bb849dbd 1543 if (pkg->desired && pkg->desired->required)
2dada532
CF
1544 {
1545 /* List other packages this package depends on */
f557695e 1546 int requires_len = 0;
2dada532 1547 Dependency *dp;
bb849dbd 1548 for (dp = pkg->desired->required; dp; dp = dp->next)
2dada532
CF
1549 if (dp->package)
1550 requires_len += strlen (dp->package) + 2;
1551
1552 if (requires_len > 0)
1553 {
4bb38dfa 1554 char *requires = (char *) malloc (requires_len);
bb849dbd
RC
1555 strcpy (requires, pkg->desired->required->package);
1556 for (dp = pkg->desired->required->next; dp; dp = dp->next)
2dada532
CF
1557 if (dp->package)
1558 {
1559 strcat (requires, ", ");
1560 strcat (requires, dp->package);
1561 }
1562 log (LOG_BABBLE, " requires=%s", requires);
1563 free (requires);
1564 }
1565 }
bb849dbd
RC
1566#if 0
1567
1568 /* FIXME: Reinstate this code, but spit out all mirror sites */
2dada532 1569
c46a33a9 1570 for (int t = 1; t < NTRUST; t++)
47f8d8b3 1571 {
c46a33a9 1572 if (pkg->info[t].install)
2dada532 1573 log (LOG_BABBLE, " [%s] ver=%s\n"
f557695e
RC
1574 " inst=%s %d exists=%s\n"
1575 " src=%s %d exists=%s",
47f8d8b3 1576 infos[t],
f557695e
RC
1577 pkg->info[t].version ? : "(none)",
1578 pkg->info[t].install ? : "(none)",
c46a33a9 1579 pkg->info[t].install_size,
3467d79f 1580 (pkg->info[t].install_exists) ? "yes" : "no",
f557695e 1581 pkg->info[t].source ? : "(none)",
c46a33a9 1582 pkg->info[t].source_size,
2dada532 1583 (pkg->info[t].source_exists) ? "yes" : "no");
47f8d8b3 1584 }
bb849dbd 1585#endif
89b1a15b 1586 }
713bbe5f 1587}
This page took 0.502833 seconds and 5 git commands to generate.