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