[mod.sources] retouch

sources-request@panda.UUCP (05/19/86)

Mod.sources:  Volume 5, Issue 4
Submitted by: seismo!s3sun!gould9!joel (Joel West @ CACI)

retouch(1) is like touch(1), except it uses the sccs id instead
of the current time.

It also contains a nifty subroutine that can be used as the inverse of 
localtime(3) or gmtime(3), to convert a date to the UNIX time format.  
The algorithm is brute force, but deterministic, and involves no
UNIX proprietary source code.

	Joel West	 	(619) 457-9681
	CACI, Inc. Federal, 3344 N. Torrey Pines Ct., La Jolla, CA  92037
	{cbosgd, ihnp4, sdcsvax, ucla-cs} !gould9!joel
	joel%gould9.uucp@NOSC.ARPA

#!/bin/sh
# 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 the files:
#	README
#	Makefile
#	retouch.c
# This archive created: Tue May 13 21:52:48 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(1001 characters)'
if test -f 'README'
then
	echo shar: over-writing existing file "'README'"
fi
sed 's/^X//' << \SHAR_EOF > 'README'
Xretouch is a command that can be used to "correct" last changed
Xdates, such as when by 'make' or 'ls -l -t'.  These dates
Xcan be inaccurate after a cp, or uucp, or kermit to create a new
Xcopy of an existing file, or to import it from another system.
X
Xretouch looks for an sccs string of the form
X	@(#) anything at all mm/dd/yy
X	@(#) anything at all yy/mm/dd
Xto get the date.  It is intended for use on source files, and
Xassumes there is no such string if it's not in the top 10 lines.
X
XIt has the following options:
X	-v	verbose
X	-g	assume the date is GMT rather than local time
X	-d date	set the last change date to "date".
X
XIt has defs for BSD and USG, although it's been tested only
Xunder BSD.  It was intended as a one-time hack, and may not
Xbe as clean as it should be, but it has proven versatile and
Xnecessary over the past 6 months.
X
XI'd appreciate any suggestions or changes.
X
X	Joel West	 CACI, Inc. Federal, La Jolla
X	{cbosgd, ihnp4, sdcsvax, ucla-cs} !gould9!joel
X	joel%gould9.uucp@NOSC.ARPA
SHAR_EOF
if test 1001 -ne "`wc -c 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 1001 characters)'
fi
echo shar: extracting "'Makefile'" '(50 characters)'
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
sed 's/^X//' << \SHAR_EOF > 'Makefile'
Xretouch: retouch.c
X	cc -DBSD -o retouch retouch.c
SHAR_EOF
if test 50 -ne "`wc -c 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 50 characters)'
fi
echo shar: extracting "'retouch.c'" '(6231 characters)'
if test -f 'retouch.c'
then
	echo shar: over-writing existing file "'retouch.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'retouch.c'
X/* @(#) retouch.c 1.0 10/25/85
X*/
X/* retouch.c: set update time to match SCCS id
X
X   Copyright (c) 1985, Joel West (ihnp4!gould9!joel)
X   License for non-commercial use freely granted as long
X   as this notice is retained.
X
X   The id should be of the form
X		@(#) xxxxxxx 10/23/85
X	or	@(#) xxxxxxx 85/10/23
X   it assumes date is the last non-blank thing on the line
X   and this program will only work between 1970 and 2000, inclusive
X
X   works best if only one id (ignores others) and if id is at the
X   top of the file.
X
X   Does not retouch if not found in first 10 lines; should be
X   an optionable parameter.  A line is a newline or a null,
X   so this just might work on a binary file.
X
X*/
X
X#include <sys/types.h>
Xtypedef struct {
X    time_t actime;
X    time_t modtime;
X} utimbuf;
X
X#include <sys/stat.h>
X#include <errno.h>
X#ifdef BSD
Xextern int errno;
X#endif
X
X#include <stdio.h>
X#define ungetchar(c) ungetc(c,stdin)
X
X#ifdef BSD
X# include <strings.h>
X# include <sys/time.h>
X#else
X# include <string.h>
X# include <time.h>
X#endif
X#ifdef USG
X# define index(s,c) strchr(s,c)
X#endif
X
X#ifndef TRUE
X# define TRUE (1)
X# define FALSE (0)
X#endif
X
X/* below are hour and minute at local time that should be
X   time-stamped; default 00:00:00.  No user control over seconds  */
X#define STDHR 00
X#define STDMIN 00
X
X#define SCCSKEY "@(#)"
X#define SCCSCHR '@'
X
X#define EOL '\n'
X#define EOS '\0'
X
Xint optg = 0, optd = 0, optv = 0;
Xlong stddate;
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{	int depthlim,line,i,sccslen,touched;
X	char *p,*filenam,buff[1024];
X	int c,errind;
X
X	depthlim = 10;
X	sccslen = strlen(SCCSKEY);
X	errind = 0;
X
X	for (i = 1; i<argc && errind == 0; i++)
X	{   if (*argv[i] != '-')
X		break;
X	    p = argv[i];
X	    while (*(++p))
X	    switch(*p)
X	    {	case 'g':
X		    optg++;
X		    break;
X		case 'v':
X		    optv++;
X		    break;
X		case 'd':
X		    if (optd)
X			errind++;
X		    else
X		    {   optd++;
X			stddate = dateatol(argv[++i]);
X			if (stddate < 0)
X			{   fprintf(stderr,"%s: invalid date format\n",argv[i]);
X			    exit (0);
X			}
X		    }
X		    break;
X		default:
X		    errind++;
X	    }
X	}
X
X	if (errind || i >= argc)
X	{   fprintf(stderr, 
X		    "usage: %s [-v ] [-g] [-d date] file1 [file2 ... ]\n", 
X		    argv[0]);
X	    exit (0);
X	}
X
X	for (; i<argc; i++)
X	{   filenam = argv[i];
X	    if (freopen(filenam, "r", stdin) == NULL)
X	    {	perror(filenam);
X		exit(errno);
X	    }
X	    touched = 0;
X	    if (optd)		/* one date for all */
X	    {	setupdtime(filenam, stddate);
X		touched++;
X		goto settouch;
X	    }
X	    
X	    for (line = 1; line <= depthlim; line++)
X	    {	while ( 1 )
X		{   c = getchar();
X		    if (c == EOF)
X			goto settouch;
X		    if (c == EOS || c == EOL)
X			break;
X		    if (c == SCCSCHR)
X		    {
X			ungetchar(c);
X			gets(buff);		/* won't work on binary */
X			if (strncmp(buff, SCCSKEY, sccslen) == 0)
X			{	p = buff+strlen(buff);	/* use last nonblank */
X			    while (*(--p) == ' ')	/* field in string */
X				;
X			    while (*p != ' ' && *p != '\t')
X				--p;
X			    if ( setupdtime(filenam, dateatol(++p)) )
X				touched++;
X			    goto settouch;
X			}
X		    }
X		} /* within line */
X	    } /* end of line */
Xsettouch:
X	    if (touched==0)
X		fprintf(stderr, "%s: not retouched\n", filenam);
X	    else
X		if (optv)
X		    fprintf(stderr, "%s: retouched\n", filenam);
X	} /* end of file */
X}
X
X/* Reset the file's update time to the specified date.  If the date is dubious,
X   don't reset it at all
X*/
Xint setupdtime(fname, mtime)
Xchar *fname;
Xlong mtime;
X{	utimbuf timep;
X	struct stat statbuf;
X
X	stat(fname, &statbuf);
X	timep.actime = statbuf.st_atime;	/* copy current accessed time */
X
X	if (mtime > 0)			/* valid date */
X	{   timep.modtime = mtime;
X	    utime(fname, &timep);
X	    return (TRUE);
X	}
X	return (FALSE);
X}
X
X#define NSECYR 31536000
X/* 365*24*60*60 */
X#define NSECDA 86400
X#define APPROXT(yr,mo,da) (((yr-70)*NSECYR) + ((mo*30)+da)*NSECDA)
X#define INVDATE (-1)
Xlong dateatol(string)
Xchar *string;
X{	char *p,*q;
X	int mdy[3],mo,da,yr,i,num;
X	struct tm *tmptr;
X	long timsec,approxsec,deltasec,lasttimsec,maxdelta,mindelta;
X	int deltasign;
X	static char *numstr = "0123456789";
X
X	p = string;
X	while (*p == ' ')			/* skip leading blanks */
X	    p++;
X	for (i = 0 ; i<3; i++)
X	{   num = 0;
X	    q = NULL;				/* watch for null field */
X	    while (*p != EOS && *p != '/' && *p != ' ')
X	    {	q = index(numstr,*p++);
X		if (q == NULL)			/* invalid digit */
X		    break;
X		num = num*10 +(q-numstr);
X	    }
X	    if (q)
X		mdy[i] = num;
X	    else
X		return (INVDATE);		/* invalid or null field */
X	    p++;	/* skip delimiter */
X	}
X	--p;
X	while (*p++ == ' ')
X	    ;
X	if (*--p != EOS)			/* not end of string */
X	    return (INVDATE);
X
X	if (mdy[0] > 11)
X	{   yr = mdy[0];		/* assume YY/MM/DD */
X	    mo = mdy[1] - 1;		/* months 0..11 not 1..12 */
X	    da = mdy[2];
X	}
X	else
X	{   mo = mdy[0] - 1;		/* assume MM/DD/YY */
X	    da = mdy[1];
X	    yr = mdy[2];
X	}
X	
X	if (yr > 1900)
X	    yr = yr - 1900;
X
X	approxsec = APPROXT(yr,mo,da);
X	timsec = approxsec;
X	lasttimsec = 0;
X	mindelta = NSECDA;
X	maxdelta = NSECYR;
X	while (1)
X	{    tmptr = (optg ? gmtime(&timsec) : localtime(&timsec)) ;
X/* decode absolute time into local or gmt */
X	     if (yr == tmptr->tm_year && 
X		 mo == tmptr->tm_mon &&
X		 da == tmptr->tm_mday)
X	     {
X/* the date is right, set the time to midnight local time; this 
Xmay behave strangely on daylight savings time changeover days */
X		if (STDHR == tmptr->tm_hour &&
X		    STDMIN == tmptr->tm_min &&
X		    0 == tmptr->tm_sec)
X		    break;			/* exactly right */
X		else
X		{   timsec -= (tmptr->tm_hour - STDHR) * 3600 + 
X			      (tmptr->tm_min - STDMIN) * 60 +
X			       tmptr->tm_sec;
X		    maxdelta = mindelta;
X		    mindelta = 1;
X		}
X	    }
X	    else
X	    {	deltasec = APPROXT(tmptr->tm_year,tmptr->tm_mon,tmptr->tm_mday)
X			   - approxsec;
X		deltasign = (deltasec < 0) ? -1 : 1;
X/* approximately the difference in the number of seconds between 
X   the guessed date and the actual date */
X		if (abs(deltasec) > abs(timsec-lasttimsec))
X		    deltasec = timsec-lasttimsec;
X		deltasec = abs(deltasec);
X		deltasec = (deltasec > maxdelta) ? deltasec / 2 :
X			((deltasec >= mindelta) ? (deltasec-1) : mindelta); 
X		lasttimsec = timsec;
X		timsec -= deltasec * deltasign;	/* binary convergence */
X	     }
X	}
X
X	return (timsec);
X}
SHAR_EOF
if test 6231 -ne "`wc -c 'retouch.c'`"
then
	echo shar: error transmitting "'retouch.c'" '(should have been 6231 characters)'
fi
#	End of shell archive
exit 0