Add proper d- and t-flag support to touch(1)

except the [,frac], [.frac] respectively, but that's ok.
This commit is contained in:
FRIGN 2015-02-19 18:54:56 +01:00
parent c2b400bbd8
commit b00a00703f
3 changed files with 89 additions and 17 deletions

2
README
View File

@ -73,7 +73,7 @@ The following tools are implemented ('*' == finished, '#' == UTF-8 support,
=* tar non-posix none =* tar non-posix none
=* tee yes none =* tee yes none
#* test yes none #* test yes none
=* touch yes none (-d) (-t) =* touch yes none
#* tr yes none #* tr yes none
=* true yes none =* true yes none
=* tty yes none =* tty yes none

41
touch.1
View File

@ -1,4 +1,4 @@
.Dd February 19, 2015 .Dd February 9, 2015
.Dt TOUCH 1 .Dt TOUCH 1
.Os sbase .Os sbase
.Sh NAME .Sh NAME
@ -7,11 +7,11 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl acm .Op Fl acm
.Op Fl r Ar ref_file | Fl t Ar timestamp .Op Fl d Ar time | Fl r Ar ref_file | Fl T Ar time | Fl t Ar time
.Ar file ... .Ar file ...
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
sets the access or modification time of each sets the access and modification time of each
.Ar file .Ar file
to the current time of day. If to the current time of day. If
.Ar file .Ar file
@ -25,19 +25,30 @@ Set the access | modification time of
Don't create Don't create
.Ar file .Ar file
if it doesn't exist, not affecting exit status. if it doesn't exist, not affecting exit status.
.It Fl d Ar time
Set the
.Ar time
of the format YYYY-MM-DDThh:mm:SS[Z] used for
.Op Fl am .
.It Fl r Ar ref_file .It Fl r Ar ref_file
Set the timestamp Set the
to be used with .Ar time
used for
.Op Fl am .Op Fl am
to the modification time of to the modification time of
.Ar ref_file . .Ar ref_file .
.It Fl t Ar timestamp .It Fl T Ar time
Set the Set the
.Ar timestamp .Ar time
to be used with used for
.Op Fl am .Op Fl am
given as the number of seconds since the given as the number of seconds since the
Unix epoch 1970-01-01T00:00:00Z. Unix epoch 1970-01-01T00:00:00Z.
.It Fl t Ar time
Set the
.Ar time
of the format [[CC]YY]MMDDhhmm[.SS] used for
.Op Fl am .
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr date 1 .Xr date 1
@ -46,10 +57,10 @@ The
.Nm .Nm
utility is compliant with the utility is compliant with the
.St -p1003.1-2008 .St -p1003.1-2008
specification except for specification, except from fractional seconds in the
.Fl d .Op Fl d
and the argument.
.Ar timestamp .Pp
format of the The
.Fl t .Op Fl T
flag. flag is an extension to this specification.

63
touch.c
View File

@ -4,6 +4,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <utime.h> #include <utime.h>
@ -43,6 +44,61 @@ touch(const char *file)
touch(file); touch(file);
} }
time_t
parsetime(char *str, time_t current)
{
struct tm *cur, t;
char *format;
size_t len = strlen(str);
cur = localtime(&current);
t.tm_isdst = -1;
switch (len) {
/* -t flag argument */
case 8:
t.tm_sec = 0;
t.tm_year = cur->tm_year;
format = "%m%d%H%M";
break;
case 10:
t.tm_sec = 0;
format = "%y%m%d%H%M";
break;
case 11:
t.tm_year = cur->tm_year;
format = "%m%d%H%M.%S";
break;
case 12:
t.tm_sec = 0;
format = "%Y%m%d%H%M";
break;
case 13:
format = "%y%m%d%H%M.%S";
break;
case 15:
format = "%Y%m%d%H%M.%S";
break;
/* -d flag argument */
case 19:
format = "%Y-%m-%dT%H:%M:%S";
break;
case 20:
/* only Zulu-timezone supported */
if (str[19] != 'Z')
goto default;
format = "%Y-%m-%dT%H:%M:%S%Z";
break;
default:
eprintf("Invalid date format length\n", str);
}
if (!strptime(str, format, &t))
weprintf("strptime %s: Invalid date format\n", str);
return mktime(&t);
}
static void static void
usage(void) usage(void)
{ {
@ -72,15 +128,20 @@ main(int argc, char *argv[])
eprintf("stat '%s':", ref); eprintf("stat '%s':", ref);
t = st.st_mtime; t = st.st_mtime;
break; break;
case 't': case 'T':
t = estrtonum(EARGF(usage()), 0, LLONG_MAX); t = estrtonum(EARGF(usage()), 0, LLONG_MAX);
break; break;
case 't':
t = parsetime(EARGF(usage()), t);
break;
default: default:
usage(); usage();
} ARGEND; } ARGEND;
if (argc < 1) if (argc < 1)
usage(); usage();
if (!aflag && !mflag)
aflag = mflag = 1;
for (; argc > 0; argc--, argv++) for (; argc > 0; argc--, argv++)
touch(argv[0]); touch(argv[0]);