Browse Source

Task selection UI Initial CVS

tags/adam_release_2-2-2
Randolph Chung 22 years ago
commit
88ff0ffa41
19 changed files with 1102 additions and 0 deletions
  1. +29
    -0
      Makefile
  2. +31
    -0
      README
  3. +2
    -0
      TODO
  4. +248
    -0
      data.c
  5. +31
    -0
      data.h
  6. +14
    -0
      help.h
  7. +54
    -0
      macros.h
  8. +11
    -0
      po/Makefile
  9. +25
    -0
      scratch/Makefile
  10. +20
    -0
      scratch/flowtest.c
  11. +35
    -0
      scratch/testdata.c
  12. +348
    -0
      slangui.c
  13. +24
    -0
      slangui.h
  14. +57
    -0
      strutl.c
  15. +7
    -0
      strutl.h
  16. +92
    -0
      tasksel.c
  17. +7
    -0
      tasksel.h
  18. +57
    -0
      util.c
  19. +10
    -0
      util.h

+ 29
- 0
Makefile View File

@@ -0,0 +1,29 @@
PROGRAM = tasksel
VERSION=\"0.1\"
CC = gcc
CFLAGS = -g -Wall
DEFS = -DVERSION=$(VERSION) -DPACKAGE=\"$(PROGRAM)\" -DLOCALEDIR=\"/usr/share/locale\" #-DDEBUG
LIBS = -lslang
OBJS = tasksel.o slangui.o data.o util.o strutl.o

COMPILE = $(CC) $(CFLAGS) $(DEFS) -c
LINK = $(CC) $(CFLAGS) $(DEFS) -o

all: $(PROGRAM)

%.o: %.c
$(COMPILE) $<

po/build_stamp:
$(MAKE) -C po

$(PROGRAM): $(OBJS) po/build_stamp
$(LINK) $(PROGRAM) $(OBJS) $(LIBS)

test:
$(MAKE) -C scratch

clean:
rm -f $(PROGRAM) *.o *~
$(MAKE) -C po clean


+ 31
- 0
README View File

@@ -0,0 +1,31 @@
$Id: README,v 1.1 1999/11/21 22:01:04 tausq Exp $
Task Selection UI v0.1
Nov 20, 1999
Randolph Chung <tausq@debian.org>

Here's a first cut at a task selection user interface.

The interface GUI is based on libslang. It has no other special library
dependencies.

On startup, the tasksel program will read /var/lib/dpkg/available to
identify task packages (matching "task-*"). These packages will be
presented in a simple list selection screen with their short descriptions.
Users can drill down into the task packages to see detailed descriptions and
some information about the packages in the task.

On exit, tasksel executes the appropriate apt-get command to install the
selected packages. If the -t option is given, then tasksel prints out the
command line to use to stdout instead. All other messages are printed to
stderr.

The appropriate display strings in the source have been marked with gettext
macros, though I have never done any other i18n work and am not sure if it
is done correctly at the moment.

A word on building.... use make CFLAGS="-Os" to get a smaller binary. The
default build rule produces binaries with debugging symbols. You can also
turn on -DDEBUG to get extra debugging info.

Comments and suggestions are most welcome.


+ 2
- 0
TODO View File

@@ -0,0 +1,2 @@
$Id: TODO,v 1.1 1999/11/21 22:01:04 tausq Exp $
- fix screen resize code

+ 248
- 0
data.c View File

@@ -0,0 +1,248 @@
/* $Id: data.c,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
/* data.c - encapsulates functions for reading a package listing like dpkg's available file
* Internally, packages are stored in a binary tree format to faciliate search operations
*/
#include "data.h"

#include <stdio.h>
#include <stdlib.h>
#include <search.h>
#include <string.h>
#include <ctype.h>

#include "util.h"
#include "macros.h"

#define PACKAGEFIELD "Package: "
#define DEPENDSFIELD "Depends: "
#define RECOMMENDSFIELD "Recommends: "
#define SUGGESTSFIELD "Suggests: "
#define DESCRIPTIONFIELD "Description: "
#define AVAILABLEFILE "/var/lib/dpkg/available"
#define BUF_SIZE 1024
#define MATCHFIELD(buf, s) (strncmp(buf, s, strlen(s)) == 0)
#define FIELDDATA(buf, s) (buf + strlen(s))
#define CHOMP(s) if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = 0

/* module variables */
static struct package_t **_packages_enumbuf = NULL;
static int _packages_enumcount = 0;
static void *_packages_root = NULL;

