2 * dselect - Debian package maintenance user interface
3 * main.cc - main program
5 * Copyright © 1994,1995 Ian Jackson <ian@chiark.greenend.org.uk>
6 * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
8 * This is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/types.h>
43 #if defined(HAVE_NCURSESW_TERM_H)
44 #include <ncursesw/term.h>
45 #elif defined(HAVE_NCURSES_TERM_H)
46 #include <ncurses/term.h>
51 #include <dpkg/i18n.h>
52 #include <dpkg/dpkg.h>
53 #include <dpkg/dpkg-db.h>
54 #include <dpkg/myopt.h>
60 const char thisname
[]= DSELECT
;
61 const char printforhelp
[]= N_("Type dselect --help for help.");
63 modstatdb_rw readwrite
;
64 const char *admindir
= ADMINDIR
;
68 static keybindings
packagelistbindings(packagelist_kinterps
,packagelist_korgbindings
);
75 static const struct table_t colourtable
[]= {
76 {"black", COLOR_BLACK
},
78 {"green", COLOR_GREEN
},
79 {"yellow", COLOR_YELLOW
},
80 {"blue", COLOR_BLUE
},
81 {"magenta", COLOR_MAGENTA
},
82 {"cyan", COLOR_CYAN
},
83 {"white", COLOR_WHITE
},
87 static const struct table_t attrtable
[]= {
88 {"normal", A_NORMAL
},
89 {"standout", A_STANDOUT
},
90 {"underline", A_UNDERLINE
},
91 {"reverse", A_REVERSE
},
93 {"bright", A_BLINK
}, // on some terminals
99 /* A slightly confusing mapping from dselect's internal names to
100 * the user-visible names.*/
101 static const struct table_t screenparttable
[]= {
103 {"listsel", listsel
},
105 {"infohead", thisstate
},
106 {"pkgstate", selstate
},
107 {"pkgstatesel", selstatesel
},
108 {"listhead", colheads
},
111 {"infodesc", info_head
},
112 {"infofoot", whatinfo
},
113 {"helpscreen", helpscreen
},
117 /* Historical (patriotic?) colours. */
118 struct colordata color
[]= {
120 {COLOR_WHITE
, COLOR_BLACK
, 0 }, // default, not used
121 {COLOR_WHITE
, COLOR_BLACK
, 0 }, // list
122 {COLOR_WHITE
, COLOR_BLACK
, A_REVERSE
}, // listsel
123 {COLOR_WHITE
, COLOR_RED
, 0 }, // title
124 {COLOR_WHITE
, COLOR_BLUE
, 0 }, // thisstate
125 {COLOR_WHITE
, COLOR_BLACK
, A_BOLD
}, // selstate
126 {COLOR_WHITE
, COLOR_BLACK
, A_REVERSE
| A_BOLD
}, // selstatesel
127 {COLOR_WHITE
, COLOR_BLUE
, 0 }, // colheads
128 {COLOR_WHITE
, COLOR_RED
, 0 }, // query
129 {COLOR_WHITE
, COLOR_BLACK
, 0 }, // info
130 {COLOR_WHITE
, COLOR_BLACK
, A_BOLD
}, // info_head
131 {COLOR_WHITE
, COLOR_BLUE
, 0 }, // whatinfo
132 {COLOR_WHITE
, COLOR_BLACK
, 0 }, // help
143 static const menuentry menuentries
[]= {
144 { "access", N_("a"), N_("[A]ccess"), N_("Choose the access method to use."), &urq_setup
},
145 { "update", N_("u"), N_("[U]pdate"), N_("Update list of available packages, if possible."), &urq_update
},
146 { "select", N_("s"), N_("[S]elect"), N_("Request which packages you want on your system."), &urq_list
},
147 { "install", N_("i"), N_("[I]nstall"),N_("Install and upgrade wanted packages."), &urq_install
},
148 { "config", N_("c"), N_("[C]onfig"), N_("Configure any packages that are unconfigured."), &urq_config
},
149 { "remove", N_("r"), N_("[R]emove"), N_("Remove unwanted software."), &urq_remove
},
150 { "quit", N_("q"), N_("[Q]uit"), N_("Quit dselect."), &urq_quit
},
151 { 0, 0, N_("menu"), 0, &urq_menu
},
155 static const char programdesc
[]=
156 N_("Debian `%s' package handling frontend version %s.\n");
158 static const char copyrightstring
[]= N_(
159 "Copyright (C) 1994-1996 Ian Jackson.\n"
160 "Copyright (C) 2000,2001 Wichert Akkerman.\n");
162 static const char licensestring
[]= N_(
163 "This is free software; see the GNU General Public License version 2 or\n"
164 "later for copying conditions. There is NO warranty.\n"
165 "See %s --license for copyright and license details.\n");
168 printversion(const struct cmdinfo
*ci
, const char *value
)
170 printf(gettext(programdesc
), DSELECT
, DPKG_VERSION_ARCH
);
171 printf(gettext(copyrightstring
));
172 printf(gettext(licensestring
), DSELECT
);
174 m_output(stdout
, _("<standard output>"));
180 usage(const struct cmdinfo
*ci
, const char *value
)
185 "Usage: %s [<option> ...] [<action> ...]\n"
190 " --admindir <directory> Use <directory> instead of %s.\n"
191 " --expert Turn on expert mode.\n"
192 " --debug <file> | -D<file> Turn on debugging, sending output to <file>.\n"
193 " --colour | --color screenpart:[foreground],[background][:attr[+attr+..]]\n"
194 " Configure screen colours.\n"
198 " --help Show this help message.\n"
199 " --version Show the version.\n"
200 " --license | --licence Show the license.\n"
205 " access update select install config remove quit\n"
208 printf(_("Screenparts:\n"));
209 for (i
=0; screenparttable
[i
].name
; i
++)
210 printf(" %s", screenparttable
[i
].name
);
211 fputs("\n\n", stdout
);
213 printf(_("Colours:\n"));
214 for (i
=0; colourtable
[i
].name
; i
++)
215 printf(" %s", colourtable
[i
].name
);
216 fputs("\n\n", stdout
);
218 printf(_("Attributes:\n"));
219 for (i
=0; attrtable
[i
].name
; i
++)
220 printf(" %s", attrtable
[i
].name
);
221 fputs("\n\n", stdout
);
223 m_output(stdout
, _("<standard output>"));
228 /* These are called by C code, so need to have C calling convention */
231 static void setdebug(const struct cmdinfo
*, const char *v
) {
233 if (!debug
) ohshite(_("couldn't open debug file `%.255s'\n"),v
);
234 setvbuf(debug
,0,_IONBF
,0);
237 static void setexpert(const struct cmdinfo
*, const char *v
) {
242 findintable(const struct table_t
*table
, const char *item
, const char *tablename
)
246 for (i
= 0; item
&& (table
[i
].name
!=NULL
); i
++)
247 if (strcasecmp(item
, table
[i
].name
) == 0)
250 ohshit(_("Invalid %s `%s'\n"), tablename
, item
);
254 * The string's format is:
255 * screenpart:[forecolor][,backcolor][:[<attr>, ...]
256 * Examples: --color title:black,cyan:bright+underline
257 * --color list:red,yellow
258 * --color colheads:,green:bright
259 * --color selstate::reverse // doesn't work FIXME
261 static void setcolor(const struct cmdinfo
*, const char *string
) {
262 char *s
= (char *) malloc((strlen(string
) + 1) * sizeof(char));
263 char *colours
, *attributes
, *attrib
, *colourname
;
264 int screenpart
, aval
;
266 strcpy(s
, string
); // strtok modifies strings, keep string const
267 screenpart
= findintable(screenparttable
, strtok(s
, ":"), _("screen part"));
268 colours
= strtok(NULL
, ":");
269 attributes
= strtok(NULL
, ":");
271 if ((colours
== NULL
|| ! strlen(colours
)) &&
272 (attributes
== NULL
|| ! strlen(attributes
))) {
273 ohshit(_("Null colour specification\n"));
276 if (colours
!= NULL
&& strlen(colours
)) {
277 colourname
= strtok(colours
, ",");
278 if (colourname
!= NULL
&& strlen(colourname
)) {
279 // normalize attributes to prevent confusion
280 color
[screenpart
].attr
= A_NORMAL
;
281 color
[screenpart
].fore
=findintable(colourtable
, colourname
, _("colour"));
283 colourname
= strtok(NULL
, ",");
284 if (colourname
!= NULL
&& strlen(colourname
)) {
285 color
[screenpart
].attr
= A_NORMAL
;
286 color
[screenpart
].back
=findintable(colourtable
, colourname
, _("colour"));
290 if (attributes
!= NULL
&& strlen(attributes
)) {
291 for (attrib
= strtok(attributes
, "+");
292 attrib
!= NULL
&& strlen(attrib
);
293 attrib
= strtok(NULL
, "+")) {
294 aval
=findintable(attrtable
, attrib
, _("colour attribute"));
295 if (aval
== A_NORMAL
) // set to normal
296 color
[screenpart
].attr
= aval
;
297 else // add to existing attribs
298 color
[screenpart
].attr
= color
[screenpart
].attr
| aval
;
303 } /* End of extern "C" */
305 static const struct cmdinfo cmdinfos
[]= {
306 { "admindir", 0, 1, 0, &admindir
, 0 },
307 { "debug", 'D', 1, 0, 0, setdebug
},
308 { "expert", 'E', 0, 0, 0, setexpert
},
309 { "help", 'h', 0, 0, 0, usage
},
310 { "version", 0, 0, 0, 0, printversion
},
311 { "licence", 0, 0, 0, 0, showcopyright
}, /* UK spelling */
312 { "license", 0, 0, 0, 0, showcopyright
}, /* US spelling */
313 { "color", 0, 1, 0, 0, setcolor
}, /* US spelling */
314 { "colour", 0, 1, 0, 0, setcolor
}, /* UK spelling */
318 static int cursesareon
= 0;
321 const char *cup
, *smso
;
323 cup
= tigetstr("cup");
324 smso
= tigetstr("smso");
328 fputs(_("Terminal does not appear to support cursor addressing.\n"),stderr
);
330 fputs(_("Terminal does not appear to support highlighting.\n"),stderr
);
332 _("Set your TERM variable correctly, use a better terminal,\n"
333 "or make do with the per-package management tool %s.\n"),
335 ohshit(_("terminal lacks necessary features, giving up"));
350 extern void *operator new(size_t size
) {
357 extern void operator delete(void *p
) {
361 urqresult
urq_list(void) {
362 readwrite
= modstatdb_init(admindir
,msdbrw_writeifposs
);
366 packagelist
*l
= new packagelist(&packagelistbindings
);
371 modstatdb_shutdown();
380 const menuentry
*me
= &menuentries
[i
];
381 sprintf(buf
," %c %d. %-11.11s %-80.80s ",
384 gettext(me
->menuent
));
387 getmaxyx(stdscr
,y
,x
);
389 attrset(so
? A_REVERSE
: A_NORMAL
);
390 mvaddnstr(i
+2,0, buf
,x
-1);
399 static char *lockfile
;
401 curseson(); cbreak(); noecho(); nonl(); keypad(stdscr
,TRUE
);
404 getmaxyx(stdscr
,y
,x
);
408 sprintf(buf
, gettext(programdesc
), DSELECT
, DPKG_VERSION_ARCH
);
409 mvaddnstr(0,0,buf
,x
-1);
412 const struct menuentry
*mep
; int i
;
413 for (mep
=menuentries
, i
=0; mep
->option
&& mep
->menuent
; mep
++, i
++)
418 "Move around with ^P and ^N, cursor keys, initial letters, or digits;\n"
419 "Press <enter> to confirm selection. ^L redraws screen.\n\n"));
422 addstr(gettext(copyrightstring
));
423 sprintf(buf
, gettext(licensestring
), DSELECT
);
427 lockfile
= new char[l
+sizeof(LOCKFILE
)+2];
428 strcpy(lockfile
,admindir
);
429 strcpy(lockfile
+l
, "/" LOCKFILE
);
430 lockfd
= open(lockfile
, O_RDWR
|O_CREAT
|O_TRUNC
, 0660);
431 if (errno
== EACCES
|| errno
== EPERM
)
433 "Read-only access: only preview of selections is available!"));
438 urqresult
urq_menu(void) {
439 #define C(x) ((x)-'a'+1)
441 entries
= refreshmenu();
448 while (c
== ERR
&& errno
== EINTR
);
451 ohshite(_("failed to getch in main menu"));
453 clearok(stdscr
,TRUE
); clear(); refreshmenu(); dme(cursor
,1);
457 if (c
==C('n') || c
==KEY_DOWN
|| c
==' ' || c
=='j') {
458 dme(cursor
,0); cursor
++; cursor
%= entries
; dme(cursor
,1);
459 } else if (c
==C('p') || c
==KEY_UP
|| c
==C('h') ||
460 c
==KEY_BACKSPACE
|| c
==KEY_DC
|| c
=='k') {
461 dme(cursor
,0); cursor
+= entries
-1; cursor
%= entries
; dme(cursor
,1);
462 } else if (c
=='\n' || c
=='\r' || c
==KEY_ENTER
) {
464 switch (menuentries
[cursor
].fn()) { /* FIXME: trap errors in urq_... */
466 return urqr_quitmenu
;
468 cursor
++; cursor
%= entries
;
472 internerr("unknown menufn");
474 refreshmenu(); dme(cursor
,1);
475 } else if (c
==C('l')) {
476 clearok(stdscr
,TRUE
); clear(); refreshmenu(); dme(cursor
,1);
477 } else if (isdigit(c
)) {
478 char buf
[2]; buf
[0]=c
; buf
[1]=0; c
=atoi(buf
);
480 dme(cursor
,0); cursor
=c
; dme(cursor
,1);
484 } else if (isalpha(c
)) {
487 while (i
< entries
&& gettext(menuentries
[i
].key
)[0] != c
)
490 dme(cursor
,0); cursor
=i
; dme(cursor
,1);
500 urqresult
urq_quit(void) {
501 /* FIXME: check packages OK. */
502 return urqr_quitmenu
;
505 int main(int, const char *const *argv
) {
508 setlocale(LC_ALL
, "");
509 bindtextdomain(DSELECT
, LOCALEDIR
);
512 if (setjmp(ejbuf
)) { /* expect warning about possible clobbering of argv */
514 error_unwind(ehflag_bombout
); exit(2);
516 push_error_handler(&ejbuf
,print_error_fatal
,0);
518 loadcfgfile(DSELECT
, cmdinfos
);
519 myopt(&argv
,cmdinfos
);
523 while ((a
= *argv
++) != 0) {
524 const menuentry
*me
= menuentries
;
525 while (me
->command
&& strcmp(me
->command
, a
))
527 if (!me
->command
) badusage(_("unknown action string `%.50s'"),a
);