[comp.sources.misc] v05i011: cronsort - chronologically sort the crontab file

gordon@prls.UUCP (Gordon Vickers) (10/28/88)

Posting-number: Volume 5, Issue 11
Submitted-by: "Gordon Vickers" <gordon@prls.UUCP>
Archive-name: cronsort

#! /bin/sh
#
#   Program Name: Cronsort - Sorts crontab file chronologically
#   Syntex: cronsort [-[mw]]
#   Written in 'C' , should be highly portable (though I'm no expert).
#   Developed on : VAX 11/750 under Ultrix 2.0-1
#   Source Size:  Just 5,217 bytes when un-shar'ed
#   Article size: Less than 8K bytes
#
#   Submitted by: Gordon Vickers ;  {mips|pyramid|philabs}!prls!gordon
#
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	cronsort.c
# This archive created: Wed Oct 19 13:27:15 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(994 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^	X//' << \SHAR_EOF > 'README'
	X
	XProgram Name: Cronsort - Sorts crontab entries chronologically
	XSyntex: cronsort [-[mw]]
	XWritten in 'C' , should be highly portable (though I'm no expert).
	XDeveloped on : VAX 11/750 under Ultrix
	XSource Size:  Just 5,217 bytes when un-shar'ed
	X
	X     Each crontab entry is sorted on four of the five time fields.
	X     These fields are (in order of precedents) month of year,
	X  day of month (default, else day of week), hour, minute.
	X
	X    The command line option -w will cause a sort by day of week rather than
	X  by day of month. In any event, the other three fields are also sorted on.
	X  The -m option is for those who have difficulty remembering that a sort
	X  on day of month is the default.
	X
	X    The output of this program is a cronological list of all crontab entries
	X  and these entries are printed to stdout.
	X
	X    There is no manual page. Sorry, but I think the program's simplistic
	X  use doesn't warrent the time required to fight with nroff again.
	X
	X    Flames, thanks, and suggestions to :
SHAR_EOF
if test 994 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 994 characters)'
fi
fi
echo shar: "extracting 'cronsort.c'" '(5217 characters)'
if test -f 'cronsort.c'
then
	echo shar: "will not over-write existing file 'cronsort.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'cronsort.c'
	X/*
	X * cronsort - chronilogically sort the crontab file by
	X *            record, and by fields within each record
	X*/
	X#include <stdio.h>
	X
	X#ifdef DEBUG
	X#define CRONTAB "crontab" 
	X#else
	X#define CRONTAB "/usr/lib/crontab" 
	X#endif
	X
	X#define FS      50       /* Maximum field size for each crontab field */
	X
	X#define RECSIZ  BUFSIZ   /* RECSIZ must be at least as long as longest 
	X                            CRONTAB entry. BUFSIZ if from <stdio.h> */
	Xstruct entry {
	X               int     num;            /* encoded value of time   */
	X               char    record[BUFSIZ]; /* a crontab entry         */
	X               struct entry *next;     /* next entry in chain     */
	X             } ;
	X
	Xstruct eplist {
	X                int      num;         /* encoded accumlitive time values */
	X                struct entry *pentry; /* points to struct that num came from */
	X              } *eplist;
	Xint entries = 0;   /* will need to know how many struct entries there are */
	X
	Xmain(argc,argv)
	X  int    argc;
	X  char **argv;
	X{
	X   void Sortmoy(), Swaps();
	X   int i,error = 0, wflag = 0;
	X   char c;
	X   char dow[FS],moy[FS],dom[FS],hr[FS],min[FS];
	X   char record[RECSIZ], progname[BUFSIZ];
	X   struct entry *entry, *top;
	X   struct eplist *teplist;
	X   FILE *fd;
	X
	X   strcat(progname,*argv);
	X   for(++argv; *argv!=NULL; argv++){
	X      if(!strcmp(*argv,"-w"))
	X        wflag = 1;
	X      else if (!strcmp(*argv,"-m"))
	X        wflag = 0;
	X      else
	X        error = 1;
	X  }
	X
	X   if(error) {
	X     fprintf(stderr,"Syntex: %s [ -[wm] ] \n",progname);
	X     fprintf(stderr,"  where  -w  will sort by day of week\n");
	X     fprintf(stderr,"         -m  will sort by day of month (default)\n");
	X     exit(0);
	X   }
	X
	X   if( (fd = fopen(CRONTAB,"r")) == NULL) {
	X      perror(*argv);
	X      exit(0);
	X   }
	X
	X   top = (struct entry *)NULL; /* intialize pointer to NULL, keep lint happy */
	X   while( (fgets(record,RECSIZ,fd)) != NULL) { /* read the records */
	X     sscanf(record,"%c %*s",&c);
	X     if( !Isdigit(c) && c != '*')
	X       continue;  /* crontab record format error or just a comment */
	X
	X     if(top == NULL) {
	X         entry = (struct entry *)malloc(sizeof(struct entry));
	X         top = entry; /* top; i.e. top of list. Value should never be changed */
	X     }
	X     else { /* add another structure to hold the record and stuf */
	X         entry->next = (struct entry *)malloc(sizeof(struct entry));
	X         entry = entry->next;
	X         entry->next = NULL;
	X     }
	X     entries++;
	X
	X     /* store it for printing later */
	X     strcat(entry->record,record); /* source of later output */
	X
	X     /* break it up into manageable pieces */
	X     sscanf(record,"%s%s%s%s%s%*s",min,hr,dom,moy,dow);
	X
	X     /* store the pieces so we can sort them later */
	X     entry->num = (Parse(moy) * 100000) +
	X                  ( (wflag ? Parse(dow) : Parse(dom)) * 10000) +
	X                  (Parse(hr) * 100 ) + Parse(min) ;
	X   }
	X
	X   /* create an array of struct pointers and integers so we will only
	X   *  need a single sort routine */
	X   eplist = (struct eplist *)malloc(sizeof(struct eplist) * entries );
	X
	X   /* load eplist with addresses for each struct entry */
	X   for(teplist=eplist,entry = top;  ; teplist++,entry=entry->next) {
	X      teplist->num = entry->num;
	X      teplist->pentry = entry;
	X      if(entry->next == NULL)
	X         break;
	X   }
	X   Sortint(eplist);
	X   
	X   /**** Print the resulting sort  ****/
	X   for(i=0,teplist=eplist; i < entries ; i++, teplist++) {
	X     entry = teplist->pentry;
	X     printf("%s",entry->record); /* Don't need newline, it's in record */
	X   }
	X}
	X
	X/****** Isdigit() ********/
	XIsdigit(c)
	X  char c;
	X{
	X   return( c>='0' && c<='9' ? c : NULL);
	X}
	X
	X/******* Parse() *******/
	XParse(field)
	X  char *field;
	X{
	X   int num, Num = 99;  /* Num set to some out-of-range value */
	X   char *p;
	X
	X   p = field;
	X
	X   /* align pointer to first digit */
	X   if(*p == '*')   /* wild card, takes precedent over explicit values */
	X     return(0);
	X
	X
	X  while(*p) {        /* scan the field til NULL, find lowest value within */
	X   if(Isdigit(*p)) {
	X      num = (int)( (*p) - '0');
	X      p++;
	X      if(Isdigit(*p)) {
	X         num = (num *10) + (int)( (*p) - '0');
	X      }
	X   }
	X   p++;
	X   Num = num < Num ? num : Num;
	X  }
	X  return(Num + 1); /* since an asteric is evaluated as zero (above) */
	X}
	X
	X/******* Sortint() ********
	X sort numeric data, swapping order also requires swapping the pointer
	X to the struct entry that contains a copy of the data.
	X*/
	XSortint(list)
	X  struct eplist *list;
	X{
	X  register struct eplist *top, *chain;
	X  register int ol, il ; /* Outter Loop, Inner Loop */
	X  register struct entry *tmp;
	X  int tmpnum, swapped = 0;
	X
	X  chain = list;
	X  for(ol=entries; ol > 0 ;ol--) {
	X     if( chain->pentry == NULL )
	X        break;
	X     for(il=0,chain = list; il < ol; il++,chain++) {
	X       if( (chain + 1)->pentry == NULL )
	X          break;
	X       if(chain->num > (chain + 1)->num) {
	X          /* do a swap */
	X          tmp = chain->pentry;
	X          tmpnum = chain->num;
	X
	X          chain->pentry = (chain + 1)->pentry;
	X          chain->num = (chain + 1)->num;
	X
	X          (chain + 1)->pentry = tmp;
	X          (chain + 1)->num = tmpnum;
	X          swapped = 1;
	X       }
	X     }
	X   if(!swapped) /* A pass with no swapping means we've finnished early */
	X     break;
	X  }
	X}
SHAR_EOF
if test 5217 -ne "`wc -c < 'cronsort.c'`"
then
	echo shar: "error transmitting 'cronsort.c'" '(should have been 5217 characters)'
fi
fi
exit 0
#	End of shell archive