diff options
author | Leah Neukirchen <leah@vuxu.org> | 2017-07-04 14:01:44 +0200 |
---|---|---|
committer | Leah Neukirchen <leah@vuxu.org> | 2017-07-04 14:01:44 +0200 |
commit | 42b6dbbbde03ac9134658fc531a1294a96f1d33d (patch) | |
tree | 680286c2b2fe4511059791f27103f1237a5de35b | |
download | xdu-42b6dbbbde03ac9134658fc531a1294a96f1d33d.tar.gz xdu-42b6dbbbde03ac9134658fc531a1294a96f1d33d.tar.xz xdu-42b6dbbbde03ac9134658fc531a1294a96f1d33d.zip |
Initial import of xdu-3.0.orig
-rw-r--r-- | Imakefile | 12 | ||||
-rw-r--r-- | README | 94 | ||||
-rw-r--r-- | XDu.ad | 19 | ||||
-rw-r--r-- | patchlevel.h | 1 | ||||
-rw-r--r-- | version.h | 1 | ||||
-rw-r--r-- | xdu.c | 770 | ||||
-rw-r--r-- | xdu.man | 204 | ||||
-rw-r--r-- | xwin.c | 496 |
8 files changed, 1597 insertions, 0 deletions
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 <casey@gauss.llnl.gov> +Stephen Gildea <gildea@expo.lcs.mit.edu> +Nelson Minar <nelson@reed.edu> +Don Tiessen <dtiessen@silver.cs.umanitoba.ca> +Gerry.Tomlinson@newcastle.ac.uk +Mark Evans <mre1@itri.bton.ac.uk> +Juha Takala <jta@piuha.sah.vtt.fi> + +And the many others who told me what they thought about it. + +Send any bugs/comments to: + +Phil Dykstra +<phil@arl.mil> +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 + * <phil@arl.mil> + * 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 <stdio.h> +#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\\ + <Key>X: reorder(reverse)\\n\\ + <Btn3Down>: 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 +<window manager name>.FocusLenience: True +.fi +.SH "SEE ALSO" +du(1) +.SH AUTHOR +Phillip C. Dykstra +.br +<phil@arl.army.mil> 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 + * <phil@arl.mil> + * 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 <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Shell.h> + +#include <X11/Xaw/AsciiText.h> +#include <X11/Xaw/AsciiSrc.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/Label.h> + +#include <stdio.h> + +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> /* 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[] = "\ +<Key>Q: quit()\n\ +<Key>Escape: quit()\n\ +:<Key>/: reset()\n\ +<Key>S: size()\n\ +<Key>I: info()\n\ +<Key>H: help()\n\ +<Key>Help: help()\n\ +:<Key>?: help()\n\ +<Key>A: reorder(alpha)\n\ +<Key>N: reorder(size)\n\ +<Key>F: reorder(first)\n\ +<Key>L: reorder(last)\n\ +<Key>R: reorder(reverse)\n\ +<Key>1: ncol(1)\n\ +<Key>2: ncol(2)\n\ +<Key>3: ncol(3)\n\ +<Key>4: ncol(4)\n\ +<Key>5: ncol(5)\n\ +<Key>6: ncol(6)\n\ +<Key>7: ncol(7)\n\ +<Key>8: ncol(8)\n\ +<Key>9: ncol(9)\n\ +<Key>0: ncol(10)\n\ +<Btn1Down>: goto()\n\ +<Btn2Down>: reset()\n\ +<Btn3Down>: 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 <phil@arl.mil>\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("<Key>Q: RemoveHelp()"); + XtAugmentTranslations(form, trans_table); + + /* Set up ICCCM delete window */ + wm_delete_window = XInternAtom(XtDisplay(popup), "WM_DELETE_WINDOW", False); + XtOverrideTranslations(popup, XtParseTranslationTable("<Message>WM_PROTOCOLS: RemoveHelp()")); + XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1); +} + +static void +help_popdown() +{ + XtPopdown(popup); +} |