From c8af480f52b46e556d23ef012f3987aa3a0fc25b Mon Sep 17 00:00:00 2001
From: Lukas Fleischer <calcurse@cryptocrack.de>
Date: Tue, 11 Jan 2011 22:10:48 +0000
Subject: Make parse_date accept several short forms.

Short forms are only accepted in interactive mode (e.g. when using the
"Go to" function, editing a recurrent item's end date, and so on).

Samples: "1/1/30" for "01/01/2030", "26" for the 26th of the currently
selected month/year or "3/1" for Mar 01 (or Jan 03, depending on the
date format) of the currently selected year.
---
 src/args.c     |   6 ++--
 src/calcurse.h |   5 +--
 src/calendar.c |   9 ++---
 src/day.c      |   4 +--
 src/recur.c    |   4 +--
 src/utils.c    | 101 ++++++++++++++++++++++++++++++++++-----------------------
 6 files changed, 73 insertions(+), 56 deletions(-)

(limited to 'src')

diff --git a/src/args.c b/src/args.c
index 1f4bd0e..f2c3361 100755
--- a/src/args.c
+++ b/src/args.c
@@ -1,4 +1,4 @@
-/*	$calcurse: args.c,v 1.63 2010/05/26 18:18:28 culot Exp $	*/
+/*	$calcurse: args.c,v 1.64 2011/01/11 22:10:48 fleischer Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -578,7 +578,7 @@ date_arg (char *ddate, int add_line, int print_note, struct conf *conf,
   else
     {				/* a date was entered */
       if (parse_date (ddate, conf->input_datefmt, (int *)&day.yyyy,
-                      (int *)&day.mm, (int *)&day.dd))
+                      (int *)&day.mm, (int *)&day.dd, NULL))
 	{
 	  app_found = app_arg (add_line, &day, 0, print_note, conf, regex);
 	}
