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