[net.sources] PPERT a program to draw PERT charts

jchvr@ihlpg.UUCP (VanRietschote) (04/29/86)

--
Wanna make your boss happy? Here is a program for him/her that can
draw a limited PERT chart form some planning info in UNITY format.
See manual page for an example.

#-- cut here file=ppert.C
/* ppert.c -*-update-version-*- 
** HFVR VERSION=Tue Mar 18 13:03:01 1986
*/

/* CAVEATS for modifiers:
** ------- --- ----------
** the program will not work after the year 1994.
** the routines inttoweek,weektoint,incweek,decweek need to be ADAPTED
**
** some years do not have exactly 52 week. In that case
** the routines incweek and decweek need to be adjusted.
** if done the program should still work ok
**
** some work is never done. Suggestions for improvement
** can be found by scanning this text for TBS, feel free
** to add any good features.
*/

#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <time.h>

typedef enum {FALSE,TRUE} BOOL;

/* global switches for command line */
int	Aflag = 0 ;		/* ALL flag */
int	Iflag = 8 ;		/* -I flag default=8 */
int	Tflag = 12;		/* -T flag default=12 */
char	oflag[255]="";		/* oflag with name of output file */
int	cflag = 1  ;		/* increment for printing weeks */
int	uflag = 1  ;		/* TRUE if need uitloop */
int	wflag = 1  ;		/* TRUE if need warnings */
int	lflag = 0  ;		/* TRUE if long listing */
int	iflag = 0  ;		/* nr of item to print */
char	isearch[255]="";	/* id to start printing */
int	dflag = 0  ;		/* debug TRUE or FALSE */
int	sflag = 501;		/* start week */
int	nflag = 12 ;		/* number of weeks to print */
int	aflag = 0  ;		/* TRUE if all entries should print */

char	PERT[255]="pert" ;	/* PERT input file */
char	READY[] = "ready";	/* ready activity string */
char	NAME[]="ppert";	/* program name for printing errors/warnings */

struct DEP {
	struct DEP	*next;	/* pointer to next dependor */
	int	nr;		/* number of entry */
           } ;

#define IDLENGTH 16
#define STATUSLENGTH 6
#define STARTLENGTH 3
#define DURATIONLENGTH 3
#define AFTERLENGTH 255
#define ENDLENGTH 3
#define TITLELENGTH 32

struct ENTRY {					/* milestone entry */
	int	printed;			/* 1 if already printed */
	int 	nr	;			/* internal number */
	char	id[IDLENGTH+1]	;		/* id of Dpert */
	char	status[STATUSLENGTH+1];		/* status of Dpert */
	char	start[STARTLENGTH+1];		/* start of Dpert */
	int	istart;				/* int version of start */
	char	duration[DURATIONLENGTH+1];	/* duration of Dpert */
	int	iduration;			/* int version of duration */
	char	after[AFTERLENGTH+1];		/* after of Dpert */
	char	end[ENDLENGTH+1];		/* end of Dpert */
	int	iend;				/* int version of end */
	char	title[TITLELENGTH+1];		/* title of Dpert */
	struct DEP *dependson;			/* pointer to other entries */
	      } ;

/* if an entry depends on items 2 3 and 4 then the pointer chain is
**
    entries[i].dependson -->  @----------@
                              |  nr=4    |
                              |----------|
                              |  next-|  |
                              @-------|--@
                                      |
                                      v
                              @-----------@
                              |  nr=3     |
                              |-----------|
                              |  next-|   |
                              @-------|---@
                                      |
                                      v
                              @-----------@
                              |  nr=2     |
                              |-----------|
                              |  next=NULL|
                              @-----------@
*/

#define MAXENTRIES 999
struct ENTRY entries[MAXENTRIES];

int	c;		/* last char read */
int	linenr; 	/* line number */
int	nr;		/* number of entries */
int	totaldep;	/* total number of dependencies per id */
FILE	*fp;		/* input file */
int	errors;		/* number of errors */
int	warnings;	/* number of warnings */

#define TAB	9
#define CR	10
#define SP	32

