this page is htmlified by HYPRF - Copyright © 1998 Patrick Davalan - distributed under the GNU GPL license
TREE INVT
this file is built from grfmake.c
#define DEBUG 1
/*@v*/
/*@t
* grf 2.0.0 1998/11/27 Copyright (C) 1997-1998 Patrick DAVALAN mailto:patrick.Davalan@wanadoo.fr
*/
#ifndef grf_version
#define grf_version "grf 2.0.0 1998/11/27 Copyright (C) 1997-1998 Patrick DAVALAN "
#endif
/*@v*/
/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
*--------------------------------------------------------------------------
* File : grfmake.c
* Library : grf
* OS : LINUX
* Author : Patrick Davalan
*
* Description:
* . build a graph from pairs of names
* . this program build a graph implied in the structure of the input.
* . each line in the input is made of a pair of name showing some kind
* of hierarchical dependancie between these names.
* . the format of the program output may be use by a printing program to
* build a pretty-to-see graph
* . the dependancies may be inverted.
*
* Terminology :
* . graf : lazy term for graph
* . node : a node of the graph which is *not* a leaf
* . leave : a node of the graph which is a leaf
* . element : either a node or a leave , when not important to make diff.
*
* Notes :
* . as all the input file is loaded and processed into memory , it does'nt
* fit for large input ( say more than 3000 pairs of names , but it may
* depends on your computer and the time you are able to wait for output )
* . this program was primarily designed to show dependancies between
* functions of a program. I think it should works well for this kind of
* task.
*
*--------------------------------------------------------------------------
*/
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <misc.h>
#include <dbg.h>
#include <lis.h>
#include <pil.h>
#define GRF_MAX_NMLENGTH 512
#define GRF_STK_MAXDEPTH 512
struct LISTDATA
{
uint lineNum ;
LisElement * pGrafSub ; /* for a node , list Element in graf */
char name[0] ;
} ;
typedef struct LISTDATA listdata ;
struct GRAFDATA
{
uint lineNum ; /* output line number */
LisElement * pListElt ; /* the corresponding List element */
} ;
typedef struct GRAFDATA grafdata ;
char delim[2] = " " ;
static int flags = 0 ;
#define FLREV 1
#define FLEXPANDALL 2
#define FLONLY 3
#define FLNORECURSE 4
/* printing */
static uint lineNum = 0 ; /* line # being edited */
static uint nestLevel = 0 ; /* nested level for indent. */
static char * rootName ; /* name to be root of graf */
static Pil * pNodeStk ; /* graf nodes stack */
static LisElement *pListTop; /* top level sublist */
static LisElement *pInputList; /* to store data from the file */
static LisElement *pGrafList; /* graf built from InputList */
static LisElement *pSchedList ; /* intermediate list to make graf */
static LisElement *pLastFoundHead = NULL ; /* may be a short cut for findHead() */
/* flags in List element to indicate Node has found a place in Graflist */
#define setDone(P) lisSetMark0(P)
#define isDone(P) lisIsMark0(P)
/* flags in graf list element to indicate Node is to be expanded */
#define setExpand(P) lisSetMark0(P)
#define isExpand(P) lisIsMark0(P)
/* get the data from a list element */
#define listData(PELT) ( (listdata *)(lisGetData(PELT)) )
/* get the data from a graf element */
#define grafData(PELT) ( (grafdata *)(lisGetData(PELT)) )
/* get the name from a list element */
#define listName(PELT) listData(PELT)->name
/* get the list element from a graf element */
#define grafListPtr(PELT) grafData(PELT)->pListElt
/* get the name from a graf element */
#define grafName(PELT) listName(grafListPtr(PELT))
/* cast the pil element to a LisElement pointer ( address of a graf element)*/
#define pilElt(PPIL) ( (LisElement *)PPIL )
/* *************************************************************************
TOP TREE INVT
*
* . misc. functions
*
* *************************************************************************
*/
/*
* -------------------------------------------------------------------------
* scanGrafNode
* -------------------------------------------------------------------------
*/
static int
scanGrafNode( LisElement *pSub ,
int (*nodeFunc)(LisElement *) , int (*leafFunc)(LisElement *) )
{
LisElement * pElt ;
dbg_enter() ;
/* check if exploration of subgraf required */
if ( (*nodeFunc)(pSub) == true )
{
pilPush(pNodeStk,pSub) ;
nestLevel++ ;
pElt = lisStart(pSub) ;
for ( ; ! lisIsEnd( (pElt = lisGetNext(pElt)) ) ; )
{
dbg_trace("%d -> %s\n",nestLevel,grafName(pElt));
if ( lisIsList(pElt) )
{
scanGrafNode(pElt,nodeFunc,leafFunc) ; ®
}
else
{
(*leafFunc)(pElt) ;
}
}
nestLevel-- ;
pilPop(pNodeStk) ;
}
dbg_return(true) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* scanGraf
* . scan the graf in depth-first order , calling back a user fonction
* for each element
* use the recursive descent algorithm.
* -------------------------------------------------------------------------
*/
static int
scanGraf( int (*nodeFunc)(LisElement *) , int (*leafFunc)(LisElement *) ) /* */
{
LisElement * pGrafSub ;
dbg_enter() ;
/* alloc a stack to check recursion */
pNodeStk = pilNew(GRF_STK_MAXDEPTH) ;
nestLevel = 0 ;
/* scan the highest level sublist */
for ( pGrafSub = lisStart(pGrafList) ;
! lisIsEnd(pGrafSub = lisGetNext(pGrafSub)) ; )
{
dbg_trace("Node %s\n",grafName(pGrafSub))
scanGrafNode(pGrafSub,nodeFunc,leafFunc) ; ®
}
pilFree(pNodeStk) ;
dbg_return(true) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* recurseCheck
* . check for recursion in graf scan by scanning the stack of Nodes
* . arg : pGrafNode : the Node to search the stack for
* . return true when pGrafNode is in the stack ( -> recursion )
* return false otherwise
* -------------------------------------------------------------------------
*/
static int
recursCheck( LisElement * pGrafNode) /* */
{
int retVal = false ;
LisElement * pNode ;
dbg_enter() ;
dbg_trace("search %lx %ls\n",pGrafNode,grafName(pGrafNode) ) ;
for ( pNode = pilElt(pilGetFirst(pNodeStk)) ;
pNode != pilElt(error) ;
pNode = pilElt(pilGetNext(pNodeStk)) )
{
dbg_trace("scan %lx %ls\n",pNode,grafName(pNode) ) ;
if ( lisStart(pNode) == lisStart(pGrafNode) )
{
retVal = true ;
break ;
}
}
dbg_return(retVal) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* findHead
* search a list for a name in a head of a sublist
* -------------------------------------------------------------------------
*/
/* INLINE */ int
cmpHead( LisElement * plisw, char * name )
{
int retVal = false ;
if (strcmp( name,listName(plisw) ) == 0 )
{
dbg_trace("FOUND %s\n",listName(plisw));
retVal = true ;
}
return(retVal) ;
}
TOP TREE INVT
static LisElement * /* return sublist or NULL */
findHead(LisElement *plist, /* list to search for */
char *name) /* name to find */
{
LisElement *plisw ;
LisElement *plisx = NULL ;
dbg_enter() ;
dbg_assert(lisIsList(plist)) ;
dbg_trace("SEARCH (%s)\n",name);
/* try a shortcut */
if ( pLastFoundHead != NULL )
{
if ( cmpHead(pLastFoundHead, name) ) ®
{
/* sometimes it works */
dbg_return(pLastFoundHead) ;
}
}
/* scan the list */
for ( plisw = lisStart(plist) ;
! lisIsEnd( plisw = lisGetNext(plisw) ) ; )
{
dbg_assert(lisIsList(plisw)) ;
dbg_trace("scan (%s)\n", listName(plisw)) ;
if ( cmpHead(plisw, name) ) ®
{
pLastFoundHead = plisx = plisw ;
break ;
}
}
dbg_return(plisx) ;
}
TOP TREE INVT
/*
* ------------------------------------------------------------------------
* findElt
* search a list for a name in a list element
* -------------------------------------------------------------------------
*/
static LisElement * /* return element or NULL */
findElt(LisElement *pList, /* list to search for */
char *name) /* name to find */
{
LisElement *plisw ;
LisElement *peltx = NULL ;
dbg_enter() ;
dbg_trace("SEARCH %s\n",name);
dbg_assert(lisIsList(pList)) ;
for ( plisw = lisStart(pList) ;
! lisIsEnd( plisw = lisGetNext(plisw) ) ; )
{
dbg_trace("scan (%s)\n",listName(plisw)) ;
if (strcmp( name, listName(plisw) ) == 0 )
{
peltx = plisw ;
dbg_trace("FOUND %s\n",listName(peltx));
break ;
}
}
dbg_return(peltx) ;
}
/*
TOP TREE INVT
* *************************************************************************
*
* . this section of code write a representation of the graf structure
* onto a file.
*
* *************************************************************************
*/
/*
* -------------------------------------------------------------------------
* outGrafNode
* -------------------------------------------------------------------------
*/
static int
outGrafNode(LisElement *pNode)
{
int retVal = true ;
grafdata * pData ;
dbg_enter() ;
lineNum++ ;
pData = grafData(pNode) ;
dbg_trace("Node %d|%d|%s\n",lineNum,nestLevel,
listName(pData->pListElt)) ;
fprintf(stdout,"%d|%d|%s",lineNum,nestLevel,
listName(pData->pListElt)) ;
if ( lisIsEmpty(pNode) )
{
retVal = false ;
}
else
{
if ( ! isExpand(pNode) )
{
if ( bit_isoff(flags,FLEXPANDALL) || recursCheck(pNode) ) ®
{
retVal = false ;
/* output reference of line where this Node is expanded */
fprintf(stdout,"|%d",pData->lineNum) ;
}
}
else
{
/* check the link count of subgraf starting here to know if
* there is a link to this target from another node
*/
dbg_trace("link#=%d\n",lisGetLink(pNode)) ;
if ( bit_isoff(flags,FLEXPANDALL)
&& lisGetLink(pNode) > 1 )
{
/* indicate it is a target */
fprintf(stdout,"|#") ;
}
}
}
fprintf(stdout,"\n") ;
#if ( DEBUG > 2 )
fflush(NULL) ;
#endif
dbg_return(retVal) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* outGrafLeaf
* -------------------------------------------------------------------------
*/
static int
outGrafLeaf(LisElement *pLeaf)
{
grafdata * pData ;
dbg_enter() ;
lineNum++ ;
pData = grafData(pLeaf) ;
dbg_trace("Leaf %s\n",listName(pData->pListElt)) ;
fprintf(stdout,"%d|%d|%s\n",lineNum,nestLevel,
listData(pData->pListElt)->name) ;
dbg_return(true) ;
}
/* *************************************************************************
*
* . this section of code make a graf representation from the input list
* structure
*
* . the graph is implement as list / sublists / ....
* for each list :
* . a list element denote a node which may be dependant of a node of
* a higher level list
* . simple list elements denote leaves
* . data pointed by list elements & simple elements consist of :
* . a line number where the element will be printed
* . a pointer to the corresponding list element in the list structure.
*
*
* Notes :
*
* . the graf is built in a manner that a node will be expanded only once ,
* even if it is referencd more than once in different branchs of the
* hierarchie.
* by expanded , i mean the dependant subgraf will be developped.
* . a Node is expanded at the highest possible level ( i.e. closest from
* the root ). to achieve that , a fifo list - hereinafter called
* schedule list - is created to put the Nodes eligible for expansion.
* by mean of flags setting , Nodes cannot be put twice in the list.
* when a node is taken out of the schedule list to be expanded
* then it's directly dependant nodes are appended to the schedule list.
* . thus , all the node at some level are expanded before they are reached
* at a lower level.
*
* . the schedule list will be initialised differently whether a root has been
* specified or not :
* . when a root is specified , the root node will be the only node put in the
* schedule list before expansion.
* then when all nodes in the schedule list has been expanded( the root
* node & dependant nodes and so on... ) , the built graf is 'correct' ,
* i.e. expansion occured at the highest possible level.
* however , when the --only option is not specified , if some
* not-expanded nodes remains in the input-list ( the list build from
* input ) , they are then put all together in the schedule list before
* expansion to occur. thus all this nodes and dependant nodes will be
* 'correct'. but when a dependant node was previously expanded in the
* hierarchy of root - possibly at a lowest level - then it will not be
* expanded twice.
* another behaviour should have been possible , we might consider that
* the nodes were not expanded when root was expanded , in this case ,
* some expansions may occur twice which may have the effects - under
* certains circumstances , depending on the choice of root - to made a
* graf almost twice as big.
* however , if it happens to be useful , this behaviour may be
* implemented without headache by resetting the appropriate flags after
* the root hierarchie expansion.
* . when a root is *not* specified , then all nodes from the input list
* are put into the schedule list before expansion occurs , thus no
* problem.
*
* . Nodes whith the same expansion are linked to that expansion.
* you may say :
* "why so much trouble to make the expansion at some particular moment
* if all the nodes refer to the same expansion regardless to their
* place in the graf".
* you are right ! thanks a lot for following me so far !
* in fact , there is a little difference when the expansion occurs
* against a particular mode , a flag is set in the node to indicate
* that expansion occured there. the main purpose of these comments
* is to indicate the signification of this bit. I hope it will be
* enough , i still have 3 bytes to comment today !
*
* NB : the --expandall option do not affect the building of graf , only
* its output.
*
* * *************************************************************************
*/
TOP TREE INVT
/*
* -------------------------------------------------------------------------
*
* LisElement * schedNode(LisElement *pNode)
* add a node to the graf and the schedule list for later expansion
* Args :
* pHighNode : the graf list where the node should be inserted
* pNode : the node of the list to be added to the graf
* Return :
* The created Node referenced in the graf and the schedule list
*
* -------------------------------------------------------------------------
*/
static LisElement *
schedNode( LisElement *pHighNode, LisElement * pNode )
{
LisElement * pGrafSub ; /* the node to be created */
grafdata * pGrafData ; /* data of the created Node */
dbg_enter() ;
/* allocate a node in the graf */
pGrafSub = lisCreListLast(pHighNode) ;
listData(pNode)->pGrafSub = pGrafSub ;
setExpand(pGrafSub) ; /* indicate Node is to expand */
setDone(pNode) ; /* not to schedule expansion later */
/* allocate data and connect it to the node */
ram_newclr(pGrafData) ;
pGrafData->pListElt = pNode ;
dbg_trace("Node %s\n",listName(pNode)) ;
lisGiveMemData(pGrafSub,pGrafData,sizeof(*pGrafData)) ;
/* put the root in the schedule List */
lisRefListLast(pSchedList,pGrafSub) ;
dbg_return(pGrafSub) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* addGrafNode
* . add a Node to the graf
* -------------------------------------------------------------------------
*/
static int
addGrafNode( LisElement *pSchedNode, LisElement *pListSub )
{
LisElement * pGrafSub ;
dbg_enter() ;
/* check if the node is already attached to the graf ,
* please note that there are 2 redondant infos :
* flag and presence of address in pListSub data
*/
dbg_trace("Node %s\n",listName(pListSub)) ;
if ( isDone(pListSub) )
{
dbg_trace("already done\n") ;
/* get the address of existing ( or at least scheduled ) subgraf */
pGrafSub = listData(pListSub)->pGrafSub ;
dbg_assert( pGrafSub != NULL ) ;
dbg_assert( isExpand(pGrafSub) ) ;
/* insert a hook to hang the sublist */
lisRefListLast(pSchedNode,pGrafSub) ;
}
else
{
/* the sub graf should be expanded here , because we are the first
* to meet it , thus it is the shortest way from the root ( at least
* there is no way shorter )
*/
schedNode(pSchedNode,pListSub) ; ®
}
dbg_return(true) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* addGrafLeaf
* . add a Leaf to the graf
* -------------------------------------------------------------------------
*/
static int
addGrafLeaf( LisElement *pSchedNode, LisElement *pListElt )
{
LisElement * pGrafElt ;
grafdata * pGrafData ;
dbg_enter() ;
dbg_trace("Leaf %s\n",listName(pListElt)) ;
/* add the node to the graf */
pGrafElt = lisCreLast(pSchedNode) ;
/* allocate data and connect it to the node */
ram_newclr(pGrafData) ;
pGrafData->pListElt = pListElt ;
lisGiveMemData(pGrafElt,pGrafData,sizeof(*pGrafData)) ;
dbg_trace("added %s -> %s\n",grafName(pSchedNode),grafName(pGrafElt)) ;
dbg_return(true) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* schedScan
* make a graf from input list
* Args :
*
* Return :
* . return true when ok
* . errors not yet implemented !
*
* -------------------------------------------------------------------------
*/
static int
schedScan()
{
LisElement * pListElt ;
LisElement * pListSub ;
LisElement * pSchedNode ;
dbg_enter() ;
/* scan the Sched schedule List to expand Nodes
* Note : the Sched list grows each time a Node is found
*/
/* for each Node scheduled for expansion */
for ( ; ! lisIsEnd( pSchedNode = lisGetFirst(pSchedList) ) ;
lisDelete(pSchedNode) )
{
pListElt = grafData(pSchedNode)->pListElt ;
dbg_trace("got a sched. Node %s\n",listName(pListElt)) ;
/* scan the sublist */
for ( pListElt = lisStart(pListElt) ;
! lisIsEnd(pListElt = lisGetNext(pListElt)) ; )
{
dbg_trace("scanning\n") ;
/* test if node element */
pListSub = findHead( pInputList, listName(pListElt) ) ; ®
if ( pListSub )
{
addGrafNode(pSchedNode,pListSub) ; ®
}
else
{
addGrafLeaf(pSchedNode,pListElt) ; ®
}
}
}
dbg_return(true) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
*
* int makeGraf(void)
* make a graf from the list
* Return :
* true when ok
*
* -------------------------------------------------------------------------
*/
static int
makeGraf()
{
static LisElement *pListRoot ; /* sublist element of root of graf */
dbg_enter() ;
/* allocate a list to schedule Nodes expansion */
pSchedList = lisCreListLast(pListTop) ;
/* check if root specified */
if ( rootName != NULL )
{
pListRoot = findHead(pInputList,rootName) ; ®
if ( pListRoot == NULL )
{
fprintf(stderr,"cannot find root : %s\n",rootName) ;
dbg_return(false) ;
}
else
{
/* put root node in graf & schedule list */
schedNode(pGrafList,pListRoot) ; ®
/* make graf from schedule list */
schedScan() ; ®
}
}
/*
* same processing when root not specified and for remainding nodes
* after root processing
*/
if ( bit_isoff(flags,FLONLY) )
{
LisElement * pListRoot ;
for ( pListRoot = lisStart(pInputList) ;
! lisIsEnd( pListRoot = lisGetNext(pListRoot) ) ; )
{
dbg_assert(lisIsList(pListRoot)) ;
if ( ! isDone(pListRoot) )
{
/* put root node in graf & schedule list */
schedNode(pGrafList,pListRoot) ; ®
}
}
/* make graf from schedule list */
schedScan() ; ®
}
lisDelete(pSchedList) ;
dbg_return(true) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* lineNode
* -------------------------------------------------------------------------
*/
static int
lineNode(LisElement *pNode)
{
int retVal = true ;
grafdata * pData ;
dbg_enter() ;
lineNum++ ;
pData = grafData(pNode) ;
dbg_trace("Node %s\n",grafName(pNode));
if ( isExpand(pNode) )
{
pData->lineNum = lineNum ;
}
else
{
if ( recursCheck(pNode) || bit_isoff(flags,FLEXPANDALL) ) ®
{
retVal = false ;
}
}
dbg_return(retVal) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* lineLeaf
* -------------------------------------------------------------------------
*/
static int
lineLeaf(LisElement *pLeaf)
{
dbg_enter() ;
lineNum++ ;
dbg_trace("Leaf %s\n",grafName(pLeaf));
dbg_return(true) ;
}
/*
* *************************************************************************
*
* . this section of code make a list structure from the input file
* the highest level of list is composed of sublist elements , one
TOP TREE INVT
* for each left name in input , the name is accessed via the list element
* each sublist is composed by the name which appears at the right of
* the name stored in the head element
*
* *************************************************************************
*/
/*
* -------------------------------------------------------------------------
* addList
* -------------------------------------------------------------------------
*/
static int
addList( char *pLeftName, /* it will be on sublist header */
char *pRightName) /* it will be on a sublist element */
{
LisElement *pListLeft ;
LisElement *peltw ;
size_t nameLen , listNameLen ;
listdata * pListName ;
dbg_enter() ;
/*
* check if left name already in a list element ,
* if not : create a list element
*/
dbg_trace("addList 1 : %s %s\n",pLeftName,pRightName) ;
pListLeft = findHead(pInputList,pLeftName) ; ®
if ( pListLeft == NULL )
{
pListLeft = lisCreListLast(pInputList) ;
nameLen = strlen(pLeftName) ;
listNameLen = sizeof(listdata)+nameLen+1 ;
pListName = malloc(listNameLen) ;
pListName->lineNum = 0 ;
strcpy(pListName->name,pLeftName) ;
lisGiveMemData(pListLeft,pListName,listNameLen) ;
dbg_trace("put head %s(%d)\n",pListName->name,listNameLen) ;
}
dbg_assert(lisIsList(pListLeft)) ;
/*
* check if pRightName already in the sublist ( obviously not if we just
* create the sublist above ) , if not : add it as a (sub)list element
*/
if ( pRightName )
{
peltw = findElt(pListLeft,pRightName) ; ®
if ( peltw == NULL )
{
peltw = lisCreLast(pListLeft) ;
nameLen = strlen(pRightName) ;
listNameLen = sizeof(listdata)+nameLen+1 ;
pListName = malloc(listNameLen) ;
dbg_trace("apres malloc\n") ;
pListName->lineNum = 0 ;
strcpy(pListName->name,pRightName) ;
lisGiveMemData(peltw,pListName,listNameLen) ;
dbg_trace("put sublist elt %s(%d)\n",pListName->name,listNameLen) ;
}
}
dbg_return(true) ;
}
TOP TREE INVT
/*
* -------------------------------------------------------------------------
* makeList
* -------------------------------------------------------------------------
*/
static int
makeList(void)
{
char inputLine[512] ;
/* these variables point to the left and right names in input lines */
char *pInputLeftName ;
char *pInputRightName ;
/* these variables may be the same as previous variables or inverted */
char *pLeftName ;
char *pRightName ;
dbg_enter() ;
/* main loop : for each line in Input file */
for ( ; fgets(inputLine,sizeof(inputLine)-1,stdin) != NULL ; )
{
if ( (* inputLine == '\n') ) continue ;
/* sorry , i never succeed to have scanf work ! */
*(inputLine+strlen(inputLine)-1) = 0 ;
pInputRightName = inputLine ;
pInputLeftName = strsep(&pInputRightName,delim) ;
if ( pInputLeftName == NULL )
{
dbg_usrerr("INVALID INPUT DATA\n") ;
exit(-1) ;
}
dbg_trace("read %s %s\n",pInputLeftName,pInputRightName) ;
/* invert pair if requested */
if ( bit_ison(flags,FLREV ) )
{
pLeftName = pInputRightName ; pRightName = pInputLeftName ;
}
else
{
pLeftName = pInputLeftName ; pRightName = pInputRightName ;
}
/* put pair in List */
if ( pLeftName )
{
addList(pLeftName,pRightName) ; ®
}
else if ( pRightName )
{
dbg_assert( bit_ison(flags,FLREV) ) ;
addList(pRightName,pLeftName) ; ®
}
}
dbg_return(true) ;
}
/*
* *************************************************************************
* . main :
TOP TREE INVT
* . get arguments.
* . read input file into a list structure.
* . from that structure build another list structure ( called graf ).
* . write output file from graf
*
* *************************************************************************
*/
/*
*------------------------------------------------------------------------
* main
*-------------------------------------------------------------------------
*/
int
main(int argc, char **argv)
{
fprintf(stderr,"%s %s started\n",argv[0],grf_version) ;
/* options */
{
int c ;
static struct option lopt[] =
{
{"invert",0,0,'i'} , /* print an inverted graph */
{"only",0,0,'c'} , /* print only graph from root */
{"root",1,0,'r'} , /* specify root of graph */
{"delim",1,0,'d'} , /* delimiter between names */
{"expandall",0,0,'x'} , /* print a subgraph for each reference to a function */
{"version",0,0,'v'} ,
{"help",0,0,'h'} ,
{0,0,0,0}
} ;
static char * hopt[( sizeof(lopt)/sizeof(struct option) ) - 1] =
{
"] : print an inverted graph" ,
"] : print only graph from root" ,
"name ] : specify root of graph" ,
"char ] : delimiter between input names" ,
"] : print each subgraph in full" ,
"] : print Version number and exit",
"] : well ... help!"
} ;
int lopt_ind = 0 ;
for ( ; ( c = getopt_long(argc,argv,"",lopt,&lopt_ind) ) != -1 ; )
{
switch ( c )
{
case ( 'c' ) :
bit_set(flags,FLONLY) ;
break ;
case ( 'i' ) :
bit_set(flags,FLREV) ;
break ;
case ( 'r' ) :
rootName = optarg ;
break ;
case ( 'd' ) :
strncpy(delim,optarg,sizeof(delim) - 1) ;
break ;
case ( 'x' ) :
bit_set(flags,FLEXPANDALL) ;
break ;
case ( 'v' ) :
fprintf(stdout,"%s\n",grf_version) ;
fprintf(stderr,"%s ended",argv[0]) ;
exit(0) ;
break ;
case ( 'h' ) :
{
struct option *l ;
char ** h ;
fprintf(stdout,"%s\n",grf_version) ;
fprintf(stdout,"options :\n") ;
h = hopt ;
for ( l = lopt ; l->name ; l++ )
{
printf(" [ --%s %s\n",l->name,*(h++)) ;
}
}
exit(0) ;
fprintf(stderr,"%s ended",argv[0]) ;
break ;
case ( ':' ) :
fprintf(stderr,"option %s missing arg\n",lopt[lopt_ind].name) ;
break ;
case ( '?' ) :
fprintf(stderr,"unknown option %c\n",c) ;
break ;
}
}
}
/* allocate lists */
dbg_trace("allocating lists\n") ;
pListTop = lisInit() ;
pInputList = lisCreListLast(pListTop) ;
/* make a list from input file */
if ( ! makeList() ) ®
{
fprintf(stderr,"%s aborted while processing input\n",argv[0]) ;
exit(1) ;
}
/* make a graf from list */
pGrafList = lisCreListLast(pListTop) ;
if ( ! makeGraf() ) ®
{
fprintf(stderr,"%s aborted while making graf (1)\n",argv[0]) ;
exit(1) ;
}
/* rescan the graf to update line # */
if ( ! scanGraf(lineNode,lineLeaf) ) ®
{
fprintf(stderr,"%s aborted while making graf (2)\n",argv[0]) ;
exit(1) ;
}
/* output the graf */
lineNum = 0 ;
if ( ! scanGraf(outGrafNode,outGrafLeaf) ) ®
{
fprintf(stderr,"%s aborted during graf output\n",argv[0]) ;
exit(1) ;
}
/* free lists */
lisTerm(pListTop) ;
fprintf(stderr,"%s ended\n",argv[0]) ;
exit(0) ;
}
/* end-of-file */