/* private functions */
static int packagecompare(const void *p1, const void *p2)
{
/* compares two packages by name; used for binary tree routines */
char *s1, *s2;
s1 = ((struct package_t *)p1)->name;
s2 = ((struct package_t *)p2)->name;
return strcmp(s1, s2);
}

static void packages_walk_enumerate(const void *nodep, const VISIT order, const int depth)
{
/* adds nodep to list of nodes if we haven't visited this node before */
struct package_t *datap = *(struct package_t **)nodep;
if (order == leaf || order == endorder) {
_packages_enumcount++;
_packages_enumbuf[_packages_enumcount - 1] = datap;
}
}

static void packages_walk_delete(const void *nodep, const VISIT order, const int depth)
{
/* deletes memory associated with nodep */
struct package_t *datap = *(struct package_t **)nodep;
int i;

if (order == leaf || order == endorder) {
tdelete((void *)datap, &_packages_root, packagecompare);
if (datap->name) FREE(datap->name);
if (datap->shortdesc) FREE(datap->shortdesc);
if (datap->longdesc) FREE(datap->longdesc);
if (datap->depends) {
for (i = 0; i < datap->dependscount; i++) FREE(datap->depends[i]);
FREE(datap->depends);
}
if (datap->suggests) {
for (i = 0; i < datap->suggestscount; i++) FREE(datap->suggests[i]);
FREE(datap->suggests);
}
if (datap->recommends) {
for (i = 0; i < datap->recommendscount; i++) FREE(datap->recommends[i]);
FREE(datap->recommends);
}
FREE(datap);
}
}

int splitlinkdesc(const char *desc, char ***array)
{
/* given a comma separate list of names, returns an array with the names split into elts of the array */
char *p;
char *token;
int i = 0, elts = 1;

VERIFY(array != NULL);
*array = NULL;
if (desc == NULL) return 0;
p = (char *)desc;
while (*p != 0) if (*p++ == ',') elts++;

*array = MALLOC(sizeof(char *) * elts);
memset(*array, 0, sizeof(char *) * elts);
p = (char *)desc;
while ((token = strsep(&p, ","))) {
while (isspace(*token)) token++;
(*array)[i++] = STRDUP(token);
}

return elts;
}

static void addpackage(struct packages_t *pkgs,
const char *name, const char *dependsdesc, const char *recommendsdesc,
const char *suggestsdesc, const char *shortdesc, const char *longdesc)
{
/* Adds package to the package list binary tree */
struct package_t *node = NEW(struct package_t);
void *p;
VERIFY(name != NULL);
/* DPRINTF("Adding package %s to list\n", name); */
memset(node, 0, sizeof(struct package_t));
node->name = STRDUP(name);
node->shortdesc = STRDUP(shortdesc);
node->longdesc = STRDUP(longdesc);

if (dependsdesc) node->dependscount = splitlinkdesc(dependsdesc, &node->depends);
if (recommendsdesc) node->recommendscount = splitlinkdesc(recommendsdesc, &node->recommends);
if (suggestsdesc) node->suggestscount = splitlinkdesc(suggestsdesc, &node->suggests);

p = tsearch((void *)node, &pkgs->packages, packagecompare);
VERIFY(p != NULL);
pkgs->count++;
}

/* public functions */
struct package_t *packages_find(const struct packages_t *pkgs, const char *name)
{
/* Given a package name, returns a pointer to the appropriate package_t structure
* or NULL if none is found */
struct package_t pkg;
void *result;
pkg.name = (char *)name;
result = tfind((void *)&pkg, &pkgs->packages, packagecompare);
if (result == NULL)
return NULL;
else
return *(struct package_t **)result;
}

struct package_t **packages_enumerate(const struct packages_t *packages)
{
/* Converts the packages binary tree into a array. Do not modify the returned array! It
* is a static variable managed by this module */
if (_packages_enumbuf != NULL) {
FREE(_packages_enumbuf);
}
_packages_enumbuf = MALLOC(sizeof(struct package_t *) * packages->count);
if (_packages_enumbuf == NULL)
DIE("Cannot allocate memory for enumeration buffer");
memset(_packages_enumbuf, 0, sizeof(struct package_t *) * packages->count);
_packages_enumcount = 0;
twalk((void *)packages->packages, packages_walk_enumerate);
ASSERT(_packages_enumcount == packages->count);
return _packages_enumbuf;
}

