dpkg (1.2.12); priority=LOW
[dpkg.git] / dselect / main.cc
blobe15d1b561b1ed1544a0a665013e78893e60356e9
1 /*
2 * dselect - Debian GNU/Linux package maintenance user interface
3 * main.cc - main program
5 * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
12 * This is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with dpkg; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <signal.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <limits.h>
33 #include <ctype.h>
34 #include <assert.h>
36 #include <ncurses.h>
37 #include <term.h>
39 extern "C" {
40 #include "config.h"
41 #include "dpkg.h"
42 #include "dpkg-db.h"
43 #include "version.h"
44 #include "myopt.h"
46 #include "dselect.h"
47 #include "bindings.h"
48 #include "pkglist.h"
50 const char thisname[]= DSELECT;
51 const char printforhelp[]= "Type " DPKG " --help for help.";
53 modstatdb_rw readwrite;
54 const char *admindir= ADMINDIR;
55 FILE *debug;
57 static keybindings packagelistbindings(packagelist_kinterps,packagelist_korgbindings);
59 struct menuentry {
60 const char *option;
61 const char *menuent;
62 urqfunction *fn;
65 static const menuentry menuentries[]= {
66 { "access", "Choose the access method to use.", &urq_setup },
67 { "update", "Update list of available packages, if possible.", &urq_update },
68 { "select", "Request which packages you want on your system.", &urq_list },
69 { "install", "Install and upgrade wanted packages.", &urq_install },
70 { "config", "Configure any packages that are unconfigured.", &urq_config },
71 { "remove", "Remove unwanted software.", &urq_remove },
72 { "quit", "Quit dselect.", &urq_quit },
73 { "menu", 0, &urq_menu },
74 { 0 }
77 static const char programdesc[]=
78 "Debian Linux `" DSELECT "' package handling frontend.";
80 static const char copyrightstring[]=
81 "Version " DPKG_VERSION_ARCH ". Copyright (C) 1994-1996 Ian Jackson. This is\n"
82 "free software; see the GNU General Public Licence version 2 or later for\n"
83 "copying conditions. There is NO warranty. See dselect --licence for details.\n";
85 static void printversion(void) {
86 if (fprintf(stdout,"%s\n%s",programdesc,copyrightstring) == EOF) werr("stdout");
89 static void usage(void) {
90 if (!fputs
91 ("Usage: dselect [options]\n"
92 " dselect [options] action ...\n"
93 "Options: --admindir <directory> (default is /var/lib/dpkg)\n"
94 " --help --version --licence --debug <file> | -D<file> | -D\n"
95 "Actions: access update select install config remove quit menu\n",
96 stdout)) werr("stdout");
99 /* These are called by C code, so need to have C calling convention */
100 extern "C" {
102 static void helponly(const struct cmdinfo*, const char*) {
103 usage(); exit(0);
105 static void versiononly(const struct cmdinfo*, const char*) {
106 printversion(); exit(0);
109 static void setdebug(const struct cmdinfo*, const char *v) {
110 debug= fopen(v,"a");
111 if (!debug) ohshite("couldn't open debug file `%.255s'\n",v);
112 setvbuf(debug,0,_IONBF,0);
115 } /* End of extern "C" */
117 static const struct cmdinfo cmdinfos[]= {
118 { "admindir", 0, 1, 0, &admindir, 0 },
119 { "debug", 'D', 1, 0, 0, setdebug },
120 { "help", 'h', 0, 0, 0, helponly },
121 { "version", 0, 0, 0, 0, versiononly },
122 { "licence", 0, 0, 0, 0, showcopyright }, /* UK spelling */
123 { "license", 0, 0, 0, 0, showcopyright }, /* US spelling */
124 { 0, 0 }
127 static int cursesareon= 0;
128 void curseson() {
129 if (!cursesareon) {
130 const char *cup, *smso;
131 initscr();
132 cup= tigetstr("cup");
133 smso= tigetstr("smso");
134 if (!cup || !smso) {
135 endwin();
136 if (!cup)
137 fputs("Terminal does not appear to support cursor addressing.\n",stderr);
138 if (!smso)
139 fputs("Terminal does not appear to support highlighting.\n",stderr);
140 fputs("Set your TERM variable correctly, use a better terminal,\n"
141 "or make do with the per-package management tool " DPKG ".\n",stderr);
142 ohshit("terminal lacks necessary features, giving up");
145 cursesareon= 1;
148 void cursesoff() {
149 if (cursesareon) {
150 clear();
151 refresh();
152 endwin();
154 cursesareon=0;
157 extern void *operator new(size_t size) {
158 void *p;
159 p= m_malloc(size);
160 assert(p);
161 return p;
164 extern void operator delete(void *p) {
165 free(p);
168 urqresult urq_list(void) {
169 readwrite= modstatdb_init(admindir,msdbrw_writeifposs);
171 curseson();
173 packagelist *l= new packagelist(&packagelistbindings);
174 l->resolvesuggest();
175 l->display();
176 delete l;
178 modstatdb_shutdown();
179 resetpackages();
180 return urqr_normal;
183 void dme(int i, int so) {
184 char buf[120];
185 const menuentry *me= &menuentries[i];
186 sprintf(buf," %c %d. [%c]%-10.10s %-80.80s ",
187 so ? '*' : ' ', i,
188 toupper(me->option[0]), me->option+1,
189 me->menuent);
191 int y,x;
192 getmaxyx(stdscr,y,x);
194 attrset(so ? A_REVERSE : A_NORMAL);
195 mvaddnstr(i+2,0, buf,x-1);
196 attrset(A_NORMAL);
199 int refreshmenu(void) {
200 curseson(); cbreak(); noecho(); nonl(); keypad(stdscr,TRUE);
202 int y,x;
203 getmaxyx(stdscr,y,x);
205 clear();
206 attrset(A_BOLD);
207 mvaddnstr(0,0, programdesc,x-1);
209 attrset(A_NORMAL);
210 const struct menuentry *mep; int i;
211 for (mep=menuentries, i=0; mep->option && mep->menuent; mep++, i++)
212 dme(i,0);
214 attrset(A_BOLD);
215 addstr("\n\n"
216 "Use ^P and ^N, cursor keys, initial letters, or digits to select;\n"
217 "Press ENTER to confirm selection. ^L to redraw screen.\n\n");
219 attrset(A_NORMAL);
220 addstr(copyrightstring);
222 return i;
225 urqresult urq_menu(void) {
226 #define C(x) ((x)-'a'+1)
227 int entries, c, i;
228 entries= refreshmenu();
229 int cursor=0;
230 dme(0,1);
231 for (;;) {
232 refresh();
233 c= getch(); if (c==ERR) ohshite("failed to getch in main menu");
234 if (c==C('n') || c==KEY_DOWN || c==' ') {
235 dme(cursor,0); cursor++; cursor %= entries; dme(cursor,1);
236 } else if (c==C('p') || c==KEY_UP || c==C('h') ||
237 c==KEY_BACKSPACE || c==KEY_DC) {
238 dme(cursor,0); cursor+= entries-1; cursor %= entries; dme(cursor,1);
239 } else if (c=='\n' || c=='\r' || c==KEY_ENTER) {
240 clear(); refresh();
241 switch (menuentries[cursor].fn()) { /* fixme: trap errors in urq_... */
242 case urqr_quitmenu:
243 return urqr_quitmenu;
244 case urqr_normal:
245 cursor++; cursor %= entries;
246 case urqr_fail:
247 break;
248 default:
249 internerr("unknown menufn");
251 refreshmenu(); dme(cursor,1);
252 } else if (c==C('l')) {
253 clearok(stdscr,TRUE); clear(); refreshmenu(); dme(cursor,1);
254 } else if (isdigit(c)) {
255 char buf[2]; buf[0]=c; buf[1]=0; c=atoi(buf);
256 if (c < entries) {
257 dme(cursor,0); cursor=c; dme(cursor,1);
258 } else {
259 beep();
261 } else if (isalpha(c)) {
262 c= tolower(c);
263 for (i=0; i<entries && menuentries[i].option[0] != c; i++);
264 if (i < entries) {
265 dme(cursor,0); cursor=i; dme(cursor,1);
266 } else {
267 beep();
269 } else {
270 beep();
275 urqresult urq_quit(void) {
276 return urqr_quitmenu;
277 /* fixme: check packages OK */
280 int main(int, const char *const *argv) {
281 jmp_buf ejbuf;
283 if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
284 cursesoff();
285 error_unwind(ehflag_bombout); exit(2);
287 push_error_handler(&ejbuf,print_error_fatal,0);
289 myopt(&argv,cmdinfos);
291 if (*argv) {
292 const char *a;
293 while ((a= *argv++) != 0) {
294 const menuentry *me;
295 for (me= menuentries; me->option && strcmp(me->option,a); me++);
296 if (!me->option) badusage("unknown action string `%.50s'",a);
297 me->fn();
299 } else {
300 urq_menu();
303 cursesoff();
304 set_error_display(0,0);
305 error_unwind(ehflag_normaltidy);
306 return(0);