/* $Id: nodeop.c,v 3.1 2005/02/19 08:29:53 mac Exp $
*
* nodeop.c
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the authors name not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The author makes no
* representations about the suitability of this software for any purpose.
* It is provided "as is" without express or implied warranty.
*/
#include "du2ps.h"
unsigned dhue;
Node *top;
int (*cmp)();
static void
drawrect(Node *nodep, double y, double height, int depth,
unsigned h, unsigned s, unsigned b)
{
printf("%d (%s \\(%d\\)) %.2f %.2f %f %f %f\n",
depth, nodep->name, nodep->size, height, y,
(double) h / 0x8000 , (double) s, (double) b);
}
/*
* create a new node with the given name and set other initial values
*/
static Node *
makenode(char *name)
{
Node *nodep;
if (NULL == (nodep = (Node *) malloc(
(unsigned) (sizeof(Node) + strlen(name) + 1)))) {
fprintf(stderr, "malloc error\n");
exit (ENOMEM);
}
nodep->child = nodep->peer = NODE_NULL;
nodep->nchild = nodep->size = 0;
nodep->name = (char *) &nodep[1];
strcpy(nodep->name, name);
return nodep;
}
static void
addtree(Node *nodep, char **path, int size)
{
Node *child;
/* check all children for a match */
for(child = nodep->child; NODE_NULL != child; child = child->peer){
if(!strcmp(path[0], child->name)) break;
}
if (NODE_NULL == child) {
child = nodep->child;
nodep->child = makenode(path[0]);
nodep->child->peer = child;
child = nodep->child;
nodep->nchild++;
}
if (NULL == path[1]) {
child->size = size;
}
else {
addtree(child, &path[1], size);
}
return;
}
int
cmp_alph(Node **p, Node **q)
{
return strcmp((*p)->name, (*q)->name);
}
int
cmp_size(Node **p, Node **q)
{
return ((*q)->size - (*p)->size);
}
static void
sorttree(Node *nodep)
{
Node *child;
Node **nodtbl;
int i, ind;
if (NODE_NULL == nodep->child) return;
if (NULL == (nodtbl = (Node **) malloc(
sizeof(Node *) * nodep->nchild))) {
fprintf(stderr, "malloc error\n");
exit (ENOMEM);
}
for(child = nodep->child, ind = 0;
NODE_NULL != child; child = child->peer, ind++){
nodtbl[ind] = child;
if (NODE_NULL != child->child) {
sorttree(child);
}
}
if (2 <= nodep->nchild) {
qsort((char *) nodtbl, nodep->nchild, sizeof(Node *), cmp);
nodep->child = nodtbl[0];
for (i = 1; i < nodep->nchild; ++i) {
nodtbl[i - 1]->peer = nodtbl[i];
}
nodtbl[i - 1]->peer = NODE_NULL;
}
free(nodtbl);
return;
}
static void
drawchildren(Node *nodep, double y, double h, int depth)
/* node whose children we should draw */
{
Node *np;
double height;
unsigned hue;
int s, b;
/* for each child */
hue = 0;
s = b = 1;
for(np = nodep->child; NODE_NULL != np; np = np->peer){
if (nodep->size == 0) {
return;
}
height = h * np->size / nodep->size;
if (dhue != 0) {
drawrect(np, y, height, depth, hue, s, b);
hue += dhue;
hue %= 0x8000;
}
else {
drawrect(np, y, height, depth, 0, 0, 1);
}
/* draw children in subrectangle */
drawchildren(np, y, height, depth + 1);
y -= height;
}
}
/*
* reads du output,
* builds hierarchy structure,
* returns the top directory name.
*/
#define MAXLL MAXPATH+80
char *
parse(void)
{
char buf[MAXLL], name[MAXPATH+2], *n;
char *path[MAXDEPTH]; /* break up path into this list */
int depth, size;
int i;
top = makenode("..");
while(fgets(buf, MAXLL, stdin) != 0){
sscanf(buf, "%d %s\n", &size, n = name);
if('/' == *n) {
if ( strlen(name) > MAXPATH ) {
fprintf(stderr, "too long path\n");
exit(ENAMETOOLONG);
}
for(i = strlen(name)+1; i >= 0; i--) {
name[i+1] = name[i];
}
name[0] = '.';
}
if ( name[0] == '.' && name[1] == '/' && name[2] == EOS ) {
name[1] = EOS;
}
path[depth = 0] = n;
for(; *n != EOS; n++){
if('/' == *n){
*n = EOS;
path[++depth] = n + 1;
if(depth > MAXDEPTH) break;
}
}
path[++depth] = NULL;
addtree(top, path, size);
}
sorttree(top);
/*
* descend hierarchy until the number of children is not 1.
* if the directory size is 0, then total the sizes of the children.
*/
for(n = name; 0 == top->size;){
Node *np;
if (1 == top->nchild) {
top = top->child;
while (EOS != *n) n++;
*n = '/';
}
else if(1 < top->nchild){
for(np = top->child; NODE_NULL != np; np = np->peer){
top->size = top->size + np->size;
}
break;
}
else break;
}
*n = 0;
return strdup(name);
}
void
drawnode(double canvas_height)
{
/* draw the top directory */
drawrect(top, canvas_height, canvas_height, 0, 0, 0, 1);
/* draw children recursively */
drawchildren(top, canvas_height, canvas_height, 1);
}
syntax highlighted by Code2HTML, v. 0.9.1