void packages_readlist(struct packages_t *taskpkgs, struct packages_t *pkgs)
{
/* Populates internal data structures with information for an available file */
FILE *f;
char buf[BUF_SIZE];
char *name, *shortdesc, *longdesc;
char *dependsdesc, *recommendsdesc, *suggestsdesc;
VERIFY(taskpkgs != NULL); VERIFY(pkgs != NULL);
/* Initialization */
memset(taskpkgs, 0, sizeof(struct packages_t));
memset(pkgs, 0, sizeof(struct packages_t));

if ((f = fopen(AVAILABLEFILE, "r")) == NULL) PERROR(AVAILABLEFILE);
while (!feof(f)) {
fgets(buf, BUF_SIZE, f);
CHOMP(buf);
if (MATCHFIELD(buf, PACKAGEFIELD)) {
/*DPRINTF("Package = %s\n", FIELDDATA(buf, PACKAGEFIELD)); */
name = shortdesc = longdesc = dependsdesc = recommendsdesc = suggestsdesc = NULL;
name = STRDUP(FIELDDATA(buf, PACKAGEFIELD));
VERIFY(name != NULL);

/* look for depends/suggests and shotdesc/longdesc */
while (!feof(f)) {
fgets(buf, BUF_SIZE, f);
CHOMP(buf);
if (buf[0] == 0) break;

if (MATCHFIELD(buf, DEPENDSFIELD)) {
dependsdesc = STRDUP(FIELDDATA(buf, DEPENDSFIELD));
VERIFY(dependsdesc != NULL);
} else if (MATCHFIELD(buf, RECOMMENDSFIELD)) {
recommendsdesc = STRDUP(FIELDDATA(buf, RECOMMENDSFIELD));
VERIFY(recommendsdesc != NULL);
} else if (MATCHFIELD(buf, SUGGESTSFIELD)) {
suggestsdesc = STRDUP(FIELDDATA(buf, SUGGESTSFIELD));
VERIFY(suggestsdesc != NULL);
} else if (MATCHFIELD(buf, DESCRIPTIONFIELD)) {
shortdesc = STRDUP(FIELDDATA(buf, DESCRIPTIONFIELD));
VERIFY(shortdesc != NULL);
do {
fgets(buf, BUF_SIZE, f);
if (buf[0] != ' ') break;
if (buf[1] == '.') buf[1] = ' ';
if (longdesc == NULL) {
longdesc = (char *)MALLOC(strlen(buf) + 1);
strcpy(longdesc, buf + 1);
} else {
longdesc = realloc(longdesc, strlen(longdesc) + strlen(buf) + 1);
strcat(longdesc, buf + 1);
}
} while (buf[0] != '\n' && !feof(f));
break;
}
}

addpackage(pkgs, name, NULL, NULL, NULL, shortdesc, NULL);
if (strncmp(name, "task-", 5) == 0)
addpackage(taskpkgs, name, dependsdesc, recommendsdesc, suggestsdesc, shortdesc, longdesc);

if (name != NULL) FREE(name);
if (dependsdesc != NULL) FREE(dependsdesc);
if (recommendsdesc != NULL) FREE(recommendsdesc);
if (suggestsdesc != NULL) FREE(suggestsdesc);
if (shortdesc != NULL) FREE(shortdesc);
if (longdesc != NULL) FREE(longdesc);
}
};
fclose(f);
}

void packages_free(struct packages_t *taskpkgs, struct packages_t *pkgs)
{
/* Frees up memory allocated by packages_readlist */
_packages_root = taskpkgs->packages;
twalk(taskpkgs->packages, packages_walk_delete);
_packages_root = pkgs->packages;
twalk(pkgs->packages, packages_walk_delete);
}


+ 31
- 0
data.h View File

@@ -0,0 +1,31 @@
/* $Id: data.h,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
#ifndef _DATA_H
#define _DATA_H

struct package_t {
char *name;
char *shortdesc;
char *longdesc;
int dependscount;
char **depends;
int recommendscount;
char **recommends;
int suggestscount;
char **suggests;
int selected;
};

struct packages_t {
int count;
void *packages;
};

/* Reads in a list of package and package descriptions */
void packages_readlist(struct packages_t *taskpackages, struct packages_t *packages);
/* free memory allocated to store packages */
void packages_free(struct packages_t *taskpackages, struct packages_t *packages);

struct package_t *packages_find(const struct packages_t *packages, const char *name);
struct package_t **packages_enumerate(const struct packages_t *packages);

#endif

+ 14
- 0
help.h View File

