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");
166 static void DPKG_ATTR_NORET
167 printversion(const struct cmdinfo
*ci
, const char *value
)
169 printf(gettext(programdesc
), DSELECT
, DPKG_VERSION_ARCH
);
170 printf(gettext(copyrightstring
));
171 printf(gettext(licensestring
), DSELECT
);
173 m_output(stdout
, _("<standard output>"));
178 static void DPKG_ATTR_NORET
179 usage(const struct cmdinfo
*ci
, const char *value
)
184 "Usage: %s [<option> ...] [<action> ...]\n"
189 " --admindir <directory> Use <directory> instead of %s.\n"
190 " --expert Turn on expert mode.\n"
191 " --debug <file> | -D<file> Turn on debugging, sending output to <file>.\n"
192 " --colour | --color screenpart:[foreground],[background][:attr[+attr+..]]\n"
193 " Configure screen colours.\n"
197 " --help Show this help message.\n"
198 " --version Show the version.\n"
203 " access update select install config remove quit\n"
206 printf(_("Screenparts:\n"));
207 for (i
=0; screenparttable
[i
].name
; i
++)
208 printf(" %s", screenparttable
[i
].name
);
209 fputs("\n\n", stdout
);
211 printf(_("Colours:\n"));
212 for (i
=0; colourtable
[i
].name
; i
++)
213 printf(" %s", colourtable
[i
].name
);
214 fputs("\n\n", stdout
);
216 printf(_("Attributes:\n"));
217 for (i
=0; attrtable
[i
].name
; i
++)
218 printf(" %s", attrtable
[i
].name
);
219 fputs("\n\n", stdout
);
221 m_output(stdout
, _("<standard output>"));
226 /* These are called by C code, so need to have C calling convention */
229 static void setdebug(const struct cmdinfo
*, const char *v
) {
231 if (!debug
) ohshite(_("couldn't open debug file `%.255s'\n"),v
);
232 setvbuf(debug
,0,_IONBF
,0);
235 static void setexpert(const struct cmdinfo
*, const char *v
) {
240 findintable(const struct table_t
*table
, const char *item
, const char *tablename
)
244 for (i
= 0; item
&& (table
[i
].name
!=NULL
); i
++)
245 if (strcasecmp(item
, table
[i
].name
) == 0)
248 ohshit(_("Invalid %s `%s'\n"), tablename
, item
);
252 * The string's format is:
253 * screenpart:[forecolor][,backcolor][:[<attr>, ...]
254 * Examples: --color title:black,cyan:bright+underline
255 * --color list:red,yellow
256 * --color colheads:,green:bright
257 * --color selstate::reverse // doesn't work FIXME
259 static void setcolor(const struct cmdinfo
*, const char *string
) {
261 char *colours
, *attributes
, *attrib
, *colourname
;
262 int screenpart
, aval
;
264 s
= m_strdup(string
); // strtok modifies strings, keep string const
265 screenpart
= findintable(screenparttable
, strtok(s
, ":"), _("screen part"));
266 colours
= strtok(NULL
, ":");
267 attributes
= strtok(NULL
, ":");
269 if ((colours
== NULL
|| ! strlen(colours
)) &&
270 (attributes
== NULL
|| ! strlen(attributes
))) {
271 ohshit(_("Null colour specification\n"));
274 if (colours
!= NULL
&& strlen(colours
)) {
275 colourname
= strtok(colours
, ",");
276 if (colourname
!= NULL
&& strlen(colourname
)) {
277 // normalize attributes to prevent confusion
278 color
[screenpart
].attr
= A_NORMAL
;
279 color
[screenpart
].fore
=findintable(colourtable
, colourname
, _("colour"));
281 colourname
= strtok(NULL
, ",");
282 if (colourname
!= NULL
&& strlen(colourname
)) {
283 color
[screenpart
].attr
= A_NORMAL
;
284 color
[screenpart
].back
=findintable(colourtable
, colourname
, _("colour"));
288 if (attributes
!= NULL
&& strlen(attributes
)) {
289 for (attrib
= strtok(attributes
, "+");
290 attrib
!= NULL
&& strlen(attrib
);
291 attrib
= strtok(NULL
, "+")) {
292 aval
=findintable(attrtable
, attrib
, _("colour attribute"));
293 if (aval
== A_NORMAL
) // set to normal
294 color
[screenpart
].attr
= aval
;
295 else // add to existing attribs
296 color
[screenpart
].attr
= color
[screenpart
].attr
| aval
;
301 } /* End of extern "C" */
303 static const struct cmdinfo cmdinfos
[]= {
304 { "admindir", 0, 1, 0, &admindir
, 0 },
305 { "debug", 'D', 1, 0, 0, setdebug
},
306 { "expert", 'E', 0, 0, 0, setexpert
},
307 { "help", 'h', 0, 0, 0, usage
},
308 { "version", 0, 0, 0, 0, printversion
},
309 { "color", 0, 1, 0, 0, setcolor
}, /* US spelling */
310 { "colour", 0, 1, 0, 0, setcolor
}, /* UK spelling */
314 static int cursesareon
= 0;
317 const char *cup
, *smso
;
319 cup
= tigetstr("cup");
320 smso
= tigetstr("smso");
324 fputs(_("Terminal does not appear to support cursor addressing.\n"),stderr
);
326 fputs(_("Terminal does not appear to support highlighting.\n"),stderr
);
328 _("Set your TERM variable correctly, use a better terminal,\n"
329 "or make do with the per-package management tool %s.\n"),
331 ohshit(_("terminal lacks necessary features, giving up"));
346 extern void *operator new(size_t size
) {
353 extern void operator delete(void *p
) {
357 urqresult
urq_list(void) {
358 readwrite
= modstatdb_init(admindir
,msdbrw_writeifposs
);
362 packagelist
*l
= new packagelist(&packagelistbindings
);
367 modstatdb_shutdown();
376 const menuentry
*me
= &menuentries
[i
];
377 sprintf(buf
," %c %d. %-11.11s %-80.80s ",
380 gettext(me
->menuent
));
383 getmaxyx(stdscr
,y
,x
);
385 attrset(so
? A_REVERSE
: A_NORMAL
);
386 mvaddnstr(i
+2,0, buf
,x
-1);
395 static char *lockfile
;
397 curseson(); cbreak(); noecho(); nonl(); keypad(stdscr
,TRUE
);
400 getmaxyx(stdscr
,y
,x
);
404 sprintf(buf
, gettext(programdesc
), DSELECT
, DPKG_VERSION_ARCH
);
405 mvaddnstr(0,0,buf
,x
-1);
408 const struct menuentry
*mep
; int i
;
409 for (mep
=menuentries
, i
=0; mep
->option
&& mep
->menuent
; mep
++, i
++)
414 "Move around with ^P and ^N, cursor keys, initial letters, or digits;\n"
415 "Press <enter> to confirm selection. ^L redraws screen.\n\n"));
418 addstr(gettext(copyrightstring
));
419 sprintf(buf
, gettext(licensestring
), DSELECT
);
423 lockfile
= new char[l
+sizeof(LOCKFILE
)+2];
424 strcpy(lockfile
,admindir
);
425 strcpy(lockfile
+l
, "/" LOCKFILE
);
426 lockfd
= open(lockfile
, O_RDWR
|O_CREAT
|O_TRUNC
, 0660);
427 if (errno
== EACCES
|| errno
== EPERM
)
429 "Read-only access: only preview of selections is available!"));
434 urqresult
urq_menu(void) {
435 #define C(x) ((x)-'a'+1)
437 entries
= refreshmenu();
444 while (c
== ERR
&& errno
== EINTR
);
447 ohshite(_("failed to getch in main menu"));
449 clearok(stdscr
,TRUE
); clear(); refreshmenu(); dme(cursor
,1);
453 if (c
==C('n') || c
==KEY_DOWN
|| c
==' ' || c
=='j') {
454 dme(cursor
,0); cursor
++; cursor
%= entries
; dme(cursor
,1);
455 } else if (c
==C('p') || c
==KEY_UP
|| c
==C('h') ||
456 c
==KEY_BACKSPACE
|| c
==KEY_DC
|| c
=='k') {
457 dme(cursor
,0); cursor
+= entries
-1; cursor
%= entries
; dme(cursor
,1);
458 } else if (c
=='\n' || c
=='\r' || c
==KEY_ENTER
) {
460 switch (menuentries
[cursor
].fn()) { /* FIXME: trap errors in urq_... */
462 return urqr_quitmenu
;
464 cursor
++; cursor
%= entries
;
468 internerr("unknown menufn");
470 refreshmenu(); dme(cursor
,1);
471 } else if (c
==C('l')) {
472 clearok(stdscr
,TRUE
); clear(); refreshmenu(); dme(cursor
,1);
473 } else if (isdigit(c
)) {
474 char buf
[2]; buf
[0]=c
; buf
[1]=0; c
=atoi(buf
);
476 dme(cursor
,0); cursor
=c
; dme(cursor
,1);
480 } else if (isalpha(c
)) {
483 while (i
< entries
&& gettext(menuentries
[i
].key
)[0] != c
)
486 dme(cursor
,0); cursor
=i
; dme(cursor
,1);
496 urqresult
urq_quit(void) {
497 /* FIXME: check packages OK. */
498 return urqr_quitmenu
;
501 int main(int, const char *const *argv
) {
504 setlocale(LC_ALL
, "");
505 bindtextdomain(DSELECT
, LOCALEDIR
);
508 if (setjmp(ejbuf
)) { /* expect warning about possible clobbering of argv */
510 error_unwind(ehflag_bombout
); exit(2);
512 push_error_handler(&ejbuf
,print_error_fatal
,0);
514 loadcfgfile(DSELECT
, cmdinfos
);
515 myopt(&argv
,cmdinfos
);
519 while ((a
= *argv
++) != 0) {
520 const menuentry
*me
= menuentries
;
521 while (me
->command
&& strcmp(me
->command
, a
))
523 if (!me
->command
) badusage(_("unknown action string `%.50s'"),a
);