int CALLBACK CSortListCtrl::CompareFunction( LPARAM lParam1, LPARAM lParam2, LPARAM lParamData ) { CSortListCtrl* pListCtrl = reinterpret_cast<CSortListCtrl*>( lParamData ); ASSERT( pListCtrl->IsKindOf( RUNTIME_CLASS( CListCtrl ) ) ); ItemData* pid1 = reinterpret_cast<ItemData*>( lParam1 ); ItemData* pid2 = reinterpret_cast<ItemData*>( lParam2 ); ASSERT( pid1 ); ASSERT( pid2 ); LPCTSTR pszText1 = pid1->arrpsz[ pListCtrl->m_iSortColumn ]; LPCTSTR pszText2 = pid2->arrpsz[ pListCtrl->m_iSortColumn ]; ASSERT_VALID_STRING( pszText1 ); ASSERT_VALID_STRING( pszText2 ); if( IsNumber( pszText1 ) ) return pListCtrl->m_bSortAscending ? NumberCompare( pszText1, pszText2 ) : NumberCompare( pszText2, pszText1 ); else if( IsDate( pszText1 ) ) return pListCtrl->m_bSortAscending ? DateCompare( pszText1, pszText2 ) : DateCompare( pszText2, pszText1 ); else // text. return pListCtrl->m_bSortAscending ? lstrcmp( pszText1, pszText2 ) : lstrcmp( pszText2, pszText1 ); }
/************************************************************ * * FUNCTION: ApptComparePackedRecords * * DESCRIPTION: Compare two packed records. * * PARAMETERS: r1 - database record 1 * r2 - database record 2 * extra - extra data, not used in the function * * RETURNS: -1 if record one is less * 1 if record two is less * * CREATED: 1/14/95 * * BY: Roger Flores * * COMMENTS: Compare the two records key by key until * there is a difference. Return -1 if r1 is less or 1 if r2 * is less. A zero is never returned because if two records * seem identical then their unique IDs are compared! * *************************************************************/ static Int16 ApptComparePackedRecords (ApptPackedDBRecordPtr r1, ApptPackedDBRecordPtr r2, Int16 extra, SortRecordInfoPtr info1, SortRecordInfoPtr info2, MemHandle appInfoH) { Int16 result; if ((r1->flags.repeat) || (r2->flags.repeat)) { if ((r1->flags.repeat) && (r2->flags.repeat)) { // In the past, two repeating events were considered equal. Now we sort them // by their end date in order to more efficiently iterate over the repeating // events on a given date or date range. First step is to find the repeat // info in each of the records so we can compare their end dates. // No end date is represented as -1, which will sort last, as desired. result = DateCompare (ApptGetRepeatInfo(r1)->repeatEndDate, ApptGetRepeatInfo(r2)->repeatEndDate); if (result == 0) // Two events than end on the same date are sorted by their start time. // We don't in fact rely on this, but might in the future. result = TimeCompare (r1->when.startTime, r2->when.startTime); } else if (r1->flags.repeat) result = -1; else result = 1; } else { result = DateCompare (r1->when.date, r2->when.date); if (result == 0) result = TimeCompare (r1->when.startTime, r2->when.startTime); } return result; }
static Boolean IsException (ApptDBRecordPtr apptRec, DateType date) { int i; DatePtr exceptions; if (apptRec->exceptions) { exceptions = &apptRec->exceptions->exception; for (i = 0; i < apptRec->exceptions->numExceptions; i++) { if (DateCompare (date, exceptions[i]) == 0) return (true); } } return (false); }
static void fileDate(TSession * const sessionP, time_t const statFilemodTime, TDate * const fileDateP) { abyss_bool haveDate; TDate filemodDate; haveDate = DateFromLocal(&filemodDate, statFilemodTime); if (haveDate) { if (DateCompare(&sessionP->date, &filemodDate) < 0) *fileDateP = sessionP->date; else *fileDateP = filemodDate; } else *fileDateP = sessionP->date; }
static abyss_bool ServerFileHandler(TSession * const r, char * const z, time_t const fileModTime, MIMEType * const mimeTypeP) { const char * mediatype; TFile file; uint64_t filesize; uint64_t start; uint64_t end; TDate date; char * p; TDate filedate; mediatype = MIMETypeGuessFromFile2(mimeTypeP, z); if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) { ResponseStatusErrno(r); return TRUE; } fileDate(r, fileModTime, &filedate); p = RequestHeaderValue(r, "if-modified-since"); if (p) { if (DateDecode(p,&date)) { if (DateCompare(&filedate, &date) <= 0) { ResponseStatus(r, 304); ResponseWrite(r); return TRUE; } else r->ranges.size = 0; } } filesize = FileSize(&file); switch (r->ranges.size) { case 0: ResponseStatus(r, 200); break; case 1: { abyss_bool decoded; decoded = RangeDecode((char *)(r->ranges.item[0]), filesize, &start, &end); if (!decoded) { ListFree(&(r->ranges)); ResponseStatus(r, 200); break; } sprintf(z, "bytes %llu-%llu/%llu", start, end, filesize); ResponseAddField(r, "Content-range", z); ResponseContentLength(r, end - start + 1); ResponseStatus(r, 206); } break; default: ResponseContentType(r, "multipart/ranges; boundary=" BOUNDARY); ResponseStatus(r, 206); break; } if (r->ranges.size == 0) { ResponseContentLength(r, filesize); ResponseContentType(r, mediatype); } if (DateToString(&filedate, z)) ResponseAddField(r, "Last-Modified", z); ResponseWrite(r); if (r->request_info.method != m_head) sendBody(r, &file, filesize, mediatype, start, end, z); FileClose(&file); return TRUE; }
static abyss_bool ServerDirectoryHandler(TSession * const r, char * const z, time_t const fileModTime, MIMEType * const mimeTypeP) { TList list; abyss_bool text; abyss_bool ascending; uint16_t sort; /* 1=by name, 2=by date */ TPool pool; TDate date; const char * error; uint16_t responseStatus; TDate dirdate; const char * imsHdr; determineSortType(r->request_info.query, &ascending, &sort, &text, &error); if (error) { ResponseStatus(r,400); xmlrpc_strfree(error); return TRUE; } fileDate(r, fileModTime, &dirdate); imsHdr = RequestHeaderValue(r, "If-Modified-Since"); if (imsHdr) { if (DateDecode(imsHdr, &date)) { if (DateCompare(&dirdate, &date) <= 0) { ResponseStatus(r, 304); ResponseWrite(r); return TRUE; } } } if (!PoolCreate(&pool, 1024)) { ResponseStatus(r, 500); return TRUE; } generateListing(&list, z, r->request_info.uri, &pool, &error, &responseStatus); if (error) { ResponseStatus(r, responseStatus); xmlrpc_strfree(error); PoolFree(&pool); return TRUE; } /* Send something to the user to show that we are still alive */ ResponseStatus(r, 200); ResponseContentType(r, (text ? "text/plain" : "text/html")); if (DateToString(&dirdate, z)) ResponseAddField(r, "Last-Modified", z); ResponseChunked(r); ResponseWrite(r); if (r->request_info.method!=m_head) sendDirectoryDocument(&list, ascending, sort, text, r->request_info.uri, mimeTypeP, r, z); HTTPWriteEndChunk(r); /* Free memory and exit */ ListFree(&list); PoolFree(&pool); return TRUE; }
/*********************************************************************** * * FUNCTION: ApptGetAppointments * * DESCRIPTION: This routine returns a list of appointments that are on * the date specified * * PARAMETERS: dbP - pointer to the database * date - date to search for * countP - number of appointments on the specified * day (returned value) * * RETURNED: handle of the appointment list (ApptInfoType) * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * art 6/15/95 Initial Revision * ***********************************************************************/ MemHandle ApptGetAppointments (DmOpenRef dbP, DateType date, UInt16 * countP) { Err error; Int16 result; Int16 count = 0; UInt16 recordNum; Boolean repeats; MemHandle recordH; MemHandle apptListH; ApptInfoPtr apptList; ApptDBRecordType apptRec; ApptPackedDBRecordPtr r; // Allocated a block to hold the appointment list. apptListH = MemHandleNew (sizeof (ApptInfoType) * apptMaxPerDay); ErrFatalDisplayIf(!apptListH, "Out of memory"); if (! apptListH) return (0); apptList = MemHandleLock (apptListH); // Find the first non-repeating appointment of the day. if (ApptFindFirst (dbP, date, &recordNum)) { while (count < apptMaxPerDay) { // Check if the appointment is on the date passed, if it is // add it to the appointment list. recordH = DmQueryRecord (dbP, recordNum); r = MemHandleLock (recordH); result = DateCompare (r->when.date, date); if (result == 0) { // Add the record to the appoitment list. apptList[count].startTime = r->when.startTime; apptList[count].endTime = r->when.endTime; apptList[count].recordNum = recordNum; count++; } MemHandleUnlock (recordH); if (result != 0) break; // Get the next record. error = DmSeekRecordInCategory (dbP, &recordNum, 1, dmSeekForward, dmAllCategories); if (error == dmErrSeekFailed) break; } } // Add the repeating appointments to the list. Repeating appointments // are stored at the beginning of the database. recordNum = 0; while (count < apptMaxPerDay) { recordH = DmQueryNextInCategory (dbP, &recordNum, dmAllCategories); if (! recordH) break; r = (ApptPackedDBRecordPtr) MemHandleLock (recordH); repeats = (r->flags.repeat != 0); if (repeats) { ApptUnpack (r, &apptRec); if (ApptRepeatsOnDate (&apptRec, date)) { // Add the record to the appoitment list. apptList[count].startTime = r->when.startTime; apptList[count].endTime = r->when.endTime; apptList[count].recordNum = recordNum; count++; } } MemHandleUnlock (recordH); // If the record has no repeating info we've reached the end of the // repeating appointments. if (! repeats) break; recordNum++; } // Sort the list by start time. // SysInsertionSort (apptList, count, sizeof (ApptInfoType), // ApptListCompare, 0L); // If there are no appointments on the specified day, free the appointment // list. if (count == 0) { MemPtrFree (apptList); apptListH = 0; } // Resize the appointment list block to release any unused space. else { MemHandleUnlock (apptListH); MemHandleResize (apptListH, count * sizeof (ApptInfoType)); } *countP = count; return (apptListH); }
/*********************************************************************** * * FUNCTION: ApptRepeatsOnDate * * DESCRIPTION: This routine returns true if a repeating appointment * occurrs on the specified date. * * PARAMETERS: apptRec - a pointer to an appointment record * date - date to check * * RETURNED: true if the appointment occurs on the date specified * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * art 6/14/95 Initial Revision * ***********************************************************************/ Boolean ApptRepeatsOnDate (ApptDBRecordPtr apptRec, DateType date) { Int16 i; UInt16 freq; UInt16 weeksDiff; UInt16 dayInMonth; UInt16 dayOfWeek; UInt16 dayOfMonth; UInt16 firstDayOfWeek; long dateInDays; long startInDays; Boolean onDate = false; DatePtr exceptions; DateType startDate; // Is the date passed before the start date of the appointment? if (DateCompare (date, apptRec->when->date) < 0) return (false); // Is the date passed after the end date of the appointment? if (DateCompare (date, apptRec->repeat->repeatEndDate) > 0) return (false); // Get the frequency of occurrecne // (ex: every 2nd day, every 3rd month, etc.). freq = apptRec->repeat->repeatFrequency; // Get the date of the first occurrecne of the appointment. startDate = apptRec->when->date; switch (apptRec->repeat->repeatType) { // Daily repeating appointment. case repeatDaily: dateInDays = DateToDays (date); startInDays = DateToDays (startDate); onDate = ((dateInDays - startInDays) % freq) == 0; break; // Weekly repeating appointment (ex: every Monday and Friday). // Yes, weekly repeating appointment can occur more then once a // week. case repeatWeekly: // Are we on a day of the week that the appointment repeats on. dayOfWeek = DayOfWeek (date.month, date.day, date.year+firstYear); onDate = ((1 << dayOfWeek) & apptRec->repeat->repeatOn); if (! onDate) break; // Are we in a week in which the appointment occurrs, if not // move to that start of the next week in which the appointment // does occur. dateInDays = DateToDays (date); startInDays = DateToDays (startDate); firstDayOfWeek = (DayOfWeek (1, 1, firstYear) - apptRec->repeat->repeatStartOfWeek + daysInWeek) % daysInWeek; weeksDiff = (((dateInDays + firstDayOfWeek) / daysInWeek) - ((startInDays + firstDayOfWeek) / daysInWeek)) %freq; onDate = (weeksDiff == 0); break; // // Compute the first occurrence of the appointment that occurs // // on the same day of the week as the date passed. // startDayOfWeek = DayOfWeek (startDate.month, startDate.day, // startDate.year+firstYear); // startInDays = DateToDays (startDate); // if (startDayOfWeek < dayOfWeek) // startInDays += dayOfWeek - startDayOfWeek; // else if (startDayOfWeek > dayOfWeek) // startInDays += dayOfWeek+ (daysInWeek *freq) - startDayOfWeek; // // // Are we in a week in which the appointment repeats. // dateInDays = DateToDays (date); // onDate = (((dateInDays - startInDays) / daysInWeek) % freq) == 0; // break; // Monthly-by-day repeating appointment (ex: the 3rd Friday of every // month). case repeatMonthlyByDay: // Are we in a month in which the appointment repeats. onDate = ((((date.year - startDate.year) * monthsInYear) + (date.month - startDate.month)) % freq) == 0; if (! onDate) break; // Do the days of the month match (ex: 3rd Friday) dayOfMonth = DayOfMonth (date.month, date.day, date.year+firstYear); onDate = (dayOfMonth == apptRec->repeat->repeatOn); if (onDate) break; // If the appointment repeats on one of the last days of the month, // check if the date passed is also one of the last days of the // month. By last days of the month we mean: last sunday, // last monday, etc. if ((apptRec->repeat->repeatOn >= domLastSun) && (dayOfMonth >= dom4thSun)) { dayOfWeek = DayOfWeek (date.month, date.day, date.year+firstYear); dayInMonth = DaysInMonth (date.month, date.year+firstYear); onDate = (((date.day + daysInWeek) > dayInMonth) && (dayOfWeek == (apptRec->repeat->repeatOn % daysInWeek))); } break; // Monthly-by-date repeating appointment (ex: the 15th of every // month). case repeatMonthlyByDate: // Are we in a month in which the appointment repeats. onDate = ((((date.year - startDate.year) * monthsInYear) + (date.month - startDate.month)) % freq) == 0; if (! onDate) break; // Are we on the same day of the month as the start date. onDate = (date.day == startDate.day); if (onDate) break; // If the staring day of the appointment is greater then the // number of day in the month passed, and the day passed is the // last day of the month, then the appointment repeats on the day. dayInMonth = DaysInMonth (date.month, date.year+firstYear); onDate = ((startDate.day > dayInMonth) && (date.day == dayInMonth)); break; // Yearly repeating appointment. case repeatYearly: // Are we in a year in which the appointment repeats. onDate = ((date.year - startDate.year) % freq) == 0; if (! onDate) break; // Are we on the month and day that the appointment repeats. onDate = (date.month == startDate.month) && (date.day == startDate.day); if (onDate) break; // Specal leap day processing. if ( (startDate.month == february) && (startDate.day == 29) && (date.month == february) && (date.day == DaysInMonth (date.month, date.year+firstYear))) { onDate = true; } break; default: break; } // Check for an exception. if ((onDate) && (apptRec->exceptions)) { exceptions = &apptRec->exceptions->exception; for (i = 0; i < apptRec->exceptions->numExceptions; i++) { if (DateCompare (date, exceptions[i]) == 0) { onDate = false; break; } } } return (onDate); }
/*********************************************************************** * * FUNCTION: ApptFindFirst * * DESCRIPTION: This routine finds the first appointment on the specified * day. * * PARAMETERS: dbP - pointer to the database * date - date to search for * indexP - pointer to the index of the first record on the * specified day (returned value) * * RETURNED: true if a record has found * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * art 6/15/95 Initial Revision * ***********************************************************************/ Boolean ApptFindFirst (DmOpenRef dbP, DateType date, UInt16 * indexP) { Err err; Int16 numOfRecords; Int16 kmin, probe, i; // all positions in the database. Int16 result = 0; // result of comparing two records UInt16 index; MemHandle recordH; Boolean found = false; ApptPackedDBRecordPtr r; kmin = probe = 0; numOfRecords = DmNumRecords(dbP); while (numOfRecords > 0) { i = numOfRecords >> 1; probe = kmin + i; index = probe; recordH = DmQueryNextInCategory (dbP, &index, dmAllCategories); if (recordH) { r = (ApptPackedDBRecordPtr) MemHandleLock (recordH); if (r->flags.repeat) result = 1; else result = DateCompare (date, r->when.date); MemHandleUnlock (recordH); } // If no handle, assume the record is deleted, deleted records // are greater. else result = -1; // If the date passed is less than the probe's date, keep searching. if (result < 0) numOfRecords = i; // If the date passed is greater than the probe's date, keep searching. else if (result > 0) { kmin = probe + 1; numOfRecords = numOfRecords - i - 1; } // If the records are equal find the first record on the day. else { found = true; *indexP = index; while (true) { err = DmSeekRecordInCategory (dbP, &index, 1, dmSeekBackward, dmAllCategories); if (err == dmErrSeekFailed) break; recordH = DmQueryRecord(dbP, index); r = (ApptPackedDBRecordPtr) MemHandleLock (recordH); if (r->flags.repeat) result = 1; else result = DateCompare (date, r->when.date); MemHandleUnlock (recordH); if (result != 0) break; *indexP = index; } break; } } // If that were no appointments on the specified day, return the // index of the next appointment (on a future day). if (! found) { if (result < 0) *indexP = probe; else *indexP = probe + 1; } return (found); }
/*********************************************************************** * * FUNCTION: NextRepeat * * DESCRIPTION: This routine computes the date of the next * occurrence of a repeating appointment. * * PARAMETERS: rec - a pointer to a DiddleBug record * date - passed: date to start from * returned: date of next occurrence * * RETURNED: true if the appointment occurs again * ***********************************************************************/ Boolean NextRepeat(DiddleBugRecordType* rec, DateTimeType* dateP) { /* ** Get the frequency on occurrence **(ex: every 2nd day, every 3rd month, etc). */ const UInt16 freq = rec->repeatInfo.repeatFrequency; Int16 i = 0; UInt16 day; UInt16 year; UInt16 adjust; UInt16 weeksDiff; UInt16 monthsDiff; UInt16 daysInMonth; UInt16 dayOfWeek; UInt16 apptWeekDay; UInt16 firstDayOfWeek; UInt16 daysTilNext; UInt16 monthsTilNext; UInt32 dateInDays; UInt32 startInDays; DateType start, date, when, next; DateTimeType nextReal; UInt32 startSecs, nextSecs; DateSecondsToDate(TimDateTimeToSeconds(dateP), &date); TimSecondsToDateTime(rec->alarmSecs, &nextReal); nextReal.year = dateP->year; nextReal.month = dateP->month; nextReal.day = dateP->day; nextReal.weekDay = dateP->weekDay; /* Calculate alarm date */ DateSecondsToDate(rec->alarmSecs, &when); /* Is the date passed after the end date of the appointment? */ if (DateCompare(date, rec->repeatInfo.repeatEndDate) > 0) return false; /* Is the date passed before the start date of the appointment? */ if (DateCompare(date, when) < 0) date = when; /* Get the date of the first occurrecne of the appointment. */ start = when; switch (rec->repeatInfo.repeatType) { /* Hourly repeating appointment */ case repeatHourly: startSecs = TimDateTimeToSeconds(dateP); nextSecs = rec->alarmSecs; while (nextSecs < startSecs) nextSecs += freq * hoursInSeconds; TimSecondsToDateTime(nextSecs, &nextReal); DateSecondsToDate(nextSecs, &next); break; /* Daily repeating appointment. */ case repeatDaily: dateInDays = DateToDays(date); startInDays = DateToDays(start); daysTilNext = (dateInDays - startInDays + freq - 1) / freq * freq; if (startInDays + daysTilNext > (UInt32) maxDays) return false; DateDaysToDate (startInDays + daysTilNext, &next); break; /* ** Weekly repeating appointment (ex: every Monday and Friday). ** Yes, weekly repeating appointment can occur more then once a ** week. */ case repeatWeekly: dateInDays = DateToDays(date); startInDays = DateToDays(start); firstDayOfWeek = (DayOfWeek (1, 1, firstYear) - rec->repeatInfo.repeatStartOfWeek + daysInWeek) % daysInWeek; dayOfWeek = DayOfWeek(date.month, date.day, date.year+firstYear); apptWeekDay = (dayOfWeek - rec->repeatInfo.repeatStartOfWeek + daysInWeek) % daysInWeek; /* ** Are we in a week in which the appointment occurrs, if not ** move to that start of the next week in which the appointment ** does occur. */ weeksDiff = (((dateInDays + firstDayOfWeek) / daysInWeek) - ((startInDays + firstDayOfWeek) / daysInWeek)) % freq; if (weeksDiff) { adjust = ((freq - weeksDiff) * daysInWeek) - apptWeekDay; apptWeekDay = 0; dayOfWeek = (dayOfWeek + adjust) % daysInWeek; } else { adjust = 0; } /* Find the next day on which the appointment repeats. */ for (; i < daysInWeek; i++) { if (rec->repeatInfo.repeatOn & (1 << dayOfWeek)) break; adjust++; if (++dayOfWeek == daysInWeek) dayOfWeek = 0; if (++apptWeekDay == daysInWeek) adjust += (freq - 1) * daysInWeek; } if (dateInDays + adjust > (UInt32) maxDays) return false; DateDaysToDate (dateInDays + adjust, &next); break; /* ** Monthly-by-day repeating appointment ** (ex: the 3rd Friday of every month). */ case repeatMonthlyByDay: /* Compute the number of month until the appointment repeats again. */ monthsTilNext = ((((date.year - start.year) * monthsInYear) + (date.month - start.month)) + freq - 1) / freq * freq; while (true) { year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return false; next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; dayOfWeek = DayOfWeek (next.month, 1, next.year+firstYear); if ((rec->repeatInfo.repeatOn % daysInWeek) >= dayOfWeek) day = rec->repeatInfo.repeatOn - dayOfWeek + 1; else day = rec->repeatInfo.repeatOn + daysInWeek - dayOfWeek + 1; /* ** If repeat-on day is between the last sunday and the last ** saturday, make sure we're not passed the end of the month. */ if ( (rec->repeatInfo.repeatOn >= domLastSun) && (day > DaysInMonth (next.month, next.year+firstYear))) { day -= daysInWeek; } next.day = day; /* ** Its posible that "next date" calculated above is ** before the date passed. If so, move forward ** by the length of the repeat freguency and preform ** the calculation again. */ if (DateToInt(date) > DateToInt(next)) monthsTilNext += freq; else break; } break; /* ** Monthly-by-date repeating appointment ** (ex: the 15th of every month). */ case repeatMonthlyByDate: /* Compute the number of month until the appointment repeats again. */ monthsDiff = (date.year - start.year) * monthsInYear + date.month - start.month; monthsTilNext = (monthsDiff + freq - 1) / freq * freq; if (date.day > start.day && !(monthsDiff % freq)) monthsTilNext += freq; year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return false; next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; next.day = start.day; /* Make sure we're not passed the last day of the month. */ daysInMonth = DaysInMonth(next.month, next.year+firstYear); if (next.day > daysInMonth) next.day = daysInMonth; break; /* Yearly repeating appointment. */ case repeatYearly: next.day = start.day; next.month = start.month; year = start.year + ((date.year - start.year + freq - 1) / freq * freq); if (date.month > start.month || (date.month == start.month && date.day > start.day)) year += freq; /* Specal leap day processing. */ if (next.month == february && next.day == 29 && next.day > DaysInMonth(next.month, year+firstYear)) { next.day = DaysInMonth (next.month, year+firstYear); } if (year >= numberOfYears) return false; next.year = year; break; default: /* ignore */ } /* Is the next occurrence after the end date of the appointment? */ if (DateCompare(next, rec->repeatInfo.repeatEndDate) > 0) return false; dateP->day = next.day; dateP->month = next.month; dateP->year = next.year + firstYear; dateP->hour = nextReal.hour; dateP->minute = nextReal.minute; dateP->second = nextReal.second; return true; }
Boolean NextRepeat (ApptDBRecordPtr apptRec, DatePtr dateP) { Int16 i; UInt16 day; UInt16 freq; UInt16 year; UInt16 adjust; UInt16 weeksDiff; UInt16 monthsDiff; UInt16 daysInMonth; UInt16 dayOfWeek; UInt16 apptWeekDay; UInt16 firstDayOfWeek; UInt16 daysTilNext; UInt16 monthsTilNext; UInt32 dateInDays; UInt32 startInDays; DateType start; DateType date; DateType next; date = *dateP; // Is the date passed after the end date of the appointment? if (DateCompare (date, apptRec->repeat->repeatEndDate) > 0) return (false); // Is the date passed before the start date of the appointment? if (DateCompare (date, apptRec->when->date) < 0) date = apptRec->when->date; // Get the frequency on occurrecne (ex: every 2nd day, every 3rd month, etc). freq = apptRec->repeat->repeatFrequency; // Get the date of the first occurrecne of the appointment. start = apptRec->when->date; switch (apptRec->repeat->repeatType) { // Daily repeating appointment. case repeatDaily: dateInDays = DateToDays (date); startInDays = DateToDays (start); daysTilNext = (dateInDays - startInDays + freq - 1) / freq * freq; if (startInDays + daysTilNext > (UInt32) maxDays) return (false); DateDaysToDate (startInDays + daysTilNext, &next); break; // Weekly repeating appointment (ex: every Monday and Friday). // Yes, weekly repeating appointment can occur more then once a // week. case repeatWeekly: dateInDays = DateToDays (date); startInDays = DateToDays (start); firstDayOfWeek = (DayOfWeek (1, 1, firstYear) - apptRec->repeat->repeatStartOfWeek + daysInWeek) % daysInWeek; dayOfWeek = DayOfWeek (date.month, date.day, date.year+firstYear); apptWeekDay = (dayOfWeek - apptRec->repeat->repeatStartOfWeek + daysInWeek) % daysInWeek; // Are we in a week in which the appointment occurrs, if not // move to that start of the next week in which the appointment // does occur. weeksDiff = (((dateInDays + firstDayOfWeek) / daysInWeek) - ((startInDays + firstDayOfWeek) / daysInWeek)) %freq; if (weeksDiff) { adjust = ((freq - weeksDiff) * daysInWeek)- apptWeekDay; apptWeekDay = 0; dayOfWeek = (dayOfWeek + adjust) % daysInWeek; } else adjust = 0; // Find the next day on which the appointment repeats. for (i = 0; i < daysInWeek; i++) { if (apptRec->repeat->repeatOn & (1 << dayOfWeek)) break; adjust++; if (++dayOfWeek == daysInWeek) dayOfWeek = 0; if (++apptWeekDay == daysInWeek) adjust += (freq - 1) * daysInWeek; } if (dateInDays + adjust > (UInt32) maxDays) return (false); DateDaysToDate (dateInDays + adjust, &next); // next = date; // DateAdjust (&next, adjust); break; // Monthly-by-day repeating appointment (ex: the 3rd Friday of every // month). case repeatMonthlyByDay: // Compute the number of month until the appointment repeats again. monthsTilNext = (date.month - start.month); monthsTilNext = ((((date.year - start.year) * monthsInYear) + (date.month - start.month)) + freq - 1) / freq * freq; while (true) { year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return (false); next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; dayOfWeek = DayOfWeek (next.month, 1, next.year+firstYear); if ((apptRec->repeat->repeatOn % daysInWeek) >= dayOfWeek) day = apptRec->repeat->repeatOn - dayOfWeek + 1; else day = apptRec->repeat->repeatOn + daysInWeek - dayOfWeek + 1; // If repeat-on day is between the last sunday and the last // saturday, make sure we're not passed the end of the month. if ( (apptRec->repeat->repeatOn >= domLastSun) && (day > DaysInMonth (next.month, next.year+firstYear))) { day -= daysInWeek; } next.day = day; // Its posible that "next date" calculated above is // before the date passed. If so, move forward // by the length of the repeat freguency and preform // the calculation again. if ( DateToInt(date) > DateToInt (next)) monthsTilNext += freq; else break; } break; // Monthly-by-date repeating appointment (ex: the 15th of every // month). case repeatMonthlyByDate: // Compute the number of month until the appointment repeats again. monthsDiff = ((date.year - start.year) * monthsInYear) + (date.month - start.month); monthsTilNext = (monthsDiff + freq - 1) / freq * freq; if ((date.day > start.day) && (!(monthsDiff % freq))) monthsTilNext += freq; year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return (false); next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; next.day = start.day; // Make sure we're not passed the last day of the month. daysInMonth = DaysInMonth (next.month, next.year+firstYear); if (next.day > daysInMonth) next.day = daysInMonth; break; // Yearly repeating appointment. case repeatYearly: next.day = start.day; next.month = start.month; year = start.year + ((date.year - start.year + freq - 1) / freq * freq); if ((date.month > start.month) || ((date.month == start.month) && (date.day > start.day))) year += freq; // Specal leap day processing. if ( (next.month == february) && (next.day == 29) && (next.day > DaysInMonth (next.month, year+firstYear))) { next.day = DaysInMonth (next.month, year+firstYear); } if (year >= numberOfYears) return (false); next.year = year; break; default: break; } // Is the next occurrence after the end date of the appointment? if (DateCompare (next, apptRec->repeat->repeatEndDate) > 0) return (false); ErrFatalDisplayIf ((DateToInt (next) < DateToInt (*dateP)), "Calculation error"); *dateP = next; return (true); }
static Int16 CompareAgeFunc(LineItemPtr p1, LineItemPtr p2, Int32 extra) { if (p1->age > p2->age) return 1*extra; else if (p1->age < p2->age) return -1*extra; else return DateCompare(p1->date, p2->date)*extra; }
static Int16 CompareHappyDaysFunc(LineItemPtr p1, LineItemPtr p2, Int32 extra) { return DateCompare(p1->date, p2->date)*extra; }