@@ -0,0 +1,14 @@
/* $Id: help.h,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
#ifndef _HELP_H
#define _HELP_H

#define HELPTXT _("Task packages are \"metapackages\" that allow you to quickly install a selection of " \
"packages that performs a given task.\n\nThe main chooser list shows a list of " \
"tasks that you can choose to install. The arrow keys moves the cursor. Pressing ENTER " \
"or the SPACEBAR toggles the selection of the package at the cursor. You can also press " \
"A to select all packages, or N to deselect all packages. Pressing Q will exit this " \
"program and begin installation of your selected tasks.\n\n\nThank you for using Debian." \
"\n\nPress enter to return to the task selection screen" \
)

#endif

+ 54
- 0
macros.h View File

@@ -0,0 +1,54 @@
/* $Id: macros.h,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
#ifndef _MACROS_H
#define _MACROS_H

#include <stdio.h>
#include <errno.h>

#ifdef DEBUG
#define DPRINTF(fmt, arg...) \
do { \
fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \
fprintf(stderr, fmt, ##arg); \
fprintf(stderr, "\r\n"); \
} while (0);
#define ASSERT(cond) \
if (!(cond)) { \
fprintf(stderr, "ASSERTION FAILED at %s:%d! (%s)\n", __FILE__, __LINE__, #cond); \
exit(255); \
}
#define VERIFY(cond) ASSERT(cond)
#define ABORT abort()
#define STRDUP(s) safe_strdup(s)
#define MALLOC(sz) safe_malloc(sz)
#define FREE(p) safe_free((void **)&p);
#else
#define DPRINTF(fmt, arg...)
#define ASSERT(cond)
#define VERIFY(cond)
#define ABORT exit(255)
#define STRDUP(s) (s ? strdup(s) : NULL)
#define MALLOC(sz) malloc(sz)
#define FREE(p) if (p) free(p)
#endif
/* Do you see a perl influence? :-) */
#define DIE(fmt, arg...) \
do { \
fprintf(stderr, "Fatal error encountered at %s:%d\r\n\t", __FILE__, __LINE__); \
fprintf(stderr, fmt, ##arg); \
fprintf(stderr, "\r\n"); \
ABORT; \
} while (0);
#define PERROR(ctx) \
do { \
fprintf(stderr, "I/O error at %s:%d\r\n\t", __FILE__, __LINE__); \
fprintf(stderr, "%s: %s\r\n", ctx, strerror(errno)); \
ABORT; \
} while (0);
#define NEW(S) (S *)MALLOC(sizeof(S))
#define _(s) gettext(s)
#endif

+ 11
- 0
po/Makefile View File

@@ -0,0 +1,11 @@
XGETTEXT = xgettext --keyword=_

%.po:
$(XGETTEXT) ../*.c

all: messages.po
touch build_stamp

clean:
-rm -f messages.po build_stamp


+ 25
- 0
scratch/Makefile View File

@@ -0,0 +1,25 @@
CC = gcc
CFLAGS = -g -Wall -I..
DEFS = -DVERSION=$(VERSION) -DPACKAGE=\"$(PROGRAM)\" -DLOCALEDIR=\"/usr/share/locale\" -DDEBUG
LIBS = -lslang

COMPILE = $(CC) $(CFLAGS) $(DEFS) -c
LINK = $(CC) $(CFLAGS) $(DEFS) -o

all: testdata flowtest

../%.o: ../%.c
$(COMPILE) $< -o $@

%.o: %.c
$(COMPILE) $<

testdata: ../data.o ../util.o testdata.o
$(LINK) testdata $^

flowtest: ../strutl.o ../util.o flowtest.o
$(LINK) flowtest $^

clean:
rm -f *.o *~ testdata flowtest


+ 20
- 0
scratch/flowtest.c View File

@@ -0,0 +1,20 @@
#include <stdio.h>
#include "strutl.h"
#include <stdlib.h>

int main(int argc, char**argv)
{
char *buf;
char *S1 = "99 bottles of beer on the wall, 99 bottles of beer, take one down, pass it around";
char *S2 = "99bottlesofbeeronthewall,99bottlesofbeer,takeonedown,passitaround";

buf = reflowtext(30, S1);
printf("Original text:\n%s\n---\nReflowed text:\n%s\n\n", S1, buf);
free(buf);

buf = reflowtext(30, S2);
printf("Original text:\n%s\n---\nReflowed text:\n%s\n\n", S2, buf);
free(buf);

return 0;
}

+ 35
- 0
scratch/testdata.c View File

@@ -0,0 +1,35 @@
#include <stdio.h>
#include "data.h"
#include "util.h"

int main(int argc, char *argv[])
{
struct packages_t taskpkgs, pkgs;
struct package_t **taskpackages, *package;
char *pkgname;
int i, j;
#ifdef DEBUG
atexit(memleak_check);
#endif
packages_readlist(&taskpkgs, &pkgs);
taskpackages = packages_enumerate(&taskpkgs);

for (i = 0; i < taskpkgs.count; i++) {
printf("Task package %d: %s\n", i+1, taskpackages[i]->name);
if (taskpackages[i]->dependscount > 0) {
printf("\tDepends:\n");
for (j = 0; j < taskpackages[i]->dependscount; j++)
pkgname = taskpackages[i]->depends[j];
package = packages_find(&pkgs, pkgname);
printf("\t\t%s: %s\n", pkgname, (package ? package->shortdesc : "(no description available)"));
}
printf("\tDescription: %s\n%s\n\n",
taskpackages[i]->shortdesc, taskpackages[i]->longdesc);
/* ... */
}

