Plan 9 from Bell Labs’s /usr/web/sources/contrib/arisawa/cdate/cdate.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
*	cdate: convert date format
*	usage: cdate [-n] date
*	usage: cdate -k key1,key2,... [file]
*	key1,key2,... are fields that begin with 0
*
*	kenji Arisawa
*/

#include <u.h>
#include <libc.h>
#include <bio.h>
#define gline() Brdstr(&in, '\n', 1)
#define atoul(s) ((ulong)atol(s))
#define MFIELD 32

Biobuf	in;
Biobuf	out;

ulong now;
char *zone;

int nflag=0;

char *mon[12] = {
	"Jan",
	"Feb",
	"Mar",
	"Apr",
	"May",
	"Jun",
	"Jul",
	"Aug",
	"Sep",
	"Oct",
	"Nov",
	"Dec",
};

void
usage(void)
{
	fprint(2,"usage: cdate [-n] ....\n");
	fprint(2,"usage: cdate -k key1,key2,... [file]\n");
	exits("usage");
}

int
smatch(char *s, char *p)
{
	char *digit="0123456789";
	char *s0;
	s0 = s;
	while(*s && *p){
		if((*p == '0' && strchr(digit,*s))|| *s == *p){
			p++; s++;
			continue;
		}
		break;
	}
	if(*s)
		return 0;
	return s - s0;
}


int
mon2int(char *m)
{
	int i;
	for(i=0; i < 12; i++)
		if(strcmp(m, mon[i]) == 0)
			break;
	if(i == 12)
		return 0;
	return i+1;
}

char *
datefmt(ulong t)
{
	static char buf[48];
	Tm *tm;

	if(nflag){
		snprint(buf,sizeof buf, "%lud", t);
		return buf;
	}
	tm = localtime(t);
	snprint(buf,sizeof buf,"%04d/%02d/%02d %02d:%02d:%02d",
		tm->year + 1900,tm->mon + 1,tm->mday, tm->hour, tm->min, tm->sec);
	return buf;
}

/*
*	note: atoi("08") returns 0
*	therefore we should have a2i()
*/
int
a2i(char *s)
{
	while(*s == '0')
		s++;
	return atoi(s);
}


/* d2n convert:
*	"2005/02/08 14:31:49" to 1107840709
*	"2005/02/08 14:31" to 1107840660
*	"2005/02/08" to 1107788400
*	"1107840709" to 1107840709
*/
long
d2n(char *s)
{
	Tm tm;
	char *args[2], *d[3], *t[3];
	int na,nd,nt;
	na = getfields(s,args,2,1," ");
	if(na == 0)
		usage();
	nd = getfields(args[0],d,3,1,"/");
	if(nd == 1)
		return atol(args[0]);
	if(nd != 3)
		usage();
	tm.year = a2i(d[0]) - 1900;
	tm.mon = a2i(d[1]) - 1;
	tm.mday = a2i(d[2]);
	tm.hour = tm.min = tm.sec = 0;
	nt = getfields(args[1],t,3,1,":");
	if(nt == 1)
		usage();
	if(nt > 1){
		tm.hour = a2i(t[0]);
		tm.min = a2i(t[1]);
	}
	if(nt ==3)
		tm.sec = a2i(t[2]);

	strcpy(tm.zone,zone);
	/* manual says:
    *     Tm2sec converts a broken-down time to seconds since the
    *     start of the epoch.  It ignores wday, and assumes the local
    *     time zone if zone is not GMT.
	*  However
	*		tm.zone[0] = 0
	*  does not work for local time zone.
	*  it seems tm.zone must be explicitly given	*/
	return tm2sec(&tm);
}

