Category : C Source Code
Archive   : CTREE.ZIP
Filename : CTREE.SHR

 
Output of file : CTREE.SHR contained in archive : CTREE.ZIP
#!/bin/sh
echo extracting Makefile
cat <<\!end-of-Makefile! >Makefile
CC=gcc
CFLAGS=-g -Wall -ansi
CTREEOBJ=bt.o ctree.o debug.o main.o mktree.o options.o scan.o strxcmp.o

ctree: $(CTREEOBJ)
$(CC) $(CFLAGS) -o ctree $(CTREEOBJ)

bt.o: bt.c bt.h
ctree.o: ctree.c bt.h ctree.h debug.h
debug.o: debug.c debug.h
main.o: main.c ctree.h debug.h mktree.h options.h
mktree.o: mktree.c bt.h ctree.h
options.o: options.c options.h
scan.o: scan.c ctree.h debug.h
strxcmp.o: strxcmp.c
!end-of-Makefile!
echo extracting archive.sh
cat <<\!end-of-archive.sh! >archive.sh
echo '#!/bin/sh' >ctree.sh;
cat <<\! | ( while read filename; do\
echo 'archiving' $filename '...' 1>&2; \
echo 'echo extracting '$filename ;\
echo 'cat <<\!end-of-'$filename'! >'$filename ;\
cat $filename ;\
echo '!end-of-'$filename'!' ;\
done; ) >>ctree.sh;
Makefile
archive.sh
bt.c
bt.h
ctree.c
ctree.h
debug.c
debug.h
main.c
mktree.c
mktree.h
options.c
options.h
scan.c
strxcmp.c
!
!end-of-archive.sh!
echo extracting bt.c
cat <<\!end-of-bt.c! >bt.c
/*
** A package of routines for handling balanced binary trees.
**
** Copyright (c) 1990 by D. R. Hipp. This code is an original work
** and has been prepared without reference to any prior
** implementations of similar functions. No part of this code is
** subject to licensing restrictions of any telephone company or
** university.
**
** Permission is hereby granted for this code to be used by anyone
** for any purpose under the following restrictions:
** 1. No attempt shall be made to prevent others (especially the
** author) from using this code.
** 2. Changes to this code are to be clearly marked.
** 3. The origins of this code are not to be misrepresented.
** 4. The user agrees that the author is in no way responsible for
** the correctness or usefulness of this program.
*/
#include
#include
#include
#include "bt.h"

#ifndef PRIVATE
# define PRIVATE static
#endif

struct _s_btn_ { /* A binary tree node. */
void *data; /* Pointer to the user's data */
void *key; /* Pointer to the key for this node */
struct _s_btn_ *left; /* Left daughter */
struct _s_btn_ *right; /* Right daughter */
int weight; /* Weight of this node */
};
typedef struct _s_btn_ node;

/*
** Definitions:
** WEIGHT:
** The weight of a node is the total number of children for the node
** plus 1. Leaf nodes have a weight of 1. The root node has a weight
** which equals the number of nodes in the tree.
**
** BALANCE:
** A node is balanced if the weight of the one child is not more than
** twice the weight of the other child.
*/

/*
** preconditions:
** + **npp is a node which might be out of balance by as much
** as (but no more than) 1.
** + All decendents of **npp are balanced and have the correct
** weight.
** + The weight of **npp is incorrect.
** postconditions:
** + **npp and all its decendents are balanced and have the
** correct weight.
*/
PRIVATE void balance(node **npp){
node *n; /* Pointer to self */
int l,r; /* Weight of left and right daughters */
int a,b; /* Weights of various nodes */

if( npp==0 || (n=*npp)==0 ) return;
l = n->left ? n->left->weight: 0;
r = n->right ? n->right->weight: 0;
if( l>r*2 ){ /* Too heavy on the left side */
node *nl; /* Pointer to left daughter */
node *nr; /* Pointer to right daughter */
int ll, lr; /* Weight of left daughter's left and right daughter */
nl = n->left;
ll = nl->left ? nl->left->weight: 0;
lr = nl->right ? nl->right->weight: 0;
if( ll>lr || nl->right==0 ){
/*
** Convert from: n to: nl
** / \ / \
** nl c a n
** / \ / \
** a b b c
*/
n->left = nl->right;
nl->right = n;
n->weight = a = r + lr + 1;
nl->weight = a + ll + 1;
*npp = nl;
}else{
/*
** Convert from: n to: nr
** / \ / \
** nl d nl n
** / \ / \ / \
** a nr a b c d
** / \
** b c
*/
int lrl, lrr; /* Weight of Great-granddaughter nodes */
nr = nl->right;
lrl = nr->left ? nr->left->weight: 0;
lrr = nr->right ? nr->right->weight: 0;
nl->right = nr->left;
nr->left = nl;
n->left = nr->right;
nr->right = n;
n->weight = a = lrr + r + 1;
nl->weight = b = ll + lrl + 1;
nr->weight = a + b + 1;
*npp = nr;
}
}else if( r>l*2 ){/* Too deep on the right side */
node *nl; /* Pointer to left daughter */
node *nr; /* Pointer to right daughter */
int rl, rr; /* Weight of right daughter's left and right daughter */
nr = n->right;
rl = nr->left ? nr->left->weight: 0;
rr = nr->right ? nr->right->weight: 0;
if( rr>rl || nr->left==0 ){
/*
** Convert from: n to: nr
** / \ / \
** a nr n c
** / \ / \
** b c a b
*/
n->right = nr->left;
nr->left = n;
n->weight = a = l + rl + 1;
nr->weight = a + rr + 1;
*npp = nr;
}else{
/*
** Convert from: n to: nl
** / \ / \
** a nr n nr
** / \ / \ / \
** nl d a b c d
** / \
** b c
*/
int rll,rlr; /* Weights of great-granddaughter nodes */
nl = nr->left;
rll = nl->left ? nl->left->weight: 0;
rlr = nl->right ? nl->right->weight: 0;
nr->left = nl->right;
nl->right = nr;
n->right = nl->left;
nl->left = n;
n->weight = a = l + rll + 1;
nr->weight = b = rr + rlr + 1;
nl->weight = a + b + 1;
*npp = nl;
}
}else{ /* Node is already balanced. Just recompute its weight. */
n->weight = l + r + 1;
}
}

#ifndef NDEBUG
PRIVATE int ntrees = 0; /* Total number of outstanding trees */
PRIVATE int nnodes = 0; /* Total number of nodes in outstanding trees */
#endif