/* prentry: prints a whole entry */
prentry(i)
int	i;
{ struct DEP *after;

  printf("\n--ENTRY--\n");
  printf("nr       =%d\n",entries[i].nr); 
  printf("id       =%s\n",entries[i].id);
  printf("status   =%s\n",entries[i].status);
  printf("start    =%s\n",entries[i].start);
  printf("istart   =%d\n",entries[i].istart);
  printf("duration =%s\n",entries[i].duration);
  printf("iduration=%d\n",entries[i].iduration);
  printf("after    =%s\n",entries[i].after);
  printf("end      =%s\n",entries[i].end);
  printf("iend     =%d\n",entries[i].iend);
  printf("title    =%s\n",entries[i].title);

/* print dependson pointer chain */
  after = entries[i].dependson;
  printf("after    =");
  while (after != NULL) {
   printf("%d ", after->nr);
   after = after->next;
  }
  printf("NULL\n");  
}/*prentry*/

/* message: will print error/warning messages
** and keep count of them
*/
#define ERRSTATE 1
#define WARSTATE 0
message(status,line,string,extra)
int	status;
int	line;
char	string[];
char	extra[];
{
 if (status==ERRSTATE) {
  errors++;
  fprintf(stderr,"\007%s: ",NAME);
  fprintf(stderr,"ERROR:    "); 
  fprintf(stderr,"at line %d: ",line);
  fprintf(stderr,"%s%s.\n",string,extra);
 }
 if ((wflag==1) && (status==WARSTATE)) {
  warnings++;
  fprintf(stderr,"\007%s: ",NAME);
  fprintf(stderr,"WARNING:  ");
  fprintf(stderr,"at line %d: ",line);
  fprintf(stderr,"%s%s.\n",string,extra);
 }
}/*message*/

/* ABORT: will print summary error/warning message and stop */
void ABORT()
{
 fprintf(stderr,"\007%s: ABORTING: after %d errors and %d warnings.\n",NAME,errors,warnings);
 exit(1);
}/*ABORT*/

/* get: will read 1 char and return its value
** EOF is returned if at end of file
** it will increment global var. linenr if CR is read
*/
int get(f)
FILE *f;
{ int ch;
  ch=getc(f);
  if( ch==CR ) {
    linenr++;
  }
  return(ch);
}/*get*/

/* usage: will scream usage message to user */
usage()
{
 fprintf(stderr,"\007Usage: %s [-dTIocuwlivsnaA] [-f input]\n",NAME);
 fprintf(stderr,"Where: -d turns on debug mode\n");
 fprintf(stderr,"       -T <length> to set printing length TITLE\n");
 fprintf(stderr,"       -I <length> to set printing length ID\n");
 fprintf(stderr,"       -o <file> to put updated pert in file\n");
 fprintf(stderr,"       -c <int> sets week increment\n");
 fprintf(stderr,"       -u turns off printing '....'\n");
 fprintf(stderr,"       -w turns off printing of warnings\n");
 fprintf(stderr,"       -l if long listing is needed\n");
 fprintf(stderr,"       -i <item-id> to set item to print\n");
 fprintf(stderr,"       -v prints version number and exit\n");
 fprintf(stderr,"       -s <int> sets start week\n");
 fprintf(stderr,"       -n <int> sets number of weeks to print\n");
 fprintf(stderr,"       -a forces all not ready entries to be printed\n"); 
 fprintf(stderr,"       -A forces all entries to be printed\n");
 fprintf(stderr,"       -f <file> names input file\n");
}/*usage*/

/* readstring: will read characters in to array
** up til either EOF, CR, or endchar
** then the array is terminated with EOS (end-of-string)
** maxlength is the maximum length of array (counting the EOS)
*/
readstring(array,maxlength,name,endchar)
char	array[];
int	maxlength;
char	name[];
int	endchar;
{ int length;		/* keeps track of where we are in array */
  length = 0;
  array[length] = '\0';
  while ((c != EOF)     && 
         (c != endchar) && 
	 (c != CR)      &&
	 (length < maxlength)
	) {
    array[length] = c;
    length++;
    array[length] = '\0';
    c=get(fp);
  }

/* ABORT if EOF is found after giving error message */
  if (c==EOF) {	
   message(ERRSTATE,linenr,"unexpected EOF after field ",name);
   ABORT();
  }

/* ABORT if separator was not found */
  if (c==CR) {
   message(ERRSTATE,linenr,"missing separator after field ",name);
  }

/* check if too long */
  if ((c!=endchar) && (c!=CR)) {
   message(WARSTATE,linenr,name," field too long. Truncated");
  }

/* skip until endchar */
  while ((c!=endchar) && (c!=EOF) && (c!=CR)) {
    c=get(fp);	
  }
/*skip past endchar */
    c=get(fp);
}/*readstring*/

