[comp.sources.atari.st] v02i049: gnutar -- GNU's version of UNIX "tar" part03/08

koreth%panarthea.ebay@sun.com (Steven Grimm) (07/20/89)

Submitted-by: 7103_300@uwovax.uwo.ca (Eric R. Smith)
Posting-number: Volume 2, Issue 49
Archive-name: gnutar/part03

#!/bin/sh
# this is part 3 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file EXTRACT.C continued
#
CurArch=3
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file EXTRACT.C"
sed 's/^X//' << 'SHAR_EOF' >> EXTRACT.C
X		 * Some other error in the mkdir.  We return to the caller.
X		 */
X		break;
X	}
X
X	errno = save_errno;		/* Restore caller's errno */
X	return madeone;			/* Tell them to retry if we made one */
X}
SHAR_EOF
echo "File EXTRACT.C is complete"
chmod 0644 EXTRACT.C || echo "restore of EXTRACT.C fails"
echo "x - extracting GETDATE.Y (Text)"
sed 's/^X//' << 'SHAR_EOF' > GETDATE.Y &&
X%token ID MONTH DAY MERIDIAN NUMBER UNIT MUNIT SUNIT ZONE DAYZONE AGO
X%{
X	/* 	Originally from: Steven M. Bellovin (unc!smb)	*/ 
X	/*	Dept. of Computer Science			*/
X	/*	University of North Carolina at Chapel Hill	*/
X	/*	@(#)getdate.y	2.17	11/30/87			*/
X
X/* #include "defs.h" JF not used any more */
X#include <sys/types.h>
X#ifdef USG
Xstruct timeb
X{
X	time_t	time;
X	unsigned short millitm;
X	short	timezone;
X	short	dstflag;
X};
X#else
X#include <sys/timeb.h>
X#endif
X#include <ctype.h>
X
X#if defined(BSD4_2) || defined (BSD4_1C)
X#include <sys/time.h>
X#else /* sane */
X#include <time.h>
X#endif /* sane */
X
X#define	NULL	0
X#define daysec (24L*60L*60L)
X	static int timeflag, zoneflag, dateflag, dayflag, relflag;
X	static time_t relsec, relmonth;
X	static int hh, mm, ss, merid, day_light;
X	static int dayord, dayreq;
X	static int month, day, year;
X	static int ourzone;
X#define AM 1
X#define PM 2
X#define DAYLIGHT 1
X#define STANDARD 2
X#define MAYBE    3
X
Xstatic time_t timeconv();
Xstatic time_t daylcorr();
Xstatic lookup();
X
X%}
X
X%%
Xtimedate: 		/* empty */
X	| timedate item
X	;
X
Xitem:	tspec
X		{timeflag++;}
X	| zone
X		{zoneflag++;}
X	| dtspec
X		{dateflag++;}
X	| dyspec
X		{dayflag++;}
X	| rspec
X		{relflag++;}
X	| nspec;
X
Xnspec:	NUMBER
X		{if (timeflag && dateflag && !relflag) year = $1;
X		else {timeflag++;hh = $1/100;mm = $1%100;ss = 0;merid = 24;}};
X
Xtspec:	NUMBER MERIDIAN
X		{hh = $1; mm = 0; ss = 0; merid = $2;}
X	| NUMBER ':' NUMBER
X		{hh = $1; mm = $3; merid = 24;}
X	| NUMBER ':' NUMBER MERIDIAN
X		{hh = $1; mm = $3; merid = $4;}
X	| NUMBER ':' NUMBER NUMBER
X		{hh = $1; mm = $3; merid = 24;
X		day_light = STANDARD; ourzone = -($4%100 + 60*($4/100));}
X	| NUMBER ':' NUMBER ':' NUMBER
X		{hh = $1; mm = $3; ss = $5; merid = 24;}
X	| NUMBER ':' NUMBER ':' NUMBER MERIDIAN
X		{hh = $1; mm = $3; ss = $5; merid = $6;}
X	| NUMBER ':' NUMBER ':' NUMBER NUMBER
X		{hh = $1; mm = $3; ss = $5; merid = 24;
X		day_light = STANDARD; ourzone = -($6%100 + 60*($6/100));};
X
Xzone:	ZONE
X		{ourzone = $1; day_light = STANDARD;}
X	| DAYZONE
X		{ourzone = $1; day_light = DAYLIGHT;};
X
Xdyspec:	DAY
X		{dayord = 1; dayreq = $1;}
X	| DAY ','
X		{dayord = 1; dayreq = $1;}
X	| NUMBER DAY
X		{dayord = $1; dayreq = $2;};
X
Xdtspec:	NUMBER '/' NUMBER
X		{month = $1; day = $3;}
X	| NUMBER '/' NUMBER '/' NUMBER
X		{month = $1; day = $3; year = $5;}
X	| MONTH NUMBER
X		{month = $1; day = $2;}
X	| MONTH NUMBER ',' NUMBER
X		{month = $1; day = $2; year = $4;}
X	| NUMBER MONTH
X		{month = $2; day = $1;}
X	| NUMBER MONTH NUMBER
X		{month = $2; day = $1; year = $3;};
X
X
Xrspec:	NUMBER UNIT
X		{relsec +=  60L * $1 * $2;}
X	| NUMBER MUNIT
X		{relmonth += $1 * $2;}
X	| NUMBER SUNIT
X		{relsec += $1;}
X	| UNIT
X		{relsec +=  60L * $1;}
X	| MUNIT
X		{relmonth += $1;}
X	| SUNIT
X		{relsec++;}
X	| rspec AGO
X		{relsec = -relsec; relmonth = -relmonth;};
X%%
X
Xstatic int mdays[12] =
X	{31, 0, 31,  30, 31, 30,  31, 31, 30,  31, 30, 31};
X#define epoch 1970
X
Xextern struct tm *localtime();
X
Xstatic time_t
Xdateconv(mm, dd, yy, h, m, s, mer, zone, dayflag)
Xint mm, dd, yy, h, m, s, mer, zone, dayflag;
X{
X	time_t tod, jdate;
X	register int i;
X
X	if (yy < 0) yy = -yy;
X	if (yy < 100) yy += 1900;
X	mdays[1] = 28 + (yy%4 == 0 && (yy%100 != 0 || yy%400 == 0));
X	if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 ||
X		dd < 1 || dd > mdays[--mm]) return (-1);
X	jdate = dd-1;
X        for (i=0; i<mm; i++) jdate += mdays[i];
X	for (i = epoch; i < yy; i++) jdate += 365 + (i%4 == 0);
X	jdate *= daysec;
X	jdate += zone * 60L;
X	if ((tod = timeconv(h, m, s, mer)) < 0) return (-1);
X	jdate += tod;
X	if (dayflag==DAYLIGHT || (dayflag==MAYBE&&localtime(&jdate)->tm_isdst))
X		jdate += -1*60*60;
X	return (jdate);
X}
X
Xstatic time_t
Xdayconv(ord, day, now)
Xint ord, day; time_t now;
X{
X	register struct tm *loctime;
X	time_t tod;
X
X	tod = now;
X	loctime = localtime(&tod);
X	tod += daysec * ((day - loctime->tm_wday + 7) % 7);
X	tod += 7*daysec*(ord<=0?ord:ord-1);
X	return daylcorr(tod, now);
X}
X
Xstatic time_t
Xtimeconv(hh, mm, ss, mer)
Xregister int hh, mm, ss, mer;
X{
X	if (mm < 0 || mm > 59 || ss < 0 || ss > 59) return (-1);
X	switch (mer) {
X		case AM: if (hh < 1 || hh > 12) return(-1);
X			 return (60L * ((hh%12)*60L + mm)+ss);
X		case PM: if (hh < 1 || hh > 12) return(-1);
X			 return (60L * ((hh%12 +12)*60L + mm)+ss);
X		case 24: if (hh < 0 || hh > 23) return (-1);
X			 return (60L * (hh*60L + mm)+ss);
X		default: return (-1);
X	}
X}
X
Xstatic time_t
Xmonthadd(sdate, relmonth)
Xtime_t sdate, relmonth;
X{
X	struct tm *ltime;
X	time_t dateconv();
X	int mm, yy;
X
X	if (relmonth == 0) return 0;
X	ltime = localtime(&sdate);
X	mm = 12*ltime->tm_year + ltime->tm_mon + relmonth;
X	yy = mm/12;
X	mm = mm%12 + 1;
X	return daylcorr(dateconv(mm, ltime->tm_mday, yy, ltime->tm_hour,
X		ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE), sdate);
X}
X
Xstatic time_t
Xdaylcorr(future, now)
Xtime_t future, now;
X{
X	int fdayl, nowdayl;
X
X	nowdayl = (localtime(&now)->tm_hour+1) % 24;
X	fdayl = (localtime(&future)->tm_hour+1) % 24;
X	return (future-now) + 60L*60L*(nowdayl-fdayl);
X}
X
Xstatic char *lptr;
X
Xstatic yylex()
X{
X	extern int yylval;
X	int sign;
X	register char c;
X	register char *p;
X	char idbuf[20];
X	int pcnt;
X
X	for (;;) {
X		while (isspace(*lptr))
X			lptr++;
X
X		if (isdigit(c = *lptr) || c == '-' || c == '+') {
X			if (c== '-' || c == '+') {
X				if (c=='-') sign = -1;
X				else sign = 1;
X				if (!isdigit(*++lptr)) {
X					/* yylval = sign; return (NUMBER); */
X					return yylex();	/* skip the '-' sign */
X				}
X			} else sign = 1;
X			yylval = 0;
X			while (isdigit(c = *lptr++))
X				yylval = 10*yylval + c - '0';
X			yylval *= sign;
X			lptr--;
X			return (NUMBER);
X
X		} else if (isalpha(c)) {
X			p = idbuf;
X			while (isalpha(c = *lptr++) || c=='.')
X				if (p < &idbuf[sizeof(idbuf)-1]) *p++ = c;
X			*p = '\0';
X			lptr--;
X			return (lookup(idbuf));
X		}
X
X		else if (c == '(') {
X			pcnt = 0;
X			do {
X				c = *lptr++;
X				if (c == '\0') return(c);
X				else if (c == '(') pcnt++;
X				else if (c == ')') pcnt--;
X			} while (pcnt > 0);
X		}
X
X		else return (*lptr++);
X	}
X}
X
Xstruct table {
X	char *name;
X	int type, value;
X};
X
Xstatic struct table mdtab[] = {
X	{"january", MONTH, 1},
X	{"february", MONTH, 2},
X	{"march", MONTH, 3},
X	{"april", MONTH, 4},
X	{"may", MONTH, 5},
X	{"june", MONTH, 6},
X	{"july", MONTH, 7},
X	{"august", MONTH, 8},
X	{"september", MONTH, 9},
X	{"sept", MONTH, 9},
X	{"october", MONTH, 10},
X	{"november", MONTH, 11},
X	{"december", MONTH, 12},
X
X	{"sunday", DAY, 0},
X	{"monday", DAY, 1},
X	{"tuesday", DAY, 2},
X	{"tues", DAY, 2},
X	{"wednesday", DAY, 3},
X	{"wednes", DAY, 3},
X	{"thursday", DAY, 4},
X	{"thur", DAY, 4},
X	{"thurs", DAY, 4},
X	{"friday", DAY, 5},
X	{"saturday", DAY, 6},
X	{0, 0, 0}};
X
X#define HRS *60
X#define HALFHR 30
X
Xstatic struct table mztab[] = {
X	{"a.m.", MERIDIAN, AM},
X	{"am", MERIDIAN, AM},
X	{"p.m.", MERIDIAN, PM},
X	{"pm", MERIDIAN, PM},
X	{"nst", ZONE, 3 HRS + HALFHR},		/* Newfoundland */
X	{"n.s.t.", ZONE, 3 HRS + HALFHR},
X	{"ast", ZONE, 4 HRS},		/* Atlantic */
X	{"a.s.t.", ZONE, 4 HRS},
X	{"adt", DAYZONE, 4 HRS},
X	{"a.d.t.", DAYZONE, 4 HRS},
X	{"est", ZONE, 5 HRS},		/* Eastern */
X	{"e.s.t.", ZONE, 5 HRS},
X	{"edt", DAYZONE, 5 HRS},
X	{"e.d.t.", DAYZONE, 5 HRS},
X	{"cst", ZONE, 6 HRS},		/* Central */
X	{"c.s.t.", ZONE, 6 HRS},
X	{"cdt", DAYZONE, 6 HRS},
X	{"c.d.t.", DAYZONE, 6 HRS},
X	{"mst", ZONE, 7 HRS},		/* Mountain */
X	{"m.s.t.", ZONE, 7 HRS},
X	{"mdt", DAYZONE, 7 HRS},
X	{"m.d.t.", DAYZONE, 7 HRS},
X	{"pst", ZONE, 8 HRS},		/* Pacific */
X	{"p.s.t.", ZONE, 8 HRS},
X	{"pdt", DAYZONE, 8 HRS},
X	{"p.d.t.", DAYZONE, 8 HRS},
X	{"yst", ZONE, 9 HRS},		/* Yukon */
X	{"y.s.t.", ZONE, 9 HRS},
X	{"ydt", DAYZONE, 9 HRS},
X	{"y.d.t.", DAYZONE, 9 HRS},
X	{"hst", ZONE, 10 HRS},		/* Hawaii */
X	{"h.s.t.", ZONE, 10 HRS},
X	{"hdt", DAYZONE, 10 HRS},
X	{"h.d.t.", DAYZONE, 10 HRS},
X
X	{"gmt", ZONE, 0 HRS},
X	{"g.m.t.", ZONE, 0 HRS},
X	{"bst", DAYZONE, 0 HRS},		/* British Summer Time */
X	{"b.s.t.", DAYZONE, 0 HRS},
X	{"eet", ZONE, 0 HRS},		/* European Eastern Time */
X	{"e.e.t.", ZONE, 0 HRS},
X	{"eest", DAYZONE, 0 HRS},	/* European Eastern Summer Time */
X	{"e.e.s.t.", DAYZONE, 0 HRS},
X	{"met", ZONE, -1 HRS},		/* Middle European Time */
X	{"m.e.t.", ZONE, -1 HRS},
X	{"mest", DAYZONE, -1 HRS},	/* Middle European Summer Time */
X	{"m.e.s.t.", DAYZONE, -1 HRS},
X	{"wet", ZONE, -2 HRS },		/* Western European Time */
X	{"w.e.t.", ZONE, -2 HRS },
X	{"west", DAYZONE, -2 HRS},	/* Western European Summer Time */
X	{"w.e.s.t.", DAYZONE, -2 HRS},
X
X	{"jst", ZONE, -9 HRS},		/* Japan Standard Time */
X	{"j.s.t.", ZONE, -9 HRS},	/* Japan Standard Time */
X					/* No daylight savings time */
X
X	{"aest", ZONE, -10 HRS},	/* Australian Eastern Time */
X	{"a.e.s.t.", ZONE, -10 HRS},
X	{"aesst", DAYZONE, -10 HRS},	/* Australian Eastern Summer Time */
X	{"a.e.s.s.t.", DAYZONE, -10 HRS},
X	{"acst", ZONE, -(9 HRS + HALFHR)},	/* Australian Central Time */
X	{"a.c.s.t.", ZONE, -(9 HRS + HALFHR)},
X	{"acsst", DAYZONE, -(9 HRS + HALFHR)},	/* Australian Central Summer */
X	{"a.c.s.s.t.", DAYZONE, -(9 HRS + HALFHR)},
X	{"awst", ZONE, -8 HRS},		/* Australian Western Time */
X	{"a.w.s.t.", ZONE, -8 HRS},	/* (no daylight time there, I'm told */
X	{0, 0, 0}};
X
Xstatic struct table unittb[] = {
X	{"year", MUNIT, 12},
X	{"month", MUNIT, 1},
X	{"fortnight", UNIT, 14*24*60},
X	{"week", UNIT, 7*24*60},
X	{"day", UNIT, 1*24*60},
X	{"hour", UNIT, 60},
X	{"minute", UNIT, 1},
X	{"min", UNIT, 1},
X	{"second", SUNIT, 1},
X	{"sec", SUNIT, 1},
X	{0, 0, 0}};
X
Xstatic struct table othertb[] = {
X	{"tomorrow", UNIT, 1*24*60},
X	{"yesterday", UNIT, -1*24*60},
X	{"today", UNIT, 0},
X	{"now", UNIT, 0},
X	{"last", NUMBER, -1},
X	{"this", UNIT, 0},
X	{"next", NUMBER, 2},
X	{"first", NUMBER, 1},
X	/* {"second", NUMBER, 2}, */
X	{"third", NUMBER, 3},
X	{"fourth", NUMBER, 4},
X	{"fifth", NUMBER, 5},
X	{"sixth", NUMBER, 6},
X	{"seventh", NUMBER, 7},
X	{"eigth", NUMBER, 8},
X	{"ninth", NUMBER, 9},
X	{"tenth", NUMBER, 10},
X	{"eleventh", NUMBER, 11},
X	{"twelfth", NUMBER, 12},
X	{"ago", AGO, 1},
X	{0, 0, 0}};
X
Xstatic struct table milzone[] = {
X	{"a", ZONE, 1 HRS},
X	{"b", ZONE, 2 HRS},
X	{"c", ZONE, 3 HRS},
X	{"d", ZONE, 4 HRS},
X	{"e", ZONE, 5 HRS},
X	{"f", ZONE, 6 HRS},
X	{"g", ZONE, 7 HRS},
X	{"h", ZONE, 8 HRS},
X	{"i", ZONE, 9 HRS},
X	{"k", ZONE, 10 HRS},
X	{"l", ZONE, 11 HRS},
X	{"m", ZONE, 12 HRS},
X	{"n", ZONE, -1 HRS},
X	{"o", ZONE, -2 HRS},
X	{"p", ZONE, -3 HRS},
X	{"q", ZONE, -4 HRS},
X	{"r", ZONE, -5 HRS},
X	{"s", ZONE, -6 HRS},
X	{"t", ZONE, -7 HRS},
X	{"u", ZONE, -8 HRS},
X	{"v", ZONE, -9 HRS},
X	{"w", ZONE, -10 HRS},
X	{"x", ZONE, -11 HRS},
X	{"y", ZONE, -12 HRS},
X	{"z", ZONE, 0 HRS},
X	{0, 0, 0}};
X
Xstatic 
Xlookup(id)
Xchar *id;
X{
X#define gotit (yylval=i->value,  i->type)
X
X	char idvar[128];
X	register char *j, *k;
X	register struct table *i;
X	int abbrev;
X
X	(void) strcpy(idvar, id);
X	j = idvar;
X	k = id - 1;
X	while (*++k)
X		*j++ = isupper(*k) ? tolower(*k) : *k;
X	*j = '\0';
X
X	if (strlen(idvar) == 3)
X		abbrev = 1;
X	else
X		if (strlen(idvar) == 4 && idvar[3] == '.') {
X			abbrev = 1;
X			idvar[3] = '\0';
X		}
X	else
X		abbrev = 0;
X
X	for (i = mdtab; i->name; i++) {
X		k = idvar;
X		for (j = i->name; *j++ == *k++;) {
X			if (abbrev && j == i->name+3)
X				return gotit;
X			if (j[-1] == 0)
X				return gotit;
X		}
X	}
X
X	for (i = mztab; i->name; i++)
X		if (strcmp(i->name, idvar) == 0)
X			return gotit;
X
X	for (i=mztab; i->name; i++)
X		if (strcmp(i->name, idvar) == 0)
X			return gotit;
X
X	for (i=unittb; i->name; i++)
X		if (strcmp(i->name, idvar) == 0)
X			return gotit;
X
X	if (idvar[strlen(idvar)-1] == 's')
X		idvar[strlen(idvar)-1] = '\0';
X
X	for (i=unittb; i->name; i++)
X		if (strcmp(i->name, idvar) == 0)
X			return gotit;
X
X	for (i = othertb; i->name; i++)
X		if (strcmp(i->name, idvar) == 0)
X			return gotit;
X
X	if (strlen(idvar) == 1 && isalpha(*idvar)) {
X		for (i = milzone; i->name; i++)
X			if (strcmp(i->name, idvar) == 0)
X				return gotit;
X	}
X
X	return ID;
X}
X
Xtime_t
Xgetdate(p, now)
Xchar *p;
Xstruct timeb *now;
X{
X#define mcheck(f)	if (f>1) err++
X	time_t monthadd();
X	int err;
X	struct tm *lt;
X	struct timeb ftz;
X
X	time_t sdate, tod;
X
X	lptr = p;
X	if (now == ((struct timeb *) NULL)) {
X		now = &ftz;
X		ftime(&ftz);
X	}
X	lt = localtime(&now->time);
X	year = lt->tm_year;
X	month = lt->tm_mon+1;
X	day = lt->tm_mday;
X	relsec = 0; relmonth = 0;
X	timeflag=zoneflag=dateflag=dayflag=relflag=0;
X	ourzone = now->timezone;
X	day_light = MAYBE;
X	hh = mm = ss = 0;
X	merid = 24;
X
X	if (err = yyparse()) return (-1);
X
X	mcheck(timeflag);
X	mcheck(zoneflag);
X	mcheck(dateflag);
X	mcheck(dayflag);
X
X	if (err) return (-1);
X	if (dateflag || timeflag || dayflag) {
X		sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,day_light);
X		if (sdate < 0) return -1;
X	}
X	else {
X		sdate = now->time;
X		if (relflag == 0)
X			sdate -= (lt->tm_sec + lt->tm_min*60 +
X				lt->tm_hour*(60L*60L));
X	}
X
X	sdate += relsec;
X	sdate += monthadd(sdate, relmonth);
X
X	if (dayflag && !dateflag) {
X		tod = dayconv(dayord, dayreq, sdate);
X		sdate += tod;
X	}
X
X	/*
X	** Have to do *something* with a legitimate -1 so it's distinguishable
X	** from the error return value.  (Alternately could set errno on error.)
X	*/
X	return (sdate == -1) ? 0 : sdate;
X}
X
Xstatic
Xyyerror(s)
Xchar *s;
X{
X}
X
X#ifdef USG
Xftime(timeb)
Xstruct timeb *timeb;
X{
X	extern long timezone;
X	extern int daylight;
X
X	time(&(timeb->time));
X	timeb->millitm=0;
X	timeb->timezone=timezone;
X	timeb->dstflag=daylight;
X}
X#endif
SHAR_EOF
chmod 0644 GETDATE.Y || echo "restore of GETDATE.Y fails"
echo "x - extracting GETOLDOP.C (Text)"
sed 's/^X//' << 'SHAR_EOF' > GETOLDOP.C &&
X/*
X
X	Copyright (C) 1988 Free Software Foundation
X
XGNU tar is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
XRefer to the GNU tar General Public License for full details.
X
XEveryone is granted permission to copy, modify and redistribute GNU tar,
Xbut only under the conditions described in the GNU tar General Public
XLicense.  A copy of this license is supposed to have been given to you
Xalong with GNU tar so you can know your rights and responsibilities.  It
Xshould be in a file named COPYING.  Among other things, the copyright
Xnotice and this notice must be preserved on all copies.
X
XIn other words, go ahead and share GNU tar, but don't try to stop
Xanyone else from sharing it farther.  Help stamp out software hoarding!
X*/
X
X/*
X * Plug-compatible replacement for getopt() for parsing tar-like
X * arguments.  If the first argument begins with "-", it uses getopt;
X * otherwise, it uses the old rules used by tar, dump, and ps.
X *
X * Written 25 August 1985 by John Gilmore (ihnp4!hoptoad!gnu)
X *
X * @(#)getoldopt.c 1.4 2/4/86 - gnu
X */
X
X#include <stdio.h>
X
X
Xint
Xgetoldopt(argc, argv, optstring)
X	int	argc;
X	char	**argv;
X	char	*optstring;
X{
X	extern char	*optarg;	/* Points to next arg */
X	extern int	optind;		/* Global argv index */
X	static char	*key;		/* Points to next keyletter */
X	static char	use_getopt;	/* !=0 if argv[1][0] was '-' */
X	extern char	*index();
X	char		c;
X	char		*place;
X
X	optarg = NULL;
X	
X	if (key == NULL) {		/* First time */
X		if (argc < 2) return EOF;
X		key = argv[1];
X		if (*key == '-')
X			use_getopt++;
X		else
X			optind = 2;
X	}
X
X	if (use_getopt)
X		return getopt(argc, argv, optstring);
X
X	c = *key++;
X	if (c == '\0') {
X		key--;
X		return EOF;
X	}
X	place = index(optstring, c);
X
X	if (place == NULL || c == ':') {
X		msg("unknown option %c", c);
X		return('?');
X	}
X
X	place++;
X	if (*place == ':') {
X		if (optind < argc) {
X			optarg = argv[optind];
X			optind++;
X		} else {
X			msg("%c argument missing", c);
X			return('?');
X		}
X	}
X
X	return(c);
X}
SHAR_EOF
chmod 0644 GETOLDOP.C || echo "restore of GETOLDOP.C fails"
echo "x - extracting LIST.C (Text)"
sed 's/^X//' << 'SHAR_EOF' > LIST.C &&
X/*
X
X	Copyright (C) 1988 Free Software Foundation
X
XGNU tar is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
XRefer to the GNU tar General Public License for full details.
X
XEveryone is granted permission to copy, modify and redistribute GNU tar,
Xbut only under the conditions described in the GNU tar General Public
XLicense.  A copy of this license is supposed to have been given to you
Xalong with GNU tar so you can know your rights and responsibilities.  It
Xshould be in a file named COPYING.  Among other things, the copyright
Xnotice and this notice must be preserved on all copies.
X
XIn other words, go ahead and share GNU tar, but don't try to stop
Xanyone else from sharing it farther.  Help stamp out software hoarding!
X*/
X
X/*
X * List a tar archive.
X *
X * Also includes support routines for reading a tar archive.
X *
X * this version written 26 Aug 1985 by John Gilmore (ihnp4!hoptoad!gnu).
X *
X * @(#)list.c 1.31 11/5/87 - gnu
X */
X#include <stdio.h>
X#include <ctype.h>
X#ifdef atarist
X#include <types.h>
X#include <stat.h>
X#else
X#include <sys/types.h>
X#include <sys/stat.h>
X#endif
X
X#ifndef	MSDOS
X#include <sys/file.h>
X#endif	/* MSDOS */
X
X#ifdef USG
X#include <sys/sysmacros.h>	/* major() and minor() defined here */
X#endif
X
Xchar *ctime();				/* From libc.a */
X
X#define	isodigit(c)	( ((c) >= '0') && ((c) <= '7') )
X
X#include "tar.h"
X#include "port.h"
X
Xlong from_oct();			/* Decode octal number */
Xvoid demode();				/* Print file mode */
X
Xunion record *head;			/* Points to current archive header */
Xstruct stat hstat;			/* Stat struct corresponding */
Xint head_standard;			/* Tape header is in ANSI format */
X
Xvoid print_header();
Xvoid skip_file();
X
Xextern char *quote_copy_string();
X#ifdef atarist
Xextern FILE *msg_file;
X#endif
X
X/*
X * Main loop for reading an archive.
X */
Xvoid
Xread_and(do_something)
X	void (*do_something)();
X{
X	int status = 3;			/* Initial status at start of archive */
X	int prev_status;
X	extern time_t new_time;
X
X	name_gather();			/* Gather all the names */
X	open_archive(1);		/* Open for reading */
X
X	for(;;) {
X		prev_status = status;
X		status = read_header();
X		switch (status) {
X
X		case 1:			/* Valid header */
X			/* We should decode next field (mode) first... */
X			/* Ensure incoming names are null terminated. */
X			head->header.name[NAMSIZ-1] = '\0';
X			
X			if (!name_match(head->header.name) || (f_new_files && hstat.st_mtime<new_time)) {
X				/* Skip past it in the archive */
X				userec(head);
X				/* Skip to the next header on the archive */
X				if(head->header.linkflag!='5')
X					skip_file((long)hstat.st_size);
X				continue;
X			}
X
X			(*do_something)();
X			continue;
X
X			/*
X			 * If the previous header was good, tell them
X			 * that we are skipping bad ones.
X			 */
X		case 0:			/* Invalid header */
X			userec(head);
X			switch (prev_status) {
X			case 3:		/* Error on first record */
X				msg("Hmm, this doesn't look like a tar archive.");
X				/* FALL THRU */
X			case 2:		/* Error after record of zeroes */
X			case 1:		/* Error after header rec */
X				msg("Skipping to next file header...\n");
X			case 0:		/* Error after error */
X				break;
X			}
X			continue;
X
X		case 2:			/* Record of zeroes */
X			userec(head);
X			status = prev_status;	/* If error after 0's */
X			if (f_ignorez)	
X				continue;
X			/* FALL THRU */
X		case EOF:		/* End of archive */
X			break;
X		}
X		break;
X	};
X
X	close_archive();
X	names_notfound();		/* Print names not found */
X}		
X
X
X/*
X * Print a header record, based on tar options.
X */
Xvoid
Xlist_archive()
X{
X	extern FILE *msg_file;
X	extern char *save_name;
X
X	/* Save the record */
X	saverec(&head);
X
X	/* Print the header record */
X	if (f_verbose) {
X		if (f_verbose > 1)
X			decode_header(head, &hstat, &head_standard, 0);
X		print_header();
X	}
X
X	if(f_gnudump && head->header.linkflag==LF_DUMPDIR) {
X		size_t	size, written, check;
X		char	*data;
X		extern int errno;
X		extern long save_totsize;
X		extern long save_sizeleft;
X
X		userec(head);
X		if(f_multivol) {
X			save_name = head->header.name;
X			save_totsize=hstat.st_size;
X		}
X		for(size = hstat.st_size;size>0;size-=written) {
X			if(f_multivol)
X				save_sizeleft=size;
X			data = findrec()->charptr;
X			if(data==NULL) {
X				msg("EOF in archive file?");
X				break;
X			}
X			written = endofrecs()->charptr - data;
X			if(written>size)
X				written=size;
X			errno=0;
X			check=fwrite(data,sizeof(char), written, msg_file);
X			userec((union record *)(data+written - 1));
X			if(check!=written) {
X				msg_perror("only wrote %ld of %ld bytes to file %s",check, written,head->header.name);
X				skip_file((long)(size)-written);
X				break;
X			}
X		}
X		if(f_multivol)
X			save_name = 0;
X		saverec((union record **) 0);	/* Unsave it */
X		fputc('\n',msg_file);
X		return;
X
X	}
X	saverec((union record **) 0);	/* Unsave it */
X	/* Skip past it in the archive */
X	userec(head);
X
X	if(f_multivol)
X		save_name=head->header.name;
X	/* Skip to the next header on the archive */
X	skip_file((long)hstat.st_size);
X	if(f_multivol)
X		save_name = 0;
X}
X
X
X/*
X * Read a record that's supposed to be a header record.
X * Return its address in "head", and if it is good, the file's
X * size in hstat.st_size.
X *
X * Return 1 for success, 0 if the checksum is bad, EOF on eof,
X * 2 for a record full of zeros (EOF marker).
X *
X * You must always userec(head) to skip past the header which this
X * routine reads.
X */
Xint
Xread_header()
X{
X	register int	i;
X	register long	sum, recsum;
X	register char	*p;
X	register union record *header;
X	long	from_oct();
X
X	header = findrec();
X	head = header;		/* This is our current header */
X	if (NULL == header) return EOF;
X
X	recsum = from_oct(8,  header->header.chksum);
X
X	sum = 0;
X	p = header->charptr;
X	for (i = sizeof(*header); --i >= 0;) {
X		/*
X		 * We can't use unsigned char here because of old compilers,
X		 * e.g. V7.
X		 */
X		sum += 0xFF & *p++;
X	}
X
X	/* Adjust checksum to count the "chksum" field as blanks. */
X	for (i = sizeof(header->header.chksum); --i >= 0;)
X		sum -= 0xFF & header->header.chksum[i];
X	sum += ' '* sizeof header->header.chksum;	
X
X	if (sum == recsum) {
X		/*
X		 * Good record.  Decode file size and return.
X		 */
X		if (header->header.linkflag == LF_LINK)
X			hstat.st_size = 0;	/* Links 0 size on tape */
X		else
X			hstat.st_size = from_oct(1+12, header->header.size);
X		return 1;
X	}
X
X	if (sum == 8*' ') {
X		/*
X		 * This is a zeroed record...whole record is 0's except
X		 * for the 8 blanks we faked for the checksum field.
X		 */
X		return 2;
X	}
X
X	return 0;
X}
X
X
X/* 
X * Decode things from a file header record into a "struct stat".
X * Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix
X * Standard" tar format or regular old tar format.
X *
X * read_header() has already decoded the checksum and length, so we don't.
X *
X * If wantug != 0, we want the uid/group info decoded from Unix Standard
X * tapes (for extraction).  If == 0, we are just printing anyway, so save time.
X *
X * decode_header should NOT be called twice for the same record, since the
X * two calls might use different "wantug" values and thus might end up with
X * different uid/gid for the two calls.  If anybody wants the uid/gid they
X * should decode it first, and other callers should decode it without uid/gid
X * before calling a routine, e.g. print_header, that assumes decoded data.
X */
Xdecode_header(header, st, stdp, wantug)
X	register union record	*header;
X	register struct stat	*st;
X	int	*stdp;
X	int	wantug;
X{
X
X	long from_oct();
X
X	st->st_mode = from_oct(8,  header->header.mode);
X	st->st_mtime = from_oct(1+12, header->header.mtime);
X	if(f_gnudump) {
X		st->st_atime = from_oct(1+12, header->header.atime);
X		st->st_ctime = from_oct(1+12, header->header.ctime);
X	}
X	
X	if (0==strcmp(header->header.magic, TMAGIC)) {
X		/* Unix Standard tar archive */
X		*stdp = 1;
X		if (wantug) {
X#ifdef NONAMES
X			st->st_uid = from_oct(8,  header->header.uid);
X			st->st_gid = from_oct(8,  header->header.gid);
X#else
X			st->st_uid = finduid(header->header.uname);
X			st->st_gid = findgid(header->header.gname);
X#endif
X		}
X		switch  (header->header.linkflag) 
X		case LF_BLK: case LF_CHR:
X		    st->st_rdev = makedev(from_oct(8, header->header.devmajor),
X			 		  from_oct(8, header->header.devminor));
X	} else {
X		/* Old fashioned tar archive */
X		*stdp = 0;
X		st->st_uid = from_oct(8,  header->header.uid);
X		st->st_gid = from_oct(8,  header->header.gid);
X		st->st_rdev = 0;
X	}
X}
X
X
X/*
X * Quick and dirty octal conversion.
X *
X * Result is -1 if the field is invalid (all blank, or nonoctal).
X */
Xlong
Xfrom_oct(digs, where)
X	register int	digs;
X	register char	*where;
X{
X	register long	value;
X
X	while (isspace(*where)) {		/* Skip spaces */
X		where++;
X		if (--digs <= 0)
X			return -1;		/* All blank field */
X	}
X	value = 0;
X	while (digs > 0 && isodigit(*where)) {	/* Scan til nonoctal */
X		value = (value << 3) | (*where++ - '0');
X		--digs;
X	}
X
X	if (digs > 0 && *where && !isspace(*where))
X		return -1;			/* Ended on non-space/nul */
X
X	return value;
X}
X
X
X/*
X * Actually print it.
X *
X * Plain and fancy file header block logging.
X * Non-verbose just prints the name, e.g. for "tar t" or "tar x".
X * This should just contain file names, so it can be fed back into tar
X * with xargs or the "-T" option.  The verbose option can give a bunch
X * of info, one line per file.  I doubt anybody tries to parse its
X * format, or if they do, they shouldn't.  Unix tar is pretty random here
X * anyway.
X *
X * Note that print_header uses the globals <head>, <hstat>, and
X * <head_standard>, which must be set up in advance.  This is not very clean
X * and should be cleaned up.  FIXME.
X */
X#define	UGSWIDTH	11		/* min width of User, group, size */
X#define	DATEWIDTH	19		/* Last mod date */
Xstatic int	ugswidth = UGSWIDTH;	/* Max width encountered so far */
X
Xvoid
Xprint_header()
X{
X	char modes[11];
X	char *timestamp;
X	char uform[11], gform[11];	/* These hold formatted ints */
X	char *user, *group;
X	char size[24];		/* Holds a formatted long or maj, min */
X	long longie;		/* To make ctime() call portable */
X	int	pad;
X	extern FILE *msg_file;
X	char *name;
X	extern long baserec;
X
X	if(f_sayblock)
X		fprintf(msg_file,"rec %10d: ",baserec + (ar_record - ar_block));
X	/* annofile(msg_file, (char *)NULL); */
X
X	if (f_verbose <= 1) {
X		/* Just the fax, mam. */
X		char *name;
X
X		name=quote_copy_string(head->header.name);
X		if(name==0)
X			name=head->header.name;
X		fprintf(msg_file, "%s\n", name);
X		if(name!=head->header.name)
X			free(name);
X		return;
X	} else {
X		/* File type and modes */
X		modes[0] = '?';
X		switch (head->header.linkflag) {
X		case LF_VOLHDR:
X			modes[0]='V';
X			break;
X
X		case LF_MULTIVOL:
X			modes[0]='M';
X			break;
X			
X		case LF_NORMAL:
X		case LF_OLDNORMAL:
X		case LF_LINK:
X				modes[0] = '-'; 
X				if ('/' == head->header.name[strlen(head->header.name)-1])
X					modes[0] = 'd';
X				break;
X		case LF_DUMPDIR:modes[0] = 'd'; break;
X		case LF_DIR:	modes[0] = 'd'; break;
X		case LF_SYMLINK:modes[0] = 'l'; break;
X		case LF_BLK:	modes[0] = 'b'; break;
X		case LF_CHR:	modes[0] = 'c'; break;
X		case LF_FIFO:	modes[0] = 'p'; break;	
X		case LF_CONTIG:	modes[0] = 'C'; break;
X		}
X
X		demode((unsigned)hstat.st_mode, modes+1);
X
X		/* Timestamp */
X		longie = hstat.st_mtime;
X		timestamp = ctime(&longie);
X		timestamp[16] = '\0';
X		timestamp[24] = '\0';
X
X		/* User and group names */
X		if (*head->header.uname && head_standard) {
X			user  = head->header.uname;
X		} else {
X			user = uform;
X			(void)sprintf(uform, "%d", (int)hstat.st_uid);
X		}
X		if (*head->header.gname && head_standard) {
X			group = head->header.gname;
X		} else {
X			group = gform;
X			(void)sprintf(gform, "%d", (int)hstat.st_gid);
X		}
X
X		/* Format the file size or major/minor device numbers */
X		switch (head->header.linkflag) {
X		case LF_CHR:
X		case LF_BLK:
X			(void)sprintf(size, "%d,%d",
X					major(hstat.st_rdev),
X					minor(hstat.st_rdev));
X			break;
X
X		default:
X			(void)sprintf(size, "%ld", (long)hstat.st_size);
X		}
X
X		/* Figure out padding and print the whole line. */
X		pad = strlen(user) + strlen(group) + strlen(size) + 1;
X		if (pad > ugswidth) ugswidth = pad;
X
X		name = quote_copy_string(head->header.name);
X		if(!name)
X			name=head->header.name;
X		fprintf(msg_file, "%s %s/%s %*s%s %s %s %.*s",
X			modes,
X			user,
X			group,
X			ugswidth - pad,
X			"",
X			size,
X			timestamp+4, timestamp+20,
X			sizeof(head->header.name),
X			name);
X
X		if(name!=head->header.name)
X			free(name);
X		switch (head->header.linkflag) {
X		case LF_SYMLINK:
X			name=quote_copy_string(head->header.linkname);
X			if(!name)
X				name=head->header.linkname;
X			fprintf(msg_file, " -> %s\n", name);
X			if(name!=head->header.linkname)
X				free(name);
X			break;
X
X		case LF_LINK:
X			name=quote_copy_string(head->header.linkname);
X			if(!name)
X				name=head->header.linkname;
X			fprintf(msg_file, " link to %s\n", head->header.linkname);
X			if(name!=head->header.linkname)
X				free(name);
X			break;
X
X		default:
X			fprintf(msg_file, " unknown file type '%c'\n",
X				head->header.linkflag);
X			break;
X
X		case LF_OLDNORMAL:
X		case LF_NORMAL:
X		case LF_CHR:
X		case LF_BLK:
X		case LF_DIR:
X		case LF_FIFO:
X		case LF_CONTIG:
X		case LF_DUMPDIR:
X			putc('\n', msg_file);
X			break;
X
X		case LF_VOLHDR:
X			fprintf(msg_file, "--Volume Header--\n");
X			break;
X			
X		case LF_MULTIVOL:
X			fprintf(msg_file, "--Continued at byte %ld--\n",from_oct(1+12,head->header.offset));
X			break;
X		}
X	}
X}
X
X/*
X * Print a similar line when we make a directory automatically.
X */
Xvoid
Xpr_mkdir(pathname, length, mode)
X	char *pathname;
X	int length;
X	int mode;
X{
X	char modes[11];
X	char *name;
X	extern long baserec;
X
X	if (f_verbose > 1) {
X		/* File type and modes */
X		modes[0] = 'd';
X		demode((unsigned)mode, modes+1);
X
X		if(f_sayblock)
X			fprintf(msg_file,"rec %10d: ",baserec + (ar_record - ar_block));
X		/* annofile(msg_file, (char *)NULL); */
X		name=quote_copy_string(pathname);
X		if(!name)
X			name=pathname;
X		fprintf(msg_file, "%s %*s %.*s\n",
X			modes,
X			ugswidth+DATEWIDTH,
X			"Creating directory:",
X			length,
X			pathname);
X		if(name!=pathname)
X			free(name);
X	}
X}
X
X
X/*
X * Skip over <size> bytes of data in records in the archive.
X */
Xvoid
Xskip_file(size)
X	register long size;
X{
X	union record *x;
X	extern long save_totsize;
X	extern long save_sizeleft;
X
X	if(f_multivol) {
X		save_totsize=size;
X		save_sizeleft=size;
X	}
X
X	while (size > 0) {
X		x = findrec();
X		if (x == NULL) {	/* Check it... */
X			msg("Unexpected EOF on archive file");
X			exit(EX_BADARCH);
X		}
X		userec(x);
X		size -= RECORDSIZE;
X		if(f_multivol)
X			save_sizeleft-=RECORDSIZE;
X	}
X}
X
X
X/*
X * Decode the mode string from a stat entry into a 9-char string and a null.
X */
Xvoid
Xdemode(mode, string)
X	register unsigned mode;
X	register char *string;
X{
X	register unsigned mask;
X	register char *rwx = "rwxrwxrwx";
X
X	for (mask = 0400; mask != 0; mask >>= 1) {
X		if (mode & mask)
X			*string++ = *rwx++;
X		else {
X			*string++ = '-';
X			rwx++;
X		}
X	}
X
X	if (mode & S_ISUID)
X		if (string[-7] == 'x')
X			string[-7] = 's';
X		else
X			string[-7] = 'S';
X	if (mode & S_ISGID)
X		if (string[-4] == 'x')
X			string[-4] = 's';
X		else
X			string[-4] = 'S';
X	if (mode & S_ISVTX)
X		if (string[-1] == 'x')
X			string[-1] = 't';
X		else
X			string[-1] = 'T';
X	*string = '\0';
X}
SHAR_EOF
chmod 0644 LIST.C || echo "restore of LIST.C fails"
echo "x - extracting MAKEFILE (Text)"
sed 's/^X//' << 'SHAR_EOF' > MAKEFILE &&
X# Makefile for public domain tar program.
X# @(#)Makefile 1.30	87/11/11
X
X## GNU version
X#DEFS = -DBSD42
X#LOCAL_SRC = 
X#LOCAL_OBJ = 
X#LDFLAGS =
X#LIBS =  -lutils
X#LINT = lint
X#LINTFLAGS = -abchx
X#DEF_AR_FILE = \"/dev/rmt8\"
X#DEFBLOCKING = 20
X#O = o
X
X## Berserkeley version
X#DEFS = -DBSD42
X#LOCAL_SRC = getdate.y  rtape_lib.c
X#LOCAL_OBJ = getdate.$O rtape_lib.$O
X#LDFLAGS =
X#LIBS =
X#LINT = lint
X#LINTFLAGS = -abchx
X#DEF_AR_FILE = \"/dev/rmt8\"
X#DEFBLOCKING = 20
X#O = o
X
X# USG version
X#DEFS = -DUSG
X#LOCAL_SRC =  getdate.y rtape_lib.c
X#LOCAL_OBJ =  getdate.$O rtape_lib.$O
X#LDFLAGS =
X#LIBS = -lndir -lPW
X#LINT = lint
X#LINTFLAGS = -p
X#DEF_AR_FILE = \"/dev/rmt8\"
X#DEFBLOCKING = 20
X#O = o
X
X# UniSoft's Uniplus SVR2 with NFS
X#DEFS = -DUSG -DUNIPLUS -DNFS -DSVR2
X#LOCAL_SRC =  getdate.y rtape_lib.c
X#LOCAL_OBJ =  getdate.$O rtape_lib.$O
X#LDFLAGS =
X#LIBS = -lndir
X#LINT = lint
X#LINTFLAGS = -bx
X#DEF_AR_FILE = \"/dev/rmt8\"
X#DEFBLOCKING = 20
X#O = o
X
X# MASSCOMP version
X#CC = ucb cc
X#DEFS = -DBSD42
X#LOCAL_SRC =  getdate.y rtape_lib.c
X#LOCAL_OBJ =  getdate.$O rtape_lib.$O
X#LDFLAGS =
X#LIBS = 
X#LINT = lint
X#LINTFLAGS = -bx
X#DEF_AR_FILE = \"/dev/rmt0\"
X#DEFBLOCKING = 20
X#O = o
X
X# (yuk) MS-DOS (Microsoft C) version
X#MODEL = S
X#DEFS = -DNONAMES -A$(MODEL) -nologo
X#LOCAL_SRC =  getdate.y rtape_lib.c
X#LOCAL_OBJ =  getdate.$O rtape_lib.$O
X#LDFLAGS =
X#LIBS = $(MODEL)dir.lib
X#LINT =	$(CC)
X#LINTFLAGS = -W3
X#DEF_AR_FILE = \"tar.out\"
X#DEFBLOCKING = 20
X#O = obj
X
X# V7 version
X# Pick open3 emulation or nonexistence.  See open3.h, port.c.
X##DEFS = -DV7 -DEMUL_OPEN3 -Dvoid=int
X##DEFS = -DV7 -DNO_OPEN3 -Dvoid=int
X#LOCAL_SRC =  getdate.y rtape_lib.c
X#LOCAL_OBJ =  getdate.$O rtape_lib.$O
X#LDFLAGS =
X#LIBS = -lndir
X#LINT = lint
X#LINTFLAGS = -abchx
X#DEF_AR_FILE = \"/dev/rmt8\"
X#DEFBLOCKING = 20
X#O = o
X
X# Minix version
X# No lint, so no lintflags.  Default file is stdin/out.  (Minix "tar"
X# doesn't even take an "f" flag, it assumes argv[2] is the archive name!)
X# Minix "make" doesn't expand macros right, so Minix users will have
X# to expand CFLAGS, SRCS, O, etc by hand, or fix your make.  Not my problem!
X# You'll also need to come up with getopt() and ctime(), the directory
X# library, and a fixed doprintf() that handles %*s.  Put this stuff in
X# the "SUBSRC/SUBOBJ" macro below if you didn't put it in your C library.
X# Note that Minix "cc" produces ".s" files, not .o's, so O = s should be
X# set (except on Atari ST, of course -- why do we have all this trouble
X# with "portable" operating systems?? -- ERS).
X#
X# Pick open3 emulation or nonexistence.  See open3.h, port.c.
X#DEFS = -DV7 -DMINIX -DEMUL_OPEN3
X##DEFS = -DV7 -DMINIX -DNO_OPEN3
X#LOCAL_SRC =  getdate.y rtape_lib.c
X#LOCAL_OBJ =  getdate.$O rtape_lib.$O
X#LDFLAGS =
X#LIBS =
X#DEF_AR_FILE = \"-\"
X#DEFBLOCKING = 8	/* No good reason for this, change at will */
X#O = o
X#YACC = /usr/local/bin/bison -y 
X
X# Xenix version
X#DEFS = -DUSG -DXENIX
X#LOCAL_SRC =  getdate.y rtape_lib.c
X#LOCAL_OBJ =  getdate.$O rtape_lib.$O
X#LDFLAGS = 
X#LIBS = -lx
X#LINT = lint
X#LINTFLAGS = -p
X#DEF_AR_FILE = \"/dev/rmt8\"
X#DEFBLOCKING = 20
X#O = o
X
X# Atari ST GEMDOS version (GCC v1.34, with new library)
X# Mostly, GEMDOS is like MSDOS, so that's what we pretend to be.
X# Also, for simplicity's sake the dumb getdate in port.c is used
X# instead of the fancy one (I hacked the dumb one up a bit, so it
X# isn't quite as bad as it used to be -- ERS).
X#
XCC = d:\gnu\bin\gcc.ttp
XDEFS = -DNONAMES -DMSDOS -DNO_REMOTE
X#LOCAL_SRC =  getdate.y rtape_lib.c
X#LOCAL_OBJ =  getdate.$O rtape_lib.$O
XLOCAL_SRC =
XLOCAL_OBJ =
XLDFLAGS = -s
XLIBS = 
XLINT =	$(CC)
XLINTFLAGS = -Wall
XDEF_AR_FILE = 0		# This means take name from argv[2].
XDEFBLOCKING = 2
XO = o
X
XCFLAGS = $(COPTS) $(ALLDEFS)
XALLDEFS = $(DEFS) \
X	-DDEF_AR_FILE=$(DEF_AR_FILE) \
X	-DDEFBLOCKING=$(DEFBLOCKING)
X# next line for Debugging
X#COPTS = -g
X# next line for Production
XCOPTS = -O
X
X# Add things here like getopt, readdir, etc that aren't in your
X# standard libraries.  (E.g. MSDOS needs getopt, msd_dir.c, msd_dir.obj)
XSUBSRC=
XSUBOBJ=	
X
X# Destination directory and installation program for make install
XDESTDIR = /usr/local
XINSTALL = cp
XRM = rm -f
X
XSRC1 =	tar.c create.c extract.c buffer.c getoldopt.c update.c
XSRC2 =  version.c list.c names.c diffarch.c port.c wildmat.c
XSRC3 =  $(LOCAL_SRC) $(SUBSRC)
XSRCS =	$(SRC1) $(SRC2) $(SRC3)
XOBJ1 =	tar.$O create.$O extract.$O buffer.$O getoldopt.$O list.$O update.$O
XOBJ2 =	version.$O names.$O diffarch.$O port.$O wildmat.$O
XOBJ3 =  $(LOCAL_OBJ) $(SUBOBJ)
XOBJS =	$(OBJ1) $(OBJ2) $(OBJ3)
X# AUX =	README PORTING Makefile TODO tar.h port.h open3.h \
X#	msd_dir.h msd_dir.c
XAUX =   README COPYING Makefile tar.texinfo tar.h port.h open3.h rmt.h \
X	msd_dir.h msd_dir.c rtape_server.c rtape_lib.c getdate.y
X
X# rmt is no good on the ST
X# all:	tar rmt
Xall:	tar
X
Xtar: $(OBJS)
X	$(CC) $(LDFLAGS) -o tar $(COPTS) $(OBJS) $(LIBS)
X
Xrmt:	rtape_server.c
X	$(CC) $(CFLAGS) -o rmt rtape_server.c
X
X# command is too long for Messy-Dos (128 char line length limit) so
X# this kludge is used...
X#	@echo $(OBJ1) + > command
X#	@echo $(OBJ2) >> command
X#	link @command, $@,,$(LIBS) /NOI;
X#	@$(RM) command
X
Xinstall: all
X	$(RM) $(DESTDIR)/bin/tar
X	$(INSTALL) tar   $(DESTDIR)/bin/tar
X	$(INSTALL) tar.texinfo $(DESTDIR)/man/tar.texinfo
X	$(INSTALL) rmt /etc/rmt
X
Xlint:	$(SRCS)
X	$(LINT) $(LINTFLAGS) $(ALLDEFS) $(SRCS)
X
Xclean:
X	$(RM) errs $(OBJS) tar rmt
X
Xtar.shar: $(SRCS) $(AUX)
X	shar >tar.shar1 $(AUX)
X	shar >tar.shar2 $(SRC1)
X	shar >tar.shar3 $(SRC2)
X
Xdist: tar.tar tar.tar.Z
X
Xtar.tar: $(SRCS) $(AUX)
X	/bin/tar cf tar.tar $(AUX) $(SRCS)
X
Xtar.tar.Z: tar.tar
X	compress < tar.tar > tar.tar.Z
X#	/bin/tar cf - $(AUX) $(SRCS) | compress -v >tar.tar.Z
X
Xtar.zoo: $(SRCS) $(AUX)
X	zoo a tar $(AUX) $(SRCS)
X
X$(OBJS): tar.h port.h
SHAR_EOF
chmod 0644 MAKEFILE || echo "restore of MAKEFILE fails"
echo "x - extracting MSD_DIR.C (Text)"
sed 's/^X//' << 'SHAR_EOF' > MSD_DIR.C &&
X/*
X * @(#)msd_dir.c 1.4 87/11/06	Public Domain.
X *
X *  A public domain implementation of BSD directory routines for
X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
X *  August 1897
X */
X
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<sys/dir.h>
X#include	<malloc.h>
X#include	<string.h>
X#include	<dos.h>
X
X#ifndef	NULL
X# define	NULL	0
X#endif	/* NULL */
X
X#ifndef	MAXPATHLEN
X# define	MAXPATHLEN	255
X#endif	/* MAXPATHLEN */
X
X/* attribute stuff */
X#define	A_RONLY		0x01
X#define	A_HIDDEN	0x02
X#define	A_SYSTEM	0x04
X#define	A_LABEL		0x08
X#define	A_DIR		0x10
X#define	A_ARCHIVE	0x20
X
X/* dos call values */
X#define	DOSI_FINDF	0x4e
X#define	DOSI_FINDN	0x4f
X#define	DOSI_SDTA	0x1a
X
X#define	Newisnull(a, t)		((a = (t *) malloc(sizeof(t))) == (t *) NULL)
X/* #define	ATTRIBUTES		(A_DIR | A_HIDDEN | A_SYSTEM) */
X#define ATTRIBUTES	(A_RONLY | A_SYSTEM | A_DIR)
X
X/* what find first/next calls look use */
Xtypedef struct {
X	char		d_buf[21];
X	char		d_attribute;
X	unsigned short	d_time;
X	unsigned short	d_date;
X	long		d_size;
X	char		d_name[13];
X} Dta_buf;
X
Xstatic	char	*getdirent();
Xstatic	void	setdta();
Xstatic	void	free_dircontents();
X
Xstatic	Dta_buf		dtabuf;
Xstatic	Dta_buf		*dtapnt = &dtabuf;
Xstatic	union REGS	reg, nreg;
X
X#if	defined(M_I86LM)
Xstatic	struct SREGS	sreg;
X#endif
X
XDIR	*
Xopendir(name)
X	char	*name;
X{
X	struct	stat		statb;
X	DIR			*dirp;
X	char			c;
X	char			*s;
X	struct _dircontents	*dp;
X	char			nbuf[MAXPATHLEN + 1];
X	
X	if (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
X		return (DIR *) NULL;
X	if (Newisnull(dirp, DIR))
X		return (DIR *) NULL;
X	if (*name && (c = name[strlen(name) - 1]) != '\\' && c != '/')
X		(void) strcat(strcpy(nbuf, name), "\\*.*");
X	else
X		(void) strcat(strcpy(nbuf, name), "*.*");
X	dirp->dd_loc = 0;
X	setdta();
X	dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL;
X	if ((s = getdirent(nbuf)) == (char *) NULL)
X		return dirp;
X	do {
X		if (Newisnull(dp, struct _dircontents) || (dp->_d_entry =
X			malloc((unsigned) (strlen(s) + 1))) == (char *) NULL)
X		{
X			if (dp)
X				free((char *) dp);
X			free_dircontents(dirp->dd_contents);
X			return (DIR *) NULL;
X		}
X		if (dirp->dd_contents)
X			dirp->dd_cp = dirp->dd_cp->_d_next = dp;
X		else
X			dirp->dd_contents = dirp->dd_cp = dp;
X		(void) strcpy(dp->_d_entry, s);
X		dp->_d_next = (struct _dircontents *) NULL;
X	} while ((s = getdirent((char *) NULL)) != (char *) NULL);
X	dirp->dd_cp = dirp->dd_contents;
X
X	return dirp;
X}
X
Xvoid
Xclosedir(dirp)
X	DIR	*dirp;
X{
X	free_dircontents(dirp->dd_contents);
X	free((char *) dirp);
X}
X
Xstruct direct	*
Xreaddir(dirp)
X	DIR	*dirp;
X{
X	static	struct direct	dp;
X	
X	if (dirp->dd_cp == (struct _dircontents *) NULL)
X		return (struct direct *) NULL;
X	dp.d_namlen = dp.d_reclen =
X		strlen(strcpy(dp.d_name, dirp->dd_cp->_d_entry));
X	strlwr(dp.d_name);		/* JF */
X	dp.d_ino = 0;
X	dirp->dd_cp = dirp->dd_cp->_d_next;
X	dirp->dd_loc++;
X
X	return &dp;
X}
X
Xvoid
Xseekdir(dirp, off)
X	DIR	*dirp;
X	long	off;
X{
X	long			i = off;
X	struct _dircontents	*dp;
X
X	if (off < 0)
X		return;
X	for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
X		;
X	dirp->dd_loc = off - (i + 1);
X	dirp->dd_cp = dp;
X}
X
Xlong
Xtelldir(dirp)
X	DIR	*dirp;
X{
X	return dirp->dd_loc;
X}
X
Xstatic	void
Xfree_dircontents(dp)
X	struct	_dircontents	*dp;
X{
X	struct _dircontents	*odp;
X
X	while (dp) {
X		if (dp->_d_entry)
X			free(dp->_d_entry);
X		dp = (odp = dp)->_d_next;
X		free((char *) odp);
X	}
X}
X
Xstatic	char	*
Xgetdirent(dir)
X	char	*dir;
X{
X	if (dir != (char *) NULL) {		/* get first entry */
X		reg.h.ah = DOSI_FINDF;
X		reg.h.cl = ATTRIBUTES;
X#if	defined(M_I86LM)
X		reg.x.dx = FP_OFF(dir);
X		sreg.ds = FP_SEG(dir);
X#else
X		reg.x.dx = (unsigned) dir;
X#endif
X	} else {				/* get next entry */
X		reg.h.ah = DOSI_FINDN;
X#if	defined(M_I86LM)
X		reg.x.dx = FP_OFF(dtapnt);
X		sreg.ds = FP_SEG(dtapnt);
X#else
X		reg.x.dx = (unsigned) dtapnt;
X#endif
X	}
X#if	defined(M_I86LM)
X	intdosx(&reg, &nreg, &sreg);
X#else
X	intdos(&reg, &nreg);
X#endif
X	if (nreg.x.cflag)
X		return (char *) NULL;
X
X	return dtabuf.d_name;
X}
X
Xstatic	void
Xsetdta()
X{
X	reg.h.ah = DOSI_SDTA;
X#if	defined(M_I86LM)
X	reg.x.dx = FP_OFF(dtapnt);
X	sreg.ds = FP_SEG(dtapnt);
X	intdosx(&reg, &nreg, &sreg);
X#else
X	reg.x.dx = (int) dtapnt;
X	intdos(&reg, &nreg);
X#endif
X}
SHAR_EOF
chmod 0644 MSD_DIR.C || echo "restore of MSD_DIR.C fails"
echo "x - extracting MSD_DIR.H (Text)"
sed 's/^X//' << 'SHAR_EOF' > MSD_DIR.H &&
X/*
X * @(#)msd_dir.h 1.4 87/11/06	Public Domain.
X *
X *  A public domain implementation of BSD directory routines for
X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
X *  August 1897
X */
X
X#define	rewinddir(dirp)	seekdir(dirp, 0L)
X
X#define	MAXNAMLEN	12
X
Xstruct direct {
X	ino_t	d_ino;			/* a bit of a farce */
X	int	d_reclen;		/* more farce */
X	int	d_namlen;		/* length of d_name */
X	char	d_name[MAXNAMLEN + 1];		/* garentee null termination */
X};
X
Xstruct _dircontents {
X	char	*_d_entry;
X	struct _dircontents	*_d_next;
X};
X
Xtypedef struct _dirdesc {
X	int		dd_id;	/* uniquely identify each open directory */
X	long		dd_loc;	/* where we are in directory entry is this */
X	struct _dircontents	*dd_contents;	/* pointer to contents of dir */
X	struct _dircontents	*dd_cp;	/* pointer to current position */
X} DIR;
X
Xextern	DIR		*opendir();
Xextern	struct direct	*readdir();
Xextern	void		seekdir();
Xextern	long		telldir();
Xextern	void		closedir();
SHAR_EOF
chmod 0644 MSD_DIR.H || echo "restore of MSD_DIR.H fails"
echo "x - extracting NAMES.C (Text)"
sed 's/^X//' << 'SHAR_EOF' > NAMES.C &&
X/*
X
X	Copyright (C) 1988 Free Software Foundation
X
XGNU tar is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
SHAR_EOF
echo "End of part 3"
echo "File NAMES.C is continued in part 4"
echo "4" > s2_seq_.tmp
exit 0