PRIVATE node *freelist = 0; /* A list of free tree nodes */

#define ALLOCAMT 100

/* allocate a node */
PRIVATE node *alloc(void){
node *rv;
if( freelist==0 ){
int i;
freelist = malloc( sizeof(node)*ALLOCAMT );
if( freelist ){
for(i=0; i freelist[ALLOCAMT-1].left = 0;
}
}
if( freelist ){
rv = freelist;
freelist = freelist->left;
assert( nnodes++>=0 );
}else{
rv = 0;
}
return rv;
}

PRIVATE void dealloc(node *n){
n->left = freelist;
freelist = n;
assert( nnodes-->0 );
}

/*
** Preconditions:
** + **npp is a balanced tree containing no more than 4e17 nodes.
** + *data is a pointer to some data structure.
** + *key is a pointer to a key.
** + *cf is the comparison function used to build the tree.
** Postconditions:
** + **npp is the root of a balanced tree with all weights correct.
** + If no error occurs, then **npp contains one node with *key and
** *data. If there is an error, then **npp is unchanged from the
** precondition.
** Return value:
** + The function returns the value of data replaced, or zero
** if new data was inserted.
*/
PRIVATE void *
insert(node **npp, void *data, void *key, int (*cf)(void*,void*)){
node *n;
void *old = 0;
node **h[100]; /* Sufficient for a tree with up to 4e17 nodes */
int level = 0;

h[0] = npp;
level = 1;
n = *npp;
while( n ){
int c;
c = (*cf)(key,n->key);
if( c<0 ){
h[level++] = &(n->left);
n = n->left;
}else if( c>0 ){
h[level++] = &(n->right);
n = n->right;
}else{
old = n->data;
n->data = data; /* Replace data in an existing node */
break;
}
}
if( n==NULL ){ /* Insert a leaf node */
level--;
n = *h[level] = alloc();
if( n!=0 ){
n->data = data;
n->key = key;
n->left = n->right = NULL;
}else{
level = -1;
}
while( level>=0 ) balance(h[level--]);
}
return old;
}

/*
** preconditions:
** + **npp is a balanced tree containing no more than 4e17 nodes.
** postconditions:
** + **npp is a balanced tree with all weights correct. The tree
** will be different from the input, unless an error occurs.
** return value:
** + The function returns a pointer to a node which used to be
** the index-th node in the tree, but which has now been removed.
** NULL is returned if an error is encountered.
*/
PRIVATE node *delete(node **npp, int index)
{
node *n, *nx;
node **h[100]; /* Sufficient for a tree with up to 4e17 nodes */
int level = 0;

h[0] = npp;
level = 1;
n = *npp;
while( n ){
int w;
w = (n->left ? n->left->weight: 0) + 1;
if( index>w ){
h[level++] = &(n->right);
n = n->right;
index -= w;
}else if( index h[level++] = &(n->left);
n = n->left;
}else{
break;
}
}
if( n ){
level--;
if( n->left==0 ){
*h[level] = n->right;
level--;
nx = n;
}else if( n->right==0 ){
*h[level] = n->left;
level--;
nx = n;
}else{
node *x;
x = delete(&(n->right),1);
x->right = n->right;
x->left = n->left;
*h[level] = x;
nx = n;
}
while( level>=0 ) balance(h[level--]);
}else{
nx = 0;
}
return nx;
}

/*
** preconditions:
** + *n is the root of a balanced tree.
** postconditions:
** + no changes occur in any data structure.
** return value:
** + A pointer to the index-th node in the tree *n. The first
** node is returned for index==1. NULL is returned on an error.
*/
PRIVATE node *findbyindex(node *n, int index){
while( n ){
int w;
w = (n->left ? n->left->weight: 0) + 1;
if( index>w ){
n = n->right;
index -= w;
}else if( index n = n->left;
}else{
break;
}
}
return n;
}

/*
** preconditions:
** + *n is the root of a balanced tree.
** + *cf is a comparison function used to build the tree.
** + *key is any key.
** + *rank is any integer.
** postconditions:
** + *rank is the index of a node in *n as follows:
** = If *key matches some node exactly, then *rank is the
** the index of that node.
** = If *key doesn't match a node, then *rank is what the index
** of a node matching *key would be if it were inserted.
** return value:
** + A pointer to the node matching *key. NULL is returned if no
** node in *n matches *key.
*/
PRIVATE node *findbykey(node *n, int (*cf)(void*,void*), void *key, int *rank){
*rank = 1;
while( n ){
int c;
c = (*cf)(key,n->key);
if( c<0 ){
n = n->left;
}else if( c>0 ){
*rank += (n->left ? n->left->weight : 0) + 1;
n = n->right;
}else{
*rank += (n->left ? n->left->weight : 0);
break;
}
}
return n;
}

/*
** preconditions:
** + *n is the root of a balanced tree
** postconditions:
** + *n and all of its children have been deallocated. (*f)() has been
** called on the data of each element.
*/
PRIVATE void deletetree(node *n, void (*f)(void*)){
if( n ){
if( n->left ) deletetree(n->left,f);
if( n->right ) deletetree(n->right,f);
if( f ) (*f)(n->data);
dealloc(n);
}
}

/***************************** PUBLIC ROUTINES *****************************/
BT *BTbegin(int (*cmpfunc)(void*,void*)){
BT *bt = 0;
if( cmpfunc && (bt=malloc(sizeof(BT)))!=0 ){
bt->cmpfunc = cmpfunc;
bt->root = 0;
assert( ntrees++>=0 );
}
return bt;
}

void *BTinsert(BT *bt, void *data, void *key){
void *rv = 0;
if( bt && key ){
rv = insert(&(bt->root),data,key,bt->cmpfunc);
}
return rv;
}

int BTrank(BT *bt, void *key){
int rank = 0;
if( key && bt && bt->root ){
findbykey(bt->root,bt->cmpfunc,key,&rank);
}
return rank;
}

void *BTkey(BT *bt, int index){
node *bp = 0;
if( bt && bt->root && index>=1 && index<=bt->root->weight ){
bp = findbyindex(bt->root,index);
}
return bp ? bp->key : 0;
}

void *BTfind(BT *bt, void *key){
int rank = 0;
node *bp = 0;
if( key && bt && bt->root ){
bp = findbykey(bt->root,bt->cmpfunc,key,&rank);
}
return bp ? bp->data : 0;
}

void *BTdata(BT *bt, int index){
node *bp = 0;
if( bt && bt->root && index>=1 && index<=bt->root->weight ){
bp = findbyindex(bt->root,index);
}
return bp ? bp->data : 0;
}

void *BTdelete(BT *bt, void *key){
int rank;
node *bp;
void *data = 0;
if( key && bt && bt->root ){
bp = findbykey(bt->root,bt->cmpfunc,key,&rank);
if( bp && (*(bt->cmpfunc))(bp->key,key)==0 ){
data = BTremove(bt,rank);
}
}
return data;
}

void *BTremove(BT *bt, int index){
node *np;
void *data = 0;
if( bt && bt->root && index>=1 && index<=bt->root->weight ){
np = delete(&(bt->root),index);
if( np ){
data = np->data;
dealloc(np);
}
}
return data;
}

int BTsize(BT *bt){
return (bt && bt->root) ? bt->root->weight : 0;
}

int BTdepth(BT *bt, int index){
node *n;
int depth = 0;
if( bt && bt->root && index>=1 && index<=bt->root->weight ){
n = bt->root;
while( n ){
int w;
depth++;
w = (n->left ? n->left->weight: 0) + 1;
if( index>w ){
n = n->right;
index -= w;
}else if( index n = n->left;
}else{
break;
}
}
}
return depth;
}

void BTend(BT *bt, void (*myfree)(void*)){
if( bt ){
if( bt->root ){
deletetree(bt->root,myfree);
}
bt->root = 0;
free(bt);
assert( ntrees-->0 );
}
}

#ifndef NDEBUG
char *BTstatus(void){
static char buf[100];
sprintf(buf,"BTrees=%-4d nodes=%-5d",ntrees,nnodes);
return buf;
}
#endif
!end-of-bt.c!
echo extracting bt.h
cat <<\!end-of-bt.h! >bt.h
/*
** Binary trees
** Copyright (c) 1990 by D. R. Hipp
*/
#ifndef _BT_H_
#define _BT_H_

typedef struct { /* The whole binary tree */
int (*cmpfunc)(void*,void*); /* Function for comparing keys */
struct _s_btn_ *root; /* Root of the tree */
} BT;

BT *BTbegin(int(*)(void*,void*)); /* Create a new binary tree. */
void *BTinsert(BT*, void*, void*); /* Insert data (2) with key (3) */
void *BTfind(BT*, void*); /* Find data given key */
void *BTdelete(BT*, void*); /* Remove a data by its key */
int BTrank(BT*, void*); /* Find the index given key */
void *BTkey(BT*, int); /* Find the key given an index */
void *BTdata(BT*, int); /* Find the data given the index */
void *BTremove(BT*, int); /* Remove a data by its index */
int BTsize(BT*); /* Find the total number of nodes */
int BTdepth(BT*, int); /* Return depth of a node */
void BTend(BT*, void(*)(void *)); /* Delete the whole tree */

#ifndef NDEBUG
char *BTstatus(void); /* Status of the package */
#endif

#endif
!end-of-bt.h!
echo extracting ctree.c
cat <<\!end-of-ctree.c! >ctree.c
/*
** Copyright (c) 1991 by D. R. Hipp.
*/
#define CTREEC
#include
#include
#include
#include "bt.h"
#include "ctree.h"
#include "debug.h"

typedef struct s_prog {
int isaprog;
char *name;
BT *calls;
BT *calledby;
} prog;

BT *set;

static void *myalloc(int size){
void *x;
x = malloc(size);
if( x==0 ){
fprintf(stderr,"Can't allocation %d bytes of memory. Aborting.\n",size);
exit(1);
}
return x;
}

static char *strdup(char *x){
char *new;
new = myalloc( strlen(x)+1 );
strcpy(new,x);
return new;
}

static int progcomp(void *a, void *b){
extern int sstrcmp(char*,char*);
return sstrcmp(((prog *)a)->name,((prog *)b)->name);
}

prog *findProg(char *name){
prog *new, template;
if( set==0 ) set = BTbegin(progcomp);
template.name = name;
new = BTfind(set,&template);
if( new==0 ){
new = myalloc( sizeof(prog) );
new->name = strdup(name);
new->isaprog = 0;
new->calls = BTbegin(progcomp);
new->calledby = BTbegin(progcomp);
BTinsert(set,new,new);
}
return new;
}

void SetIsProgram(char *a){
prog *A;
A = findProg(a);
if( A ) A->isaprog = 1;
}

int IsProgram(char *a){
prog *A;
A = findProg(a);
return A? A->isaprog : 0;
}

void AcallsB(char *a, char *b){
prog *A,*B;
BUG(bugab,printf("%-20s --> %s\n",a,b);)
A = findProg(a);
B = findProg(b);
if( A && B ){
A->isaprog = 1;
if( !BTfind(A->calls,B) ) BTinsert(A->calls,B,B);
if( !BTfind(B->calledby,A) ) BTinsert(B->calledby,A,A);
}
}

char *ACallsWhom(char *a, int n){
prog *A,*B;
A = findProg(a);
B = (A&&A->calls)? BTdata(A->calls,n) : 0;
return B? B->name : 0;
}

char *WhoCallsA(char *a, int n){
prog *A,*B;
A = findProg(a);
B = (A&&A->calledby)? BTdata(A->calledby,n) : 0;
return B? B->name : 0;
}

int CountCallsTo(char *a){
prog *A;
A = findProg(a);
return A? BTsize(A->calledby): 0;
}

int CountCalledBy(char *a){
prog *A;
A = findProg(a);
return A? BTsize(A->calls): 0;
}
!end-of-ctree.c!
echo extracting ctree.h
cat <<\!end-of-ctree.h! >ctree.h
#ifndef CTREEH
#define CTREEH

void AcallsB(char*, char*);
char *ACallsWhom(char*, int);
char *WhoCallsA(char*, int);
int CountCallsTo(char *);
int CountCalledBy(char *);
void SetIsProgram(char*);
int IsProgram(char*);

#endif
!end-of-ctree.h!
echo extracting debug.c
cat <<\!end-of-debug.c! >debug.c
#include
#include
#include
#define DEBUG_C
#include "debug.h"

void DebugSet(char *name){
int i;
for(i=0; sw[i].name; i++){
if( strcmp(sw[i].name,name)==0 ){
*sw[i].var = 1;
break;
}
}
if( sw[i].name==0 ){
fprintf(stderr,"Bad debug option: \"%s\". Valid debug options are:\n",
name);
for(i=0; sw[i].name; i++) fprintf(stderr," %s\n",sw[i].name);
exit(1);
}
}
!end-of-debug.c!
echo extracting debug.h
cat <<\!end-of-debug.h! >debug.h
#ifndef DEBUG_H
#define DEBUG_H

#ifndef NDEBUG
#define BUG(L,X) if(L)X
#else
#define BUG(L,X)
#endif

void DebugSet(char*);

#ifdef DEBUG_C
#define EXTERN
#else
#define EXTERN extern
#endif

EXTERN int bugprog;
EXTERN int bugcall;
EXTERN int bugab;

#ifdef DEBUG_C
static struct s_names {
int *var;
char *name;
} sw[] = {
/* Variable name Debug option name */
/* ------------------ -------------------- */
&bugprog, "Functions",
&bugcall, "Calls",
&bugab, "AB",
0,0};
#endif

#endif

!end-of-debug.h!
echo extracting main.c
cat <<\!end-of-main.c! >main.c
/*
** Copyright (c) 1991 by D. R. Hipp.
*/
/*
** Main program
*/
#include
#include
#include "ctree.h"
#include "debug.h"
#include "mktree.h"
#include "options.h"

extern void scan(char*);

void
main(int argc, char **argv)
{
static char *base = "main";
static int maxDepth =1000;
static int maxWidth = 79;
static int reverse = 0;
static struct s_options options[] = {
{ OPT_STR, "base", (void*)&base, "Base function name"},
{ OPT_FSTR,"debug",(void*)DebugSet,"Turn on debugging." },
{ OPT_INT, "depth",(void*)&maxDepth,"Maximum recursion depth" },
{ OPT_FLAG,"reverse",(void*)&reverse,"Reverse the direction of the tree"},
{ OPT_INT, "width",(void*)&maxWidth,"Maximum page width" },
{ 0,0,0,0 }
};
int nargs;
int i;

/*
** Process the command line.
*/
optinit(argv,options,stderr);
nargs = optnargs();
for(i=0; i if( reverse ){
BkTree(base,maxDepth,maxWidth);
}else{
MkTree(base,maxDepth,maxWidth);
}
exit(0);
}
!end-of-main.c!
echo extracting mktree.c
cat <<\!end-of-mktree.c! >mktree.c
/*
** Copyright (c) 1991 by D. R. Hipp.
*/
/*
** Draw a tree
*/
#include
#include
#include "bt.h"
#include "ctree.h"

#define MAXWIDTH 150

struct s_mktree{
char prefix[3][MAXWIDTH+1];
BT *used;
int depth;
int maxdepth;
int maxwidth;
int total;
int n;
};

static void rMkTree(struct s_mktree *mtp, char *name){
int i,count;
char *child;
int namelen;
struct s_mktree mt;

mt.used = mtp->used;
mt.depth = mtp->depth+1;
mt.maxdepth = mtp->maxdepth;
mt.maxwidth = mtp->maxwidth;
count = CountCalledBy(name);
for(mt.total=0, i=1; i<=count; i++){
child = ACallsWhom(name,i);
if( child && IsProgram(child) ) mt.total++;
}
namelen = strlen(name);
if( strlen(mtp->prefix[0])+namelen+8>mt.maxwidth ){
printf("%s--...\n",mtp->prefix[1]);
}else if( mt.depth>=mt.maxdepth ){
printf("%s--%s...\n",mtp->prefix[1],name);
}else if( mt.total==0 ){
printf("%s--%s\n",mtp->prefix[1],name);
}else if( BTfind(mt.used,name) ){
printf("%s--%s...\n",mtp->prefix[1],name);
}else if( mt.total==1 ){
sprintf(mt.prefix[0],"%s %*s",mtp->prefix[0],namelen,"");
sprintf(mt.prefix[1],"%s--%s",mtp->prefix[1],name);
sprintf(mt.prefix[2],"%s %*s",mtp->prefix[2],namelen,"");
BTinsert(mt.used,name,name);
for(i=1; i<=count; i++){
child = ACallsWhom(name,i);
if( child && IsProgram(child) ) break;
}
rMkTree(&mt,child);
BTdelete(mt.used,name);
}else{
int showpoint;
if( (mt.total&1)==1 ) showpoint = mt.total/2 + 1;
else if( mtp->n>mtp->total/2 ) showpoint = mt.total/2;
else showpoint = mt.total/2 + 1;
BTinsert(mt.used,name,name);
for(i=1, mt.n=1; i<=count; i++){
child = ACallsWhom(name,i);
if( child==0 || !IsProgram(child) ) continue;
if( mt.n==1 && mt.n!=showpoint ){
sprintf(mt.prefix[0],"%s %*s ",mtp->prefix[0],namelen,"");
sprintf(mt.prefix[1],"%s %*s ,",mtp->prefix[0],namelen,"");
sprintf(mt.prefix[2],"%s %*s |",mtp->prefix[0],namelen,"");
}else if( mt.n==1 && mt.n==showpoint ){
sprintf(mt.prefix[0],"%s %*s ",mtp->prefix[0],namelen,"");
sprintf(mt.prefix[1],"%s--%s--v",mtp->prefix[1],name);
sprintf(mt.prefix[2],"%s %*s |",mtp->prefix[2],namelen,"");
}else if( mt.n==mt.total && mt.n!=showpoint ){
sprintf(mt.prefix[0],"%s %*s |",mtp->prefix[2],namelen,"");
sprintf(mt.prefix[1],"%s %*s `",mtp->prefix[2],namelen,"");
sprintf(mt.prefix[2],"%s %*s ",mtp->prefix[2],namelen,"");
}else if( mt.n==mt.total && mt.n==showpoint ){
sprintf(mt.prefix[0],"%s %*s |",mtp->prefix[0],namelen,"");
sprintf(mt.prefix[1],"%s--%s--^",mtp->prefix[1],name);
sprintf(mt.prefix[2],"%s %*s ",mtp->prefix[2],namelen,"");
}else if( mt.n==showpoint ){
sprintf(mt.prefix[0],"%s %*s |",mtp->prefix[0],namelen,"");
sprintf(mt.prefix[1],"%s--%s--|",mtp->prefix[1],name);
sprintf(mt.prefix[2],"%s %*s |",mtp->prefix[2],namelen,"");
}else if( mt.n sprintf(mt.prefix[0],"%s %*s |",mtp->prefix[0],namelen,"");
sprintf(mt.prefix[1],"%s %*s |",mtp->prefix[0],namelen,"");
sprintf(mt.prefix[2],"%s %*s |",mtp->prefix[0],namelen,"");
}else if( mt.n>showpoint ){
sprintf(mt.prefix[0],"%s %*s |",mtp->prefix[2],namelen,"");
sprintf(mt.prefix[1],"%s %*s |",mtp->prefix[2],namelen,"");
sprintf(mt.prefix[2],"%s %*s |",mtp->prefix[2],namelen,"");
}
rMkTree(&mt,child);
mt.n++;
}
BTdelete(mt.used,name);
}
}

void MkTree(char *name, int depth, int width){
struct s_mktree mt;
extern int sstrcmp(void*,void*);

mt.prefix[0][0] = 0;
mt.prefix[1][0] = 0;
mt.prefix[2][0] = 0;
mt.used = BTbegin(sstrcmp);
mt.depth = 0;
mt.maxdepth = depth;
if( width>MAXWIDTH ) width = MAXWIDTH;
mt.maxwidth = width;
rMkTree(&mt,name);
BTend(mt.used,0);
}


static void rBkTree(struct s_mktree *mtp, char *name){
int i,count;
char *child;
int namelen;
struct s_mktree mt;
int printline = 0;
char line[MAXWIDTH+1];

mt.used = mtp->used;
mt.depth = mtp->depth+1;
mt.maxdepth = mtp->maxdepth;
mt.maxwidth = mtp->maxwidth;
count = CountCallsTo(name);
for(mt.total=0, i=1; i<=count; i++){
child = WhoCallsA(name,i);
if( child && IsProgram(child) ) mt.total++;
}
namelen = strlen(name);

if( strlen(mtp->prefix[0])+namelen+8>mt.maxwidth ){
sprintf(line,"...--%s",mtp->prefix[1]);
printline = 1;
}else if( mt.depth>=mt.maxdepth ){
sprintf(line,"...%s--%s",name,mtp->prefix[1]);
printline = 1;
}else if( mt.total==0 ){
sprintf(line,"%s--%s",name,mtp->prefix[1]);
printline = 1;
}else if( BTfind(mt.used,name) ){
sprintf(line,"...%s--%s",name,mtp->prefix[1]);
printline = 1;
}else if( mt.total==1 ){
sprintf(mt.prefix[0],"%*s %s",namelen,"",mtp->prefix[0]);
sprintf(mt.prefix[1],"%s--%s",name,mtp->prefix[1]);
sprintf(mt.prefix[2],"%*s %s",namelen,"",mtp->prefix[2]);
BTinsert(mt.used,name,name);
for(i=1; i<=count; i++){
child = WhoCallsA(name,i);
if( child && IsProgram(child) ) break;
}
rBkTree(&mt,child);
BTdelete(mt.used,name);
}else{
int showpoint;
if( (mt.total&1)==1 ) showpoint = mt.total/2 + 1;
else if( mtp->n>mtp->total/2 ) showpoint = mt.total/2;
else showpoint = mt.total/2 + 1;
BTinsert(mt.used,name,name);
for(i=1, mt.n=1; i<=count; i++){
child = WhoCallsA(name,i);
if( child==0 || !IsProgram(child) ) continue;
if( mt.n==1 && mt.n!=showpoint ){
sprintf(mt.prefix[0]," %*s %s",namelen,"",mtp->prefix[0]);
sprintf(mt.prefix[1],". %*s %s",namelen,"",mtp->prefix[0]);
sprintf(mt.prefix[2],"| %*s %s",namelen,"",mtp->prefix[0]);
}else if( mt.n==1 && mt.n==showpoint ){
sprintf(mt.prefix[0]," %*s %s",namelen,"",mtp->prefix[0]);
sprintf(mt.prefix[1],"v--%s--%s",name,mtp->prefix[1]);
sprintf(mt.prefix[2],"| %*s %s",namelen,"",mtp->prefix[2]);
}else if( mt.n==mt.total && mt.n!=showpoint ){
sprintf(mt.prefix[0],"| %*s %s",namelen,"",mtp->prefix[2]);
sprintf(mt.prefix[1],"' %*s %s",namelen,"",mtp->prefix[2]);
sprintf(mt.prefix[2]," %*s %s",namelen,"",mtp->prefix[2]);
}else if( mt.n==mt.total && mt.n==showpoint ){
sprintf(mt.prefix[0],"| %*s %s",namelen,"",mtp->prefix[0]);
sprintf(mt.prefix[1],"^--%s--%s",name,mtp->prefix[1]);
sprintf(mt.prefix[2]," %*s %s",namelen,"",mtp->prefix[2]);
}else if( mt.n==showpoint ){
sprintf(mt.prefix[0],"| %*s %s",namelen,"",mtp->prefix[0]);
sprintf(mt.prefix[1],"|--%s--%s",name,mtp->prefix[1]);
sprintf(mt.prefix[2],"| %*s %s",namelen,"",mtp->prefix[2]);
}else if( mt.n sprintf(mt.prefix[0],"| %*s %s",namelen,"",mtp->prefix[0]);
sprintf(mt.prefix[1],"| %*s %s",namelen,"",mtp->prefix[0]);
sprintf(mt.prefix[2],"| %*s %s",namelen,"",mtp->prefix[0]);
}else if( mt.n>showpoint ){
sprintf(mt.prefix[0],"| %*s %s",namelen,"",mtp->prefix[2]);
sprintf(mt.prefix[1],"| %*s %s",namelen,"",mtp->prefix[2]);
sprintf(mt.prefix[2],"| %*s %s",namelen,"",mtp->prefix[2]);
}
rBkTree(&mt,child);
mt.n++;
}
BTdelete(mt.used,name);
}
if( printline ){
int i,j;
i = strlen(line)-1;
j = 0;
while( i>0 && line[i]==' ' ){ i--; j++; }
line[i+1] = 0;
printf("%*s\n",mt.maxwidth-j,line);
}
}

void BkTree(char *name, int depth, int width){
struct s_mktree mt;
extern int sstrcmp(void*,void*);

mt.prefix[0][0] = 0;
mt.prefix[1][0] = 0;
mt.prefix[2][0] = 0;
mt.used = BTbegin(sstrcmp);
mt.depth = 0;
mt.maxdepth = depth;
if( width>MAXWIDTH ) width = MAXWIDTH;
mt.maxwidth = width;
rBkTree(&mt,name);
BTend(mt.used,0);
}
!end-of-mktree.c!
echo extracting mktree.h
cat <<\!end-of-mktree.h! >mktree.h
#ifndef MKTREE_H
#define MKTREE_H

void MkTree(char*,int,int);
void BkTree(char*,int,int);

#endif
!end-of-mktree.h!
echo extracting options.c
cat <<\!end-of-options.c! >options.c
/*
** Copyright (c) 1991 by D. R. Hipp.
*/
#include
#include
#include
#include "options.h"

static char **argv;
static struct s_options *op;
static FILE *errstream;

#define ISOPT(X) ((X)[0]=='-'||(X)[0]=='+'||strchr((X),'=')!=0)


/*
** Print the command line with a carrot pointing to the k-th character
** of the n-th field.
*/
static void errline(int n, int k, FILE *err){
int spcnt, i;
spcnt = 0;
if( argv[0] ) fprintf(err,"%s",argv[0]);
spcnt = strlen(argv[0]) + 1;
for(i=1; i fprintf(err," %s",argv[i]);
spcnt += strlen(argv[i]+1);
}
spcnt += k;
for(; argv[i]; i++) fprintf(err," %s",argv[i]);
if( spcnt<20 ){
fprintf(err,"\n%*s^-- here\n",spcnt,"");
}else{
fprintf(err,"\n%*shere --^\n",spcnt-7,"");
}
}

/*
** Return the index of the N-th non-switch argument. Return -1
** if N is out of range.
*/
static int argindex(int n){
int i;
int dashdash = 0;
if( argv!=0 && *argv!=0 ){
for(i=1; argv[i]; i++){
if( dashdash || !ISOPT(argv[i]) ){
if( n==0 ) return i;
n--;
}
if( strcmp(argv[i],"--")==0 ) dashdash = 1;
}
}
return -1;
}

static char emsg[] = "Command line syntax error: ";

/*
** Process a flag command line argument.
*/
static int handleflags(int i, FILE *err){
int v;
int errcnt = 0;
int j;
for(j=0; op[j].label; j++){
if( strcmp(&argv[i][1],op[j].label)==0 ) break;
}
v = argv[i][0]=='-' ? 1 : 0;
if( op[j].label==0 ){
if( err ){
fprintf(err,"%sundefined option.\n",emsg);
errline(i,1,err);
}
errcnt++;
}else if( op[j].type==OPT_FLAG ){
*((int*)op[j].arg) = v;
}else if( op[j].type==OPT_FFLAG ){
(*(void(*)(int))(op[j].arg))(v);
}else{
if( err ){
fprintf(err,"%smissing argument on switch.\n",emsg);
errline(i,1,err);
}
errcnt++;
}
return errcnt;
}

/*
** Process a command line switch which has an argument.
*/
static int handleswitch(int i, FILE *err){
int lv;
double dv;
char *sv, *end;
char *cp;
int j;
int errcnt = 0;
cp = strchr(argv[i],'=');
*cp = 0;
for(j=0; op[j].label; j++){
if( strcmp(argv[i],op[j].label)==0 ) break;
}
*cp = '=';
if( op[j].label==0 ){
if( err ){
fprintf(err,"%sundefined option.\n",emsg);
errline(i,0,err);
}
errcnt++;
}else{
cp++;
switch( op[j].type ){
case OPT_FLAG:
case OPT_FFLAG:
if( err ){
fprintf(err,"%soption requires an argument.\n",emsg);
errline(i,0,err);
}
errcnt++;
break;
case OPT_DBL:
case OPT_FDBL:
dv = strtod(cp,&end);
if( *end ){
if( err ){
fprintf(err,"%sillegal character in floating-point argument.\n",emsg);
errline(i,((int)end)-(int)argv[i],err);
}
errcnt++;
}
break;
case OPT_INT:
case OPT_FINT:
lv = strtol(cp,&end,0);
if( *end ){
if( err ){
fprintf(err,"%sillegal character in integer argument.\n",emsg);
errline(i,((int)end)-(int)argv[i],err);
}
errcnt++;
}
break;
case OPT_STR:
case OPT_FSTR:
sv = cp;
break;
}
switch( op[j].type ){
case OPT_FLAG:
case OPT_FFLAG:
break;
case OPT_DBL:
*(double*)(op[j].arg) = dv;
break;
case OPT_FDBL:
(*(void(*)(double))(op[j].arg))(dv);
break;
case OPT_INT:
*(int*)(op[j].arg) = lv;
break;
case OPT_FINT:
(*(void(*)(int))(op[j].arg))((int)lv);
break;
case OPT_STR:
*(char**)(op[j].arg) = sv;
break;
case OPT_FSTR:
(*(void(*)(char*))(op[j].arg))(sv);
break;
}
}
return errcnt;
}

/******************* Public Routines *********************************/


int optinit(char **a, struct s_options *o, FILE *err){
int errcnt = 0;
argv = a;
op = o;
errstream = err;
if( argv && *argv && op ){
int i;
for(i=1; argv[i]; i++){
if( argv[i][0]=='+' || argv[i][0]=='-' ){
errcnt += handleflags(i,err);
}else if( strchr(argv[i],'=') ){
errcnt += handleswitch(i,err);
}
}
}
if( errcnt>0 ){
fprintf(err,"Valid command line options for \"%s\" are:\n",*a);
optprint();
exit(1);
}
return 0;
}

int optnargs(void){
int cnt = 0;
int dashdash = 0;
int i;
if( argv!=0 && argv[0]!=0 ){
for(i=1; argv[i]; i++){
if( dashdash || !ISOPT(argv[i]) ) cnt++;
if( strcmp(argv[i],"--")==0 ) dashdash = 1;
}
}
return cnt;
}

char *optarg(int n){
int i;
i = argindex(n);
return i>=0 ? argv[i] : 0;
}

void opterr(int n){
int i;
i = argindex(n);
if( i>=0 ) errline(i,0,errstream);
}

void optprint(void){
int i;
int max, len;
max = 0;
for(i=0; op[i].label; i++){
len = strlen(op[i].label) + 1;
switch( op[i].type ){
case OPT_FLAG:
case OPT_FFLAG:
break;
case OPT_INT:
case OPT_FINT:
len += 9; /* length of "" */
break;
case OPT_DBL:
case OPT_FDBL:
len += 6; /* length of "" */
break;
case OPT_STR:
case OPT_FSTR:
len += 8; /* length of "" */
break;
}
if( len>max ) max = len;
}
for(i=0; op[i].label; i++){
switch( op[i].type ){
case OPT_FLAG:
case OPT_FFLAG:
fprintf(errstream," -%-*s %s\n",max,op[i].label,op[i].message);
break;
case OPT_INT:
case OPT_FINT:
fprintf(errstream," %s=%*s %s\n",op[i].label,
max-strlen(op[i].label)-9,"",op[i].message);
break;
case OPT_DBL:
case OPT_FDBL:
fprintf(errstream," %s=%*s %s\n",op[i].label,
max-strlen(op[i].label)-6,"",op[i].message);
break;
case OPT_STR:
case OPT_FSTR:
fprintf(errstream," %s=%*s %s\n",op[i].label,
max-strlen(op[i].label)-8,"",op[i].message);
break;
}
}
}
!end-of-options.c!
echo extracting options.h
cat <<\!end-of-options.h! >options.h
/*
** Copyright (c) 1991 by D. R. Hipp.
*/
#ifndef _OPTIONS_H_
#define _OPTIONS_H_

struct s_options {
enum { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR,
OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type;
char *label;
void *arg;
char *message;
};
int optinit(char**,struct s_options*,FILE*);
int optnargs(void);
char *optarg(int);
void opterr(int);
void optprint(void);

#endif

/*
** NOTES:
**
** optinit(char **argv, struct s_options*, FILE *);
**
** Initializes the package. Argc and argv are the arguments given
** to main(). The 3rd argument is a pointer to an initialized
** null-terminated array describing the allowed command line options.
** The 4th and last argument is the stream to use for error output.
** This may be NULL to suppress error messages. The function returns
** non-zero in the event of an error.
**
** optnargs(void);
**
** This returns the number of non-switch arguments on the command
** line.
**
** optarg(int N);
**
** This returns a pointer to the N-th non-switch argument on the
** command line. NULL is returned if N is out of range. The first
** option is number 0.
**
** opterr(int N);
**
** This function prints the command line with an error pointing to
** the N-th non-switch argument to the stream identified in the
** second argument.
**
** optprint(void);
**
** This function prints a message describing all of the allowed
** command line switches.
*/
!end-of-options.h!
echo extracting scan.c
cat <<\!end-of-scan.c! >scan.c
/*
** Copyright (c) 1991 by D. R. Hipp.
*/
/*
** The scanner
*/
#include
#include
#include
#include
#include
#include "ctree.h"
#include "debug.h"

#define TOKENSIZE 1000 /* Maximum length of a token */

int parse(char *text){
static int bcnt = 0, pcnt = 0;
static enum {START, WANTARG, INARG, AFTERARG, INDECL, INSIDE, IDSEEN, WAIT}
state = START;
static char name1[TOKENSIZE+1];
static char name2[TOKENSIZE+1];
char c;

c = text[0];
switch( state ){
case START:
if( c=='{' ){
bcnt = 1;
state = WAIT;
}else if( isalpha(c) || c=='_' ){
strcpy(name1,text);
state = WANTARG;
}
break;
case WANTARG:
if( c=='(' ){
pcnt = 1;
state = INARG;
}else if( isalpha(c) || c=='_' ){
strcpy(name1,text);
}else{
state = START;
}
break;
case INARG:
if( c==')' ){
pcnt--;
if( pcnt==0 ) state = AFTERARG;
}else if( c=='(' ){
pcnt++;
}
break;
case AFTERARG:
if( c=='{' ){
BUG(bugprog,printf("Function: %s\n",name1);)
SetIsProgram(name1);
state = INSIDE;
bcnt = 1;
}else if( isalpha(c) ){
state = INDECL;
}else{
state = START;
}
break;
case INDECL:
if( c=='=' ){
state = START;
}else if( c=='{' ){
BUG(bugprog,printf("Function: %s\n",name1);)
SetIsProgram(name1);
state = INSIDE;
bcnt = 1;
}
break;
case INSIDE:
if( c=='}' ){
bcnt--;
if( bcnt==0 ) state = START;
}else if( c=='{' ){
bcnt++;
}else if( isalpha(c) || c=='_' ){
strcpy(name2,text);
state = IDSEEN;
}
break;
case IDSEEN:
state = INSIDE;
if( c=='}' ){
bcnt--;
if( bcnt==0 ) state = START;
}else if( c=='{' ){
bcnt++;
}else if( isalpha(c) || c=='_' ){
strcpy(name2,text);
state = IDSEEN;
}else if( c=='(' ){
BUG(bugcall,printf(" %s\n",name2);)
AcallsB(name1,name2);
}
break;
case WAIT:
if( c=='}' ){
bcnt--;
if( bcnt==0 ) state = START;
}else if( c=='{' ){
bcnt++;
}
break;
}
return 0;
}

/*
** Scan the specified input file. Pass tokens to the function
** parse().
*/
void scan(char *filename){
FILE *fp;
int c;

fp = fopen(filename,"r");
if( fp==0 ){
fprintf(stderr,"Can't open \"%s\" for reading.\n",filename);
perror("Reason");
exit(1);
}
c = getc(fp);
while( c!=EOF ){
if( isspace(c) ){
while( isspace(c) ) c = getc(fp);
}else if( c=='/' ){
c = getc(fp);
if( c=='/' ){
do c=getc(fp); while( c!='\n' && c!=EOF );
}else if( c=='*' ){
int pc = 0;
while( !(pc=='*' && c=='/') && c!=EOF ){
pc = c;
c = getc(fp);
}
if( c!=EOF ){
c = getc(fp);
}
}else{
parse("/");
}
}else if( c=='\"' || c=='\'' ){
int backslash = 0;
int starter;
char buf[3];
starter = c;
while( (c=getc(fp))!=EOF && (backslash || c!=starter) ){
backslash = !backslash && c=='\\';
}
if( c!=EOF ) c = getc(fp);
buf[0] = buf[1] = starter;
buf[2] = 0;
parse(buf);
}else if( isalnum(c) || c=='_' ){
char buf[TOKENSIZE+1];
int i = 0;
int numflag;
numflag = isdigit(c);
do{
buf[i++] = c;
c = getc(fp);
}while( (isalnum(c) || c=='_' || (c=='.' && numflag)) && i if( i==TOKENSIZE ){
while( isalnum(c) || c=='_' ) c = getc(fp);
}
buf[i] = 0;
parse(buf);
}else{
char buf[2];
buf[0] = c;
buf[1] = 0;
parse(buf);
c = getc(fp);
}
}
fclose(fp);
}
!end-of-scan.c!
echo extracting strxcmp.c
cat <<\!end-of-strxcmp.c! >strxcmp.c
/*
** Copyright (c) 1991 by D. R. Hipp.
*/
/*
** Compare strings sensibly.
*/
#include

/* An array to map all upper-case characters into their corresponding
** lower-case character. */
static unsigned char case_map[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
252,253,254,255};


/* Compare strings without case. Strings of digits compare
** in numerical order */
int strivcmp(atext,btext)
const char *atext;
const char *btext;
{
register unsigned char *a, *b, *map, ca, cb;
int result;

map = case_map;
a = (unsigned char *)atext;
b = (unsigned char *)btext;
do{
if( (ca=map[*a++])!=(cb=map[*b++]) ) break;
}while( ca!=0 );
if( isdigit(ca) ){
if( !isdigit(cb) ){
result = 1;
}else{
int acnt, bcnt;
acnt = bcnt = 0;
while( isdigit(*a++) ) acnt++;
while( isdigit(*b++) ) bcnt++;
result = acnt - bcnt;
if( result==0 ) result = ca-cb;
}
}else if( isdigit(cb) ){
result = -1;
}else{
result = ca - cb;
}
return result;
}

/* Compare strings case sensitive. Strings of digits compare
** in numerical order */
int strvcmp(atext,btext)
const char *atext;
const char *btext;
{
register unsigned char *a, *b, ca, cb;
int result;

a = (unsigned char *)atext;
b = (unsigned char *)btext;
do{
if( (ca=*a++)!=(cb=*b++) ) break;
}while( ca!=0 );
if( isdigit(ca) ){
if( !isdigit(cb) ){
result = 1;
}else{
int acnt, bcnt;
acnt = bcnt = 0;
while( isdigit(*a++) ) acnt++;
while( isdigit(*b++) ) bcnt++;
result = acnt - bcnt;
if( result==0 ) result = ca-cb;
}
}else if( isdigit(cb) ){
result = -1;
}else{
result = ca - cb;
}
return result;
}

/* Compare strings without case. Strings of digits compare
** in numerical order. No more than "n" characters are compared */
int strnivcmp(atext,btext,n)
const char *atext;
const char *btext;
int n;
{
register unsigned char *a, *b, *map, ca, cb;
int result;

map = case_map;
a = (unsigned char *)atext;
b = (unsigned char *)btext;
if( n>0 ){
do{
if( (ca=map[*a++])!=(cb=map[*b++]) ) break;
}while( ca!=0 && n-->1 );
}
if( n>0 ){
if( isdigit(ca) ){
if( !isdigit(cb) ){
result = 1;
}else{
int acnt, bcnt;
acnt = bcnt = 1;
while( acnt while( bcnt result = acnt - bcnt;
if( result==0 ) result = ca-cb;
}
}else if( isdigit(cb) ){
result = -1;
}else{
result = ca - cb;
}
}else{
result = 0;
}
return result;
}

/* Compare strings case sensitive. Strings of digits compare
** in numerical order. No more than "n" characters are compared */
int strnvcmp(atext,btext,n)
const char *atext;
const char *btext;
int n;
{
register unsigned char *a, *b, ca, cb;
int result;

a = (unsigned char *)atext;
b = (unsigned char *)btext;
if( n>0 ){
do{
if( (ca=*a++)!=(cb=*b++) ) break;
}while( ca!=0 && n-->1 );
}
if( n>0 ){
if( isdigit(ca) ){
if( !isdigit(cb) ){
result = 1;
}else{
int acnt, bcnt;
acnt = bcnt = 1;
while( acnt while( bcnt result = acnt - bcnt;
if( result==0 ) result = ca-cb;
}
}else if( isdigit(cb) ){
result = -1;
}else{
result = ca - cb;
}
}else{
result = 0;
}
return result;
}

/* Do a "sensible" comparison of two strings */
int sstrcmp(atext,btext)
const char *atext;
const char *btext;
{
int result;
result = strivcmp(atext,btext);
if( result==0 ) result = strvcmp(atext,btext);
return result;
}


/* Do a "sensible" comparison of two strings */
int sstrncmp(atext,btext,n)
const char *atext;
const char *btext;
int n;
{
int result;
result = strnivcmp(atext,btext,n);
if( result==0 ) result = strnvcmp(atext,btext,n);
return result;
}

#ifdef TEST
/* gcc -DTEST strxcmp.c; a.out */
/* Run this version to check the routines for correctness */
#include

static int cmpi(char *a, char *b){
return strnivcmp(a,b,4);
}
static int cmp(char *a, char *b){
return strnvcmp(a,b,4);
}

void main(void){
char buf[1000][50];
int i,j;

for(i=0; i<1000 && fgets(buf[i],50,stdin); i++);
qsort(buf,i,50,strivcmp);
printf("**** strivcmp ****\n");
for(j=0; j if( j>0 && strivcmp(buf[j-1],buf[j])==0 ) printf("= ");
printf("%s",buf[j]);
}
qsort(buf,i,50,strvcmp);
printf("**** strvcmp ****\n");
for(j=0; j if( j>0 && strvcmp(buf[j-1],buf[j])==0 ) printf("= ");
printf("%s",buf[j]);
}
qsort(buf,i,50,cmpi);
printf("**** strnivcmp(_,_,4) ****\n");
for(j=0; j if( j>0 && cmpi(buf[j-1],buf[j])==0 ) printf("= ");
printf("%s",buf[j]);
}
qsort(buf,i,50,cmp);
printf("**** strnvcmp(_,_,4) ****\n");
for(j=0; j if( j>0 && cmp(buf[j-1],buf[j])==0 ) printf("= ");
printf("%s",buf[j]);
}
}
#endif
#ifdef SPEEDTRIAL
/* gcc -DSPEEDTRIAL -p strxcmp.c */
/* To check the speed of these routines, run the following program
** with LOTS of input and look and the results from the profiler */
#include

void main(void){
char line1[1000];
char line2[1000];

if( fgets(line1,1000,stdin) ){
while( fgets(line2,1000,stdin) ){
strcmp(line1,line2);
stricmp(line1,line2);
strncmp(line1,line2,8);
strnicmp(line1,line2,8);
strvcmp(line1,line2);
strivcmp(line1,line2);
strnvcmp(line1,line2,8);
strnivcmp(line1,line2,8);
strcpy(line1,line2);
}
}
}
#endif
!end-of-strxcmp.c!


  3 Responses to “Category : C Source Code
Archive   : CTREE.ZIP
Filename : CTREE.SHR

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/