/*********************************************************************** * * FUNCTION: DateCompare * * DESCRIPTION: This routine compares two dates. * * PARAMETERS: d1 - a date * d2 - a date * * RETURNED: if d1 > d2 returns a positive int * if d1 < d2 returns a negative int * if d1 = d2 returns zero * * NOTE: This routine treats the DateType structure like an unsigned int, * it depends on the fact the the members of the structure are ordered * year, month, day form high bit to low low bit. * ***********************************************************************/ Int16 DateCompare(DateType d1, DateType d2) { UInt16 int1, int2; int1 = DateToInt(d1); int2 = DateToInt(d2); if (int1 > int2) return (1); else if (int1 < int2) return (-1); return 0; }
/*********************************************************************** * * FUNCTION: RepeatSelectEndDate * * DESCRIPTION: This routine selects the end date of a repeating event. * * PARAMETERS: event - pointer to a popup select event * * RETURNED: nothing * ***********************************************************************/ static void RepeatSelectEndDate(EventType* event) { Int16 month, day, year; Char* titleP = NULL; MemHandle titleH = NULL; /* "No due date" items selected? */ if (event->data.popSelect.selection == repeatNoEndDateItem) DateToInt(d.repeat_end_date) = apptNoEndDate; /* "Select date" item selected? */ else if (event->data.popSelect.selection == repeatChooseDateItem) { if (DateToInt (d.repeat_end_date) == apptNoEndDate) { year = d.frm_date.year; month = d.frm_date.month; day = d.frm_date.day; } else { year = d.repeat_end_date.year + firstYear; month = d.repeat_end_date.month; day = d.repeat_end_date.day; } titleH = DmGetResource(strRsc, endDateTitleString); titleP = MemHandleLock(titleH); if (SelectDay (selectDayByDay, &month, &day, &year, titleP)) { d.repeat_end_date.day = day; d.repeat_end_date.month = month; d.repeat_end_date.year = year - firstYear; /* Make sure the end date is not before the start date. */ if (DateToInt(d.repeat_end_date) < DateToInt (d.frm_date)) { SndPlaySystemSound (sndError); DateToInt (d.repeat_end_date) = apptNoEndDate; } } MemHandleUnlock(titleH); } RepeatSetDateTrigger(d.repeat_end_date); }
/*********************************************************************** * * FUNCTION: RepeatSetDateTrigger * * DESCRIPTION: This routine sets the label of the trigger that displays * the end date of a repeating appointment. * * PARAMETERS: endDate - date or -1 if no end date * * RETURNED: nothing * * NOTES: * This routine assumes that the memory allocated for the label of * the due date trigger is large enough to hold the lagest posible * label. This label's memory is reserved by initializing the label * in the resource file. * ***********************************************************************/ static void RepeatSetDateTrigger (DateType endDate) { FormType* frm = FrmGetFormPtr(RepeatForm); ListType* lst = GetObjectPointer(frm, RepeatEndOnList); ControlType* ctl = GetObjectPointer(frm, RepeatEndOnTrigger); Char* label = (Char*)CtlGetLabel(ctl); /* OK to cast; we call CtlSetLabel */ ASSERT(lst); ASSERT(ctl); ASSERT(label); if (DateToInt(endDate) == apptNoEndDate) { StrCopy(label, LstGetSelectionText(lst, repeatNoEndDateItem)); LstSetSelection(lst, noEndDateItem); } else { /* Format the end date into a string. */ DateToDOWDMFormat(endDate.month, endDate.day, endDate.year + firstYear, PrefGetPreference(prefDateFormat), label); LstSetSelection(lst, repeatChooseDateItem); } CtlSetLabel(ctl, label); }
/*********************************************************************** * * FUNCTION: RepeatChangeType * * DESCRIPTION: This routine changes the ui gadgets in the repeat dialog * such that they match the newly selected repeat type. The * routine is called when one of the repeat type push buttons * are pushed. * * PARAMETERS: event - pointer to and event * * RETURNED: nothing * ***********************************************************************/ static void RepeatChangeType(EventType* event) { UInt16 id; FormType* frm = FrmGetFormPtr(RepeatForm); const RepeatType oldType = d.repeat_event_type; RepeatType newType; RepeatInfoType repeat; /* If the type if monthly default to monthly-by-date. */ newType = (RepeatType) (event->data.ctlSelect.controlID - RepeatNone); if (newType > repeatWeekly) newType++; if (oldType == newType) return; /* Initialize the UI gadgets. */ if (newType == d.tmp_repeat.repeatType) { RepeatSetUIValues(frm, &d.tmp_repeat); /* ** If reselecting current repeat type, reset d.repeat_end_date global ** to current date so if user attemps to "choose" a new day, the ** default matches date displayed as opposed to last date picked ** last in choose form. */ d.repeat_end_date = d.tmp_repeat.repeatEndDate; } else { repeat.repeatType = newType; /* ** When switching to a repeat type different from the current ** setting, always start user with default end date and frequency ** settings. */ DateToInt(repeat.repeatEndDate) = defaultRepeatEndDate; DateToInt(d.repeat_end_date) = defaultRepeatEndDate; repeat.repeatFrequency = defaultRepeatFrequency; repeat.repeatStartOfWeek = PrefGetPreference(prefWeekStartDay); if (newType == repeatWeekly) { repeat.repeatOn = (1 << DayOfWeek(d.frm_date.month, d.frm_date.day, d.frm_date.year/*+firstYear*/)); } else if (newType == repeatMonthlyByDay) { repeat.repeatOn = DayOfMonth(d.frm_date.month, d.frm_date.day, d.frm_date.year/* + firstYear*/); } else { repeat.repeatOn = 0; } RepeatSetUIValues (frm, &repeat); } /* ** Hide the UI gadgets that are unique to the repeat type we are ** no longer editing. */ switch (oldType) { case repeatNone: HideObject(frm, RepeatNoRepeatLabel); break; case repeatHourly: HideObject(frm, RepeatHoursLabel); break; case repeatDaily: HideObject(frm, RepeatDaysLabel); break; case repeatWeekly: HideObject(frm, RepeatWeeksLabel); for (id = RepeatRepeatOnLabel; id <= RepeatDayOfWeek7PushButton; id++) HideObject (frm, id); break; case repeatMonthlyByDay: case repeatMonthlyByDate: HideObject(frm, RepeatMonthsLabel); for (id = RepeatByLabel; id <= RepeatByDatePushButton; id++) HideObject (frm, id); break; case repeatYearly: HideObject(frm, RepeatYearsLabel); break; } /* Handle switching to or from "no" repeat. */ if (oldType == repeatNone) { ShowObject(frm, RepeatEveryLabel); ShowObject(frm, RepeatFrequenceField); ShowObject(frm, RepeatEndOnLabel); ShowObject(frm, RepeatEndOnTrigger); } else if (newType == repeatNone) { HideObject(frm, RepeatEveryLabel); HideObject(frm, RepeatFrequenceField); HideObject(frm, RepeatEndOnLabel); HideObject(frm, RepeatEndOnTrigger); } /* Show the UI object that are appropriate for the new repeat type. */ switch (newType) { case repeatNone: ShowObject(frm, RepeatNoRepeatLabel); break; case repeatHourly: ShowObject(frm, RepeatHoursLabel); break; case repeatDaily: ShowObject(frm, RepeatDaysLabel); break; case repeatWeekly: ShowObject(frm, RepeatWeeksLabel); ShowObject(frm, RepeatRepeatOnLabel); for (id = RepeatRepeatOnLabel; id <= RepeatDayOfWeek7PushButton; id++) ShowObject(frm, id); break; case repeatMonthlyByDay: case repeatMonthlyByDate: ShowObject(frm, RepeatMonthsLabel); ShowObject(frm, RepeatByLabel); ShowObject(frm, RepeatByDayPushButton); ShowObject(frm, RepeatByDatePushButton); break; case repeatYearly: ShowObject(frm, RepeatYearsLabel); break; } d.repeat_event_type = newType; /* Update the display of the repeat descrition. */ RepeatDrawDescription(frm); }
/*********************************************************************** * * 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; }
/* ** Compare two dates */ extern inline Int16 DateCompare(DateType d1, DateType d2) { return (DateToInt(d1) > DateToInt(d2)) ? 1 : ((DateToInt(d1) < DateToInt(d2)) ? -1 : 0); }
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); }
/** * @brief * @param dbP Happydays DB pointer * @param AddrCategory The category of Address to be displayed * @param start Start position * @return The number of total Item * @remarks * @endif */ UInt16 AddrGetHappyDays(DmOpenRef dbP, UInt16 AddrCategory, DateType start) { UInt16 totalItems; UInt16 recordNum = 0; MemHandle recordH = 0; LineItemPtr ptr; PackedHappyDays* rp; HappyDays r; DateType converted; UInt16 currindex = 0; Int16 age; // if exist, free the memory // if (gTableRowHandle) { MemHandleFree(gTableRowHandle); gTableRowHandle = 0; } totalItems = DmNumRecordsInCategory(dbP, AddrCategory); if (totalItems > 0) { gTableRowHandle = MemHandleNew(sizeof(LineItemType)* totalItems); ErrFatalDisplayIf(!gTableRowHandle, "Out of memory"); if ((ptr = MemHandleLock(gTableRowHandle))) { for (recordNum = 0; recordNum < totalItems; recordNum++) { if ((recordH = DmQueryNextInCategory(dbP, &currindex, (UInt16)AddrCategory))) { ptr[recordNum].birthRecordNum = currindex; rp = (PackedHappyDays *) MemHandleLock(recordH); /* * Build the unpacked structure for an AddressDB * record. It is just a bunch of pointers into the rp * structure. */ UnpackHappyDays(&r, rp); // original r(in MainDB) not changed // local change for LineItemType // converted = r.date; if (r.flag.bits.nthdays) { int syear, smonth, sday; if (r.flag.bits.lunar || r.flag.bits.lunar_leap) { if (lunarL2S(lunarRefNum, converted.year + firstYear, converted.month, converted.day, r.flag.bits.lunar_leap, &syear, &smonth, &sday) != errNone) { MemHandleUnlock(recordH); currindex++; recordNum--; totalItems--; continue; } converted.day = sday; converted.month = smonth; converted.year = syear - firstYear; } DateAdjust(&converted, r.nth); if (DateToDays(converted) < DateToDays(start)) { MemHandleUnlock(recordH); currindex++; recordNum--; totalItems--; continue; } } else if (r.flag.bits.lunar || r.flag.bits.lunar_leap) { if (!FindNearLunar(&converted, start, r.flag.bits.lunar_leap)) { // ignore the records // converted.year = INVALID_CONV_DATE; // max year(for sorting) // indicate for invalid date } } else if (r.flag.bits.solar) { int maxtry = 4; DateType dt; dt = start; DateToInt(dt) = (DateToInt(dt) > DateToInt(converted)) ? DateToInt(dt) : DateToInt(converted); if (converted.month < dt.month || ( converted.month == dt.month && converted.day < dt.day)) { // birthdate is in last year? while (DaysInMonth(converted.month, ++dt.year) < converted.day && maxtry-- > 0) ; } else { while (DaysInMonth(converted.month, dt.year) < converted.day && maxtry-- >0) { dt.year++; } } if (maxtry >0) converted.year = dt.year; else { converted.year = INVALID_CONV_DATE; // max year // indicate for invalid date } } if (converted.year != INVALID_CONV_DATE && !r.flag.bits.nthdays && r.flag.bits.year && (age = CalculateAge(converted, r.date, r.flag)) >= 0) { // calculate age if year exists // ptr[recordNum].age = age; } else { ptr[recordNum].age = -1; } // save the converted data // ptr[recordNum].date = converted; MemHandleUnlock(recordH); currindex++; } } // sort the order if sort order is converted date // if (gPrefsR.sort == 1) { // date sort SysInsertionSort(ptr, totalItems, sizeof(LineItemType), (_comparF *)CompareHappyDaysFunc, 1L); } else if (gPrefsR.sort == 3) { // age sort SysInsertionSort(ptr, totalItems, sizeof(LineItemType), (_comparF *)CompareAgeFunc, 1L); } else if (gPrefsR.sort == 2) { // age sort(re) SysInsertionSort(ptr, totalItems, sizeof(LineItemType), (_comparF *)CompareAgeFunc, -1L); } MemPtrUnlock(ptr); } else return 0; } return totalItems; }
/** * @brief Read the happydays information from address db, and insert into Happydays DB * @param frm StartForm to display indicator bars * @return If success, return true, or return false */ Boolean NewUpdateHappyDaysDB(FormPtr frm) { UInt16 currIndex = 0; PrvAddrPackedDBRecord *rp; AddrDBRecordType r; MemHandle recordH = 0; UInt16 recordNum; int i = 0, indicateNext; int step; // create the happydays cache db HappyDays hd; Boolean ignore = false; // ignore error record Char* hdField; UInt16 addrattr, index; Char *p, *q, *end; Int16 err; // display collecting information // FrmDrawForm(frm); // clean up old database // CleanupHappyDaysCache(MainDB); recordNum = DmNumRecords(AddressDB); indicateNext = step = recordNum / INDICATE_NUM; if (recordNum > 50) initIndicate(); while (1) { char *name1, *name2; Int8 whichField; // birthday field or note field? recordH = DmQueryNextInCategory(AddressDB, &currIndex, dmAllCategories); if (!recordH) break; if (i++ == indicateNext) { if (recordNum > 50) displayNextIndicate( (i-1) / step); indicateNext += step; } DmRecordInfo(AddressDB, currIndex, &addrattr, NULL, NULL); addrattr &= dmRecAttrCategoryMask; // get category info rp = (PrvAddrPackedDBRecord*)MemHandleLock(recordH); /* * Build the unpacked structure for an AddressDB record. It * is just a bunch of pointers into the rp structure. */ NewAddrUnpack(rp, &r); if ( (gHappyDaysField <= 0 || !r.fields[gHappyDaysField]) // there is no birthday info(trick. should check flags, but I think it is ok) // && DateToInt(r.birthdayInfo.birthdayDate) == 0 && !(gPrefsR.scannote && r.fields[note] && StrStr(r.fields[note], gPrefsR.notifywith) ) ) { // If there is not exist Happydays field or note field, or internal birthday field(in NEW PIMS) // MemHandleUnlock(recordH); currIndex++; continue; } MemSet(&hd, sizeof(hd), 0); hd.addrRecordNum = currIndex; if (DetermineRecordName(&r, gSortByCompany, &hd.name1, &hd.name2)) { // name 1 has priority; hd.flag.bits.priority_name1 = 1; } // =========================================================== // Process Birthday field first // =========================================================== if (DateToInt(r.birthdayInfo.birthdayDate) != 0) { hd.date = r.birthdayInfo.birthdayDate; hd.flag.bits.year = 1; hd.flag.bits.solar = 1; // maintain address book order(name order) // list order is determined by sort err = HDNewRecord(MainDB, &hd, &index); if (!err) { UInt16 attr; // set the category of the new record to the category // it belongs in DmRecordInfo(MainDB, index, &attr, NULL, NULL); attr &= ~dmRecAttrCategoryMask; attr |= addrattr; DmSetRecordInfo(MainDB, index, &attr, NULL); DmReleaseRecord(MainDB, index, true); } } // =========================================================== // save the temporary name name1 = hd.name1; name2 = hd.name2; if (gHappyDaysField >= 0 && r.fields[gHappyDaysField]) { whichField = gHappyDaysField; } else if (gPrefsR.scannote // scanNote & exists && r.fields[note] && StrStr(r.fields[note], gPrefsR.notifywith)) { whichField = note; } else whichField = -1; while (whichField >= 0) { if (whichField == note) { p = StrStr(r.fields[note], gPrefsR.notifywith) + StrLen(gPrefsR.notifywith) + 1; if ( StrLen(r.fields[note]) < (p - r.fields[note]) ) break; } else { p = r.fields[whichField]; } hdField = MemPtrNew(StrLen(r.fields[whichField]) - (p - r.fields[whichField])+1); SysCopyStringResource(gAppErrStr, NotEnoughMemoryString); ErrFatalDisplayIf(!hdField, gAppErrStr); p = StrCopy(hdField, p); if (whichField == note && (end = StrStr(p, gPrefsR.notifywith))) { // end delimeter // *end = 0; } while ((q = StrChr(p, '\n'))) { // multiple event // *q = 0; if (AnalizeOneRecord(addrattr, p, &hd, &ignore)) goto Update_ErrHandler; p = q+1; // restore the saved name hd.name1 = name1; hd.name2 = name2; // reset multiple flag hd.flag.bits.multiple_event = 0; while (*p == ' ' || *p == '\t' || *p == '\n') p++; // skip white space } // last record if (*p) { // check the null '\n' if (AnalizeOneRecord(addrattr, p, &hd, &ignore)) goto Update_ErrHandler; } if (whichField == gHappyDaysField // next is note field && (gPrefsR.scannote // scanNote & exists && r.fields[note] && StrStr(r.fields[note], gPrefsR.notifywith)) ) { whichField = note; } else whichField = -1; MemPtrFree(hdField); } MemHandleUnlock(recordH); currIndex++; } if (recordNum > 50) displayNextIndicate( INDICATE_NUM -1); return true; Update_ErrHandler: MemPtrFree(hdField); MemHandleUnlock(recordH); return false; }