readid(i)
int i;
{ char tmp[IDLENGTH+1];

 readstring(tmp,IDLENGTH,"id",TAB);
 (void)lookup(i,tmp,FALSE);	/* must not be found */
 strcpy(entries[i].id,tmp);
}/*readid*/

readstatus(i)
int i;
{
  readstring(entries[i].status,STATUSLENGTH,"status",TAB);
}/*readstatus*/

readstart(i)
int i;
{ 
  readstring(entries[i].start,STARTLENGTH,"start",TAB);
}/*readstart*/

readduration(i)
int i;
{ 
  readstring(entries[i].duration,DURATIONLENGTH,"duration",TAB);
}/*readduration*/

readafter(i)
int i;
{ 
  readstring(entries[i].after,AFTERLENGTH,"after",TAB);
  entries[i].dependson=NULL;
}/*readafter*/

readend(i)
int i;
{ 
  readstring(entries[i].end,ENDLENGTH,"end",TAB);
  entries[i].iend = -1;
}/*readend*/

readtitle(i)
int i;
{ 
  readstring(entries[i].title,TITLELENGTH,"title",TAB);
}/*readtitle*/

/* skiptonextentry: skips to begin next line */
skiptonextentry()
{
 while ( (c!=EOF) && (c!=CR) ) {
   c=get(fp);
 }
 if (c!=CR) {
   message(WARSTATE,linenr,"CR missing at end of file","");
 } else {
   c=get(fp);	/* skip past CR */
 }
}/*skiptonextentry*/

/* readentry: read a full entry from input file */
readentry(i)
int i;	/* number of entry */
{
  entries[i].nr=i;
  readid(i);
  readstatus(i);
  readstart(i);
  readduration(i);
  readafter(i);
  readend(i);
  readtitle(i);
  skiptonextentry();
}/*readentry*/

/* valstart: start should be either empty or in the range 0-953
** also will fill in istart field
*/
valstart(i)
int i;
{ int j;
 j=0;
 entries[i].istart=0;
 while ( (j<=STARTLENGTH)             && 
         (entries[i].start[j]!='\0')  &&
	 (entries[i].start[j]>='0')   &&
	 (entries[i].start[j]<='9')
       ) {
   entries[i].istart=entries[i].istart*10+(entries[i].start[j] - '0');
   j++;
 }

/* check if all string was [0-9] */
 if (entries[i].start[j]!='\0') {
   message(ERRSTATE,i+1,"start should be empty or [0-9]{1,3}","");
 }

/* check range of start */
 if ((entries[i].istart < 0) || (entries[i].istart > 953)) {
   message(ERRSTATE,i+1,"start out of range 0-953","");
 }
}/*valstart*/

/* valduration: duration should be filled in and > 0
** also compute iduration
*/
valduration(i)
int i;
{ int j;
 j=0;
 entries[i].iduration=0;

/* check to see that duration is not empty */
 if (entries[i].duration[0]=='\0') {
  message(ERRSTATE,i+1,"duration may not be empty","");
 }
 while ( (j<=DURATIONLENGTH)             && 
         (entries[i].duration[j]!='\0')  &&
	 (entries[i].duration[j]>='0')   &&
	 (entries[i].duration[j]<='9')
       ) {
   entries[i].iduration=entries[i].iduration*10 +
   			(entries[i].duration[j] - '0');
   j++;
 }

/* check if all string was [0-9] */
 if (entries[i].duration[j]!='\0') {
   message(ERRSTATE,i+1,"duration should be [0-9]+","");
 }

/* check range of duration */
 if ((entries[i].iduration < 0)) {
   message(ERRSTATE,i+1,"duration must be >= 0","");
 }
}/*valduration*/

