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 */