packages_free(&taskpkgs, &pkgs);
return 0;
}

+ 348
- 0
slangui.c View File

@@ -0,0 +1,348 @@
/* $Id: slangui.c,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
/* slangui.c - SLang user interface routines */
/* TODO: the redraw code is a bit broken */
#include "slangui.h"
#include <slang.h>
#include <libintl.h>
#include <string.h>
#include <ctype.h>

#include "data.h"
#include "strutl.h"
#include "macros.h"
#include "help.h"

/* Slang object number mapping */
#define DEFAULTOBJ 0
#define CHOOSEROBJ 1
#define DESCOBJ 2
#define STATUSOBJ 3
#define DIALOGOBJ 4
#define POINTEROBJ 5
#define BUTTONOBJ 6

#define ROWS SLtt_Screen_Rows
#define COLUMNS SLtt_Screen_Cols

/* Module private variables */
static int _chooser_coloffset = 5;
static int _chooser_rowoffset = 3;
static int _chooser_height = 0;
static int _chooser_width = 0;
static int _chooser_topindex = 0;
static int _resized = 0;
static struct packages_t *_packages = NULL;
static struct packages_t *_taskpackages = NULL;
static struct package_t **_taskpackagesary = NULL;

static void write_centered_str(int row, int coloffset, int width, char *txt)
{
int col;
int len = strlen(txt);
if (txt == NULL) return;

SLsmg_fill_region(row, coloffset, 1, width, ' ');
if (coloffset + len >= width) col = 0;
else col = (width - len) / 2;

SLsmg_gotorc(row, coloffset + col);
SLsmg_write_nstring(txt, width);
}


void ui_init(int argc, char * const argv[], struct packages_t *taskpkgs, struct packages_t *pkgs)
{
_taskpackages = taskpkgs;
_taskpackagesary = packages_enumerate(taskpkgs);
_packages = pkgs;
SLang_set_abort_signal(NULL);
/* assign attributes to objects */
SLtt_set_color(DEFAULTOBJ, NULL, "white", "black");
SLtt_set_color(CHOOSEROBJ, NULL, "black", "cyan");
SLtt_set_color(POINTEROBJ, NULL, "brightblue", "cyan");
SLtt_set_color(DESCOBJ, NULL, "black", "cyan");
SLtt_set_color(STATUSOBJ, NULL, "yellow", "blue");
SLtt_set_color(DIALOGOBJ, NULL, "black", "white");
SLtt_set_color(BUTTONOBJ, NULL, "white", "red");
ui_resize();
}

int ui_shutdown(void)
{
SLsmg_reset_smg();
SLang_reset_tty();
return 0;
}

void ui_resize(void)
{
/* SIGWINCH handler */
if (-1 == SLang_init_tty(-1, 0, 1)) DIE(_("Unable to initialize the terminal"));
SLtt_get_terminfo();
if (-1 == SLsmg_init_smg()) DIE(_("Unable to initialize screen output"));
if (-1 == SLkp_init()) DIE(_("Unable to initialize keyboard interface"));

if (SLtt_Screen_Rows < 20 || SLtt_Screen_Cols < 70) {
DIE(_("Sorry, tasksel needs a terminal with at least 70 columns and 20 rows"));
}
_chooser_height = ROWS - 2 * _chooser_rowoffset;
_chooser_width = COLUMNS - 2 * _chooser_coloffset;
ui_drawscreen();
_resized = 1;
}