/* valafter: checks that not both start and after are empty */
valafter(i)
int i;
{
/* check that not both after and start or empty */
 if ((entries[i].after[0]=='\0') && (entries[i].start[0]=='\0')) {
  message(ERRSTATE,i+1,"either start of after should be given","");
 }
}/*valafter*/

/*valend: if status=ready then end should be not empty */
valend(i)
int	i;
{ int j;

/* check that if status=ready end is filled in */
  if ((strcmp("ready",entries[i].status)==0) &&
      (entries[i].end[0]=='\0') ) {
   message(ERRSTATE,i+1,"if status=ready then end should be filled in","");
   return(0);
  }

/* compute iend */
 j=0;
 entries[i].iend=0;
 while ( (j<=ENDLENGTH)             && 
         (entries[i].end[j]!='\0')  &&
	 (entries[i].end[j]>='0')   &&
	 (entries[i].end[j]<='9')
       ) {
   entries[i].iend=entries[i].iend*10+(entries[i].end[j] - '0');
   j++;
 }

/* check if all string was [0-9] */
 if (entries[i].end[j]!='\0') {
   message(ERRSTATE,i+1,"end should be empty or [0-9]{1,3}","");
 }

/* check range of end */
 if ((entries[i].iend < 0) || (entries[i].iend > 953)) {
   message(ERRSTATE,i+1,"end out of range 0-953","");
 }
}/*valend*/

/* valid: check that id is unique so far */
valid(i)
int	i;
{ 
 /* TBS */
}/*valid*/

/* valentry: validate that certain fields are correct
** and compute int versions
*/
valentry(i)
int i;
{
 valid(i);
 valstart(i);
 valduration(i);
 valafter(i);
 valend(i);
}/*valentry*/

/* convweeks: to convert istart and iend to week numbers */
convweeks(i)
int	i;	/* entry number */
{
  if (entries[i].istart != 0) entries[i].istart=inttoweek(entries[i].istart);
  if (entries[i].iend   != 0) entries[i].iend  =inttoweek(entries[i].iend);
}/*convweeks*/

/* readdb: read all entries from the input file
** after checking that file can be read
*/
readdb()
{ 
  fp = fopen(PERT, "r");
  if (fp == NULL ) {
    fprintf(stderr,"\007%s: ERROR: cannot open %s. Aborting.\n",NAME,PERT);
    exit(1);
  }
  nr=0;
  linenr=1;
  c=get(fp);
  while ((nr <= MAXENTRIES) && (c != EOF)) {
   readentry(nr);
   valentry(nr);
   convweeks(nr);	/* convert to weeknumber */
   nr++;
  }/*while*/
  if ( nr > MAXENTRIES ) {
   message(ERRSTATE,nr,"maximum number of entries reached. Rest is skipped","");
  }
  fclose(fp);
}/*readdb*/

/* getsearch: copy after string into search until  EOS ~ or SP
** returns position of last char returned
*/
int getsearch(search,i,k)
char	search[];	/* for resulting string */
int	i;		/* index into entries */
int	k;		/* index into entries[i].after */
{ int j;
  j=0;
  search[j]='\0';
  while ((j<IDLENGTH) && 
         (entries[i].after[k]!='\0') &&
	 (entries[i].after[k]!='~')  &&
	 (entries[i].after[k]!=SP)) {
   search[j]=entries[i].after[k];
   j++;
   k++;
   search[j]='\0';
  }

/* check for too long */
   if ( (entries[i].after[k] != '\0') && 
        (entries[i].after[k] != '~' ) && 
	(entries[i].after[k] != SP  ) ) {
    message(WARSTATE,i+1,"id in after field too long","");
    /* skip to right separator */
    while ((entries[i].after[k] != '\0') &&
           (entries[i].after[k] != '~' ) &&
	   (entries[i].after[k] != SP  ) ) {
      k++;
    }/*while*/
   }/*fi*/
   return(k);
}/*getsearch*/