@@ -630,7 +630,7 @@ date_arg_extended (char *startday, char *range, int add_line, int print_note,
   if (startday != NULL)
     {
       if (parse_date (startday, conf->input_datefmt, (int *)&t.tm_year,
-		      (int *)&t.tm_mon, (int *)&t.tm_mday))
+		      (int *)&t.tm_mon, (int *)&t.tm_mday, NULL))
 	{
 	  t.tm_year -= 1900;
 	  t.tm_mon--;
diff --git a/src/calcurse.h b/src/calcurse.h
index b6e233c..f301b2e 100644
--- a/src/calcurse.h
+++ b/src/calcurse.h
@@ -1,4 +1,4 @@
-/*	$Id: calcurse.h,v 1.5 2010/03/22 08:16:33 culot Exp $	*/
+/*	$Id: calcurse.h,v 1.6 2011/01/11 22:10:48 fleischer Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -873,7 +873,8 @@ long         mystrtol (const char *);
 void         print_bool_option_incolor (WINDOW *, unsigned, int, int);
 char        *new_tempfile (const char *, int);
 void         erase_note (char **, enum eraseflg);
-int          parse_date (char *, enum datefmt, int *, int *, int *);
+int          parse_date (char *, enum datefmt, int *, int *, int *,
+                         struct date *);
 char        *str_toupper (char *);
 void         file_close (FILE *, const char *);
 void         psleep (unsigned);
diff --git a/src/calendar.c b/src/calendar.c
index 085a239..c5aeae8 100755
--- a/src/calendar.c
+++ b/src/calendar.c
@@ -1,4 +1,4 @@
-/*	$calcurse: calendar.c,v 1.38 2010/10/23 10:19:47 culot Exp $	*/
+/*	$calcurse: calendar.c,v 1.39 2011/01/11 22:10:48 fleischer Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -646,11 +646,8 @@ calendar_change_day (int datefmt)
 	      wrong_day = 0;
               calendar_goto_today ();
 	    }
-	  else if (strlen (selected_day) != LDAY - 1)
-	    {
-	      wrong_day = 1;
-	    }
-	  else if (parse_date (selected_day, datefmt, &dyear, &dmonth, &dday))
+	  else if (parse_date (selected_day, datefmt, &dyear, &dmonth, &dday,
+                         calendar_get_slctd_day ()))
 	    {
 	      wrong_day = 0;
 	      /* go to chosen day */
diff --git a/src/day.c b/src/day.c
index 4bcb5ec..17c2a31 100755
--- a/src/day.c
+++ b/src/day.c
@@ -1,4 +1,4 @@
-/*	$calcurse: day.c,v 1.53 2010/03/20 10:54:44 culot Exp $	*/
+/*	$calcurse: day.c,v 1.54 2011/01/11 22:10:48 fleischer Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -757,7 +757,7 @@ update_rept (struct rpt **rpt, const long start, struct conf *conf)
 	  int newmonth, newday, newyear;
 
 	  if (parse_date (timstr, conf->input_datefmt,
-			  &newyear, &newmonth, &newday))
+			  &newyear, &newmonth, &newday, calendar_get_slctd_day ()))
 	    {
 	      t = start;
 	      lt = localtime (&t);
diff --git a/src/recur.c b/src/recur.c
index 34910a4..096c961 100755
--- a/src/recur.c
+++ b/src/recur.c
@@ -1,4 +1,4 @@
-/*	$calcurse: recur.c,v 1.54 2010/03/20 10:54:47 culot Exp $	*/
+/*	$calcurse: recur.c,v 1.55 2011/01/11 22:10:48 fleischer Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -971,7 +971,7 @@ recur_repeat_item (struct conf *conf)
 	  else
 	    {
 	      if (parse_date (user_input, conf->input_datefmt,
-			      &year, &month, &day))
+			      &year, &month, &day, calendar_get_slctd_day ()))
 		{
 		  t = p->start;
 		  lt = localtime (&t);
diff --git a/src/utils.c b/src/utils.c
index 243de4c..63f3320 100755
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,4 +1,4 @@
-/*	$calcurse: utils.c,v 1.86 2010/11/04 10:55:07 fleischer Exp $	*/
+/*	$calcurse: utils.c,v 1.87 2011/01/11 22:10:48 fleischer Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -47,6 +47,8 @@
 
 #include "calcurse.h"
 
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
 /* General routine to exit calcurse properly. */
 void
 exit_calcurse (int status)
@@ -883,64 +885,81 @@ erase_note (char **note, enum eraseflg flag)
 /*
  * Convert a string containing a date into three integers containing the year,
  * month and day.
+ *
+ * If a pointer to a date structure containing the current date is passed as
+ * last parameter ("slctd_date"), the function will accept several short forms,
+ * e.g. "26" for the 26th of the current month/year or "3/1" for Mar 01 (or Jan
+ * 03, depending on the date format) of the current year. If a null pointer is
+ * passed, short forms won't be accepted at all.
+ *
  * Returns 1 if sucessfully converted or 0 if the string is an invalid date.
  */
 int
 parse_date (char *date_string, enum datefmt datefmt, int *year, int *month,
-            int *day)
+            int *day, struct date *slctd_date)
 {
-  int in1, in2, in3;
-  int lyear, lmonth, lday;
+  char sep = (datefmt == DATEFMT_ISO) ? '-' : '/';
+  char *p;
+  int in[3] = {0, 0, 0}, n = 0;
+  int d, m, y;
 
-  if (date_string == 0)
-    return 0;
+  if (!date_string) return 0;
 
-  if (datefmt == DATEFMT_ISO)
-    {
-      if (sscanf (date_string, "%d - %d - %d", &in1, &in2, &in3) < 3)
-        return 0;
+  /* parse string into in[], read up to three integers */
+  for (p = date_string; *p; p++) {
+    if (*p == sep) {
+      if ((++n) > 2) return 0;
     }
-  else
-    {
-      if (sscanf (date_string, "%d / %d / %d", &in1, &in2, &in3) < 3)
-        return 0;
+    else if ((*p >= '0') && (*p <= '9')) {
+      in[n] = in[n] * 10 + (int)(*p - '0');
     }
-  switch (datefmt)
-    {
+    else
+      return 0;
+  }
+
+  if ((!slctd_date && n < 2) || in[n] == 0) return 0;
+
+  /* convert into day, month and year, depending on the date format */
+  switch (datefmt) {
     case DATEFMT_MMDDYYYY:
-      lmonth = in1;
-      lday = in2;
-      lyear = in3;
+      m = in[n > 0 ? 0 : 1];
+      d = in[n > 0 ? 1 : 0];
+      y = in[2];
       break;
     case DATEFMT_DDMMYYYY:
-      lday = in1;
-      lmonth = in2;
-      lyear = in3;
+      d = in[0];
+      m = in[1];
+      y = in[2];
       break;
     case DATEFMT_YYYYMMDD:
-    case DATEFMT_ISO:      
-      lyear = in1;
-      lmonth = in2;
-      lday = in3;
+    case DATEFMT_ISO:
+      y = in[0];
+      m = in[n - 1];
+      d = in[n];
       break;
     default:
       return 0;
-    }
-  
-  if (lyear < 1 || lyear > 9999
-      || lmonth < 1 || lmonth > 12
-      || lday < 1 || lday > 31)
+  }
+
+  if (y > 0 && y < 100) {
+    /* convert "YY" format into "YYYY" */
+    y += slctd_date->yyyy - slctd_date->yyyy % 100;
+  }
+  else if (n < 2) {
+    /* set year and, optionally, month if short from is used */
+    y = slctd_date->yyyy;
+    if (n < 1) m = slctd_date->mm;
+  }
+
+  /* check if date is valid, take leap years into account */
+  if (y < 1902 || y > 2037 || m < 1 || m > 12 || d < 1 ||
+      d > days[m - 1] + (m == 2 && isleap (y)) ? 1 : 0)
     return 0;
-  
-  if (year != NULL)
-    *year = lyear;
-  
-  if (month != NULL)
-    *month = lmonth;
-  
-  if (day != NULL)
-    *day = lday;
-  
+
+  if (year) *year = y;
+  if (month) *month = m;
+  if (day) *day = d;
+
   return 1;
 }
 
-- 
cgit v1.2.3-70-g09d2