/*
* 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);
}
|