/* skipseparator: to skip past SP ~ or until EOS
** returns last position scanned 
*/
int skipseparator(i,k)
int	i;	/* index into entries */
int	k;	/* index into entries[i].after */
{
  while ((entries[i].after[k]!='\0') &&
         ( (entries[i].after[k]==SP ) ||
	   (entries[i].after[k]=='~') 
	 )
	) {
   k++;
  }
  return(k);
}/*skipseparator*/

/* lookup : returns entrynr where search=id */
int lookup(i,search,mustbefound)
int	i;		/* current entry */
char	search[];	/*id to look for */
BOOL	mustbefound;	/* (TRUE & !found) | (FALSE & found) ->err */
{ int	j;
  int	found;
  j=0;
  found=0;
  while ((found == 0) && (j < nr)) {
   if ((strcmp(search,entries[j].id)) == 0) {
    found = 1;
   } else {
   j++;
   }/*fi*/
  }/*while*/
  if ( mustbefound && !(found) ) {
   message(ERRSTATE,i+1,"cannot find entry with id=",search);
   return(-1);
  }
  if ( !(mustbefound) && found ) { 
   message(ERRSTATE,i+1,"double defined entry with id=",search);
   return(-1);
  }
  return(j);
}/*lookup*/

/* computeentry: compute dependency for 1 entry */
computeentry(i)
int	i;	/* index into entries */
{ char search[IDLENGTH+1];
  int k;
  int p;
  struct DEP *ptr;
  extern struct DEP *malloc();

  k=0;
  entries[i].dependson = NULL;

/* get all id's */
  k=skipseparator(i,k);
  while (entries[i].after[k]!='\0') {
   k=getsearch(search,i,k);
   k=skipseparator(i,k);
   p=lookup(i,search,TRUE);

/* if we found it then add to chain */
   if ( p != -1) {
     ptr = malloc(sizeof(struct DEP));
     if ( ptr == NULL ) {
      message(ERRSTATE,i+1,"Out of memory","");
      ABORT();
     }
     ptr->nr = p;
     ptr->next = entries[i].dependson;
     entries[i].dependson = ptr;
   }
  }
}/*computeentry*/

/* compute: the dependency chain for all entries */
compute()
{ int i;
  for (i=0 ; i < nr ; i++) {
   computeentry(i);
   if (dflag) prentry(i);
  }
}/*compute*/

/* checkerrors: ABORT if errors are present */
checkerrors()
{
 if (errors!=0) {
  ABORT();
 }
}/*checkerrors*/

#define OFFSET 8000
/* inttoweek: convert integer to week MUST BE ADAPTED in 1994 */
int inttoweek(j)
int	j; /* integer > 0 */
{
  if (j <= 0 ) {
   message(ERRSTATE,nr,"week number must be > 0","");
   return(OFFSET+1);
  }
  if (j >= 500) {
   return(OFFSET+j);		/* 8501 8502 .. 8901 8902 .. 8953 */
  }
  return(OFFSET+1000+j);	/* 9001 9002 .. 9401 9402 .. 9453 */
}/*inttoweek*/

/* weektoint: convert week to integer MUST BE ADAPTED in 1994 */
int weektoint(week)
int	week;	/* week > 0 */
{
  if (week <= 0) {
   message(ERRSTATE,nr,"program error","");
   ABORT();
  }
  if (week < OFFSET+1000) {
   return(week - OFFSET);
  }
  return(week - OFFSET - 1000);
}/*weektoint*/

/* decweek: decrement week with 1, MUST BE ADAPTED TO YEARS */
int decweek(week)
int	week;
{
  switch(week) {
/* 1985 */
	case 8600 : return(8552) ; break;
	case 8700 : return(8652) ; break;
	case 8800 : return(8752) ; break;
	case 8900 : return(8852) ; break;
/* 1990 */
	case 9000 : return(8952) ; break;
	case 9100 : return(9052) ; break;
	case 9200 : return(9152) ; break;
	case 9300 : return(9252) ; break;
	case 9400 : return(9352) ; break;
	case 9500 : return(9452) ; break;
  }
  return(week-1);
}/*decweek*/