int ui_eventloop(void)
{
int done = 0;
int ret = 0;
int pos = 0;
int c, i;
_chooser_topindex = 0;
ui_redrawcursor(0);
while (!done) {

c = SLkp_getkey();
switch (c) {
case SL_KEY_UP:
case SL_KEY_LEFT:
if (pos > 0) pos--; else pos = _taskpackages->count - 1;
ui_redrawcursor(pos);
break;
case SL_KEY_DOWN:
case SL_KEY_RIGHT:
if (pos < _taskpackages->count - 1) pos++; else pos = 0;
ui_redrawcursor(pos);
break;
case SL_KEY_PPAGE:
pos -= _chooser_height;
if (pos < 0) pos = 0;
ui_redrawcursor(pos);
break;
case SL_KEY_NPAGE:
pos += _chooser_height;
if (pos >= _taskpackages->count - 1) pos = _taskpackages->count - 1;
ui_redrawcursor(pos);
break;
case SL_KEY_ENTER: case '\r': case '\n':
case ' ': ui_toggleselection(pos); break;
case 'A': case 'a':
for (i = 0; i < _taskpackages->count; i++) _taskpackagesary[i]->selected = 1;
ui_drawscreen();
break;
case 'N': case 'n':
for (i = 0; i < _taskpackages->count; i++) _taskpackagesary[i]->selected = 0;
ui_drawscreen();
break;
case 'H': case 'h': case SL_KEY_F(1): ui_showhelp(); break;
case 'I': case 'i': ui_showpackageinfo(pos); break;
case 'Q': case 'q': done = 1; break;
}
}
return ret;
}

int ui_drawbox(int obj, int r, int c, unsigned int dr, unsigned int dc)
{
SLsmg_set_color(obj);
SLsmg_draw_box(r, c, dr, dc);
return 0;
}

int ui_drawscreen(void)
{
int i;
char buf[160];
SLsmg_cls();
/* Show version and status lines */
SLsmg_set_color(STATUSOBJ);

snprintf(buf, 160, "%s v%s - %s",
_(" Debian Installation Task Selector"), VERSION,
_("(c) 1999 SPI and others "));

write_centered_str(0, 0, COLUMNS, buf);
write_centered_str(ROWS-1, 0, COLUMNS,
_(" h - Help SPACE - Toggle selection i - Task info q - Exit"));

/* Draw the chooser screen */
SLsmg_set_color(DEFAULTOBJ);
write_centered_str(1, 0, COLUMNS,
_("Select the task package(s) appropriate for your system:"));
ui_drawbox(CHOOSEROBJ, _chooser_rowoffset - 1, _chooser_coloffset - 1, _chooser_height + 2, _chooser_width + 2);

for (i = 0; i < _taskpackages->count && i < _chooser_height; i++)
ui_drawchooseritem(i);
ui_redrawcursor(0);

SLsmg_refresh();
_resized = 0;
return 0;
}

void ui_button(int row, int col, char *txt)
{
SLsmg_set_color(BUTTONOBJ);
SLsmg_gotorc(row, col);
SLsmg_write_char(' ');
SLsmg_write_string(txt);
SLsmg_write_char(' ');
}

void ui_dialog(int row, int col, int height, int width, char *title, char *msg)
{
char *reflowbuf;
int ri, c, pos;
char *line, *txt;

reflowbuf = reflowtext(width - 4, msg);
SLsmg_set_color(DIALOGOBJ);

ui_drawbox(DIALOGOBJ, row, col, height, width);
SLsmg_fill_region(row+1, col+1, height-2, width-2, ' ');
if (title) {
pos = col + (width - strlen(title))/2;
SLsmg_gotorc(row, pos);
SLsmg_write_char(' ');
SLsmg_write_string(title);
SLsmg_write_char(' ');
}
if (reflowbuf != NULL) {
txt = reflowbuf;
ri = 0;
while ((line = strsep(&txt, "\n")) && (ri < height - 3)) {
SLsmg_gotorc(row + 1 + ri, col + 1);
SLsmg_write_nstring(line, width - 4);
ri++;
}
}

ui_button(row+height-2, col+(width-4)/2, " OK ");
SLsmg_refresh();
do {
c = SLkp_getkey();
} while (!(c == '\n' || c == '\r' || c == SL_KEY_ENTER || isspace(c)) && (_resized == 0));
}

void ui_drawchooseritem(int index)
{
char buf[1024];
ASSERT(_taskpackages != NULL);
if (index >= _taskpackages->count) DIE("Index out of bounds: %d >= %d", index, _taskpackages->count);
if (index < _chooser_topindex) return;
SLsmg_set_color(CHOOSEROBJ);
SLsmg_gotorc(_chooser_rowoffset + index - _chooser_topindex, _chooser_coloffset);
snprintf(buf, 1024, " (%c) %s: %s",
(_taskpackagesary[index]->selected == 0 ? ' ' : '*'),
_taskpackagesary[index]->name, _taskpackagesary[index]->shortdesc);
SLsmg_write_nstring(buf, _chooser_width);
}

