xref: /freebsd-src/contrib/dialog/calendar.c (revision a96ef4501919d7ac08e94e98dc34b0bdd744802b)
14c8945a0SNathan Whitehorn /*
2*a96ef450SBaptiste Daroussin  * $Id: calendar.c,v 1.106 2020/11/23 09:03:49 tom Exp $
34c8945a0SNathan Whitehorn  *
44c8945a0SNathan Whitehorn  *  calendar.c -- implements the calendar box
54c8945a0SNathan Whitehorn  *
6*a96ef450SBaptiste Daroussin  *  Copyright 2001-2019,2020	Thomas E. Dickey
74c8945a0SNathan Whitehorn  *
84c8945a0SNathan Whitehorn  *  This program is free software; you can redistribute it and/or modify
94c8945a0SNathan Whitehorn  *  it under the terms of the GNU Lesser General Public License, version 2.1
104c8945a0SNathan Whitehorn  *  as published by the Free Software Foundation.
114c8945a0SNathan Whitehorn  *
124c8945a0SNathan Whitehorn  *  This program is distributed in the hope that it will be useful, but
134c8945a0SNathan Whitehorn  *  WITHOUT ANY WARRANTY; without even the implied warranty of
144c8945a0SNathan Whitehorn  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
154c8945a0SNathan Whitehorn  *  Lesser General Public License for more details.
164c8945a0SNathan Whitehorn  *
174c8945a0SNathan Whitehorn  *  You should have received a copy of the GNU Lesser General Public
184c8945a0SNathan Whitehorn  *  License along with this program; if not, write to
194c8945a0SNathan Whitehorn  *	Free Software Foundation, Inc.
204c8945a0SNathan Whitehorn  *	51 Franklin St., Fifth Floor
214c8945a0SNathan Whitehorn  *	Boston, MA 02110, USA.
224c8945a0SNathan Whitehorn  */
234c8945a0SNathan Whitehorn 
24*a96ef450SBaptiste Daroussin #include <dlg_internals.h>
254c8945a0SNathan Whitehorn #include <dlg_keys.h>
264c8945a0SNathan Whitehorn 
274c8945a0SNathan Whitehorn #include <time.h>
284c8945a0SNathan Whitehorn 
29f4f33ea0SBaptiste Daroussin #ifdef HAVE_STDINT_H
30f4f33ea0SBaptiste Daroussin #include <stdint.h>
31f4f33ea0SBaptiste Daroussin #else
32f4f33ea0SBaptiste Daroussin #define intptr_t long
33f4f33ea0SBaptiste Daroussin #endif
34f4f33ea0SBaptiste Daroussin 
354c8945a0SNathan Whitehorn #define ONE_DAY  (60 * 60 * 24)
364c8945a0SNathan Whitehorn 
374c8945a0SNathan Whitehorn #define MON_WIDE 4		/* width of a month-name */
384c8945a0SNathan Whitehorn #define DAY_HIGH 6		/* maximum lines in day-grid */
394c8945a0SNathan Whitehorn #define DAY_WIDE (8 * MON_WIDE)	/* width of the day-grid */
404c8945a0SNathan Whitehorn #define HDR_HIGH 1		/* height of cells with month/year */
414c8945a0SNathan Whitehorn #define BTN_HIGH 1		/* height of button-row excluding margin */
424c8945a0SNathan Whitehorn 
434c8945a0SNathan Whitehorn /* two more lines: titles for day-of-week and month/year boxes */
44f4f33ea0SBaptiste Daroussin #define MIN_HIGH (DAY_HIGH + 2 + HDR_HIGH + BTN_HIGH + (MAX_DAYS * MARGIN))
454c8945a0SNathan Whitehorn #define MIN_WIDE (DAY_WIDE + (4 * MARGIN))
464c8945a0SNathan Whitehorn 
474c8945a0SNathan Whitehorn typedef enum {
484c8945a0SNathan Whitehorn     sMONTH = -3
494c8945a0SNathan Whitehorn     ,sYEAR = -2
504c8945a0SNathan Whitehorn     ,sDAY = -1
514c8945a0SNathan Whitehorn } STATES;
524c8945a0SNathan Whitehorn 
534c8945a0SNathan Whitehorn struct _box;
544c8945a0SNathan Whitehorn 
554c8945a0SNathan Whitehorn typedef int (*BOX_DRAW) (struct _box *, struct tm *);
564c8945a0SNathan Whitehorn 
574c8945a0SNathan Whitehorn typedef struct _box {
584c8945a0SNathan Whitehorn     WINDOW *parent;
594c8945a0SNathan Whitehorn     WINDOW *window;
604c8945a0SNathan Whitehorn     int x;
614c8945a0SNathan Whitehorn     int y;
624c8945a0SNathan Whitehorn     int width;
634c8945a0SNathan Whitehorn     int height;
644c8945a0SNathan Whitehorn     BOX_DRAW box_draw;
65f4f33ea0SBaptiste Daroussin     int week_start;
664c8945a0SNathan Whitehorn } BOX;
674c8945a0SNathan Whitehorn 
68f4f33ea0SBaptiste Daroussin #define MAX_DAYS 7
69f4f33ea0SBaptiste Daroussin #define MAX_MONTHS 12
70f4f33ea0SBaptiste Daroussin 
71f4f33ea0SBaptiste Daroussin static char *cached_days[MAX_DAYS];
72f4f33ea0SBaptiste Daroussin static char *cached_months[MAX_MONTHS];
73f4f33ea0SBaptiste Daroussin 
744c8945a0SNathan Whitehorn static const char *
nameOfDayOfWeek(int n)754c8945a0SNathan Whitehorn nameOfDayOfWeek(int n)
764c8945a0SNathan Whitehorn {
77f4f33ea0SBaptiste Daroussin     static bool shown[MAX_DAYS];
784c8945a0SNathan Whitehorn 
79f4f33ea0SBaptiste Daroussin     while (n < 0) {
80f4f33ea0SBaptiste Daroussin 	n += MAX_DAYS;
81f4f33ea0SBaptiste Daroussin     }
82f4f33ea0SBaptiste Daroussin     n %= MAX_DAYS;
834c8945a0SNathan Whitehorn #ifdef ENABLE_NLS
84f4f33ea0SBaptiste Daroussin     if (cached_days[n] == 0) {
85f4f33ea0SBaptiste Daroussin 	const nl_item items[MAX_DAYS] =
864c8945a0SNathan Whitehorn 	{
874c8945a0SNathan Whitehorn 	    ABDAY_1, ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7
884c8945a0SNathan Whitehorn 	};
89f4f33ea0SBaptiste Daroussin 	cached_days[n] = dlg_strclone(nl_langinfo(items[n]));
90f4f33ea0SBaptiste Daroussin 	memset(shown, 0, sizeof(shown));
914c8945a0SNathan Whitehorn     }
924c8945a0SNathan Whitehorn #endif
93f4f33ea0SBaptiste Daroussin     if (cached_days[n] == 0) {
94*a96ef450SBaptiste Daroussin 	static const char *posix_days[MAX_DAYS] =
95*a96ef450SBaptiste Daroussin 	{
96*a96ef450SBaptiste Daroussin 	    "Sunday",
97*a96ef450SBaptiste Daroussin 	    "Monday",
98*a96ef450SBaptiste Daroussin 	    "Tuesday",
99*a96ef450SBaptiste Daroussin 	    "Wednesday",
100*a96ef450SBaptiste Daroussin 	    "Thursday",
101*a96ef450SBaptiste Daroussin 	    "Friday",
102*a96ef450SBaptiste Daroussin 	    "Saturday"
103*a96ef450SBaptiste Daroussin 	};
104*a96ef450SBaptiste Daroussin 	size_t limit = MON_WIDE - 1;
105f4f33ea0SBaptiste Daroussin 	char *value = dlg_strclone(posix_days[n]);
106f4f33ea0SBaptiste Daroussin 
107f4f33ea0SBaptiste Daroussin 	/*
108f4f33ea0SBaptiste Daroussin 	 * POSIX does not actually say what the length of an abbreviated name
109f4f33ea0SBaptiste Daroussin 	 * is.  Typically it is 2, which will fit into our layout.  That also
110f4f33ea0SBaptiste Daroussin 	 * happens to work with CJK entries as seen in glibc, which are a
111f4f33ea0SBaptiste Daroussin 	 * double-width cell.  For now (2016/01/26), handle too-long names only
112f4f33ea0SBaptiste Daroussin 	 * for POSIX values.
113f4f33ea0SBaptiste Daroussin 	 */
114*a96ef450SBaptiste Daroussin 	if (strlen(value) > limit)
115f4f33ea0SBaptiste Daroussin 	    value[limit] = '\0';
116f4f33ea0SBaptiste Daroussin 	cached_days[n] = value;
1174c8945a0SNathan Whitehorn     }
118f4f33ea0SBaptiste Daroussin     if (!shown[n]) {
119f4f33ea0SBaptiste Daroussin 	DLG_TRACE(("# DAY(%d) = '%s'\n", n, cached_days[n]));
120f4f33ea0SBaptiste Daroussin 	shown[n] = TRUE;
1214c8945a0SNathan Whitehorn     }
122f4f33ea0SBaptiste Daroussin     return cached_days[n];
1234c8945a0SNathan Whitehorn }
1244c8945a0SNathan Whitehorn 
1254c8945a0SNathan Whitehorn static const char *
nameOfMonth(int n)1264c8945a0SNathan Whitehorn nameOfMonth(int n)
1274c8945a0SNathan Whitehorn {
128f4f33ea0SBaptiste Daroussin     static bool shown[MAX_MONTHS];
1294c8945a0SNathan Whitehorn 
130f4f33ea0SBaptiste Daroussin     while (n < 0) {
131f4f33ea0SBaptiste Daroussin 	n += MAX_MONTHS;
132f4f33ea0SBaptiste Daroussin     }
133f4f33ea0SBaptiste Daroussin     n %= MAX_MONTHS;
1344c8945a0SNathan Whitehorn #ifdef ENABLE_NLS
135f4f33ea0SBaptiste Daroussin     if (cached_months[n] == 0) {
136f4f33ea0SBaptiste Daroussin 	const nl_item items[MAX_MONTHS] =
1374c8945a0SNathan Whitehorn 	{
1384c8945a0SNathan Whitehorn 	    MON_1, MON_2, MON_3, MON_4, MON_5, MON_6,
1394c8945a0SNathan Whitehorn 	    MON_7, MON_8, MON_9, MON_10, MON_11, MON_12
1404c8945a0SNathan Whitehorn 	};
141f4f33ea0SBaptiste Daroussin 	cached_months[n] = dlg_strclone(nl_langinfo(items[n]));
142f4f33ea0SBaptiste Daroussin 	memset(shown, 0, sizeof(shown));
1434c8945a0SNathan Whitehorn     }
1444c8945a0SNathan Whitehorn #endif
145f4f33ea0SBaptiste Daroussin     if (cached_months[n] == 0) {
146*a96ef450SBaptiste Daroussin 	static const char *posix_mons[MAX_MONTHS] =
147*a96ef450SBaptiste Daroussin 	{
148*a96ef450SBaptiste Daroussin 	    "January",
149*a96ef450SBaptiste Daroussin 	    "February",
150*a96ef450SBaptiste Daroussin 	    "March",
151*a96ef450SBaptiste Daroussin 	    "April",
152*a96ef450SBaptiste Daroussin 	    "May",
153*a96ef450SBaptiste Daroussin 	    "June",
154*a96ef450SBaptiste Daroussin 	    "July",
155*a96ef450SBaptiste Daroussin 	    "August",
156*a96ef450SBaptiste Daroussin 	    "September",
157*a96ef450SBaptiste Daroussin 	    "October",
158*a96ef450SBaptiste Daroussin 	    "November",
159*a96ef450SBaptiste Daroussin 	    "December"
160*a96ef450SBaptiste Daroussin 	};
161f4f33ea0SBaptiste Daroussin 	cached_months[n] = dlg_strclone(posix_mons[n]);
1624c8945a0SNathan Whitehorn     }
163f4f33ea0SBaptiste Daroussin     if (!shown[n]) {
164f4f33ea0SBaptiste Daroussin 	DLG_TRACE(("# MON(%d) = '%s'\n", n, cached_months[n]));
165f4f33ea0SBaptiste Daroussin 	shown[n] = TRUE;
1664c8945a0SNathan Whitehorn     }
167f4f33ea0SBaptiste Daroussin     return cached_months[n];
168f4f33ea0SBaptiste Daroussin }
169f4f33ea0SBaptiste Daroussin 
170f4f33ea0SBaptiste Daroussin /*
171f4f33ea0SBaptiste Daroussin  * Algorithm for Gregorian calendar.
172f4f33ea0SBaptiste Daroussin  */
173f4f33ea0SBaptiste Daroussin static int
isleap(int y)174f4f33ea0SBaptiste Daroussin isleap(int y)
175f4f33ea0SBaptiste Daroussin {
176f4f33ea0SBaptiste Daroussin     return ((y % 4 == 0) &&
177f4f33ea0SBaptiste Daroussin 	    ((y % 100 != 0) ||
178f4f33ea0SBaptiste Daroussin 	     (y % 400 == 0))) ? 1 : 0;
179f4f33ea0SBaptiste Daroussin }
180f4f33ea0SBaptiste Daroussin 
181f4f33ea0SBaptiste Daroussin static void
adjust_year_month(int * year,int * month)182f4f33ea0SBaptiste Daroussin adjust_year_month(int *year, int *month)
183f4f33ea0SBaptiste Daroussin {
184f4f33ea0SBaptiste Daroussin     while (*month < 0) {
185f4f33ea0SBaptiste Daroussin 	*month += MAX_MONTHS;
186f4f33ea0SBaptiste Daroussin 	*year -= 1;
187f4f33ea0SBaptiste Daroussin     }
188f4f33ea0SBaptiste Daroussin     while (*month >= MAX_MONTHS) {
189f4f33ea0SBaptiste Daroussin 	*month -= MAX_MONTHS;
190f4f33ea0SBaptiste Daroussin 	*year += 1;
191f4f33ea0SBaptiste Daroussin     }
1924c8945a0SNathan Whitehorn }
1934c8945a0SNathan Whitehorn 
1944c8945a0SNathan Whitehorn static int
days_per_month(int year,int month)195f4f33ea0SBaptiste Daroussin days_per_month(int year, int month)
1964c8945a0SNathan Whitehorn {
1974c8945a0SNathan Whitehorn     static const int nominal[] =
1984c8945a0SNathan Whitehorn     {
1994c8945a0SNathan Whitehorn 	31, 28, 31, 30, 31, 30,
2004c8945a0SNathan Whitehorn 	31, 31, 30, 31, 30, 31
2014c8945a0SNathan Whitehorn     };
2024c8945a0SNathan Whitehorn     int result;
2034c8945a0SNathan Whitehorn 
204f4f33ea0SBaptiste Daroussin     adjust_year_month(&year, &month);
2054c8945a0SNathan Whitehorn     result = nominal[month];
2064c8945a0SNathan Whitehorn     if (month == 1)
207f4f33ea0SBaptiste Daroussin 	result += isleap(year);
2084c8945a0SNathan Whitehorn     return result;
2094c8945a0SNathan Whitehorn }
2104c8945a0SNathan Whitehorn 
2114c8945a0SNathan Whitehorn static int
days_in_month(struct tm * current,int offset)212f4f33ea0SBaptiste Daroussin days_in_month(struct tm *current, int offset /* -1, 0, 1 */ )
213f4f33ea0SBaptiste Daroussin {
214f4f33ea0SBaptiste Daroussin     int year = current->tm_year + 1900;
215f4f33ea0SBaptiste Daroussin     int month = current->tm_mon + offset;
216f4f33ea0SBaptiste Daroussin 
217f4f33ea0SBaptiste Daroussin     adjust_year_month(&year, &month);
218f4f33ea0SBaptiste Daroussin     return days_per_month(year, month);
219f4f33ea0SBaptiste Daroussin }
220f4f33ea0SBaptiste Daroussin 
221f4f33ea0SBaptiste Daroussin static int
days_per_year(int year)222f4f33ea0SBaptiste Daroussin days_per_year(int year)
223f4f33ea0SBaptiste Daroussin {
224f4f33ea0SBaptiste Daroussin     return (isleap(year) ? 366 : 365);
225f4f33ea0SBaptiste Daroussin }
226f4f33ea0SBaptiste Daroussin 
227f4f33ea0SBaptiste Daroussin static int
days_in_year(struct tm * current,int offset)2284c8945a0SNathan Whitehorn days_in_year(struct tm *current, int offset /* -1, 0, 1 */ )
2294c8945a0SNathan Whitehorn {
230f4f33ea0SBaptiste Daroussin     return days_per_year(current->tm_year + 1900 + offset);
231f4f33ea0SBaptiste Daroussin }
2324c8945a0SNathan Whitehorn 
233f4f33ea0SBaptiste Daroussin /*
234f4f33ea0SBaptiste Daroussin  * Adapted from C FAQ
235f4f33ea0SBaptiste Daroussin  * "17.28: How can I find the day of the week given the date?"
236f4f33ea0SBaptiste Daroussin  * implementation by Tomohiko Sakamoto.
237f4f33ea0SBaptiste Daroussin  *
238f4f33ea0SBaptiste Daroussin  * d = day (0 to whatever)
239f4f33ea0SBaptiste Daroussin  * m = month (1 through 12)
240f4f33ea0SBaptiste Daroussin  * y = year (1752 and later, for Gregorian calendar)
241f4f33ea0SBaptiste Daroussin  */
242f4f33ea0SBaptiste Daroussin static int
day_of_week(int y,int m,int d)243f4f33ea0SBaptiste Daroussin day_of_week(int y, int m, int d)
244f4f33ea0SBaptiste Daroussin {
245f4f33ea0SBaptiste Daroussin     static int t[] =
246f4f33ea0SBaptiste Daroussin     {
247f4f33ea0SBaptiste Daroussin 	0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4
248f4f33ea0SBaptiste Daroussin     };
249f4f33ea0SBaptiste Daroussin     y -= (m < 3);
250f4f33ea0SBaptiste Daroussin     return (6 + (y + (y / 4) - (y / 100) + (y / 400) + t[m - 1] + d)) % MAX_DAYS;
251f4f33ea0SBaptiste Daroussin }
252f4f33ea0SBaptiste Daroussin 
253f4f33ea0SBaptiste Daroussin static int
day_in_year(int year,int month,int day)254f4f33ea0SBaptiste Daroussin day_in_year(int year, int month, int day)
255f4f33ea0SBaptiste Daroussin {
256f4f33ea0SBaptiste Daroussin     int result = day;
257f4f33ea0SBaptiste Daroussin     while (--month >= 1)
258f4f33ea0SBaptiste Daroussin 	result += days_per_month(year, month);
259f4f33ea0SBaptiste Daroussin     return result;
260f4f33ea0SBaptiste Daroussin }
261f4f33ea0SBaptiste Daroussin 
262f4f33ea0SBaptiste Daroussin static int
iso_week(int year,int month,int day)263f4f33ea0SBaptiste Daroussin iso_week(int year, int month, int day)
264f4f33ea0SBaptiste Daroussin {
265f4f33ea0SBaptiste Daroussin     int week = 1;
266f4f33ea0SBaptiste Daroussin     int dow;
267f4f33ea0SBaptiste Daroussin     int new_year_dow;
268f4f33ea0SBaptiste Daroussin     int diy;
269f4f33ea0SBaptiste Daroussin     int new_years_eve_dow;
270f4f33ea0SBaptiste Daroussin     static const int thursday = 3;
271f4f33ea0SBaptiste Daroussin 
272f4f33ea0SBaptiste Daroussin     /* add the number weeks *between* date and newyear */
273f4f33ea0SBaptiste Daroussin     diy = day_in_year(year, month, day);
274f4f33ea0SBaptiste Daroussin     week += (diy - 1) / MAX_DAYS;
275f4f33ea0SBaptiste Daroussin 
276f4f33ea0SBaptiste Daroussin     /* 0 = Monday */
277f4f33ea0SBaptiste Daroussin     dow = day_of_week(year, month, day);
278f4f33ea0SBaptiste Daroussin     new_year_dow = day_of_week(year, 1, 1);
279f4f33ea0SBaptiste Daroussin 
280f4f33ea0SBaptiste Daroussin     /*
281f4f33ea0SBaptiste Daroussin      * If New Year falls on Friday, Saturday or Sunday, then New Years's week
282f4f33ea0SBaptiste Daroussin      * is the last week of the preceding year.  In that case subtract one week.
283f4f33ea0SBaptiste Daroussin      */
284f4f33ea0SBaptiste Daroussin     if (new_year_dow > thursday)
285f4f33ea0SBaptiste Daroussin 	--week;
286f4f33ea0SBaptiste Daroussin 
287f4f33ea0SBaptiste Daroussin     /* Add one week if there is a Sunday to Monday transition. */
288f4f33ea0SBaptiste Daroussin     if (dow - new_year_dow < 0)
289f4f33ea0SBaptiste Daroussin 	++week;
290f4f33ea0SBaptiste Daroussin 
291f4f33ea0SBaptiste Daroussin     /* Check if we are in the last week of the preceding year. */
292f4f33ea0SBaptiste Daroussin     if (week < 1) {
293f4f33ea0SBaptiste Daroussin 	week = iso_week(--year, 12, 31);
294f4f33ea0SBaptiste Daroussin     }
295f4f33ea0SBaptiste Daroussin 
296f4f33ea0SBaptiste Daroussin     /*
297f4f33ea0SBaptiste Daroussin      * If we are in the same week as New Year's eve, check if New Year's eve is
298f4f33ea0SBaptiste Daroussin      * in the first week of the next year.
299f4f33ea0SBaptiste Daroussin      */
300f4f33ea0SBaptiste Daroussin     new_years_eve_dow = (new_year_dow + 364 + isleap(year)) % MAX_DAYS;
301f4f33ea0SBaptiste Daroussin     if (365 + isleap(year) - diy < MAX_DAYS
302f4f33ea0SBaptiste Daroussin 	&& new_years_eve_dow >= dow
303f4f33ea0SBaptiste Daroussin 	&& new_years_eve_dow < thursday) {
304f4f33ea0SBaptiste Daroussin 	week = 1;
305f4f33ea0SBaptiste Daroussin     }
306f4f33ea0SBaptiste Daroussin     return week;
307f4f33ea0SBaptiste Daroussin }
308f4f33ea0SBaptiste Daroussin 
309f4f33ea0SBaptiste Daroussin static int *
getisoweeks(int year,int month)310f4f33ea0SBaptiste Daroussin getisoweeks(int year, int month)
311f4f33ea0SBaptiste Daroussin {
312f4f33ea0SBaptiste Daroussin     static int result[10];
313f4f33ea0SBaptiste Daroussin     int windx = 0;
314f4f33ea0SBaptiste Daroussin     int day;
315f4f33ea0SBaptiste Daroussin     int dpm = days_per_month(year, month);
316f4f33ea0SBaptiste Daroussin 
317f4f33ea0SBaptiste Daroussin     for (day = 1; day <= dpm; day += MAX_DAYS)
318f4f33ea0SBaptiste Daroussin 	result[windx++] = iso_week(year, month, day);
319f4f33ea0SBaptiste Daroussin     /*
320f4f33ea0SBaptiste Daroussin      * Ensure that there is a week number associated with the last day of the
321f4f33ea0SBaptiste Daroussin      * month, e.g., in case the last day of the month falls before Thursday,
322f4f33ea0SBaptiste Daroussin      * so that we have to show the week-number for the beginning of the
323f4f33ea0SBaptiste Daroussin      * following month.
324f4f33ea0SBaptiste Daroussin      */
325f4f33ea0SBaptiste Daroussin     result[windx] = iso_week(year, month, dpm);
326f4f33ea0SBaptiste Daroussin     return result;
3274c8945a0SNathan Whitehorn }
3284c8945a0SNathan Whitehorn 
3294c8945a0SNathan Whitehorn static int
day_cell_number(struct tm * current)3304c8945a0SNathan Whitehorn day_cell_number(struct tm *current)
3314c8945a0SNathan Whitehorn {
3324c8945a0SNathan Whitehorn     int cell;
333f4f33ea0SBaptiste Daroussin     cell = current->tm_mday - ((6 + current->tm_mday - current->tm_wday) % MAX_DAYS);
334f4f33ea0SBaptiste Daroussin     if ((current->tm_mday - 1) % MAX_DAYS != current->tm_wday)
3354c8945a0SNathan Whitehorn 	cell += 6;
3364c8945a0SNathan Whitehorn     else
3374c8945a0SNathan Whitehorn 	cell--;
3384c8945a0SNathan Whitehorn     return cell;
3394c8945a0SNathan Whitehorn }
3404c8945a0SNathan Whitehorn 
3414c8945a0SNathan Whitehorn static int
next_or_previous(int key,int two_d)3424c8945a0SNathan Whitehorn next_or_previous(int key, int two_d)
3434c8945a0SNathan Whitehorn {
3444c8945a0SNathan Whitehorn     int result = 0;
3454c8945a0SNathan Whitehorn 
3464c8945a0SNathan Whitehorn     switch (key) {
3474c8945a0SNathan Whitehorn     case DLGK_GRID_UP:
348f4f33ea0SBaptiste Daroussin 	result = two_d ? -MAX_DAYS : -1;
3494c8945a0SNathan Whitehorn 	break;
3504c8945a0SNathan Whitehorn     case DLGK_GRID_LEFT:
3514c8945a0SNathan Whitehorn 	result = -1;
3524c8945a0SNathan Whitehorn 	break;
3534c8945a0SNathan Whitehorn     case DLGK_GRID_DOWN:
354f4f33ea0SBaptiste Daroussin 	result = two_d ? MAX_DAYS : 1;
3554c8945a0SNathan Whitehorn 	break;
3564c8945a0SNathan Whitehorn     case DLGK_GRID_RIGHT:
3574c8945a0SNathan Whitehorn 	result = 1;
3584c8945a0SNathan Whitehorn 	break;
3594c8945a0SNathan Whitehorn     default:
3604c8945a0SNathan Whitehorn 	beep();
3614c8945a0SNathan Whitehorn 	break;
3624c8945a0SNathan Whitehorn     }
3634c8945a0SNathan Whitehorn     return result;
3644c8945a0SNathan Whitehorn }
3654c8945a0SNathan Whitehorn 
3664c8945a0SNathan Whitehorn /*
3674c8945a0SNathan Whitehorn  * Draw the day-of-month selection box
3684c8945a0SNathan Whitehorn  */
3694c8945a0SNathan Whitehorn static int
draw_day(BOX * data,struct tm * current)3704c8945a0SNathan Whitehorn draw_day(BOX * data, struct tm *current)
3714c8945a0SNathan Whitehorn {
3724c8945a0SNathan Whitehorn     int cell_wide = MON_WIDE;
373*a96ef450SBaptiste Daroussin     int y, x, this_x;
3744c8945a0SNathan Whitehorn     int save_y = 0, save_x = 0;
3754c8945a0SNathan Whitehorn     int day = current->tm_mday;
3764c8945a0SNathan Whitehorn     int mday;
377f4f33ea0SBaptiste Daroussin     int week = 0;
378f4f33ea0SBaptiste Daroussin     int windx = 0;
379f4f33ea0SBaptiste Daroussin     int *weeks = 0;
3804c8945a0SNathan Whitehorn     int last = days_in_month(current, 0);
3814c8945a0SNathan Whitehorn     int prev = days_in_month(current, -1);
3824c8945a0SNathan Whitehorn 
3834c8945a0SNathan Whitehorn     werase(data->window);
3842a3e3873SBaptiste Daroussin     dlg_draw_box2(data->parent,
3854c8945a0SNathan Whitehorn 		  data->y - MARGIN, data->x - MARGIN,
3864c8945a0SNathan Whitehorn 		  data->height + (2 * MARGIN), data->width + (2 * MARGIN),
3872a3e3873SBaptiste Daroussin 		  menubox_attr,
3882a3e3873SBaptiste Daroussin 		  menubox_border_attr,
3892a3e3873SBaptiste Daroussin 		  menubox_border2_attr);
3904c8945a0SNathan Whitehorn 
391f4f33ea0SBaptiste Daroussin     dlg_attrset(data->window, menubox_attr);	/* daynames headline */
392f4f33ea0SBaptiste Daroussin     for (x = 0; x < MAX_DAYS; x++) {
3934c8945a0SNathan Whitehorn 	mvwprintw(data->window,
3944c8945a0SNathan Whitehorn 		  0, (x + 1) * cell_wide, "%*.*s ",
3954c8945a0SNathan Whitehorn 		  cell_wide - 1,
3964c8945a0SNathan Whitehorn 		  cell_wide - 1,
397f4f33ea0SBaptiste Daroussin 		  nameOfDayOfWeek(x + data->week_start));
3984c8945a0SNathan Whitehorn     }
3994c8945a0SNathan Whitehorn 
400f4f33ea0SBaptiste Daroussin     mday = ((6 + current->tm_mday -
401f4f33ea0SBaptiste Daroussin 	     current->tm_wday +
402f4f33ea0SBaptiste Daroussin 	     data->week_start) % MAX_DAYS) - MAX_DAYS;
403f4f33ea0SBaptiste Daroussin     if (mday <= -MAX_DAYS)
404f4f33ea0SBaptiste Daroussin 	mday += MAX_DAYS;
405f4f33ea0SBaptiste Daroussin 
406f4f33ea0SBaptiste Daroussin     if (dialog_vars.iso_week) {
407f4f33ea0SBaptiste Daroussin 	weeks = getisoweeks(current->tm_year + 1900, current->tm_mon + 1);
408f4f33ea0SBaptiste Daroussin     } else {
4094c8945a0SNathan Whitehorn 	/* mday is now in the range -6 to 0. */
410f4f33ea0SBaptiste Daroussin 	week = (current->tm_yday + 6 + mday - current->tm_mday) / MAX_DAYS;
411f4f33ea0SBaptiste Daroussin     }
4124c8945a0SNathan Whitehorn 
4134c8945a0SNathan Whitehorn     for (y = 1; mday < last; y++) {
414f4f33ea0SBaptiste Daroussin 	dlg_attrset(data->window, menubox_attr);	/* weeknumbers headline */
4154c8945a0SNathan Whitehorn 	mvwprintw(data->window,
4164c8945a0SNathan Whitehorn 		  y, 0,
4174c8945a0SNathan Whitehorn 		  "%*d ",
4184c8945a0SNathan Whitehorn 		  cell_wide - 1,
419f4f33ea0SBaptiste Daroussin 		  weeks ? weeks[windx++] : ++week);
420f4f33ea0SBaptiste Daroussin 	for (x = 0; x < MAX_DAYS; x++) {
4214c8945a0SNathan Whitehorn 	    this_x = 1 + (x + 1) * cell_wide;
4224c8945a0SNathan Whitehorn 	    ++mday;
4234c8945a0SNathan Whitehorn 	    if (wmove(data->window, y, this_x) == ERR)
4244c8945a0SNathan Whitehorn 		continue;
425f4f33ea0SBaptiste Daroussin 	    dlg_attrset(data->window, item_attr);	/* not selected days */
4264c8945a0SNathan Whitehorn 	    if (mday == day) {
427f4f33ea0SBaptiste Daroussin 		dlg_attrset(data->window, item_selected_attr);	/* selected day */
4284c8945a0SNathan Whitehorn 		save_y = y;
4294c8945a0SNathan Whitehorn 		save_x = this_x;
4304c8945a0SNathan Whitehorn 	    }
4314c8945a0SNathan Whitehorn 	    if (mday > 0) {
4324c8945a0SNathan Whitehorn 		if (mday <= last) {
4334c8945a0SNathan Whitehorn 		    wprintw(data->window, "%*d", cell_wide - 2, mday);
4344c8945a0SNathan Whitehorn 		} else if (mday == day) {
4354c8945a0SNathan Whitehorn 		    wprintw(data->window, "%*d", cell_wide - 2, mday - last);
4364c8945a0SNathan Whitehorn 		}
4374c8945a0SNathan Whitehorn 	    } else if (mday == day) {
4384c8945a0SNathan Whitehorn 		wprintw(data->window, "%*d", cell_wide - 2, mday + prev);
4394c8945a0SNathan Whitehorn 	    }
4404c8945a0SNathan Whitehorn 	}
4414c8945a0SNathan Whitehorn 	wmove(data->window, save_y, save_x);
4424c8945a0SNathan Whitehorn     }
4434c8945a0SNathan Whitehorn     /* just draw arrows - scrollbar is unsuitable here */
4444c8945a0SNathan Whitehorn     dlg_draw_arrows(data->parent, TRUE, TRUE,
4454c8945a0SNathan Whitehorn 		    data->x + ARROWS_COL,
4464c8945a0SNathan Whitehorn 		    data->y - 1,
4474c8945a0SNathan Whitehorn 		    data->y + data->height);
4484c8945a0SNathan Whitehorn 
4494c8945a0SNathan Whitehorn     return 0;
4504c8945a0SNathan Whitehorn }
4514c8945a0SNathan Whitehorn 
4524c8945a0SNathan Whitehorn /*
4534c8945a0SNathan Whitehorn  * Draw the month-of-year selection box
4544c8945a0SNathan Whitehorn  */
4554c8945a0SNathan Whitehorn static int
draw_month(BOX * data,struct tm * current)4564c8945a0SNathan Whitehorn draw_month(BOX * data, struct tm *current)
4574c8945a0SNathan Whitehorn {
4584c8945a0SNathan Whitehorn     int month;
4594c8945a0SNathan Whitehorn 
4604c8945a0SNathan Whitehorn     month = current->tm_mon + 1;
4614c8945a0SNathan Whitehorn 
462f4f33ea0SBaptiste Daroussin     dlg_attrset(data->parent, dialog_attr);	/* Headline "Month" */
4634c8945a0SNathan Whitehorn     (void) mvwprintw(data->parent, data->y - 2, data->x - 1, _("Month"));
4642a3e3873SBaptiste Daroussin     dlg_draw_box2(data->parent,
4654c8945a0SNathan Whitehorn 		  data->y - 1, data->x - 1,
4664c8945a0SNathan Whitehorn 		  data->height + 2, data->width + 2,
4672a3e3873SBaptiste Daroussin 		  menubox_attr,
4682a3e3873SBaptiste Daroussin 		  menubox_border_attr,
4692a3e3873SBaptiste Daroussin 		  menubox_border2_attr);
470f4f33ea0SBaptiste Daroussin     dlg_attrset(data->window, item_attr);	/* color the month selection */
4714c8945a0SNathan Whitehorn     mvwprintw(data->window, 0, 0, "%s", nameOfMonth(month - 1));
4724c8945a0SNathan Whitehorn     wmove(data->window, 0, 0);
4734c8945a0SNathan Whitehorn     return 0;
4744c8945a0SNathan Whitehorn }
4754c8945a0SNathan Whitehorn 
4764c8945a0SNathan Whitehorn /*
4774c8945a0SNathan Whitehorn  * Draw the year selection box
4784c8945a0SNathan Whitehorn  */
4794c8945a0SNathan Whitehorn static int
draw_year(BOX * data,struct tm * current)4804c8945a0SNathan Whitehorn draw_year(BOX * data, struct tm *current)
4814c8945a0SNathan Whitehorn {
4824c8945a0SNathan Whitehorn     int year = current->tm_year + 1900;
4834c8945a0SNathan Whitehorn 
484f4f33ea0SBaptiste Daroussin     dlg_attrset(data->parent, dialog_attr);	/* Headline "Year" */
4854c8945a0SNathan Whitehorn     (void) mvwprintw(data->parent, data->y - 2, data->x - 1, _("Year"));
4862a3e3873SBaptiste Daroussin     dlg_draw_box2(data->parent,
4874c8945a0SNathan Whitehorn 		  data->y - 1, data->x - 1,
4884c8945a0SNathan Whitehorn 		  data->height + 2, data->width + 2,
4892a3e3873SBaptiste Daroussin 		  menubox_attr,
4902a3e3873SBaptiste Daroussin 		  menubox_border_attr,
4912a3e3873SBaptiste Daroussin 		  menubox_border2_attr);
492f4f33ea0SBaptiste Daroussin     dlg_attrset(data->window, item_attr);	/* color the year selection */
4934c8945a0SNathan Whitehorn     mvwprintw(data->window, 0, 0, "%4d", year);
4944c8945a0SNathan Whitehorn     wmove(data->window, 0, 0);
4954c8945a0SNathan Whitehorn     return 0;
4964c8945a0SNathan Whitehorn }
4974c8945a0SNathan Whitehorn 
4984c8945a0SNathan Whitehorn static int
init_object(BOX * data,WINDOW * parent,int x,int y,int width,int height,BOX_DRAW box_draw,int key_offset,int code)4994c8945a0SNathan Whitehorn init_object(BOX * data,
5004c8945a0SNathan Whitehorn 	    WINDOW *parent,
5014c8945a0SNathan Whitehorn 	    int x, int y,
5024c8945a0SNathan Whitehorn 	    int width, int height,
5034c8945a0SNathan Whitehorn 	    BOX_DRAW box_draw,
504f4f33ea0SBaptiste Daroussin 	    int key_offset,
5054c8945a0SNathan Whitehorn 	    int code)
5064c8945a0SNathan Whitehorn {
5074c8945a0SNathan Whitehorn     data->parent = parent;
5084c8945a0SNathan Whitehorn     data->x = x;
5094c8945a0SNathan Whitehorn     data->y = y;
5104c8945a0SNathan Whitehorn     data->width = width;
5114c8945a0SNathan Whitehorn     data->height = height;
5124c8945a0SNathan Whitehorn     data->box_draw = box_draw;
513f4f33ea0SBaptiste Daroussin     data->week_start = key_offset;
5144c8945a0SNathan Whitehorn 
515*a96ef450SBaptiste Daroussin     data->window = dlg_der_window(data->parent,
5164c8945a0SNathan Whitehorn 				  data->height, data->width,
5174c8945a0SNathan Whitehorn 				  data->y, data->x);
5184c8945a0SNathan Whitehorn     if (data->window == 0)
5194c8945a0SNathan Whitehorn 	return -1;
5204c8945a0SNathan Whitehorn 
5214c8945a0SNathan Whitehorn     dlg_mouse_setbase(getbegx(parent), getbegy(parent));
5224c8945a0SNathan Whitehorn     if (code == 'D') {
5234c8945a0SNathan Whitehorn 	dlg_mouse_mkbigregion(y + 1, x + MON_WIDE, height - 1, width - MON_WIDE,
524f4f33ea0SBaptiste Daroussin 			      KEY_MAX + key_offset, 1, MON_WIDE, 3);
5254c8945a0SNathan Whitehorn     } else {
5264c8945a0SNathan Whitehorn 	dlg_mouse_mkregion(y, x, height, width, code);
5274c8945a0SNathan Whitehorn     }
5284c8945a0SNathan Whitehorn 
5294c8945a0SNathan Whitehorn     return 0;
5304c8945a0SNathan Whitehorn }
5314c8945a0SNathan Whitehorn 
532f4f33ea0SBaptiste Daroussin #if defined(ENABLE_NLS) && defined(HAVE_NL_LANGINFO_1STDAY)
533f4f33ea0SBaptiste Daroussin #elif defined(HAVE_DLG_GAUGE)
534f4f33ea0SBaptiste Daroussin static int
read_locale_setting(const char * name,int which)535f4f33ea0SBaptiste Daroussin read_locale_setting(const char *name, int which)
536f4f33ea0SBaptiste Daroussin {
537f4f33ea0SBaptiste Daroussin     FILE *fp;
538f4f33ea0SBaptiste Daroussin     char command[80];
539f4f33ea0SBaptiste Daroussin     int result = -1;
540f4f33ea0SBaptiste Daroussin 
541f4f33ea0SBaptiste Daroussin     sprintf(command, "locale %s", name);
542f4f33ea0SBaptiste Daroussin     if ((fp = dlg_popen(command, "r")) != 0) {
543f4f33ea0SBaptiste Daroussin 	int count = 0;
544f4f33ea0SBaptiste Daroussin 	char buf[80];
545f4f33ea0SBaptiste Daroussin 
546f4f33ea0SBaptiste Daroussin 	while (fgets(buf, (int) sizeof(buf) - 1, fp) != 0) {
547f4f33ea0SBaptiste Daroussin 	    if (++count > which) {
548f4f33ea0SBaptiste Daroussin 		char *next = 0;
549f4f33ea0SBaptiste Daroussin 		long check = strtol(buf, &next, 0);
550f4f33ea0SBaptiste Daroussin 		if (next != 0 &&
551f4f33ea0SBaptiste Daroussin 		    next != buf &&
552f4f33ea0SBaptiste Daroussin 		    *next == '\n') {
553f4f33ea0SBaptiste Daroussin 		    result = (int) check;
554f4f33ea0SBaptiste Daroussin 		}
555f4f33ea0SBaptiste Daroussin 		break;
556f4f33ea0SBaptiste Daroussin 	    }
557f4f33ea0SBaptiste Daroussin 	}
558f4f33ea0SBaptiste Daroussin 	pclose(fp);
559f4f33ea0SBaptiste Daroussin     }
560f4f33ea0SBaptiste Daroussin     return result;
561f4f33ea0SBaptiste Daroussin }
562f4f33ea0SBaptiste Daroussin #endif
563f4f33ea0SBaptiste Daroussin 
564f4f33ea0SBaptiste Daroussin static int
WeekStart(void)565f4f33ea0SBaptiste Daroussin WeekStart(void)
566f4f33ea0SBaptiste Daroussin {
567f4f33ea0SBaptiste Daroussin     int result = 0;
568f4f33ea0SBaptiste Daroussin     char *option = dialog_vars.week_start;
569f4f33ea0SBaptiste Daroussin     if (option != 0) {
570f4f33ea0SBaptiste Daroussin 	if (option[0]) {
571f4f33ea0SBaptiste Daroussin 	    char *next = 0;
572f4f33ea0SBaptiste Daroussin 	    long check = strtol(option, &next, 0);
573f4f33ea0SBaptiste Daroussin 	    if (next == 0 ||
574f4f33ea0SBaptiste Daroussin 		next == option ||
575f4f33ea0SBaptiste Daroussin 		*next != '\0') {
576f4f33ea0SBaptiste Daroussin 		if (!strcmp(option, "locale")) {
577f4f33ea0SBaptiste Daroussin #if defined(ENABLE_NLS) && defined(HAVE_NL_LANGINFO_1STDAY)
578f4f33ea0SBaptiste Daroussin 		    /*
579f4f33ea0SBaptiste Daroussin 		     * glibc-specific.
580f4f33ea0SBaptiste Daroussin 		     */
581f4f33ea0SBaptiste Daroussin 		    int first_day = nl_langinfo(_NL_TIME_FIRST_WEEKDAY)[0];
582f4f33ea0SBaptiste Daroussin 		    char *basis_ptr = nl_langinfo(_NL_TIME_WEEK_1STDAY);
583f4f33ea0SBaptiste Daroussin 		    int basis_day = (int) (intptr_t) basis_ptr;
584f4f33ea0SBaptiste Daroussin #elif defined(HAVE_DLG_GAUGE)
585f4f33ea0SBaptiste Daroussin 		    /*
586f4f33ea0SBaptiste Daroussin 		     * probably Linux-specific, but harmless otherwise.  When
587f4f33ea0SBaptiste Daroussin 		     * available, the locale program will return a single
588f4f33ea0SBaptiste Daroussin 		     * integer on one line.
589f4f33ea0SBaptiste Daroussin 		     */
590f4f33ea0SBaptiste Daroussin 		    int first_day = read_locale_setting("first_weekday", 0);
591f4f33ea0SBaptiste Daroussin 		    int basis_day = read_locale_setting("week-1stday", 0);
592f4f33ea0SBaptiste Daroussin #endif
593f4f33ea0SBaptiste Daroussin #if (defined(ENABLE_NLS) && defined(HAVE_NL_LANGINFO_1STDAY)) || defined(HAVE_DLG_GAUGE)
594f4f33ea0SBaptiste Daroussin 		    int week_1stday = -1;
595f4f33ea0SBaptiste Daroussin 		    if (basis_day == 19971130)
596f4f33ea0SBaptiste Daroussin 			week_1stday = 0;	/* Sun */
597f4f33ea0SBaptiste Daroussin 		    else if (basis_day == 19971201)
598f4f33ea0SBaptiste Daroussin 			week_1stday = 1;	/* Mon */
599f4f33ea0SBaptiste Daroussin 		    if (week_1stday >= 0) {
600f4f33ea0SBaptiste Daroussin 			result = first_day - week_1stday - 1;
601f4f33ea0SBaptiste Daroussin 		    }
602f4f33ea0SBaptiste Daroussin #else
603f4f33ea0SBaptiste Daroussin 		    result = 0;	/* Sun */
604f4f33ea0SBaptiste Daroussin #endif
605f4f33ea0SBaptiste Daroussin 		} else {
606f4f33ea0SBaptiste Daroussin 		    int day;
607f4f33ea0SBaptiste Daroussin 		    size_t eql = strlen(option);
608f4f33ea0SBaptiste Daroussin 		    for (day = 0; day < MAX_DAYS; ++day) {
609f4f33ea0SBaptiste Daroussin 			if (!strncmp(nameOfDayOfWeek(day), option, eql)) {
610f4f33ea0SBaptiste Daroussin 			    result = day;
611f4f33ea0SBaptiste Daroussin 			    break;
612f4f33ea0SBaptiste Daroussin 			}
613f4f33ea0SBaptiste Daroussin 		    }
614f4f33ea0SBaptiste Daroussin 		}
615f4f33ea0SBaptiste Daroussin 	    } else if (check < 0) {
616f4f33ea0SBaptiste Daroussin 		result = -1;
617f4f33ea0SBaptiste Daroussin 	    } else {
618f4f33ea0SBaptiste Daroussin 		result = (int) (check % MAX_DAYS);
619f4f33ea0SBaptiste Daroussin 	    }
620f4f33ea0SBaptiste Daroussin 	}
621f4f33ea0SBaptiste Daroussin     }
622f4f33ea0SBaptiste Daroussin     return result;
623f4f33ea0SBaptiste Daroussin }
624f4f33ea0SBaptiste Daroussin 
6254c8945a0SNathan Whitehorn static int
CleanupResult(int code,WINDOW * dialog,char * prompt,DIALOG_VARS * save_vars)6264c8945a0SNathan Whitehorn CleanupResult(int code, WINDOW *dialog, char *prompt, DIALOG_VARS * save_vars)
6274c8945a0SNathan Whitehorn {
628f4f33ea0SBaptiste Daroussin     int n;
629f4f33ea0SBaptiste Daroussin 
6304c8945a0SNathan Whitehorn     if (dialog != 0)
6314c8945a0SNathan Whitehorn 	dlg_del_window(dialog);
6324c8945a0SNathan Whitehorn     dlg_mouse_free_regions();
6334c8945a0SNathan Whitehorn     if (prompt != 0)
6344c8945a0SNathan Whitehorn 	free(prompt);
6354c8945a0SNathan Whitehorn     dlg_restore_vars(save_vars);
6364c8945a0SNathan Whitehorn 
637f4f33ea0SBaptiste Daroussin     for (n = 0; n < MAX_DAYS; ++n) {
638f4f33ea0SBaptiste Daroussin 	free(cached_days[n]);
639f4f33ea0SBaptiste Daroussin 	cached_days[n] = 0;
640f4f33ea0SBaptiste Daroussin     }
641f4f33ea0SBaptiste Daroussin     for (n = 0; n < MAX_MONTHS; ++n) {
642f4f33ea0SBaptiste Daroussin 	free(cached_months[n]);
643f4f33ea0SBaptiste Daroussin 	cached_months[n] = 0;
644f4f33ea0SBaptiste Daroussin     }
645f4f33ea0SBaptiste Daroussin 
6464c8945a0SNathan Whitehorn     return code;
6474c8945a0SNathan Whitehorn }
6484c8945a0SNathan Whitehorn 
649f4f33ea0SBaptiste Daroussin static void
trace_date(struct tm * current,struct tm * old)650f4f33ea0SBaptiste Daroussin trace_date(struct tm *current, struct tm *old)
651f4f33ea0SBaptiste Daroussin {
652f4f33ea0SBaptiste Daroussin     bool changed = (old == 0 ||
653f4f33ea0SBaptiste Daroussin 		    current->tm_mday != old->tm_mday ||
654f4f33ea0SBaptiste Daroussin 		    current->tm_mon != old->tm_mon ||
655f4f33ea0SBaptiste Daroussin 		    current->tm_year != old->tm_year);
656f4f33ea0SBaptiste Daroussin     if (changed) {
657f4f33ea0SBaptiste Daroussin 	DLG_TRACE(("# current %04d/%02d/%02d\n",
658f4f33ea0SBaptiste Daroussin 		   current->tm_year + 1900,
659f4f33ea0SBaptiste Daroussin 		   current->tm_mon + 1,
660f4f33ea0SBaptiste Daroussin 		   current->tm_mday));
661f4f33ea0SBaptiste Daroussin     } else {
662f4f33ea0SBaptiste Daroussin 	DLG_TRACE(("# current (unchanged)\n"));
663f4f33ea0SBaptiste Daroussin     }
664f4f33ea0SBaptiste Daroussin }
665f4f33ea0SBaptiste Daroussin 
6664c8945a0SNathan Whitehorn #define DrawObject(data) (data)->box_draw(data, &current)
6674c8945a0SNathan Whitehorn 
6684c8945a0SNathan Whitehorn /*
6694c8945a0SNathan Whitehorn  * Display a dialog box for entering a date
6704c8945a0SNathan Whitehorn  */
6714c8945a0SNathan Whitehorn int
dialog_calendar(const char * title,const char * subtitle,int height,int width,int day,int month,int year)6724c8945a0SNathan Whitehorn dialog_calendar(const char *title,
6734c8945a0SNathan Whitehorn 		const char *subtitle,
6744c8945a0SNathan Whitehorn 		int height,
6754c8945a0SNathan Whitehorn 		int width,
6764c8945a0SNathan Whitehorn 		int day,
6774c8945a0SNathan Whitehorn 		int month,
6784c8945a0SNathan Whitehorn 		int year)
6794c8945a0SNathan Whitehorn {
6804c8945a0SNathan Whitehorn     /* *INDENT-OFF* */
6814c8945a0SNathan Whitehorn     static DLG_KEYS_BINDING binding[] = {
682682c9e0fSNathan Whitehorn 	HELPKEY_BINDINGS,
6834c8945a0SNathan Whitehorn 	ENTERKEY_BINDINGS,
684f4f33ea0SBaptiste Daroussin 	TOGGLEKEY_BINDINGS,
6854c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
6864c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
6874c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_DOWN,	'j' ),
6884c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_DOWN,	DLGK_MOUSE(KEY_NPAGE) ),
6894c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_DOWN,	KEY_DOWN ),
6904c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_DOWN,	KEY_NPAGE ),
6914c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_LEFT,	'-' ),
6924c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_LEFT,  'h' ),
6934c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_LEFT,  CHR_BACKSPACE ),
6944c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_LEFT,  CHR_PREVIOUS ),
6954c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_LEFT,  KEY_LEFT ),
6964c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_RIGHT,	'+' ),
6974c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_RIGHT, 'l' ),
6984c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_RIGHT, CHR_NEXT ),
6994c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_RIGHT, KEY_NEXT ),
7004c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_RIGHT, KEY_RIGHT ),
7014c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_UP,	'k' ),
7024c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_UP,	KEY_PPAGE ),
7034c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_UP,	KEY_PREVIOUS ),
7044c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_UP,	KEY_UP ),
7054c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_GRID_UP,  	DLGK_MOUSE(KEY_PPAGE) ),
7064c8945a0SNathan Whitehorn 	END_KEYS_BINDING
7074c8945a0SNathan Whitehorn     };
7084c8945a0SNathan Whitehorn     /* *INDENT-ON* */
7094c8945a0SNathan Whitehorn 
7104c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
7114c8945a0SNathan Whitehorn     int old_height = height;
7124c8945a0SNathan Whitehorn     int old_width = width;
7134c8945a0SNathan Whitehorn #endif
7144c8945a0SNathan Whitehorn     BOX dy_box, mn_box, yr_box;
7154c8945a0SNathan Whitehorn     int fkey;
716*a96ef450SBaptiste Daroussin     int key;
7174c8945a0SNathan Whitehorn     int step;
7184c8945a0SNathan Whitehorn     int button;
7194c8945a0SNathan Whitehorn     int result = DLG_EXIT_UNKNOWN;
720f4f33ea0SBaptiste Daroussin     int week_start;
7214c8945a0SNathan Whitehorn     WINDOW *dialog;
722*a96ef450SBaptiste Daroussin     time_t now_time;
7234c8945a0SNathan Whitehorn     struct tm current;
7242a3e3873SBaptiste Daroussin     int state = dlg_default_button();
7254c8945a0SNathan Whitehorn     const char **buttons = dlg_ok_labels();
726f4f33ea0SBaptiste Daroussin     char *prompt;
7274c8945a0SNathan Whitehorn     int mincols = MIN_WIDE;
7284c8945a0SNathan Whitehorn     char buffer[MAX_LEN];
7294c8945a0SNathan Whitehorn     DIALOG_VARS save_vars;
7304c8945a0SNathan Whitehorn 
731f4f33ea0SBaptiste Daroussin     DLG_TRACE(("# calendar args:\n"));
732f4f33ea0SBaptiste Daroussin     DLG_TRACE2S("title", title);
733f4f33ea0SBaptiste Daroussin     DLG_TRACE2S("message", subtitle);
734f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("height", height);
735f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("width", width);
736f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("day", day);
737f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("month", month);
738f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("year", year);
739f4f33ea0SBaptiste Daroussin 
7404c8945a0SNathan Whitehorn     dlg_save_vars(&save_vars);
7414c8945a0SNathan Whitehorn     dialog_vars.separate_output = TRUE;
7424c8945a0SNathan Whitehorn 
7434c8945a0SNathan Whitehorn     dlg_does_output();
7444c8945a0SNathan Whitehorn 
745f4f33ea0SBaptiste Daroussin     /*
746*a96ef450SBaptiste Daroussin      * Unless overridden, the current time/date is our starting point.
747f4f33ea0SBaptiste Daroussin      */
7484c8945a0SNathan Whitehorn     now_time = time((time_t *) 0);
7494c8945a0SNathan Whitehorn     current = *localtime(&now_time);
750f4f33ea0SBaptiste Daroussin 
751f4f33ea0SBaptiste Daroussin #if HAVE_MKTIME
752f4f33ea0SBaptiste Daroussin     current.tm_isdst = -1;
753f4f33ea0SBaptiste Daroussin     if (year >= 1900) {
754f4f33ea0SBaptiste Daroussin 	current.tm_year = year - 1900;
755f4f33ea0SBaptiste Daroussin     }
756f4f33ea0SBaptiste Daroussin     if (month >= 1) {
757f4f33ea0SBaptiste Daroussin 	current.tm_mon = month - 1;
758f4f33ea0SBaptiste Daroussin     }
759f4f33ea0SBaptiste Daroussin     if (day > 0 && day <= days_per_month(current.tm_year + 1900,
760f4f33ea0SBaptiste Daroussin 					 current.tm_mon + 1)) {
761f4f33ea0SBaptiste Daroussin 	current.tm_mday = day;
762f4f33ea0SBaptiste Daroussin     }
763f4f33ea0SBaptiste Daroussin     now_time = mktime(&current);
764f4f33ea0SBaptiste Daroussin #else
7654c8945a0SNathan Whitehorn     if (day < 0)
7664c8945a0SNathan Whitehorn 	day = current.tm_mday;
7674c8945a0SNathan Whitehorn     if (month < 0)
7684c8945a0SNathan Whitehorn 	month = current.tm_mon + 1;
7694c8945a0SNathan Whitehorn     if (year < 0)
7704c8945a0SNathan Whitehorn 	year = current.tm_year + 1900;
7714c8945a0SNathan Whitehorn 
7724c8945a0SNathan Whitehorn     /* compute a struct tm that matches the day/month/year parameters */
7734c8945a0SNathan Whitehorn     if (((year -= 1900) > 0) && (year < 200)) {
7744c8945a0SNathan Whitehorn 	/* ugly, but I'd like to run this on older machines w/o mktime -TD */
7754c8945a0SNathan Whitehorn 	for (;;) {
7764c8945a0SNathan Whitehorn 	    if (year > current.tm_year) {
7774c8945a0SNathan Whitehorn 		now_time += ONE_DAY * days_in_year(&current, 0);
7784c8945a0SNathan Whitehorn 	    } else if (year < current.tm_year) {
7794c8945a0SNathan Whitehorn 		now_time -= ONE_DAY * days_in_year(&current, -1);
7804c8945a0SNathan Whitehorn 	    } else if (month > current.tm_mon + 1) {
7814c8945a0SNathan Whitehorn 		now_time += ONE_DAY * days_in_month(&current, 0);
7824c8945a0SNathan Whitehorn 	    } else if (month < current.tm_mon + 1) {
7834c8945a0SNathan Whitehorn 		now_time -= ONE_DAY * days_in_month(&current, -1);
7844c8945a0SNathan Whitehorn 	    } else if (day > current.tm_mday) {
7854c8945a0SNathan Whitehorn 		now_time += ONE_DAY;
7864c8945a0SNathan Whitehorn 	    } else if (day < current.tm_mday) {
7874c8945a0SNathan Whitehorn 		now_time -= ONE_DAY;
7884c8945a0SNathan Whitehorn 	    } else {
7894c8945a0SNathan Whitehorn 		break;
7904c8945a0SNathan Whitehorn 	    }
7914c8945a0SNathan Whitehorn 	    current = *localtime(&now_time);
7924c8945a0SNathan Whitehorn 	}
7934c8945a0SNathan Whitehorn     }
794f4f33ea0SBaptiste Daroussin #endif
795f4f33ea0SBaptiste Daroussin 
7964c8945a0SNathan Whitehorn     dlg_button_layout(buttons, &mincols);
7974c8945a0SNathan Whitehorn 
7984c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
7994c8945a0SNathan Whitehorn   retry:
8004c8945a0SNathan Whitehorn #endif
8014c8945a0SNathan Whitehorn 
802f4f33ea0SBaptiste Daroussin     prompt = dlg_strclone(subtitle);
8034c8945a0SNathan Whitehorn     dlg_auto_size(title, prompt, &height, &width, 0, mincols);
804f4f33ea0SBaptiste Daroussin 
8054c8945a0SNathan Whitehorn     height += MIN_HIGH - 1;
8064c8945a0SNathan Whitehorn     dlg_print_size(height, width);
8074c8945a0SNathan Whitehorn     dlg_ctl_size(height, width);
8084c8945a0SNathan Whitehorn 
8094c8945a0SNathan Whitehorn     dialog = dlg_new_window(height, width,
8104c8945a0SNathan Whitehorn 			    dlg_box_y_ordinate(height),
8114c8945a0SNathan Whitehorn 			    dlg_box_x_ordinate(width));
8124c8945a0SNathan Whitehorn     dlg_register_window(dialog, "calendar", binding);
8134c8945a0SNathan Whitehorn     dlg_register_buttons(dialog, "calendar", buttons);
8144c8945a0SNathan Whitehorn 
8154c8945a0SNathan Whitehorn     /* mainbox */
8162a3e3873SBaptiste Daroussin     dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
8172a3e3873SBaptiste Daroussin     dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
8184c8945a0SNathan Whitehorn     dlg_draw_title(dialog, title);
8194c8945a0SNathan Whitehorn 
820f4f33ea0SBaptiste Daroussin     dlg_attrset(dialog, dialog_attr);	/* text mainbox */
8214c8945a0SNathan Whitehorn     dlg_print_autowrap(dialog, prompt, height, width);
8224c8945a0SNathan Whitehorn 
8234c8945a0SNathan Whitehorn     /* compute positions of day, month and year boxes */
8244c8945a0SNathan Whitehorn     memset(&dy_box, 0, sizeof(dy_box));
8254c8945a0SNathan Whitehorn     memset(&mn_box, 0, sizeof(mn_box));
8264c8945a0SNathan Whitehorn     memset(&yr_box, 0, sizeof(yr_box));
8274c8945a0SNathan Whitehorn 
828f4f33ea0SBaptiste Daroussin     if ((week_start = WeekStart()) < 0 ||
829f4f33ea0SBaptiste Daroussin 	init_object(&dy_box,
8304c8945a0SNathan Whitehorn 		    dialog,
8314c8945a0SNathan Whitehorn 		    (width - DAY_WIDE) / 2,
8324c8945a0SNathan Whitehorn 		    1 + (height - (DAY_HIGH + BTN_HIGH + (5 * MARGIN))),
8334c8945a0SNathan Whitehorn 		    DAY_WIDE,
8344c8945a0SNathan Whitehorn 		    DAY_HIGH + 1,
8354c8945a0SNathan Whitehorn 		    draw_day,
836f4f33ea0SBaptiste Daroussin 		    week_start,
837f4f33ea0SBaptiste Daroussin 		    'D') < 0 ||
838f4f33ea0SBaptiste Daroussin 	((dy_box.week_start = WeekStart()) < 0) ||
839f4f33ea0SBaptiste Daroussin 	DrawObject(&dy_box) < 0) {
8404c8945a0SNathan Whitehorn 	return CleanupResult(DLG_EXIT_ERROR, dialog, prompt, &save_vars);
8414c8945a0SNathan Whitehorn     }
8424c8945a0SNathan Whitehorn 
8434c8945a0SNathan Whitehorn     if (init_object(&mn_box,
8444c8945a0SNathan Whitehorn 		    dialog,
8454c8945a0SNathan Whitehorn 		    dy_box.x,
8464c8945a0SNathan Whitehorn 		    dy_box.y - (HDR_HIGH + 2 * MARGIN),
8474c8945a0SNathan Whitehorn 		    (DAY_WIDE / 2) - MARGIN,
8484c8945a0SNathan Whitehorn 		    HDR_HIGH,
8494c8945a0SNathan Whitehorn 		    draw_month,
850f4f33ea0SBaptiste Daroussin 		    0,
8514c8945a0SNathan Whitehorn 		    'M') < 0
8524c8945a0SNathan Whitehorn 	|| DrawObject(&mn_box) < 0) {
8534c8945a0SNathan Whitehorn 	return CleanupResult(DLG_EXIT_ERROR, dialog, prompt, &save_vars);
8544c8945a0SNathan Whitehorn     }
8554c8945a0SNathan Whitehorn 
8564c8945a0SNathan Whitehorn     if (init_object(&yr_box,
8574c8945a0SNathan Whitehorn 		    dialog,
8584c8945a0SNathan Whitehorn 		    dy_box.x + mn_box.width + 2,
8594c8945a0SNathan Whitehorn 		    mn_box.y,
8604c8945a0SNathan Whitehorn 		    mn_box.width,
8614c8945a0SNathan Whitehorn 		    mn_box.height,
8624c8945a0SNathan Whitehorn 		    draw_year,
863f4f33ea0SBaptiste Daroussin 		    0,
8644c8945a0SNathan Whitehorn 		    'Y') < 0
8654c8945a0SNathan Whitehorn 	|| DrawObject(&yr_box) < 0) {
8664c8945a0SNathan Whitehorn 	return CleanupResult(DLG_EXIT_ERROR, dialog, prompt, &save_vars);
8674c8945a0SNathan Whitehorn     }
8684c8945a0SNathan Whitehorn 
8692a3e3873SBaptiste Daroussin     dlg_trace_win(dialog);
8704c8945a0SNathan Whitehorn     while (result == DLG_EXIT_UNKNOWN) {
871*a96ef450SBaptiste Daroussin 	int key2;
8724c8945a0SNathan Whitehorn 	BOX *obj = (state == sDAY ? &dy_box
8734c8945a0SNathan Whitehorn 		    : (state == sMONTH ? &mn_box :
8744c8945a0SNathan Whitehorn 		       (state == sYEAR ? &yr_box : 0)));
8754c8945a0SNathan Whitehorn 
8764c8945a0SNathan Whitehorn 	button = (state < 0) ? 0 : state;
8774c8945a0SNathan Whitehorn 	dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);
8784c8945a0SNathan Whitehorn 	if (obj != 0)
8794c8945a0SNathan Whitehorn 	    dlg_set_focus(dialog, obj->window);
8804c8945a0SNathan Whitehorn 
8814c8945a0SNathan Whitehorn 	key = dlg_mouse_wgetch(dialog, &fkey);
882*a96ef450SBaptiste Daroussin 	if (dlg_result_key(key, fkey, &result)) {
883*a96ef450SBaptiste Daroussin 	    if (!dlg_button_key(result, &button, &key, &fkey))
8844c8945a0SNathan Whitehorn 		break;
885*a96ef450SBaptiste Daroussin 	}
886f4f33ea0SBaptiste Daroussin #define Mouse2Key(key) (key - M_EVENT)
8874c8945a0SNathan Whitehorn 	if (fkey && (key >= DLGK_MOUSE(KEY_MIN) && key <= DLGK_MOUSE(KEY_MAX))) {
888f4f33ea0SBaptiste Daroussin 	    key = dlg_lookup_key(dialog, Mouse2Key(key), &fkey);
8894c8945a0SNathan Whitehorn 	}
8904c8945a0SNathan Whitehorn 
8914c8945a0SNathan Whitehorn 	if ((key2 = dlg_char_to_button(key, buttons)) >= 0) {
8924c8945a0SNathan Whitehorn 	    result = key2;
8934c8945a0SNathan Whitehorn 	} else if (fkey) {
8944c8945a0SNathan Whitehorn 	    /* handle function-keys */
8954c8945a0SNathan Whitehorn 	    switch (key) {
8964c8945a0SNathan Whitehorn 	    case DLGK_MOUSE('D'):
8974c8945a0SNathan Whitehorn 		state = sDAY;
8984c8945a0SNathan Whitehorn 		break;
8994c8945a0SNathan Whitehorn 	    case DLGK_MOUSE('M'):
9004c8945a0SNathan Whitehorn 		state = sMONTH;
9014c8945a0SNathan Whitehorn 		break;
9024c8945a0SNathan Whitehorn 	    case DLGK_MOUSE('Y'):
9034c8945a0SNathan Whitehorn 		state = sYEAR;
9044c8945a0SNathan Whitehorn 		break;
905f4f33ea0SBaptiste Daroussin 	    case DLGK_TOGGLE:
9064c8945a0SNathan Whitehorn 	    case DLGK_ENTER:
907682c9e0fSNathan Whitehorn 		result = dlg_enter_buttoncode(button);
9084c8945a0SNathan Whitehorn 		break;
909*a96ef450SBaptiste Daroussin 	    case DLGK_LEAVE:
910*a96ef450SBaptiste Daroussin 		result = dlg_ok_buttoncode(button);
911*a96ef450SBaptiste Daroussin 		break;
9124c8945a0SNathan Whitehorn 	    case DLGK_FIELD_PREV:
9134c8945a0SNathan Whitehorn 		state = dlg_prev_ok_buttonindex(state, sMONTH);
9144c8945a0SNathan Whitehorn 		break;
9154c8945a0SNathan Whitehorn 	    case DLGK_FIELD_NEXT:
9164c8945a0SNathan Whitehorn 		state = dlg_next_ok_buttonindex(state, sMONTH);
9174c8945a0SNathan Whitehorn 		break;
9184c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
9194c8945a0SNathan Whitehorn 	    case KEY_RESIZE:
920f4f33ea0SBaptiste Daroussin 		dlg_will_resize(dialog);
9214c8945a0SNathan Whitehorn 		/* reset data */
9224c8945a0SNathan Whitehorn 		height = old_height;
9234c8945a0SNathan Whitehorn 		width = old_width;
924f4f33ea0SBaptiste Daroussin 		free(prompt);
925*a96ef450SBaptiste Daroussin 		_dlg_resize_cleanup(dialog);
926f4f33ea0SBaptiste Daroussin 		/* repaint */
9274c8945a0SNathan Whitehorn 		goto retry;
9284c8945a0SNathan Whitehorn #endif
9294c8945a0SNathan Whitehorn 	    default:
9304c8945a0SNathan Whitehorn 		step = 0;
9314c8945a0SNathan Whitehorn 		key2 = -1;
9324c8945a0SNathan Whitehorn 		if (is_DLGK_MOUSE(key)) {
933f4f33ea0SBaptiste Daroussin 		    if ((key2 = dlg_ok_buttoncode(Mouse2Key(key))) >= 0) {
9344c8945a0SNathan Whitehorn 			result = key2;
9354c8945a0SNathan Whitehorn 			break;
9364c8945a0SNathan Whitehorn 		    } else if (key >= DLGK_MOUSE(KEY_MAX)) {
9374c8945a0SNathan Whitehorn 			state = sDAY;
9384c8945a0SNathan Whitehorn 			obj = &dy_box;
9394c8945a0SNathan Whitehorn 			key2 = 1;
9404c8945a0SNathan Whitehorn 			step = (key
9414c8945a0SNathan Whitehorn 				- DLGK_MOUSE(KEY_MAX)
9424c8945a0SNathan Whitehorn 				- day_cell_number(&current));
943f4f33ea0SBaptiste Daroussin 			DLG_TRACE(("# mouseclick decoded %d\n", step));
9444c8945a0SNathan Whitehorn 		    }
9454c8945a0SNathan Whitehorn 		}
9464c8945a0SNathan Whitehorn 		if (obj != 0) {
947f4f33ea0SBaptiste Daroussin 		    if (key2 < 0) {
9484c8945a0SNathan Whitehorn 			step = next_or_previous(key, (obj == &dy_box));
949f4f33ea0SBaptiste Daroussin 		    }
9504c8945a0SNathan Whitehorn 		    if (step != 0) {
9514c8945a0SNathan Whitehorn 			struct tm old = current;
9524c8945a0SNathan Whitehorn 
9534c8945a0SNathan Whitehorn 			/* see comment regarding mktime -TD */
9544c8945a0SNathan Whitehorn 			if (obj == &dy_box) {
9554c8945a0SNathan Whitehorn 			    now_time += ONE_DAY * step;
9564c8945a0SNathan Whitehorn 			} else if (obj == &mn_box) {
9574c8945a0SNathan Whitehorn 			    if (step > 0)
9584c8945a0SNathan Whitehorn 				now_time += ONE_DAY *
9594c8945a0SNathan Whitehorn 				    days_in_month(&current, 0);
9604c8945a0SNathan Whitehorn 			    else
9614c8945a0SNathan Whitehorn 				now_time -= ONE_DAY *
9624c8945a0SNathan Whitehorn 				    days_in_month(&current, -1);
9634c8945a0SNathan Whitehorn 			} else if (obj == &yr_box) {
9644c8945a0SNathan Whitehorn 			    if (step > 0)
9654c8945a0SNathan Whitehorn 				now_time += (ONE_DAY
9664c8945a0SNathan Whitehorn 					     * days_in_year(&current, 0));
9674c8945a0SNathan Whitehorn 			    else
9684c8945a0SNathan Whitehorn 				now_time -= (ONE_DAY
9694c8945a0SNathan Whitehorn 					     * days_in_year(&current, -1));
9704c8945a0SNathan Whitehorn 			}
9714c8945a0SNathan Whitehorn 
9724c8945a0SNathan Whitehorn 			current = *localtime(&now_time);
9734c8945a0SNathan Whitehorn 
974f4f33ea0SBaptiste Daroussin 			trace_date(&current, &old);
9754c8945a0SNathan Whitehorn 			if (obj != &dy_box
9764c8945a0SNathan Whitehorn 			    && (current.tm_mday != old.tm_mday
9774c8945a0SNathan Whitehorn 				|| current.tm_mon != old.tm_mon
9784c8945a0SNathan Whitehorn 				|| current.tm_year != old.tm_year))
9794c8945a0SNathan Whitehorn 			    DrawObject(&dy_box);
9804c8945a0SNathan Whitehorn 			if (obj != &mn_box && current.tm_mon != old.tm_mon)
9814c8945a0SNathan Whitehorn 			    DrawObject(&mn_box);
9824c8945a0SNathan Whitehorn 			if (obj != &yr_box && current.tm_year != old.tm_year)
9834c8945a0SNathan Whitehorn 			    DrawObject(&yr_box);
9844c8945a0SNathan Whitehorn 			(void) DrawObject(obj);
9854c8945a0SNathan Whitehorn 		    }
9864c8945a0SNathan Whitehorn 		} else if (state >= 0) {
9874c8945a0SNathan Whitehorn 		    if (next_or_previous(key, FALSE) < 0)
9884c8945a0SNathan Whitehorn 			state = dlg_prev_ok_buttonindex(state, sMONTH);
9894c8945a0SNathan Whitehorn 		    else if (next_or_previous(key, FALSE) > 0)
9904c8945a0SNathan Whitehorn 			state = dlg_next_ok_buttonindex(state, sMONTH);
9914c8945a0SNathan Whitehorn 		}
9924c8945a0SNathan Whitehorn 		break;
9934c8945a0SNathan Whitehorn 	    }
9944c8945a0SNathan Whitehorn 	}
9954c8945a0SNathan Whitehorn     }
9964c8945a0SNathan Whitehorn 
9974c8945a0SNathan Whitehorn #define DefaultFormat(dst, src) \
9984c8945a0SNathan Whitehorn 	sprintf(dst, "%02d/%02d/%0d", \
9994c8945a0SNathan Whitehorn 		src.tm_mday, src.tm_mon + 1, src.tm_year + 1900)
10004c8945a0SNathan Whitehorn #ifdef HAVE_STRFTIME
10014c8945a0SNathan Whitehorn     if (dialog_vars.date_format != 0) {
10024c8945a0SNathan Whitehorn 	size_t used = strftime(buffer,
10034c8945a0SNathan Whitehorn 			       sizeof(buffer) - 1,
10044c8945a0SNathan Whitehorn 			       dialog_vars.date_format,
10054c8945a0SNathan Whitehorn 			       &current);
10064c8945a0SNathan Whitehorn 	if (used == 0 || *buffer == '\0')
10074c8945a0SNathan Whitehorn 	    DefaultFormat(buffer, current);
10084c8945a0SNathan Whitehorn     } else
10094c8945a0SNathan Whitehorn #endif
10104c8945a0SNathan Whitehorn 	DefaultFormat(buffer, current);
10114c8945a0SNathan Whitehorn 
10124c8945a0SNathan Whitehorn     dlg_add_result(buffer);
1013*a96ef450SBaptiste Daroussin     AddLastKey();
10144c8945a0SNathan Whitehorn 
10154c8945a0SNathan Whitehorn     return CleanupResult(result, dialog, prompt, &save_vars);
10164c8945a0SNathan Whitehorn }
1017