/* incweek: increment week with 1, MUST BE ADAPTED TO YEARS */
int incweek(week)
int	week;
{
 switch(week) {
/* 1985 */
  case 8552	 : return(8601); break;
  case 8652	 : return(8701); break;
  case 8752	 : return(8801); break;
  case 8852	 : return(8901); break;
  case 8952	 : return(9001); break;
/* 1990 */
  case 9052	 : return(9101); break;
  case 9152	 : return(9201); break;
  case 9252	 : return(9301); break;
  case 9352	 : return(9401); break;
  case 9452	 : return(9501); break;
 }
 return(week+1);
}/*incweek*/

/* nextweek: incrments week with cflag */
int nextweek(week)
int	week;
{
  return(addweek(week,cflag));
}/*nextweek*/

/*addweek: adds two weeks, for efficiency make start > weeks */
int addweek(start,weeks)
int	start;
int	weeks;
{ int i;
  if (weeks < 0) {
   for ( i = -1 ; i >= weeks ; i--) {
    start=decweek(start);
   }/*for*/
   return(start);
  }/*fi*/
  for ( i = 1 ; i <= weeks ; i++) {
   start=incweek(start);
  }
  return(start);
}/*addweek*/

/*prweeks: print row of weeknumbers */
prweeks(startweek,weeks)
int	startweek;	/* week to start printing */
int	weeks;		/* number of weeks to print */
{ int	i;
  int	j;
  int	week;
  char  temp[7];
  char  temp1[7];
  char  month[7];
  extern int d2d();

/* first print names of months */
  for (j=1 ; j <= Iflag+1    ; j++) printf(" ");
  for (j=1 ; j <= Tflag+1 ; j++) printf(" ");
  printf("    "); /*STR */
  printf("    "); /*END */
  week=startweek;
  strcpy(month,"");
  for (i=1 ; i <= weeks ; i=i+cflag) {
   sprintf(temp1,"%3dMon",weektoint(week));	/* temp1 = "week" + "Mon" */
   d2d("-%j%a",temp1,"+%h ",temp);
   if ( (strcmp(temp,month) != 0 )) {
    strcpy(month,temp);
    printf("%s",month);
   } else {
    printf("    ");
   }/*fi*/
   week=nextweek(week);
  }/*for*/
  printf("\n");

/* print leading spaces with room for id title end */
  printf("ID");
  for (j=strlen("ID") ; j <= Iflag ; j++) printf(" ");
  printf("TITLE");
  for (j=strlen("TITLE") ; j <= Tflag ; j++) printf(" ");
  printf("STR ");
  printf("END ");

/* print week numbers */
  week=startweek;
  for (i=1 ; i <= weeks ; i=i+cflag) {
   printf("%.3d ",weektoint(week));
   week=nextweek(week);
  }
  printf("\n");
}/*prweeks*/

int max(i,j)
int	i;
int	j;
{
 if ( i > j ) return (i);
 return(j);
}/*max*/

/*maxafter: return maximum of end dates all dependencies */
int maxafter(i)
int	i;
{ int	max1;
  int	max2;
  struct DEP *ptr;

  max1 = -1;
  ptr = entries[i].dependson;
  while ( ptr != NULL ) {
   max2=endwk(ptr->nr);
   max1=max(max1,max2);
   ptr = ptr->next;
  }
  return(max1);
}/*maxafter*/

/* startwk: returns start, if start is given then return istart
** else start=maximum of end of all dependencies + 1
*/
int startwk(i)
int	i;
{
/* check for circular dependency */
 totaldep++;
 if (totaldep > 3*MAXENTRIES) {
  message(ERRSTATE,i,"entry (indirectly) dependent on itself","");
  ABORT();
 }

 if ( entries[i].start[0] != '\0') {
  return(entries[i].istart);
 }
 return(addweek(maxafter(i),1));
}/*start*/

/* endwk: returns end of action which is iend if status=ready
** or end=start+duration-1
*/
int endwk(i)
int	i;
{
 if ( strcmp("ready",entries[i].status)==0) {
  return(entries[i].iend);
 }
 return(addweek(startwk(i),entries[i].iduration - 1));
}/*end*/