void
pndate(char **argv, int argc)
{
	Tm *tm;
	int m,n,d;
	char *mday,*other;
	char buf[32];

	if(argc == 0)
		usage();
	if(smatch(argv[0],"0000000000") == 10){
		if(nflag)
			print("%s\n", argv[0]);
		else
			print("%s\n",datefmt(atol(argv[0])));
		return;
	}
	if(smatch(argv[0],"0000/00/00") == 10){
		if(argc == 1)
			snprint(buf, sizeof buf,"%s 00:00:00", argv[0]);
		else if(argc == 2){
			n = smatch(argv[1],"00:00:00");
			if(n == 2)
				snprint(buf, sizeof buf,"%s %s:00:00", argv[0],argv[1]);
			else if(n == 5)
				snprint(buf, sizeof buf,"%s %s:00", argv[0],argv[1]);
			else if(n == 8)
				snprint(buf, sizeof buf,"%s %s", argv[0],argv[1]);
			else
				usage();
		}
	}
	else{
		/*	Hera we treat the types:
		*	Nov  8 08:25	-> 2004/10/08 08:25:00 	# 180 days past
		*	Jul 19  2002	-> 2002/07/19 00:00:00
		*/

		now = time(0);
		tm = localtime(now);
		m = mon2int(argv[0]);
		if(m == 0 || argc != 3)
			usage();
		if((smatch(argv[1],"0") != 1) && (smatch(argv[1],"00") != 2))
			usage();
		mday = argv[1];
		d = atoi(mday);
		other = argv[2];
		if(smatch(other,"0000") == 4)
			snprint(buf, sizeof buf,"%s/%02d/%02d 00:00:00",
				other, m, d);
		else if(smatch(other,"00:00") == 5){
			if(d2n(buf) > now + 30L*24*60*60)
				snprint(buf, sizeof buf, "%d/%02d/%02d %s:00",
					tm->year + 1899, m, d, other);
			else
				snprint(buf, sizeof buf, "%d/%02d/%02d %s:00",
					tm->year + 1900, m, d, other);
		}
		else
			usage();
	}
	if(nflag)
		print("%ld\n", d2n(buf));
	else
		print("%s\n", buf);
}

char *
skipfields(char *s, int n)
{
	int i;
	for(i=0; i < n; i++){
		while(*s == ' ' || *s == '\t')
			s++;
		while(*s && *s != ' ' && *s != '\t')
			s++;
	}
	return s;
}


void
pline(char *s, int *keys, long nkeys)
{
	int i,k,n;
	char *t,c;
	c = 0;
	for(n = 0, i = 0; i < nkeys;i++){
		k = keys[i];
		if(k < n)
			continue;
		if( k > n){
			t = skipfields(s, k - n);
			c = *t;
			*t = 0;
			if(c == 0){
				Bprint(&out, "%s\n", s);
				break;
			}
			else{
				Bprint(&out, "%s%c", s,c);
				*t = c;
				s = ++t;
			}
		}
		t = skipfields(s,1);
		c = *t;
		*t = 0;
		if(c == 0){
			Bprint(&out, "%s\n", datefmt(atoul(s)));
			break;
		}
		else{
			Bprint(&out, "%s%c", datefmt(atoul(s)),c);
			*t = c;
			s = ++t;
			n = k + 1;
		}
	}
	if(c != 0)
		Bprint(&out, "%s\n",s);
}

int
compar(int *x, int *y)
{
	//print("%d %d\n", *x, *y);
	if(*x > *y)
		return 1;
	if(*x < *y)
		return -1;
	return 0;
}

void
main(int argc, char *argv[])
{	char *key=nil;
	char *s,c,*file;
	int fd,k,n;
	long nkeys;
	int keys[MFIELD];
	ARGBEGIN{
	case 'k':	key=ARGF();
		if(key==nil) usage();
		break;
	case 'n':	nflag = 1; break;
	default: usage();
	}ARGEND

	zone=getenv("timezone");
	if(zone == nil)
		sysfatal("# getenv: %r");
	strdup(zone);
	zone[3] = 0;

	if(key==nil){
		if(*argv == nil)
			print("%s\n", datefmt(time(0)));
		else
			pndate(argv, argc);
		exits(nil);
	}

	for(n = 0;;){
		for(s = key; *s && *s != ','; s++);
		c = *s;
		if(*s == ',')
			*s = 0;
		k=atoi(key);
		if(n == MFIELD)
			sysfatal("# error: keys exceed limit %d", MFIELD);
		keys[n++] = k;
		if(c == 0)
			break;
		key = ++s;
	}
	nkeys = n;
	qsort(keys, nkeys, sizeof keys[0], (int (*)(void*, void*))compar);

	file = *argv++;
	if(file && *argv != nil)
		usage();
	fd = 0;
	if(file){
		fd = open(file, OREAD);
		if(fd < 0)
			sysfatal("# cannot open %s: %r\n", *argv);
	}

	Binit(&in, fd, OREAD);
	Binit(&out, 1, OWRITE);

	while((s = gline()))
		pline(s,keys,nkeys);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.