void ui_toggleselection(int index)
{
ASSERT(_taskpackages != NULL);
if (index >= _taskpackages->count) DIE("Index out of bounds: %d >= %d", index, _taskpackages->count);
if (_taskpackagesary[index]->selected == 0)
_taskpackagesary[index]->selected = 1;
else
_taskpackagesary[index]->selected = 0;
SLsmg_set_color(CHOOSEROBJ);
SLsmg_gotorc(_chooser_rowoffset + index - _chooser_topindex, _chooser_coloffset + 3);

if (_taskpackagesary[index]->selected == 0)
SLsmg_write_string("( )");
else
SLsmg_write_string("(*)");
SLsmg_refresh();
}

void ui_showhelp(void)
{
ui_dialog(3, 3, ROWS-6, COLUMNS-6, "Help", HELPTXT);
ui_drawscreen();
}

void ui_redrawchooser(int index)
{
int i;
for (i = _chooser_topindex; i < _chooser_topindex + _chooser_height; i++)
if (i < _taskpackages->count) ui_drawchooseritem(i);
}

void ui_redrawcursor(int index)
{
/* Check to see if we have to scroll the selection */
if (index + 1 - _chooser_height > _chooser_topindex) {
_chooser_topindex = index + 1 - _chooser_height;
ui_redrawchooser(index);
} else if (index < _chooser_topindex) {
_chooser_topindex = 0;
ui_redrawchooser(index);
}

SLsmg_set_color(POINTEROBJ);
SLsmg_fill_region(_chooser_rowoffset, _chooser_coloffset, _chooser_height, 3, ' ');
SLsmg_gotorc(_chooser_rowoffset + index - _chooser_topindex, _chooser_coloffset);
SLsmg_write_string("->");
SLsmg_refresh();
}

void ui_showpackageinfo(int index)
{
struct package_t *pkg, *deppkg;
int i;
int width;
char buf[4096];
char shortbuf[256];
int bufleft;
ASSERT(_taskpackages != NULL);
if (index >= _taskpackages->count) DIE("Index out of bounds: %d >= %d", index, _taskpackages->count);
pkg = _taskpackagesary[index];
/* pack buf with package info */
snprintf(buf, sizeof(buf), "Name: %s\nDescription:\n%s\n\nDependent packages:\n", pkg->name, pkg->longdesc);
bufleft = sizeof(buf) - strlen(buf) - 1;
width = COLUMNS - 5;
ASSERT(width < sizeof(shortbuf));
for (i = 0; i < pkg->dependscount; i++) {
deppkg = packages_find(_packages, pkg->depends[i]);
snprintf(shortbuf, width, "%s - %s\n", pkg->depends[i],
(deppkg && deppkg->shortdesc ? deppkg->shortdesc : "(no description available)"));
strncat(buf, shortbuf, bufleft);
bufleft = sizeof(buf) - strlen(buf) - 1;
}

ui_dialog(2, 2, ROWS-4, COLUMNS-4, pkg->name, buf);
ui_drawscreen();
}


+ 24
- 0
slangui.h View File

@@ -0,0 +1,24 @@
/* $Id */
#ifndef _SLANGUI_H
#define _SLANGUI_H

struct packages_t;

void ui_init(int argc, char * const argv[], struct packages_t *taskpkgs, struct packages_t *packages);
int ui_shutdown(void);
void ui_resize(void);
int ui_eventloop(void);

int ui_drawbox(int obj, int x, int y, unsigned int dx, unsigned int dy);
void ui_button(int row, int col, char *txt);
void ui_dialog(int row, int col, int height, int width, char *title, char *msg);

int ui_drawscreen(void);
void ui_drawchooseritem(int index);
void ui_toggleselection(int index);
void ui_showhelp(void);
void ui_showpackageinfo(int index);
void ui_redrawchooser(int index);
void ui_redrawcursor(int index);

#endif

+ 57
- 0
strutl.c View File

@@ -0,0 +1,57 @@
/* $Id: strutl.c,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
#include "strutl.h"

#include <string.h>
#include <stdlib.h>

#include "macros.h"

char *reflowtext(int width, char *txt)
{
/* A simple greedy text formatting algorithm. Tries to put as many characters as possible
* on a line without going over width
*
* Returns a malloc'ed string buffer that should be freed by the caller
*/
char *buf;
char *begin, *end;

