Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / programs / dtcm / server / reutil.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: reutil.c /main/7 1996/11/21 19:47:12 drk $ */
24 /*
25  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26  *  (c) Copyright 1993, 1994 International Business Machines Corp.
27  *  (c) Copyright 1993, 1994 Novell, Inc.
28  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
29  */
30
31 #include <time.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "rerule.h"
35 #include "reutil.h"
36 #include "repeat.h"
37
38 #define XOS_USE_NO_LOCKING
39 #define X_INCLUDE_TIME_H
40 #if defined(__linux__)
41 #undef SVR4
42 #endif
43 #include <X11/Xos_r.h>
44
45 extern int monthdays[12];
46 extern RepeatEvent      *_DtCm_repeat_info;
47 extern char             *_DtCm_rule_buf;
48 extern void              _DtCm_rule_parser();
49 extern char             *ReToString(RepeatEvent *);
50
51
52 /*
53  * Check to make sure the current interval number is not greater than the
54  * duration.
55  */
56 int
57 InTimeRange(
58         const unsigned int    ninterval,
59         const Duration        duration)
60 {
61         if (duration == RE_INFINITY || duration == RE_NOTSET) return TRUE;
62
63         if (ninterval >= duration)
64                 return FALSE;
65
66         return TRUE;
67 }
68
69 /*
70  * Given two days of the week, compute the forward difference between them. 
71  */
72 int
73 GetWDayDiff(
74         const int     start,
75         const int     end)
76 {
77         if (start <= end)
78                 return end - start;
79
80         return (7 - (start - end));
81 }
82
83 /*
84  * Returns true if a day exists in the specified month and year.
85  */
86 int
87 DayExists(
88         const int     day,
89         const int     month,
90         const int     year)
91 {
92         int valid_day = DayOfMonth(day, month, year);
93
94         if (valid_day < 29) return TRUE;
95
96         /* month = 0 = January */
97         if ((month == 1) && leapyr(year + 1900)) {
98                 if (valid_day == 29)
99                         return TRUE;
100                 else
101                         return FALSE;
102         }
103
104         if (valid_day <= monthdays[month]) 
105                 return TRUE;
106
107         return FALSE;
108 }
109
110 /* 
111  * Given a date (specifically a month and year) determine if any of the
112  * occurences of a weekday (e.g. 4th Sunday) exist in the given month.
113  */
114 int
115 OccurenceExists(
116         const WeekDayTime       *wdt_list,
117         const unsigned int       nwdt_list,
118         const Tick               date)
119 {
120         int              i, j, k;
121
122         for (i = 0; i < nwdt_list; i++) {
123                 for (j = 0; j < wdt_list[i].wdt_nweek; j++) {
124                         for (k = 0; k < wdt_list[i].wdt_nday; k++) {
125                                 if (WeekNumberToDay(date,
126                                                 wdt_list[i].wdt_week[j],
127                                                 wdt_list[i].wdt_day[k])) {
128                                         return TRUE;
129                                 }
130                         }
131                 }
132         }
133
134         return FALSE;
135 }
136
137 WeekNumber
138 GetWeekNumber(
139         const Tick date)
140 {
141         switch (DayToWeekNumber(date)) {
142         case 1:
143                 return WK_F1;
144         case 2:
145                 return WK_F2;
146         case 3:
147                 return WK_F3;
148         case 4:
149                 return WK_F4;
150         case 5:
151                 return WK_F5;
152         default:
153                 return WK_L1;
154         }
155 }
156
157 /*
158  * Calculate the position of a week day (e.g. SU) in the month:
159  *      7/1/94  would return 1 since this is the first Friday of the month.
160  *      7/6/94  would return 1 even though it is in the second week since this
161  *              is the first Wed of the month.
162  *      7/15/94 would return 3.
163  */
164 WeekNumber
165 DayToWeekNumber(
166         const Tick date)
167 {
168         _Xltimeparams    localtime_buf;
169         struct tm       *date_tm = _XLocaltime(&date, localtime_buf);
170         int              week_number;
171
172         week_number = date_tm->tm_mday / 7;
173  
174         if (date_tm->tm_mday % 7)
175                 week_number++;
176  
177         return week_number;
178 }
179
180 /*
181  * Given a week number and a day of the week determine what day of the month
182  * it falls on given a month in ``date''.
183  */
184 Tick
185 WeekNumberToDay(
186         const Tick            date,
187         const WeekNumber      week,
188         const WeekDay         weekday)
189 {
190         _Xltimeparams    localtime_buf;
191         struct tm       *date_tm = _XLocaltime(&date, localtime_buf);
192         int              first_weekday,
193                          last_weekday,
194                          day_of_month,
195                          initial_month_number = date_tm->tm_mon;
196         Tick             _date;
197
198         /* From the first day (or last day in the WK_L* cases) of the month
199          * work forward (or backward) to find the weekday requested. 
200          */
201         if (week <= (const WeekDay)WK_F5) {
202                 day_of_month = 1;
203                 first_weekday = fdom(date);
204                 if (weekday != first_weekday)
205                         day_of_month += GetWDayDiff(first_weekday, weekday);
206         } else {
207                 day_of_month = monthlength(date);
208                 last_weekday = ldom(date);
209                 if (weekday != last_weekday)
210                         day_of_month -= GetWDayDiff(weekday, last_weekday);
211         }
212
213         /* Now move forward or backward through the month added or subtracting
214          * the appropriate number of weeks to get to the correct location.
215          */
216         if (week <= (const WeekDay)WK_F5) {
217                 date_tm->tm_mday = day_of_month + (int)week * 7;
218         } else {
219                 /* ((int)week - WK_L1) normalizes the WK_L* to the values
220                  * of 0 to 4.  See the WeekNumber enum.
221                  */
222                 date_tm->tm_mday = day_of_month - ((int)week - WK_L1) * 7;
223         } 
224
225         date_tm->tm_isdst = -1;
226         _date = mktime(date_tm);
227         date_tm = _XLocaltime(&_date, localtime_buf);
228
229         /* It is possible that the requested week number is not in this
230          * month.
231          */
232         if (date_tm->tm_mon != initial_month_number)
233                 return ((Tick)NULL);
234
235         return (_date);
236 }
237
238 unsigned int
239 DayOfMonth(
240         const int     day,
241         const int     month,
242         const int     year)
243 {
244
245         if (day != RE_LASTDAY) return day;
246
247         /* month = 0 = January */
248         if ((month == 1) && leapyr(year + 1900))
249                 return 29;
250         else
251                 return monthdays[month];
252 }
253
254 int
255 same_week(
256         struct tm       *tm1,
257         struct tm       *tm2)
258 {
259         struct tm        tm11 = *tm1;
260         struct tm        tm22 = *tm2;
261         Tick             time1, time2;
262         _Xltimeparams    localtime_buf;
263
264         tm11.tm_mday -= tm11.tm_wday;
265         tm22.tm_mday -= tm22.tm_wday;
266         time1 = mktime(&tm11);
267         time2 = mktime(&tm22);
268         tm11 = *_XLocaltime(&time1, localtime_buf);
269         tm22 = *_XLocaltime(&time2, localtime_buf);
270
271         if (tm11.tm_yday == tm22.tm_yday)
272                 return TRUE;
273
274         return FALSE;
275 }
276
277 Tick
278 DeriveNewStartTime(
279         const Tick       start_time,
280         RepeatEvent     *old_re,
281         const Tick       current_time,
282         const Tick       target_time,
283         RepeatEvent     *new_re)
284 {
285         Tick             end_date;
286         Tick             an_event;
287         int              num_events;
288         RepeatEventState *res = NULL;
289
290         /* Count the number of events from the start time to the current time */
291         end_date = old_re->re_end_date;
292         old_re->re_end_date = current_time;
293         /* XXX: Need to deal with excluded events */
294         num_events = CountEvents(start_time, old_re, NULL);
295         old_re->re_end_date = end_date;
296  
297         if (!ClosestTick(current_time, start_time, old_re, &res)) {
298                 /* XXX: Are we at the last tick or are there other problems? */
299                 return 0;
300         }
301
302         an_event = target_time;
303  
304         /* Walk backwards from the new target time to where the new start
305          * time should be.
306          */
307         while (--num_events &&
308                (an_event = PrevTick(an_event, 0, new_re, res))) {
309                ;
310         }
311
312         free(res);
313
314         return an_event;
315 }
316
317 /*
318  * Return True if rule1 is the same as rule2.  This function returns True
319  * if the rule portion of the rules are == reguardless of the duration or 
320  * end_date's. 
321  * re1 should point to the RepeatEvent struct for rule1. If you pass in
322  * NULL for re1 the function *may* parse rule1 for you and return the
323  * RepeatEvent struct through re1.  You will need to free it.
324  * The same applies for re2.
325  */
326 boolean_t
327 RulesMatch(
328         char            *rule1,
329         char            *rule2)
330 {
331         Duration         old_duration;
332         time_t           old_end_date;
333         char            *new_rule1,
334                         *new_rule2;
335         RepeatEvent     *re1,
336                         *re2;
337
338         /* If rules are the same then we are done */
339         if (!strcmp(rule1, rule2))
340                 return TRUE;
341
342         _DtCm_rule_buf = rule1;
343         _DtCm_rule_parser();
344         if (!_DtCm_repeat_info) {
345                 /* Bad rule - fail */
346                 return FALSE;
347         }
348         re1 = _DtCm_repeat_info;
349
350         _DtCm_rule_buf = rule2;
351         _DtCm_rule_parser();
352         if (!_DtCm_repeat_info) {
353                 /* Bad rule - fail */
354                 _DtCm_free_re(re1);
355                 return FALSE;
356         }
357         re2 = _DtCm_repeat_info;
358
359         /* If rule1 != rule2 and the duration and end_date are the same
360          * then the rules themselves must be different.
361          */
362         if (re1->re_duration == re2->re_duration &&
363             re1->re_end_date == re2->re_end_date) {
364                 _DtCm_free_re(re1);
365                 _DtCm_free_re(re2);
366                 return FALSE;
367         }
368
369         
370         /* If the duration or end_date are different, the rules themselves
371          * may still be different.  So we make the durations and end_dates
372          * the same and reconstruct the rules.
373          */
374         old_duration = re2->re_duration;
375         old_end_date = re2->re_end_date;
376
377         re2->re_duration = re1->re_duration;
378         re2->re_end_date = re1->re_end_date;
379
380         new_rule1 = ReToString(re1);
381         new_rule2 = ReToString(re2);
382
383         re2->re_duration = old_duration;
384         re2->re_end_date = old_end_date;
385
386         if (!strcmp(new_rule1, new_rule2)) {
387                 _DtCm_free_re(re1);
388                 _DtCm_free_re(re2);
389                 free(new_rule1);
390                 free(new_rule2);
391                 return TRUE;
392         }
393         free(new_rule1);
394         free(new_rule2);
395         _DtCm_free_re(re1);
396         _DtCm_free_re(re2);
397         return FALSE;
398 }