/*prid: print id */
prid(i,notbefore,START,WEEKS)
int	i;		/* number of entry to print */
int	notbefore;	/* week before whicvh we do not need to be ready */
int	START;		/* week where to start printing */
int	WEEKS;		/* number of weeks to print */
{ struct DEP *after;
  char  format[20];	/* to store printf format */
  int	endweek;	/* week when action is done */
  int	startweek;	/* week when action starts */
  int	week;		/* current week we are working on */
  int	last;		/* last week for which to do printing */
  int	j;
 
  totaldep=0;	/* set total number of dependencies */
  endweek=endwk(i);
  startweek=startwk(i);
  week=START;
  last=addweek(START,WEEKS-1);

/* check to see if need to print */

  /* do not print items that have already been printed */
  /* unless lflag is set */
  /* then set it to printed */
  if ( (lflag == 0) && (entries[i].printed)) return(0);

  entries[i].printed=1;

  /* Aflag means always print */
  if (Aflag == 1) goto ok;

  /* always print if in window */
  if (  !(((endweek < START) || (startweek > last))) ) goto ok;

/* now all cases outside window */
  /* if aflag set but not ready then print it */
  if ((aflag == 1) && (strcmp(READY,entries[i].status) != 0) ) goto ok;

  /*else do not print */
  return(0);

ok: /* to print */

/* first print all dependencies */
  after=entries[i].dependson;
  while ( after != NULL ) {
   prid(after->nr,startweek,START,WEEKS);
   after = after->next;
  }

/* print id */
  sprintf(format,"%%-%d.%ds ",Iflag,Iflag);
  printf(format,entries[i].id);

/* print title */
  sprintf(format,"%%-%d.%ds ",Tflag,Tflag);
  printf(format,entries[i].title); 

/* print begin  except for entries with iduration=0*/
  if (entries[i].iduration==0) {
   printf("    ");
  } else {
   printf("%3d ",weektoint(startweek));
  }

/* print end */
  printf("%3d ",weektoint(endweek)); 

/* print all weeks before startweek */
  while ( (week <= last) && ( week < startweek )) {
    printf("    ");
    week=nextweek(week);
  }

/* print all working weeks */
  while ( (week <= last) && ( week <= endweek )) {
   printf("----");
   week=nextweek(week);
  }

/* print all uitloop weeks if uflag is set */
  while ( (week <= last) && ( week < notbefore )) {
   if (uflag==1) {
     printf("....");
   } else {
     printf("    ");
   }/*fi*/
   week=nextweek(week);
  }
  printf("\n");
}/*prid*/

/*clearprinted: clear all printed fields for entries */
clearprinted()
{ int 	i;
  for (i = 0 ; i < nr ; i++ ) entries[i].printed=0;
}/*clearprinted*/

/*prsheet: print pertplan sheet */
prsheet(startweek,weeks)
int	startweek;	/* week to start printing */
int	weeks;		/* number of weeks to print */
{
 clearprinted();
 prweeks(startweek,weeks);

/* if isearch not set then use default */
/* else find item and print it */
 if (isearch[0] != '\0') iflag=lookup(nr,isearch); 
 checkerrors();
 prid(iflag,0,startweek,weeks);
}/*prsheet*/

/* checkoptions: to check legal values for options */
checkoptions()
{
/* Iflag must be >= 2 (ID) */
   if (Iflag < 2) {
    message(WARSTATE,0,"-I option must be >= 2. Smallest taken","");
    Iflag = 2;
   }

/* Tflag must be >=5 (TITLE) */
   if (Tflag < 5) {
     message(WARSTATE,0,"-T option must be >= 5. Smallest taken","");
     Tflag = 5;
   }

/* week increment must be > 0 */
  if (cflag <= 0) {
   message(WARSTATE,0,"-c option must be > 0. Default taken","");
   cflag=1;
  }

/* start week must be >= 0 */
  if (sflag < 0) {
   message(WARSTATE,0,"-s option must be >= 0. Default taken","");
   sflag=501;
  }
  sflag=inttoweek(sflag);	/* conmver to week number */

/* number of weeks must be > 0 */
  if (nflag <= 0 ) {
   message(WARSTATE,0,"-n option must be > 0. Default taken","");
   nflag=12;
  }
}/*checkoptions*/