if (txt == NULL) return NULL;
buf = MALLOC(strlen(txt) + strlen(txt) / width + 2);
buf[0] = 0;
begin = txt;
while (*begin != 0) {
end = begin;
while (*end != 0 && *end != '\n' && end - begin < width) end++;
if (end - begin < width) {
/* don't need to wrap -- saw a newline or EOS */
if (*end == 0) {
strncat(buf, begin, end - begin);
break;
} else {
strncat(buf, begin, end - begin);
strcat(buf, "\n");
begin = end + 1;
}
} else {
/* wrap the text */
end--;
while (*end != ' ' && end > begin) end--;
if (end != begin) {
strncat(buf, begin, end - begin);
strcat(buf, "\n");
begin = end + 1;
} else {
/* this is where it gets gross.. nowhere to break the line */
end = begin + width - 1;
strncat(buf, begin, end - begin);
strcat(buf, "\n");
begin = end;
}
}
}
return buf;
}


+ 7
- 0
strutl.h View File

@@ -0,0 +1,7 @@
/* $Id: strutl.h,v 1.1 1999/11/21 22:01:04 tausq Rel $ */
#ifndef _STRUTL_H
#define _STRUTL_H

char *reflowtext(int width, char *txt);

#endif

+ 92
- 0
tasksel.c View File

@@ -0,0 +1,92 @@
/* $Id: tasksel.c,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
#include "tasksel.h"

#include <string.h>
#include <signal.h>
#include <libintl.h>
#include <locale.h>
#include <stdlib.h>
#include <unistd.h>

#include "slangui.h"
#include "data.h"
#include "macros.h"

static void signalhandler(int sig)
{
switch (sig) {
case SIGWINCH:
ui_resize();
break;
default:
DPRINTF("%s\n", _("Unknown signal seen"));
}
}

void help(void)
{
fprintf(stderr, "tasksel [-t]\n\t");
fprintf(stderr, "%s\n\n", _("-t -- test mode; don't actually run apt-get on exit"));
exit(0);
}

int main(int argc, char * const argv[])
{
int i, c, r, testmode = 0;
struct packages_t taskpkgs, packages;
struct package_t **pkglist;
char buf[2048];
signal(SIGWINCH, signalhandler);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
while (1) {
c = getopt(argc, argv, "t");
if (c == -1) break;

switch (c) {
case 't': testmode = 1; break;
default: help();
}
}
packages_readlist(&taskpkgs, &packages);
ui_init(argc, argv, &taskpkgs, &packages);
ui_drawscreen();
r = ui_eventloop();
ui_shutdown();

pkglist = packages_enumerate(&taskpkgs);

if (r == 0) {
sprintf(buf, "apt-get install ");
c = 0;
for (i = 0; i < taskpkgs.count; i++) {
if (pkglist[i]->selected > 0) {
/* TODO check buffer overflow; not likely, but still... */
strcat(buf, pkglist[i]->name);
strcat(buf, " ");
c++;
}
}

if (c > 0) {
if (testmode == 1)
printf("%s\n", buf);
else
system(buf);
} else {
fprintf(stderr, "No packages selected\n");
r = 1;
}
}
packages_free(&taskpkgs, &packages);
return r;
}


+ 7
- 0
tasksel.h View File

@@ -0,0 +1,7 @@
/* $Id: tasksel.h,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
#ifndef _TASKSEL_H
#define _TASKSEL_H

void help(void);

#endif

+ 57
- 0
util.c View File

@@ -0,0 +1,57 @@
/* $Id: util.c,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
#include "util.h"

#include <string.h>
#include <stdlib.h>

#include "macros.h"

#ifdef DEBUG
static int _num_mallocs = 0;

char *safe_strdup(const char *s)
{
char *p;
if (s != NULL) {
p = strdup(s);
_num_mallocs++;
if (p == NULL) DIE("Cannot allocate memory for strdup");
return p;
} else {
return NULL;
}
}

void *safe_malloc(int size)
{
void *p;
if (size == 0) {
DPRINTF("Attempting to allocate 0 bytes!");
return NULL;
}
p = malloc(size);
_num_mallocs++;
if (p == NULL) DIE("Cannot allocate %d bytes of memory", size);
return p;
}

void safe_free(void **p)
{
if (p == NULL || *p == NULL) {
DPRINTF("Attempting to dereference NULL pointer");
} else {
free(*p);
}
if (p) *p = NULL;
_num_mallocs--;
}

void memleak_check(void)
{
DPRINTF("Outstanding mallocs : %d\n", _num_mallocs);
}

#endif

+ 10
- 0
util.h View File

@@ -0,0 +1,10 @@
/* $Id: util.h,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
#ifndef _UTIL_H
#define _UTIL_H

char *safe_strdup(const char *);
void *safe_malloc(int);
void safe_free(void **);
void memleak_check(void);

#endif

Loading…
Cancel
Save