From 42b6dbbbde03ac9134658fc531a1294a96f1d33d Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Tue, 4 Jul 2017 14:01:44 +0200 Subject: Initial import of xdu-3.0.orig --- Imakefile | 12 + README | 94 ++++++++ XDu.ad | 19 ++ patchlevel.h | 1 + version.h | 1 + xdu.c | 770 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xdu.man | 204 ++++++++++++++++ xwin.c | 496 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 1597 insertions(+) create mode 100644 Imakefile create mode 100644 README create mode 100644 XDu.ad create mode 100644 patchlevel.h create mode 100644 version.h create mode 100644 xdu.c create mode 100644 xdu.man create mode 100644 xwin.c diff --git a/Imakefile b/Imakefile new file mode 100644 index 0000000..a40e57b --- /dev/null +++ b/Imakefile @@ -0,0 +1,12 @@ +XCOMM +XCOMM Imakefile for xdu : X11 display of du output +XCOMM +XCOMM Phillip Dykstra, phil@arl.mil +XCOMM + DEPLIBS = XawClientDepLibs +LOCAL_LIBRARIES = XawClientLibs + SRCS = xdu.c xwin.c + OBJS = xdu.o xwin.o + +ComplexProgramTarget(xdu) +InstallAppDefaults(XDu) diff --git a/README b/README new file mode 100644 index 0000000..84b306e --- /dev/null +++ b/README @@ -0,0 +1,94 @@ +================================================================ +XDU - Display the output of "du" in an X window +================================================================ + +XDU is a program for displaying a graphical tree of disk space +utilization as reported by the UNIX utility "du". You can +navigate up and down in the tree, sort things, and print out +information. See the manual page for details. + +This program can be found by anonymous ftp at + + ftp.arl.mil:pub/xdu-3.0.tar.Z + +and should appear in the X11R6 contrib files. + +================================================================ +Compilation +================================================================ + +Use "xmkmf" to build a Makefile from the Imakefile. +Then "make", "make install", "make install.man". +But if for some reason you can't do that, try: + + cc -o xdu xdu.c xwin.c -lXaw -lXt -lXext -lX11 + +See the XDu.ad file if e.g. you have problems with + the selected font. + +This release was tested against X11R6 patch level 1 on an +SGI running Irix 5.2. It has been tested against X11R5 on +SunOS 4.1.3, SunOS 5.2 (Solaris), SGI Irix 4.0.5, Gould +UTX 2.1. + +================================================================ +Revision History +================================================================ + +Version 3.0 5 Jun 94 + X11R6 contrib release + Popup help window + Now uses Athena widgets, but no menus or buttons yet + +Version 2.1 22 Jul 93 + Fixed a bug in the sorting code where traversal back up a + sorted tree could land you in the wrong parent directory. + +Version 2.0 21 Jul 93 + Added sorting. + Command line options. + More resources. + Better redraw behavior. + Bug fixes (to handle trailing slashes and directories + with no or zero size information). + +Version 1.1 5 Oct 91 + Added resource control + Display of size information + More accurate label positioning + +Version 1.0 4 Sep 91 + First public release + +================================================================ +Remaining Bug? +================================================================ + + On startup on a Sun (but not on an SGI), keyboard input + may not be received by the application until you move the + mouse out of and back into the window. Button presses are + fine. Does anyone know what's going on there? + Mark Evans pointed out a fix - now in the BUG section of + the manual page, but I would still like to hear how/why + this happens. + +================================================================ +Acknowledgements +================================================================ +Thanks for bug reports and code fixes from: + +Casey Leedom +Stephen Gildea +Nelson Minar +Don Tiessen +Gerry.Tomlinson@newcastle.ac.uk +Mark Evans +Juha Takala + +And the many others who told me what they thought about it. + +Send any bugs/comments to: + +Phil Dykstra + +http://info.arl.mil/~phil/ diff --git a/XDu.ad b/XDu.ad new file mode 100644 index 0000000..62f60c0 --- /dev/null +++ b/XDu.ad @@ -0,0 +1,19 @@ +! +! XDu Resources +! +! I recommend the "-*-helvetica-bold-r-normal--14-*" font, but if +! you don't have it, or want your server default, then change it +! or comment it out respectively. +! Order choices: first, last, alpha, ralpha, size, rsize +! Color to taste. +! +!XDu*foreground: yellow +!XDu*background: blue4 +!XDu*help*foreground: green +!XDu*help*background: red4 +XDu*window.width: 600 +XDu*window.height: 480 +XDu.font: -*-helvetica-bold-r-normal--14-* +XDu.ncol: 5 +XDu.showsize: true +XDu.order: first diff --git a/patchlevel.h b/patchlevel.h new file mode 100644 index 0000000..935ec35 --- /dev/null +++ b/patchlevel.h @@ -0,0 +1 @@ +#define PATCHLEVEL 0 diff --git a/version.h b/version.h new file mode 100644 index 0000000..a650768 --- /dev/null +++ b/version.h @@ -0,0 +1 @@ +#define XDU_VERSION "3.0" diff --git a/xdu.c b/xdu.c new file mode 100644 index 0000000..fe05843 --- /dev/null +++ b/xdu.c @@ -0,0 +1,770 @@ +/* + * X D U . C + * + * Display the output of "du" in an X window. + * + * Phillip C. Dykstra + * + * 4 Sep 1991. + * + * Copyright (c) Phillip C. Dykstra 1991, 1993, 1994 + * The X Consortium, and any party obtaining a copy of these files from + * the X Consortium, directly or indirectly, is granted, free of charge, a + * full and unrestricted irrevocable, world-wide, paid up, royalty-free, + * nonexclusive right and license to deal in this software and + * documentation files (the "Software"), including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons who receive + * copies from any such party to do so. This license includes without + * limitation a license to do the foregoing actions under any patents of + * the party supplying this software to the X Consortium. + */ +#include +#include "version.h" + +extern char *malloc(), *calloc(); + +#define MAXDEPTH 80 /* max elements in a path */ +#define MAXNAME 1024 /* max pathname element length */ +#define MAXPATH 4096 /* max total pathname length */ +#define NCOLS 5 /* default number of columns in display */ + +/* What we IMPORT from xwin.c */ +extern int xsetup(), xmainloop(), xdrawrect(), xrepaint(); + +/* What we EXPORT to xwin.c */ +extern int press(), reset(), repaint(), setorder(), reorder(); +extern nodeinfo(), helpinfo(); +int ncols = NCOLS; + +/* internal routines */ +char *strdup(); +void addtree(); +void parse_file(); +void parse_entry(); +void dumptree(); +void clearrects(); +void sorttree(); + +/* order to sort paths by */ +#define ORD_FIRST 1 +#define ORD_LAST 2 +#define ORD_ALPHA 3 +#define ORD_SIZE 4 +#define ORD_RALPHA 5 +#define ORD_RSIZE 6 +#define ORD_DEFAULT ORD_FIRST +int order = ORD_DEFAULT; + +/* + * Rectangle Structure + * Stores window coordinates of a displayed rectangle + * so that we can "find" it again on key presses. + */ +struct rect { + int left; + int top; + int width; + int height; +}; + +/* + * Node Structure + * Each node in the path tree is linked in with one of these. + */ +struct node { + char *name; + long size; /* from here down in the tree */ + long num; /* entry number - for resorting */ + struct rect rect; /* last drawn screen rectangle */ + struct node *peer; /* siblings */ + struct node *child; /* list of children if !NULL */ + struct node *parent; /* backpointer to parent */ +} top; +struct node *topp = ⊤ +#define NODE_NULL ((struct node *)0) +long nnodes = 0; + +/* + * create a new node with the given name and size info + */ +struct node * +makenode(name,size) +char *name; +int size; +{ + struct node *np; + + np = (struct node *)calloc(1,sizeof(struct node)); + np->name = strdup(name); + np->size = size; + np->num = nnodes; + nnodes++; + + return np; +} + +/* + * Return the node (if any) which has a draw rectangle containing + * the given x,y point. + */ +struct node * +findnode(treep, x, y) +struct node *treep; +int x, y; +{ + struct node *np; + struct node *np2; + + if (treep == NODE_NULL) + return NODE_NULL; + + if (x >= treep->rect.left && x < treep->rect.left+treep->rect.width + && y >= treep->rect.top && y < treep->rect.top+treep->rect.height) { + /*printf("found %s\n", treep->name);*/ + return treep; /* found */ + } + + /* for each child */ + for (np = treep->child; np != NULL; np = np->peer) { + if ((np2 = findnode(np,x,y)) != NODE_NULL) + return np2; + } + return NODE_NULL; +} + +/* + * return a count of the number of children of a given node + */ +int +numchildren(nodep) +struct node *nodep; +{ + int n; + + if (nodep == NODE_NULL) + return 0; + + n = 0; + for (nodep = nodep->child; nodep != NODE_NULL; nodep=nodep->peer) + n++; + + return n; +} + +/* + * fix_tree - This function repairs the tree when certain nodes haven't + * had their sizes initialized. [DPT911113] + * * * * This function is recursive * * * + */ +long +fix_tree(top) +struct node *top; +{ + struct node *nd; + + if (top == NODE_NULL) /* recursion end conditions */ + return 0; + if (top->size >= 0) /* also halt recursion on valid size */ + return top->size; /* (remember: sizes init. to -1) */ + + top->size = 0; + for (nd = top->child; nd != NODE_NULL; nd = nd->peer) + top->size += fix_tree(nd); + + return top->size; +} + +static char usage[] = "\ +Usage: xdu [-options ...] filename\n\ + or xdu [-options ...] < du.out\n\ +\n\ +Graphically displays the output of du in an X window\n\ + options include:\n\ + -s Don't display size information\n\ + +s Display size information (default)\n\ + -n Sort in numerical order (largest first)\n\ + -rn Sort in reverse numerical order\n\ + -a Sort in alphabetical order\n\ + -ra Sort in reverse alphabetical order\n\ + -c num Set number of columns to num\n\ + Toolkit options: -fg, -bg, -rv, -display, -geometry, etc.\n\ +"; + +main(argc,argv) +int argc; +char **argv; +{ + top.name = strdup("[root]"); + top.size = -1; + + xsetup(&argc,argv); + if (argc == 1) { + if (isatty(fileno(stdin))) { + fprintf(stderr, usage); + exit(1); + } else { + parse_file("-"); + } + } else if (argc == 2 && strcmp(argv[1],"-help") != 0) { + parse_file(argv[1]); + } else { + fprintf(stderr, usage); + exit(1); + } + top.size = fix_tree(&top); + + /*dumptree(&top,0);*/ + if (order != ORD_DEFAULT) + sorttree(&top, order); + + topp = ⊤ + /* don't display root if only one child */ + if (numchildren(topp) == 1) + topp = topp->child; + + xmainloop(); + exit(0); +} + +void +parse_file(filename) +char *filename; +{ + char buf[4096]; + char name[4096]; + int size; + FILE *fp; + + if (strcmp(filename, "-") == 0) { + fp = stdin; + } else { + if ((fp = fopen(filename, "r")) == 0) { + fprintf(stderr, "xdu: can't open \"%s\"\n", filename); + exit(1); + } + } + while (fgets(buf,sizeof(buf),fp) != NULL) { + sscanf(buf, "%d %s\n", &size, name); + /*printf("%d %s\n", size, name);*/ + parse_entry(name,size); + } + fclose(fp); +} + +/* bust up a path string and link it into the tree */ +void +parse_entry(name,size) +char *name; +int size; +{ + char *path[MAXDEPTH]; /* break up path into this list */ + char buf[MAXNAME]; /* temp space for path element name */ + int arg, indx; + int length; /* nelson@reed.edu - trailing / fix */ + + if (*name == '/') + name++; /* skip leading / */ + + length = strlen(name); + if ((length > 0) && (name[length-1] == '/')) { + /* strip off trailing / (e.g. GNU du) */ + name[length-1] = 0; + } + + arg = 0; indx = 0; + bzero(path,sizeof(path)); + bzero(buf,sizeof(buf)); + while (*name != NULL) { + if (*name == '/') { + buf[indx] = 0; + path[arg++] = strdup(buf); + indx = 0; + if (arg >= MAXDEPTH) + break; + } else { + buf[indx++] = *name; + if (indx >= MAXNAME) + break; + } + name++; + } + buf[indx] = 0; + path[arg++] = strdup(buf); + path[arg] = NULL; + + addtree(&top,path,size); +} + +/* + * Determine where n1 should go compared to n2 + * based on the current sorting order. + * Return -1 if is should be before. + * 0 if it is a toss up. + * 1 if it should go after. + */ +int +compare(n1,n2,order) +struct node *n1, *n2; +int order; +{ + int ret; + + switch (order) { + case ORD_SIZE: + ret = n2->size - n1->size; + if (ret == 0) + return strcmp(n1->name,n2->name); + else + return ret; + break; + case ORD_RSIZE: + ret = n1->size - n2->size; + if (ret == 0) + return strcmp(n1->name,n2->name); + else + return ret; + break; + case ORD_ALPHA: + return strcmp(n1->name,n2->name); + break; + case ORD_RALPHA: + return strcmp(n2->name,n1->name); + break; + case ORD_FIRST: + /*return -1;*/ + return (n1->num - n2->num); + break; + case ORD_LAST: + /*return 1;*/ + return (n2->num - n1->num); + break; + } + + /* shouldn't get here */ + fprintf(stderr,"xdu: bad insertion order\n"); + return 0; +} + +void +insertchild(nodep,childp,order) +struct node *nodep; /* parent */ +struct node *childp; /* child to be added */ +int order; /* FIRST, LAST, ALPHA, SIZE */ +{ + struct node *np, *np1; + + if (nodep == NODE_NULL || childp == NODE_NULL) + return; + if (childp->peer != NODE_NULL) { + fprintf(stderr, "xdu: can't insert child with peers\n"); + return; + } + + childp->parent = nodep; + if (nodep->child == NODE_NULL) { + /* no children, order doesn't matter */ + nodep->child = childp; + return; + } + /* nodep has at least one child already */ + if (compare(childp,nodep->child,order) < 0) { + /* new first child */ + childp->peer = nodep->child; + nodep->child = childp; + return; + } + np1 = nodep->child; + for (np = np1->peer; np != NODE_NULL; np = np->peer) { + if (compare(childp,np,order) < 0) { + /* insert between np1 and np */ + childp->peer = np; + np1->peer = childp; + return; + } + np1 = np; + } + /* at end, link new child on */ + np1->peer = childp; +} + +/* add path as a child of top - recursively */ +void +addtree(top, path, size) +struct node *top; +char *path[]; +int size; +{ + struct node *np; + + /*printf("addtree(\"%s\",\"%s\",%d)\n", top->name, path[0], size);*/ + + /* check all children for a match */ + for (np = top->child; np != NULL; np = np->peer) { + if (strcmp(path[0],np->name) == 0) { + /* name matches */ + if (path[1] == NULL) { + /* end of the chain, save size */ + np->size = size; + return; + } + /* recurse */ + addtree(np,&path[1],size); + return; + } + } + /* no child matched, add a new child */ + np = makenode(path[0],-1); + insertchild(top,np,order); + + if (path[1] == NULL) { + /* end of the chain, save size */ + np->size = size; + return; + } + /* recurse */ + addtree(np,&path[1],size); + return; +} + +/* debug tree print */ +void +dumptree(np,level) +struct node *np; +int level; +{ + int i; + struct node *subnp; + + for (i = 0; i < level; i++) + printf(" "); + + printf("%s %d\n", np->name, np->size); + for (subnp = np->child; subnp != NULL; subnp = subnp->peer) { + dumptree(subnp,level+1); + } +} + +void +sorttree(np, order) +struct node *np; +int order; +{ + struct node *subnp; + struct node *np0, *np1, *np2, *np3; + + /* sort the trees of each of this nodes children */ + for (subnp = np->child; subnp != NODE_NULL; subnp = subnp->peer) { + sorttree(subnp, order); + } + /* then put the given nodes children in order */ + np0 = np; /* np0 points to node before np1 */ + for (np1 = np->child; np1 != NODE_NULL; np1 = np1->peer) { + np2 = np1; /* np2 points to node before np3 */ + for (np3 = np1->peer; np3 != NODE_NULL; np3 = np3->peer) { + if (compare(np3,np1,order) < 0) { + /* swap links */ + if (np0 == np) + np0->child = np3; + else + np0->peer = np3; + np2->peer = np3->peer; + np3->peer = np1; + + /* adjust pointers */ + np1 = np3; + np3 = np2; + } + np2 = np3; + } + np0 = np1; + } +} + +/* + * Draws a node in the given rectangle, and all of its children + * to the "right" of the given rectangle. + */ +drawnode(nodep, rect) +struct node *nodep; /* node whose children we should draw */ +struct rect rect; /* rectangle to draw all children in */ +{ + struct rect subrect; + + /*printf("Drawing \"%s\" %d\n", nodep->name, nodep->size);*/ + + xdrawrect(nodep->name, nodep->size, + rect.left,rect.top,rect.width,rect.height); + + /* save current screen rectangle for lookups */ + nodep->rect.left = rect.left; + nodep->rect.top = rect.top; + nodep->rect.width = rect.width; + nodep->rect.height = rect.height; + + /* draw children in subrectangle */ + subrect.left = rect.left+rect.width; + subrect.top = rect.top; + subrect.width = rect.width; + subrect.height = rect.height; + drawchildren(nodep, subrect); +} + +/* + * Draws all children of a node within the given rectangle. + * Recurses on children. + */ +drawchildren(nodep, rect) +struct node *nodep; /* node whose children we should draw */ +struct rect rect; /* rectangle to draw all children in */ +{ + int totalsize; + int totalheight; + struct node *np; + double fractsize; + int height; + int top; + + /*printf("Drawing children of \"%s\", %d\n", nodep->name, nodep->size);*/ + /*printf("In [%d,%d,%d,%d]\n", rect.left,rect.top,rect.width,rect.height);*/ + + top = rect.top; + totalheight = rect.height; + totalsize = nodep->size; + if (totalsize == 0) { + /* total the sizes of the children */ + totalsize = 0; + for (np = nodep->child; np != NULL; np = np->peer) + totalsize += np->size; + nodep->size = totalsize; + } + + /* for each child */ + for (np = nodep->child; np != NULL; np = np->peer) { + fractsize = np->size / (double)totalsize; + height = fractsize * totalheight + 0.5; + if (height > 1) { + struct rect subrect; + /*printf("%s, drawrect[%d,%d,%d,%d]\n", np->name, + rect.left,top,rect.width,height);*/ + xdrawrect(np->name, np->size, + rect.left,top,rect.width,height); + + /* save current screen rectangle for lookups */ + np->rect.left = rect.left; + np->rect.top = top; + np->rect.width = rect.width; + np->rect.height = height; + + /* draw children in subrectangle */ + subrect.left = rect.left+rect.width; + subrect.top = top; + subrect.width = rect.width; + subrect.height = height; + drawchildren(np, subrect); + + top += height; + } + } +} + +/* + * clear the rectangle information of a given node + * and all of its decendents + */ +void +clearrects(nodep) +struct node *nodep; +{ + struct node *np; + + if (nodep == NODE_NULL) + return; + + nodep->rect.left = 0; + nodep->rect.top = 0; + nodep->rect.width = 0; + nodep->rect.height = 0; + + /* for each child */ + for (np = nodep->child; np != NULL; np = np->peer) { + clearrects(np); + } +} + +pwd() +{ + struct node *np; + struct node *stack[MAXDEPTH]; + int num = 0; + struct node *rootp; + char path[MAXPATH]; + + rootp = ⊤ + if (numchildren(rootp) == 1) + rootp = rootp->child; + + np = topp; + while (np != NODE_NULL) { + stack[num++] = np; + if (np == rootp) + break; + np = np->parent; + } + + path[0] = '\0'; + while (--num >= 0) { + strcat(path,stack[num]->name); + if (num != 0) + strcat(path,"/"); + } + printf("%s %d (%.2f%%)\n", path, topp->size, + 100.0*topp->size/rootp->size); +} + +char * +strdup(s) +char *s; +{ + int n; + char *cp; + + n = strlen(s); + cp = malloc(n+1); + strcpy(cp,s); + + return cp; +} + +/**************** External Entry Points ****************/ + +int +press(x,y) +int x, y; +{ + struct node *np; + + /*printf("press(%d,%d)...\n",x,y);*/ + np = findnode(&top,x,y); + /*printf("Found \"%s\"\n", np?np->name:"(null)");*/ + if (np == topp) { + /* already top, go up if possible */ + if (np->parent != &top || numchildren(&top) != 1) + np = np->parent; + /*printf("Already top, parent = \"%s\"\n", np?np->name:"(null)");*/ + } + if (np != NODE_NULL) { + topp = np; + xrepaint(); + } +} + +int +reset() +{ + topp = ⊤ + if (numchildren(topp) == 1) + topp = topp->child; + xrepaint(); +} + +int +repaint(width,height) +int width, height; +{ + struct rect rect; + + /* define a rectangle to draw into */ + rect.top = 0; + rect.left = 0; + rect.width = width/ncols; + rect.height = height; + + clearrects(&top); /* clear current rectangle info */ + drawnode(topp,rect); /* draw tree into given rectangle */ +#if 0 + pwd(); /* display current path */ +#endif +} + +int +setorder(op) +char *op; +{ + if (strcmp(op, "size") == 0) { + order = ORD_SIZE; + } else if (strcmp(op, "rsize") == 0) { + order = ORD_RSIZE; + } else if (strcmp(op, "alpha") == 0) { + order = ORD_ALPHA; + } else if (strcmp(op, "ralpha") == 0) { + order = ORD_RALPHA; + } else if (strcmp(op, "first") == 0) { + order = ORD_FIRST; + } else if (strcmp(op, "last") == 0) { + order = ORD_LAST; + } else if (strcmp(op, "reverse") == 0) { + switch (order) { + case ORD_ALPHA: + order = ORD_RALPHA; + break; + case ORD_RALPHA: + order = ORD_ALPHA; + break; + case ORD_SIZE: + order = ORD_RSIZE; + break; + case ORD_RSIZE: + order = ORD_SIZE; + break; + case ORD_FIRST: + order = ORD_LAST; + break; + case ORD_LAST: + order = ORD_FIRST; + break; + } + } else { + fprintf(stderr, "xdu: bad order \"%s\"\n", op); + } +} + +int +reorder(op) +char *op; /* order name */ +{ + setorder(op); + sorttree(topp, order); + xrepaint(); +} + +int +nodeinfo() +{ + struct node *np; + + /* display current root path */ + pwd(); + + /* display each child of this node */ + for (np = topp->child; np != NULL; np = np->peer) { + printf("%-8d %s\n", np->size, np->name); + } +} + +int +helpinfo() +{ + fprintf(stdout, "\n\ +XDU Version %s - Keyboard Commands\n\ + a sort alphabetically\n\ + n sort numerically (largest first)\n\ + f sort first-in-first-out\n\ + l sort last-in-first-out\n\ + r reverse sort\n\ + / goto the root\n\ + q quit (also Escape)\n\ + i info to standard out\n\ +0-9 set number of columns (0=10)\n\ +", XDU_VERSION); +} diff --git a/xdu.man b/xdu.man new file mode 100644 index 0000000..1f5da2e --- /dev/null +++ b/xdu.man @@ -0,0 +1,204 @@ +.TH XDU 1 X11 +.SH NAME +xdu \- display the output of "du" in an X window +.SH SYNOPSIS +.B du \|| xdu [options] +.SH DESCRIPTION +.I Xdu +is a program for displaying a graphical tree of disk space +utilization as reported by the UNIX utility "du". The +user can navigate through the tree structure and change +the order of the displayed information. The window +is divided up into several columns, each of which is one level +deeper in the directory hierarchy (from left to right). Boxes +are drawn for each directory. The amount of vertical space +occupied by each box is directly proportional to the amount of +disk space consumed by it and all of its children. The name of +each directory and the amount of data are displayed provided +that there is enough space within its box. Any space at the +"bottom" of a box not covered by its children to the right +represents the space consumed by files \fIin\fR that directory +(as opposed to space from its children). +.PP +There are several command line options available. Equivalent +resources (if any) are shown with each option. +.TP +.B \+s +(.showsize: true) +display sizes (the default). +.TP +.B \-s +(.showsize: false) +don't display sizes. +.TP +.BI \-c " num" +display \fInum\fR columns. +.TP +.B \-a +(.order: alpha) +sorts display alphabetically. +.TP +.B \-ra +(.order: ralpha) +sorts display reverse alphabetically. +.TP +.B \-n +(.order: size) +sorts display numerically (largest first). +.TP +.B \-rn +(.order: rsize) +sorts display reverse numerically (smallest first). +.TP +.BI \-fg " color" +(.foregound) +determines the color of the text and lines. +.TP +.BI \-bg " color" +(.background) +determines the color of the background. +.TP +.B \-rv +reverse video (for monochrome displays) +.PP +In addition to these the usual toolkit options such as +\-rv, \-font, \-display, \-geometry, are supported. +.SH MOUSE ACTIONS +The user can move up or down the tree by clicking the left mouse on +a directory box. If the left most box is selected, the display will +move up one level (assuming you are not already at the root). If any +other box is selected, it will be placed against the left edge of the +window and the display will be rescaled appropriately. +At any time the middle mouse will bring you back to the root. +Clicking the right mouse will exit the program. +.SH KEYSTROKES +Several keystroke commands are supported. Note that all sorting happens +from the current root node down, so it is possible to sort one subtree +differently than another by clicking into it, doing a sort, and going +back up to the parent. +.TP +.B 1-9,0 +sets the number of columns in the display (0 = 10). +.TP +.B a +alphabetical sort. +.TP +.B n +numerical sort (largest first). +.TP +.B f +first-in-first-out sort (this is the order the +data was read into the program). +.TP +.B l +last-in-first-out sort. +.TP +.B r +reverse sense of sort. +.TP +.B s +toggle size display. +.TP +.B h +display a popup help window. +.TP +.B i +display information about the current root node to standard out. +The first line shows the path within the tree, the total size +from this node on down, and the precentage that total represents +of all of the data given to \fIxdu\fR. Subsequent lines show the +size and name information for all children of this node in the +order they are currently sorted in. This allows tiny directories +to be seen that otherwise could not be labled on the display, +and also allows for cutting and pasting of the information. +.TP +.B / +goto the root. +.TP +.B q +(or Escape) +exit the program. +.SH ACTIONS +All mouse and keyboard events trigger actions so they can all +be rebound by translations to suit the individual. The action +functions are: +.TP +.B reset() +goes to the root node. +.TP +.B goto() +moves down into the directory currently under the mouse +(and is thus probably only useful bound to a mouse button). +.TP +.B quit() +exits the program. +.TP +.B reorder(type) +sorts the display from the current root node down according to +one of: alpha, ralpha (reverse alphabetical), size (largest to +smallest), rsize (smallest to largest), first (as originally read +in), last (opposite of original data), reverse (reverse whatever +sort mode is currently selected). +.TP +.B size() +toggles size display on/off +.TP +.B ncol(num) +sets the number of columns to num. +.TP +.B info() +displays directory information as described in the KEYBOARD section. +.TP +.B help() +displays a popup help window. +.PP +As an example of rebinding these, you could put the following +in your resources file: +.sp +.nf +XDu*translations: #override\\n\\ + X: reorder(reverse)\\n\\ + : info() +.fi +.sp +to make the 'x' key reverse the current sort order and the right +mouse button print the directory information message. +.SH RESOURCES +The following resources are supported with some sample values. +.PP +.nf +XDu*foreground: yellow +XDu*background: blue4 +XDu*window.width: 600 +XDu*window.height: 480 +XDu*help*foreground: green +XDu*help*background: red4 +XDu.ncol: 5 +XDu.font: -*-helvetica-bold-r-normal--14-* +XDu.showsize: False +XDu.order: size +.fi +.SH EXAMPLE +.I +cd /usr/src +.br +.I +du > /tmp/du.out +.br +.I +xdu \-n /tmp/du.out +.SH BUGS +On some machines keyboard input may not be accepted by xdu until +the mouse is moved out of and back into the window. I have been +told that putting the following in your resources file may fix +this. +.sp +.nf +.FocusLenience: True +.fi +.SH "SEE ALSO" +du(1) +.SH AUTHOR +Phillip C. Dykstra +.br + diff --git a/xwin.c b/xwin.c new file mode 100644 index 0000000..dbecb5d --- /dev/null +++ b/xwin.c @@ -0,0 +1,496 @@ +/* + * XDU - X Window System Interface. + * + * We hide all of the X hieroglyphics inside of this module. + * + * Phillip C. Dykstra + * + * 4 Sep 1991. + * + * Copyright (c) Phillip C. Dykstra 1991, 1993, 1994 + * The X Consortium, and any party obtaining a copy of these files from + * the X Consortium, directly or indirectly, is granted, free of charge, a + * full and unrestricted irrevocable, world-wide, paid up, royalty-free, + * nonexclusive right and license to deal in this software and + * documentation files (the "Software"), including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons who receive + * copies from any such party to do so. This license includes without + * limitation a license to do the foregoing actions under any patents of + * the party supplying this software to the X Consortium. + */ +#include +#include +#include + +#include +#include +#include +#include + +#include + +#ifndef X_NOT_STDC_ENV +#include /* for exit() */ +#endif + +/* IMPORTS: routines that this module vectors out to */ +extern int press(); +extern int reset(); +extern int repaint(); +extern int reorder(); +extern int setorder(); +extern int nodeinfo(); +extern int helpinfo(); +extern int ncols; + +/* EXPORTS: routines that this module exports outside */ +extern int xsetup(); +extern int xmainloop(); +extern int xclear(); +extern int xrepaint(); +extern int xrepaint_noclear(); +extern int xdrawrect(); + +/* internal routines */ +static void help_popup(); +static void help_popdown(); + +static String fallback_resources[] = { +"*window.width: 600", +"*window.height: 480", +"*help.width: 500", +"*help.height: 330", +"*order: first", +NULL +}; + +/* Application Resources */ +typedef struct { + Pixel foreground; + Pixel background; + XFontStruct *font; + int ncol; + Boolean showsize; + char *order; +} res_data, *res_data_ptr; +static res_data res; + +static XtResource application_resources[] = { + { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), + XtOffset(res_data_ptr,foreground), XtRString, XtDefaultForeground}, + { XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), + XtOffset(res_data_ptr,background), XtRString, XtDefaultBackground}, + { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), + XtOffset(res_data_ptr,font), XtRString, XtDefaultFont }, + { "ncol", "Ncol", XtRInt, sizeof(int), + XtOffset(res_data_ptr,ncol), XtRString, "5"}, + { "showsize", "ShowSize", XtRBoolean, sizeof(Boolean), + XtOffset(res_data_ptr,showsize), XtRString, "True"}, + { "order", "Order", XtRString, sizeof(String), + XtOffset(res_data_ptr,order), XtRString, "first"} +}; + +/* Command Line Options */ +static XrmOptionDescRec options[] = { + {"-c", "*ncol", XrmoptionSepArg, NULL}, + {"+s", "*showsize", XrmoptionNoArg, "True"}, + {"-s", "*showsize", XrmoptionNoArg, "False"}, + {"-n", "*order", XrmoptionNoArg, "size"}, + {"-rn", "*order", XrmoptionNoArg, "rsize"}, + {"-a", "*order", XrmoptionNoArg, "alpha"}, + {"-ra", "*order", XrmoptionNoArg, "ralpha"} +}; + +/* action routines */ +static void a_goto(); +static void a_reset(); +static void a_quit(); +static void a_reorder(); +static void a_size(); +static void a_ncol(); +static void a_info(); +static void a_help(); +static void a_removehelp(); + +static XtActionsRec actionsTable[] = { + { "reset", a_reset }, + { "goto", a_goto }, + { "quit", a_quit }, + { "reorder", a_reorder }, + { "size", a_size }, + { "ncol", a_ncol }, + { "info", a_info }, + { "help", a_help }, + { "RemoveHelp", a_removehelp } +}; + +static char defaultTranslations[] = "\ +Q: quit()\n\ +Escape: quit()\n\ +:/: reset()\n\ +S: size()\n\ +I: info()\n\ +H: help()\n\ +Help: help()\n\ +:?: help()\n\ +A: reorder(alpha)\n\ +N: reorder(size)\n\ +F: reorder(first)\n\ +L: reorder(last)\n\ +R: reorder(reverse)\n\ +1: ncol(1)\n\ +2: ncol(2)\n\ +3: ncol(3)\n\ +4: ncol(4)\n\ +5: ncol(5)\n\ +6: ncol(6)\n\ +7: ncol(7)\n\ +8: ncol(8)\n\ +9: ncol(9)\n\ +0: ncol(10)\n\ +: goto()\n\ +: reset()\n\ +: quit()\n\ +"; + +/* action routines */ + +static void a_quit(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + XtDestroyApplicationContext(XtWidgetToApplicationContext(w)); + exit(0); +} + +static void a_goto(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + press(event->xbutton.x, event->xbutton.y); +} + +static void a_reset(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + reset(); +} + +static void a_reorder(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + if (*num_params != 1) { + fprintf(stderr, "xdu: bad number of params to reorder action\n"); + } else { + reorder(*params); + } +} + +static void a_size(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + if (res.showsize) + res.showsize = 0; + else + res.showsize = 1; + xrepaint(); +} + +static void a_ncol(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + int n; + + if (*num_params != 1) { + fprintf(stderr, "xdu: bad number of params to ncol action\n"); + return; + } + n = atoi(*params); + if (n < 1 || n > 1000) { + fprintf(stderr, "xdu: bad value to ncol action\n"); + return; + } + ncols = res.ncol = n; + xrepaint(); +} + +static void a_info(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + nodeinfo(); +} + +static void a_help(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + /*helpinfo();*/ + help_popup(); +} + +static void a_removehelp(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + help_popdown(); +} + +/* callback routines */ + +static void c_resize(w, data, event, continue_to_dispatch) +Widget w; +XtPointer data; +XEvent *event; +Boolean *continue_to_dispatch; +{ + /*printf("Resize\n");*/ + xrepaint(); +} + +static void c_repaint(w, data, event, continue_to_dispatch) +Widget w; +XtPointer data; +XEvent *event; +Boolean *continue_to_dispatch; +{ + /*printf("Expose\n");*/ + xrepaint_noclear(); +} + +/* X Window related variables */ +static Cursor WorkingCursor; +static Display *dpy; +static int screen; +static Visual *vis; +static Window win; +static GC gc; +static GC cleargc; +static XtAppContext app_con; + +Widget toplevel; + +/* External Functions */ + +int +xsetup(argcp, argv) +int *argcp; +char **argv; +{ + XtTranslations trans_table; + Widget w; + XGCValues gcv; + int n; + Arg args[5]; + + /* Create the top level Widget */ + n = 0; + XtSetArg(args[n], XtNtitle, "XDU Disk Usage Display ('h' for help)\n"); n++; + toplevel = XtAppInitialize(&app_con, "XDu", + options, XtNumber(options), + argcp, argv, + fallback_resources, args, n); + + XtGetApplicationResources(toplevel, (XtPointer)&res, + application_resources, XtNumber(application_resources), + NULL, 0 ); + + XtAppAddActions(app_con, actionsTable, XtNumber(actionsTable)); + trans_table = XtParseTranslationTable(defaultTranslations); + + /* Create a simple Label class widget to draw in */ + n = 0; + XtSetArg(args[n], XtNlabel, ""); n++; + w = XtCreateManagedWidget("window", labelWidgetClass, toplevel, + args, n); + + /* events */ + XtAddEventHandler(w, ExposureMask, False, c_repaint, NULL); + XtAddEventHandler(w, StructureNotifyMask, False, c_resize, NULL); + XtAugmentTranslations(w, trans_table); + + XtRealizeWidget(toplevel); + + /* We need these for the raw Xlib calls */ + win = XtWindow(w); + dpy = XtDisplay(w); + screen = DefaultScreen(dpy); + vis = DefaultVisual(dpy,screen); + + gcv.foreground = res.foreground; + gcv.background = res.background; + gcv.font = res.font->fid; + gc = XCreateGC(dpy, win, (GCFont|GCForeground|GCBackground), &gcv); + + setorder(res.order); + ncols = res.ncol; +} + +xmainloop() +{ + XtAppMainLoop(app_con); + return(0); +} + +xclear() +{ + XClearWindow(dpy, win); +} + +xrepaint() +{ + XWindowAttributes xwa; + + XClearWindow(dpy, win); + XGetWindowAttributes(dpy, win, &xwa); + repaint(xwa.width, xwa.height); +} + +xrepaint_noclear() +{ + XWindowAttributes xwa; + + XGetWindowAttributes(dpy, win, &xwa); + repaint(xwa.width, xwa.height); +} + +xdrawrect(name, size, x, y, width, height) +char *name; +int size; +int x, y, width, height; +{ + int textx, texty; + char label[1024]; + XCharStruct overall; + int ascent, descent, direction; + int cheight; + + /*printf("draw(%d,%d,%d,%d)\n", x, y, width, height );*/ + XDrawRectangle(dpy, win, gc, x, y, width, height); + + if (res.showsize) { + sprintf(label,"%s (%d)", name, size); + name = label; + } + + XTextExtents(res.font, name, strlen(name), &direction, + &ascent, &descent, &overall); + cheight = overall.ascent + overall.descent; + if (height < (cheight + 2)) + return; + + /* print label */ + textx = x + 4; + texty = y + height/2.0 + (overall.ascent - overall.descent)/2.0 + 1.5; + XDrawString(dpy, win, gc, textx, texty, name, strlen(name)); +} + +static Widget popup; + +static void +help_popup() +{ + Widget form, text, src; + Arg args[15]; + int n; + Atom wm_delete_window; + XtTranslations trans_table; + + if (popup != NULL) { + XtPopup(popup, XtGrabNone); + return; + } + + /* popup shell */ + n = 0; + XtSetArg(args[n], XtNtitle, "XDU Help"); n++; + popup = XtCreatePopupShell("helpPopup", transientShellWidgetClass, + toplevel, args, n); + + /* form container */ + n = 0; + XtSetArg(args[n], XtNborderWidth, 0); n++; + XtSetArg(args[n], XtNdefaultDistance, 0); n++; + form = XtCreateManagedWidget("form", formWidgetClass, + popup, args, n); + + /* text widget in form */ + n = 0; + XtSetArg(args[n], XtNborderWidth, 0); n++; + XtSetArg(args[n], XtNresize, XawtextResizeBoth); n++; + /* fallback resources weren't working here on the Sun */ + XtSetArg(args[n], XtNwidth, 500); n++; + XtSetArg(args[n], XtNheight, 330); n++; + text = XtCreateManagedWidget("help", asciiTextWidgetClass, + form, args, n); + + /* create text source */ + n = 0; + XtSetArg(args[n], XtNtype, XawAsciiString); n++; + XtSetArg(args[n], XtNeditType, XawtextRead); n++; + XtSetArg(args[n], XtNstring, "\ +XDU Version 3.0 - Phil Dykstra \n\ +\n\ +Keyboard Commands\n\ + a sort alphabetically\n\ + n sort numerically (largest first)\n\ + f sort first-in-first-out\n\ + l sort last-in-first-out\n\ + r reverse sort\n\ + s toggle size display\n\ + / goto the root\n\ + i node info to standard out\n\ + h this help message\n\ + q quit (also Escape)\n\ +0-9 set number of columns (0=10)\n\ +\n\ +Mouse Commands\n\ + Left Goto node (goto parent if leftmost box)\n\ + Middle Back to root\n\ + Right Quit\n\ +"); n++; + src = XtCreateWidget("textSource", asciiSrcObjectClass, + text, args, n); + /* set text source */ + XawTextSetSource(text, src, 0); + + XtRealizeWidget(popup); + XtPopup(popup, XtGrabNone); + + trans_table = XtParseTranslationTable("Q: RemoveHelp()"); + XtAugmentTranslations(form, trans_table); + + /* Set up ICCCM delete window */ + wm_delete_window = XInternAtom(XtDisplay(popup), "WM_DELETE_WINDOW", False); + XtOverrideTranslations(popup, XtParseTranslationTable("WM_PROTOCOLS: RemoveHelp()")); + XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1); +} + +static void +help_popdown() +{ + XtPopdown(popup); +} -- cgit 1.4.1