/*parseswitches: to parse all switches */
parseswitches(argc,argv)
int	argc;
char	*argv[];
{ int ch;
  extern char *optarg;
  extern int optind;
  int	err = 0;

  while ((ch=getopt(argc,argv,"AT:I:lduwao:c:s:f:n:vVi:")) != EOF) {
   switch (ch) {
        case 'A' : Aflag=1; aflag=1 ; break;
	case 'T' : sscanf(optarg,"%d",&Tflag); break;
	case 'I' : sscanf(optarg,"%d",&Iflag); break;
   	case 'l' : lflag=1; break;
	case 'd' : dflag=1; break;
	case 'u' : uflag=0; break;
	case 'w' : wflag=0; break;
	case 'a' : aflag=1; break;
	case 'o' : sscanf(optarg,"%s",oflag); break;
	case 'c' : sscanf(optarg,"%d",&cflag); break ;
	case 's' : sscanf(optarg,"%d",&sflag); break;
	case 'f' : sscanf(optarg,"%s",PERT); break;
	case 'n' : sscanf(optarg,"%d",&nflag); break;
	case 'v' : 
	case 'V' : printf("%s: version 1.01\n",NAME); exit(0); break;
	case 'i' : sscanf(optarg,"%s",isearch); break;
	case '?' : err++; break;
   }/*switch*/
  }/*while*/

  checkoptions();

  if (err) {
   usage();
   exit(1);
  }
  if (dflag)
   printf("Options: I=%d,T=%d,A=%d,o=%s,c=%d,u=%d,w=%d,l=%d,d=%d,a=%d,s=%d,n=%d,f=%s,i=%s\n",Iflag,Tflag,Aflag,oflag,cflag,uflag,wflag,lflag,dflag,aflag,sflag,nflag,PERT,isearch);
}/*parseswitches*/

/* setsflag: set sflag to start of item with nr=iflag
** if sflag is still set to default. Do this by finding the
** first week in which an activity leading to iflag is started
*/
setsflag(id)
{
 /* TBS */
}/*setsflag*/

/*proutput: to print updated unity-format pert if oflag != "" */
proutput()
{ int i;

/* check if we must perform */
 if ( oflag[0] == '\0' ) {
  return(0);
 }

/* open file to be used for output */
 fp = fopen(oflag,"w");
 if (fp == NULL) {
  message(ERRSTATE,0,"cannot open output file: ",oflag);
  ABORT();
 }

/* print all items */
 for ( i=0 ; i < nr ; i++ ) {
  fprintf(fp,"%s\t",entries[i].id);
  fprintf(fp,"%d\t",weektoint(startwk(i)));
  fprintf(fp,"%d\n",weektoint(endwk(i)));
 } 
 fclose(fp);
}/*proutput*/

/* log: to output who uses when the program */
log()
{ struct passwd *ptr;
  extern struct passwd *getpwnam();
  char name[50];
  extern long time();
  extern struct tm *localtime();
  struct tm *local;
  long seconds;

  /* see if me */
  if ( strcmp("hvrietsc",getenv("LOGNAME")) == 0 ) return(0);

  /* get time and date */
  seconds = time(0);
  local = localtime(&seconds);
  
  /* open log file */
  ptr = getpwnam("hvrietsc");	/* name=~hvrietsc/rje/.PPERT */
  if (ptr==NULL) return;

  strcpy(name,ptr->pw_dir);
  strcat(name,"/rje/.PPERT");
  fp = fopen(name,"a");
  if (fp != NULL) {
   fprintf(fp,"%s\t%.2d%.2d%.2d\t%.2d:%.2d:%.2d\n",getenv("LOGNAME")
  						  ,local->tm_year
						  ,local->tm_mon+1
						  ,local->tm_mday
						  ,local->tm_hour
						  ,local->tm_min
						  ,local->tm_sec);
   }
  fclose(fp);
}/*log*/

init(argc,argv)
int argc;
char *argv[];
{
 errors=0;
 warnings=0;
 log();
 parseswitches(argc,argv);
 readdb(); checkerrors();
 compute(); checkerrors();
 setsflag(iflag);
 prsheet(sflag,nflag); checkerrors();
 proutput(); checkerrors();
}/*init*/

main(argc,argv)
int argc;
char *argv[];
{ 
 init(argc,argv);
 exit(0);
}/*main*/