summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/date/Makefile4
-rw-r--r--bin/date/date.160
-rw-r--r--bin/date/date.c28
-rw-r--r--bin/date/vary.c337
-rw-r--r--bin/date/vary.h9
5 files changed, 430 insertions, 8 deletions
diff --git a/bin/date/Makefile b/bin/date/Makefile
index 294aae0..ed2bf8f 100644
--- a/bin/date/Makefile
+++ b/bin/date/Makefile
@@ -1,8 +1,8 @@
# @(#)Makefile 8.1 (Berkeley) 5/31/93
-# $Id$
+# $Id: Makefile,v 1.4 1997/02/22 14:02:30 peter Exp $
PROG= date
-SRCS= date.c netdate.c
+SRCS= date.c netdate.c vary.c
DPADD= ${LIBUTIL}
LDADD= -lutil
diff --git a/bin/date/date.1 b/bin/date/date.1
index 9d02c09..7e8bf48 100644
--- a/bin/date/date.1
+++ b/bin/date/date.1
@@ -33,7 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
-.\" $Id: date.1,v 1.11 1997/02/22 14:02:31 peter Exp $
+.\" $Id: date.1,v 1.12 1997/04/16 05:59:20 danny Exp $
.\"
.Dd November 17, 1993
.Dt DATE 1
@@ -48,7 +48,8 @@
.Op Fl t Ar minutes_west
.Op Fl nu
.Op Cm + Ns Ar format
-.Op [yy[mm[dd[hh]]]]mm[\&.ss]
+.Op Fl DWMY Ar [+|-]val
+.Op [[[[yy]mm]dd]hh]mm[\&.ss]
.Sh DESCRIPTION
.Nm
displays the current date and time when invoked without arguments.
@@ -97,6 +98,27 @@ by future calls to
Display or set the date in
.Tn UCT
(universal) time.
+.It Fl DWMY
+Adjust the month day, week day, month or year according to
+.Ar val .
+If
+.Ar val
+is preceeded with a plus or minus sign, the date is adjusted forwards
+or backwards according to the remaining string, otherwise the relevent
+part of the date is set. The date can be adjusted as many times as
+required using these flags. Flags are processed in the order given.
+.Pp
+Month days are in the range 1-31, week days are in the range 0-6
+(sun-sat), months are in the range 1-12 (jan-dec) and years are in
+the range 80-38 or 1980-2038.
+.Pp
+The week day or month may be specified using a name rather than a
+number. If a name is used with the plus (or minus) sign, the date
+will be put forwards (or backwards) to the next (previous) date that
+matches the given week day or month. This will not adjust the date
+if the given week day or month is the same as the current one.
+.Pp
+Refer to the examples below for further details.
.El
.Pp
An operand with a leading plus (``+'') sign signals a user-defined format
@@ -150,6 +172,40 @@ TIME: 13:36:16
.Pp
The command:
.Bd -literal -offset indent
+date -M1 -Y+1
+.Ed
+.Pp
+will display:
+.Bd -literal -offset indent
+Sun Jan 4 03:15:24 GMT 1998
+.Ed
+.Pp
+(where it is currently Mon Aug 4 04:15:24 BST 1997).
+.Pp
+The command:
+.Bd -literal -offset indent
+date -D1 -M3 -Y0 -D-1
+.Ed
+.Pp
+will display the last day of February in the year 2000:
+.Bd -literal -offset indent
+Tue Feb 29 03:18:00 GMT 2000
+.Ed
+.Pp
+The command:
+.Bd -literal -offset indent
+date -D1 -M+1 -D-1 -W-fri
+.Ed
+.Pp
+will display the last friday of the month:
+.Bd -literal -offset indent
+Fri Aug 29 04:31:11 BST 1997
+.Ed
+.Pp
+(where it is currently Mon Aug 4 04:31:11 BST 1997).
+.Pp
+The command:
+.Bd -literal -offset indent
date 8506131627
.Ed
.Pp
diff --git a/bin/date/date.c b/bin/date/date.c
index 8d95bda..ad9ffca 100644
--- a/bin/date/date.c
+++ b/bin/date/date.c
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: date.c,v 1.12 1997/04/16 05:59:21 danny Exp $
+ * $Id: date.c,v 1.13 1997/06/06 06:34:37 charnier Exp $
*/
#ifndef lint
@@ -57,6 +57,7 @@ static char const sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
#include <locale.h>
#include "extern.h"
+#include "vary.h"
time_t tval;
int retval, nflag;
@@ -79,12 +80,16 @@ main(argc, argv)
char *format, buf[1024];
char *endptr;
int set_timezone;
+ struct vary *v;
+ const struct vary *badv;
+ struct tm lt;
+ v = NULL;
(void) setlocale(LC_TIME, "");
tz.tz_dsttime = tz.tz_minuteswest = 0;
rflag = 0;
set_timezone = 0;
- while ((ch = getopt(argc, argv, "d:nr:ut:")) != -1)
+ while ((ch = getopt(argc, argv, "D:W:M:Y:d:nr:ut:")) != -1)
switch((char)ch) {
case 'd': /* daylight savings time */
tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;
@@ -109,6 +114,12 @@ main(argc, argv)
usage();
set_timezone = 1;
break;
+ case 'D':
+ case 'W':
+ case 'M':
+ case 'Y':
+ v = vary_append(v, ch, optarg);
+ break;
default:
usage();
}
@@ -141,7 +152,16 @@ main(argc, argv)
if (*argv && **argv == '+')
format = *argv + 1;
- (void)strftime(buf, sizeof(buf), format, localtime(&tval));
+ lt = *localtime(&tval);
+ badv = vary_apply(v, &lt);
+ if (badv) {
+ fprintf(stderr, "-%c %s: Cannot apply date adjustment\n",
+ badv->flag, badv->arg);
+ vary_destroy(v);
+ usage();
+ }
+ vary_destroy(v);
+ (void)strftime(buf, sizeof(buf), format, &lt);
(void)printf("%s\n", buf);
exit(retval);
}
@@ -239,6 +259,6 @@ usage()
{
(void)fprintf(stderr, "%s\n%s\n",
"usage: date [-nu] [-d dst] [-r seconds] [-t west] [+format]",
- " [yy[mm[dd[hh]]]]mm[.ss]]");
+ " [-DWMY [+|-]val] [[[[yy]mm]dd]HH]MM[.ss]]");
exit(1);
}
diff --git a/bin/date/vary.c b/bin/date/vary.c
new file mode 100644
index 0000000..5df3a0c
--- /dev/null
+++ b/bin/date/vary.c
@@ -0,0 +1,337 @@
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include "vary.h"
+
+struct trans {
+ int val;
+ char *str;
+};
+
+static struct trans trans_mon[] = {
+ { 1, "jan" }, { 2, "feb" }, { 3, "mar" }, { 4, "apr" }, { 5, "may" },
+ { 6, "jun" }, { 7, "jul" }, { 8, "aug" }, { 9, "sep" }, { 10, "oct" },
+ { 11, "nov" }, { 12, "dec" },
+ { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
+ { 6, "june" }, { 7, "july" }, { 8, "august" }, { 9, "september" },
+ { 10, "october" }, { 11, "november" }, { 12, "december" },
+ { -1, NULL }
+};
+
+static struct trans trans_wday[] = {
+ { 0, "sun" }, { 1, "mon" }, { 2, "tue" }, { 3, "wed" }, { 4, "thr" },
+ { 4, "thu" }, { 5, "fri" }, { 6, "sat" },
+ { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
+ { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
+ { -1, NULL }
+};
+
+static char digits[] = "0123456789";
+
+static int
+trans(const struct trans t[], const char *arg)
+{
+ int f;
+
+ if (strspn(arg, digits) == strlen(arg))
+ return atoi(arg);
+
+ for (f = 0; t[f].val != -1; f++)
+ if (!strcasecmp(t[f].str, arg))
+ return t[f].val;
+
+ return -1;
+}
+
+struct vary *
+vary_append(struct vary *v, char flag, char *arg)
+{
+ struct vary *result, **nextp;
+
+ if (!strchr("DWMY", flag))
+ return 0;
+
+ if (v) {
+ result = v;
+ while (v->next)
+ v = v->next;
+ nextp = &v->next;
+ } else
+ nextp = &result;
+
+ *nextp = (struct vary *)malloc(sizeof(struct vary));
+ (*nextp)->flag = flag;
+ (*nextp)->arg = arg;
+ (*nextp)->next = NULL;
+ return result;
+}
+
+static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static int
+daysinmonth(const struct tm *t)
+{
+ int year;
+
+ year = t->tm_year + 1900;
+
+ if (t->tm_mon == 1)
+ if (!(year % 400))
+ return 29;
+ else if (!(year % 100))
+ return 28;
+ else if (!(year % 4))
+ return 29;
+ else
+ return 28;
+ else if (t->tm_mon >= 0 && t->tm_mon < 12)
+ return mdays[t->tm_mon];
+
+ return 0;
+}
+
+
+static int
+adjyear(struct tm *t, char type, int val)
+{
+ switch (type) {
+ case '+':
+ t->tm_year += val;
+ break;
+ case '-':
+ t->tm_year -= val;
+ break;
+ default:
+ t->tm_year = val;
+ if (t->tm_year < 69)
+ t->tm_year += 100; /* as per date.c */
+ else if (t->tm_year > 1900)
+ t->tm_year -= 1900; /* struct tm holds years since 1900 */
+ break;
+ }
+ return mktime(t) != -1;
+}
+
+static int
+sadjyear(struct tm *t, char *arg)
+{
+ switch (*arg) {
+ case '+':
+ case '-':
+ return adjyear(t, *arg, atoi(arg+1));
+ default:
+ return adjyear(t, '\0', atoi(arg));
+ }
+}
+
+static int
+adjmon(struct tm *t, char type, int val, int istext)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (istext)
+ if (val <= t->tm_mon)
+ val += 11 - t->tm_mon; /* early next year */
+ else
+ val -= t->tm_mon + 1; /* later this year */
+ if (!adjyear(t, '+', (t->tm_mon + val) / 12))
+ return 0;
+ val %= 12;
+ t->tm_mon += val;
+ if (t->tm_mon > 11)
+ t->tm_mon -= 12;
+ break;
+
+ case '-':
+ if (istext)
+ if (val-1 > t->tm_mon)
+ val = 13 - val + t->tm_mon; /* later last year */
+ else
+ val = t->tm_mon - val + 1; /* early this year */
+ if (!adjyear(t, '-', val / 12))
+ return 0;
+ val %= 12;
+ if (val > t->tm_mon) {
+ if (!adjyear(t, '-', 1))
+ return 0;
+ val -= 12;
+ }
+ t->tm_mon -= val;
+ break;
+
+ default:
+ if (val > 12 || val < 1)
+ return 0;
+ t->tm_mon = --val;
+ }
+
+ return mktime(t) != -1;
+}
+
+static int
+sadjmon(struct tm *t, char *arg)
+{
+ int istext;
+ int val;
+
+ switch (*arg) {
+ case '+':
+ case '-':
+ istext = strspn(arg+1, digits) != strlen(arg+1);
+ val = trans(trans_mon, arg+1);
+ return adjmon(t, *arg, val, istext);
+ default:
+ istext = strspn(arg, digits) != strlen(arg);
+ val = trans(trans_mon, arg);
+ return adjmon(t, '\0', val, istext);
+ }
+}
+
+static int
+adjday(struct tm *t, char type, int val)
+{
+ int mdays;
+ switch (type) {
+ case '+':
+ while (val) {
+ mdays = daysinmonth(t);
+ if (val > mdays - t->tm_mday) {
+ val -= mdays - t->tm_mday + 1;
+ t->tm_mday = 1;
+ if (!adjmon(t, '+', 1, 0))
+ return 0;
+ } else {
+ t->tm_mday += val;
+ val = 0;
+ }
+ }
+ break;
+ case '-':
+ while (val)
+ if (val >= t->tm_mday) {
+ val -= t->tm_mday;
+ t->tm_mday = 1;
+ if (!adjmon(t, '-', 1, 0))
+ return 0;
+ t->tm_mday = daysinmonth(t);
+ } else {
+ t->tm_mday -= val;
+ val = 0;
+ }
+ break;
+ default:
+ if (val > 0 && val <= daysinmonth(t))
+ t->tm_mday = val;
+ else
+ return 0;
+ break;
+ }
+
+ return mktime(t) != -1;
+}
+
+static int
+sadjwday(struct tm *t, char *arg)
+{
+ int istext;
+ int val;
+
+ switch (*arg) {
+ case '+':
+ case '-':
+ istext = strspn(arg+1, digits) != strlen(arg+1);
+ val = trans(trans_wday, arg+1);
+ break;
+ default:
+ istext = 0;
+ val = trans(trans_wday, arg);
+ break;
+ }
+
+ if (val < 0)
+ return 0;
+
+ switch (*arg) {
+ case '+':
+ if (istext)
+ if (val < t->tm_wday)
+ val = 7 - t->tm_wday + val; /* early next week */
+ else
+ val -= t->tm_wday; /* later this week */
+ else
+ val *= 7; /* "-W +5" == "5 weeks in the future" */
+ return adjday(t, '+', val);
+ case '-':
+ if (istext)
+ if (val > t->tm_wday)
+ val = 7 - val + t->tm_wday; /* later last week */
+ else
+ val = t->tm_wday - val; /* early this week */
+ else
+ val *= 7; /* "-W -5" == "5 weeks ago" */
+ return adjday(t, '-', val);
+ default:
+ if (val < t->tm_wday)
+ return adjday(t, '-', t->tm_wday - val);
+ else if (val > 6)
+ return 0;
+ else if (val > t->tm_wday)
+ return adjday(t, '+', val - t->tm_wday);
+ }
+ return 1;
+}
+
+static int
+sadjday(struct tm *t, char *arg)
+{
+ switch (*arg) {
+ case '+':
+ case '-':
+ return adjday(t, *arg, atoi(arg+1));
+ default:
+ return adjday(t, '\0', atoi(arg));
+ }
+}
+
+const struct vary *
+vary_apply(const struct vary *v, struct tm *t)
+{
+ for (; v; v = v->next) {
+ switch (v->flag) {
+ case 'D':
+ if (!sadjday(t, v->arg))
+ return v;
+ break;
+ case 'W':
+ if (!sadjwday(t, v->arg))
+ return v;
+ break;
+ case 'M':
+ if (!sadjmon(t, v->arg))
+ return v;
+ break;
+ case 'Y':
+ if (!sadjyear(t, v->arg))
+ return v;
+ break;
+ default:
+ return v;
+ }
+ }
+ return 0;
+}
+
+void
+vary_destroy(struct vary *v)
+{
+ struct vary *n;
+
+ while (v) {
+ n = v->next;
+ free(v);
+ v = n;
+ }
+}
diff --git a/bin/date/vary.h b/bin/date/vary.h
new file mode 100644
index 0000000..146706f
--- /dev/null
+++ b/bin/date/vary.h
@@ -0,0 +1,9 @@
+struct vary {
+ char flag;
+ char *arg;
+ struct vary *next;
+};
+
+extern struct vary *vary_append(struct vary *v, char flag, char *arg);
+extern const struct vary *vary_apply(const struct vary *v, struct tm *t);
+extern void vary_destroy(struct vary *v);
OpenPOWER on IntegriCloud