summaryrefslogtreecommitdiff
path: root/dselect/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dselect/main.cc')
-rw-r--r--dselect/main.cc308
1 files changed, 308 insertions, 0 deletions
diff --git a/dselect/main.cc b/dselect/main.cc
new file mode 100644
index 000000000..e65f63528
--- /dev/null
+++ b/dselect/main.cc
@@ -0,0 +1,308 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * main.cc - main program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <ncurses.h>
+#include <term.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "version.h"
+#include "myopt.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+#include "pkglist.h"
+
+const char thisname[]= DSELECT;
+const char printforhelp[]= "Type " DPKG " --help for help.";
+
+modstatdb_rw readwrite;
+const char *admindir= ADMINDIR;
+FILE *debug;
+
+static keybindings packagelistbindings(packagelist_kinterps,packagelist_korgbindings);
+
+struct menuentry {
+ const char *option;
+ const char *menuent;
+ urqfunction *fn;
+};
+
+static const menuentry menuentries[]= {
+ { "access", "Choose the access method to use.", &urq_setup },
+ { "update", "Update list of available packages, if possible.", &urq_update },
+ { "select", "Select which packages to install (or deinstall).", &urq_list },
+ { "install", "Install selected software.", &urq_install },
+ { "config", "Configure packages that are unconfigured.", &urq_config },
+ { "remove", "Remove software selected for deinstallation.", &urq_remove },
+ { "quit", "Quit dselect.", &urq_quit },
+ { "menu", 0, &urq_menu },
+ { 0 }
+};
+
+static const char programdesc[]=
+ "Debian GNU/Linux `" DSELECT "' package handling frontend.";
+
+static const char copyrightstring[]=
+ "Version " DPKG_VERSION_ARCH ". Copyright (C) 1994,1995 Ian Jackson. This is\n"
+ "free software; see the GNU General Public Licence version 2 or later for\n"
+ "copying conditions. There is NO warranty. See dselect --licence for details.\n";
+
+static void printversion(void) {
+ if (fprintf(stderr,"%s\n%s",programdesc,copyrightstring) == EOF) werr("stderr");
+}
+
+static void usage(void) {
+ if (!fputs
+ ("Usage: dselect [options]\n"
+ " dselect [options] action ...\n"
+ "Options: --admindir <directory> (default is /var/lib/dpkg)\n"
+ " --help --version --licence --debug <file> | -D<file> | -D\n"
+ "Actions: access update select install config remove quit menu\n",
+ stderr)) werr("stderr");
+}
+
+/* These are called by C code, so need to have C calling convention */
+extern "C" {
+
+ static void helponly(const struct cmdinfo*, const char*) {
+ usage(); exit(0);
+ }
+ static void versiononly(const struct cmdinfo*, const char*) {
+ printversion(); exit(0);
+ }
+
+ static void setdebug(const struct cmdinfo*, const char *v) {
+ debug= fopen(v,"a");
+ if (!debug) ohshite("couldn't open debug file `%.255s'\n",v);
+ setvbuf(debug,0,_IONBF,0);
+ }
+
+} /* End of extern "C" */
+
+static const struct cmdinfo cmdinfos[]= {
+ { "admindir", 0, 1, 0, &admindir, 0 },
+ { "debug", 'D', 1, 0, 0, setdebug },
+ { "help", 'h', 0, 0, 0, helponly },
+ { "version", 0, 0, 0, 0, versiononly },
+ { "licence", 0, 0, 0, 0, showcopyright }, /* UK spelling */
+ { "license", 0, 0, 0, 0, showcopyright }, /* US spelling */
+ { 0, 0 }
+};
+
+static int cursesareon= 0;
+void curseson() {
+ if (!cursesareon) {
+ const char *cup, *smso;
+ initscr();
+ cup= tigetstr("cup");
+ smso= tigetstr("smso");
+ if (!cup || !smso) {
+ endwin();
+ if (!cup)
+ fputs("Terminal does not appear to support cursor addressing.\n",stderr);
+ if (!smso)
+ fputs("Terminal does not appear to support highlighting.\n",stderr);
+ fputs("Set your TERM variable correctly, use a better terminal,\n"
+ "or make do with the per-package management tool " DPKG ".\n",stderr);
+ ohshit("terminal lacks necessary features, giving up");
+ }
+ }
+ cursesareon= 1;
+}
+
+void cursesoff() {
+ if (cursesareon) {
+ clear();
+ refresh();
+ endwin();
+ }
+ cursesareon=0;
+}
+
+extern void *operator new(size_t size) {
+ void *p;
+ p= m_malloc(size);
+ assert(p);
+ return p;
+}
+
+extern void operator delete(void *p) {
+ free(p);
+}
+
+urqresult urq_list(void) {
+ readwrite= modstatdb_init(admindir,
+ msdbrw_writeifposs|msdbrw_availablepreferversion);
+
+ curseson();
+
+ packagelist *l= new packagelist(&packagelistbindings);
+ l->resolvesuggest();
+ l->display();
+ delete l;
+
+ modstatdb_shutdown();
+ resetpackages();
+ return urqr_normal;
+}
+
+void dme(int i, int so) {
+ char buf[120];
+ const menuentry *me= &menuentries[i];
+ sprintf(buf," %c %d. [%c]%-10.10s %-80.80s ",
+ so ? '*' : ' ', i,
+ toupper(me->option[0]), me->option+1,
+ me->menuent);
+
+ int y,x;
+ getmaxyx(stdscr,y,x);
+
+ attrset(so ? A_REVERSE : A_NORMAL);
+ mvaddnstr(i+2,0, buf,x-1);
+ attrset(A_NORMAL);
+}
+
+int refreshmenu(void) {
+ curseson(); cbreak(); noecho(); nonl(); keypad(stdscr,TRUE);
+
+ int y,x;
+ getmaxyx(stdscr,y,x);
+
+ clear();
+ attrset(A_BOLD);
+ mvaddnstr(0,0, programdesc,x-1);
+
+ attrset(A_NORMAL);
+ const struct menuentry *mep; int i;
+ for (mep=menuentries, i=0; mep->option && mep->menuent; mep++, i++)
+ dme(i,0);
+
+ attrset(A_BOLD);
+ addstr("\n\n"
+ "Use ^P and ^N, cursor keys, initial letters, or digits to select;\n"
+ "Press ENTER to confirm selection. ^L to redraw screen.\n\n");
+
+ attrset(A_NORMAL);
+ addstr(copyrightstring);
+
+ return i;
+}
+
+urqresult urq_menu(void) {
+#define C(x) ((x)-'a'+1)
+ int entries, c, i;
+ entries= refreshmenu();
+ int cursor=0;
+ dme(0,1);
+ for (;;) {
+ refresh();
+ c= getch(); if (c==ERR) ohshite("failed to getch in main menu");
+ if (c==C('n') || c==KEY_DOWN || c==' ') {
+ dme(cursor,0); cursor++; cursor %= entries; dme(cursor,1);
+ } else if (c==C('p') || c==KEY_UP || c==C('h') ||
+ c==KEY_BACKSPACE || c==KEY_DC) {
+ dme(cursor,0); cursor+= entries-1; cursor %= entries; dme(cursor,1);
+ } else if (c=='\n' || c=='\r' || c==KEY_ENTER) {
+ clear(); refresh();
+ switch (menuentries[cursor].fn()) { /* fixme: trap errors in urq_... */
+ case urqr_quitmenu:
+ return urqr_quitmenu;
+ case urqr_normal:
+ cursor++; cursor %= entries;
+ case urqr_fail:
+ break;
+ default:
+ internerr("unknown menufn");
+ }
+ refreshmenu(); dme(cursor,1);
+ } else if (c==C('l')) {
+ clearok(stdscr,TRUE); clear(); refreshmenu(); dme(cursor,1);
+ } else if (isdigit(c)) {
+ char buf[2]; buf[0]=c; buf[1]=0; c=atoi(buf);
+ if (c < entries) {
+ dme(cursor,0); cursor=c; dme(cursor,1);
+ } else {
+ beep();
+ }
+ } else if (isalpha(c)) {
+ c= tolower(c);
+ for (i=0; i<entries && menuentries[i].option[0] != c; i++);
+ if (i < entries) {
+ dme(cursor,0); cursor=i; dme(cursor,1);
+ } else {
+ beep();
+ }
+ } else {
+ beep();
+ }
+ }
+}
+
+urqresult urq_quit(void) {
+ return urqr_quitmenu;
+ /* fixme: check packages OK */
+}
+
+int main(int, const char *const *argv) {
+ jmp_buf ejbuf;
+
+ if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
+ cursesoff();
+ error_unwind(ehflag_bombout); exit(2);
+ }
+ push_error_handler(&ejbuf,print_error_fatal,0);
+
+ myopt(&argv,cmdinfos);
+
+ if (*argv) {
+ const char *a;
+ while ((a= *argv++) != 0) {
+ const menuentry *me;
+ for (me= menuentries; me->option && strcmp(me->option,a); me++);
+ if (!me->option) badusage("unknown action string `%.50s'",a);
+ me->fn();
+ }
+ } else {
+ urq_menu();
+ }
+
+ cursesoff();
+ set_error_display(0,0);
+ error_unwind(ehflag_normaltidy);
+ return(0);
+}