///////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1998 Active Voice Corporation. All Rights Reserved. // // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation. // // Other brand and product names used herein are trademarks of their respective owners. // // The entire program and user interface including the structure, sequence, selection, // and arrangement of the dialog, the exclusively "yes" and "no" choices represented // by "1" and "2," and each dialog message are protected by copyrights registered in // the United States and by international treaties. // // Protected by one or more of the following United States patents: 5,070,526, 5,488,650, // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054. // // Active Voice Corporation // Seattle, Washington // USA // ///////////////////////////////////////////////////////////////////////////////////////// //// // intl.c - internationalization functions //// #include "winlocal.h" #include #include "intl.h" #include "mem.h" #include "str.h" #include "trace.h" //// // private definitions //// // intl control struct // typedef struct INTL { DWORD dwVersion; HINSTANCE hInst; HTASK hTask; TCHAR szShortDate[32]; TCHAR szDateSep[32]; TCHAR szTimeSep[32]; TCHAR szAMPMSep[32]; TCHAR szAM[32]; TCHAR szPM[32]; int iDate; int iTime; int iTLZero; BOOL fYearCentury; BOOL fMonthLeadingZero; BOOL fDayLeadingZero; BOOL fHourLeadingZero; BOOL fMinuteLeadingZero; BOOL fSecondLeadingZero; int iLZero; TCHAR szDecimal[32]; } INTL, FAR *LPINTL; // helper functions // static LPINTL IntlGetPtr(HINTL hIntl); static HINTL IntlGetHandle(LPINTL lpIntl); //// // public functions //// // IntlInit - initialize intl engine // (i) must be INTL_VERSION // (i) instance handle of calling module // return handle (NULL if error) // HINTL DLLEXPORT WINAPI IntlInit(DWORD dwVersion, HINSTANCE hInst) { BOOL fSuccess = TRUE; LPINTL lpIntl = NULL; if (dwVersion != INTL_VERSION) fSuccess = TraceFALSE(NULL); else if (hInst == NULL) fSuccess = TraceFALSE(NULL); else if ((lpIntl = (LPINTL) MemAlloc(NULL, sizeof(INTL), 0)) == NULL) fSuccess = TraceFALSE(NULL); else { lpIntl->dwVersion = dwVersion; lpIntl->hInst = hInst; lpIntl->hTask = GetCurrentTask(); GetProfileString(TEXT("intl"), TEXT("sShortDate"), TEXT("M/d/yy"), lpIntl->szShortDate, SIZEOFARRAY(lpIntl->szShortDate)); GetProfileString(TEXT("intl"), TEXT("sDate"), TEXT("/"), lpIntl->szDateSep, SIZEOFARRAY(lpIntl->szDateSep)); GetProfileString(TEXT("intl"), TEXT("sTime"), TEXT(":"), lpIntl->szTimeSep, SIZEOFARRAY(lpIntl->szTimeSep)); StrCpy(lpIntl->szAMPMSep, TEXT(" ")); GetProfileString(TEXT("intl"), TEXT("s1159"), TEXT("AM"), lpIntl->szAM, SIZEOFARRAY(lpIntl->szAM)); GetProfileString(TEXT("intl"), TEXT("s2359"), TEXT("PM"), lpIntl->szPM, SIZEOFARRAY(lpIntl->szPM)); lpIntl->iDate = GetProfileInt(TEXT("intl"), TEXT("iDate"), 0); lpIntl->iTime = GetProfileInt(TEXT("intl"), TEXT("iTime"), 0); lpIntl->iTLZero = GetProfileInt(TEXT("intl"), TEXT("iTLZero"), 0); lpIntl->fYearCentury = (BOOL) (StrStr(lpIntl->szShortDate, TEXT("yyyy")) != NULL); lpIntl->fMonthLeadingZero = (BOOL) (StrStr(lpIntl->szShortDate, TEXT("MM")) != NULL); lpIntl->fDayLeadingZero = (BOOL) (StrStr(lpIntl->szShortDate, TEXT("dd")) != NULL); lpIntl->fHourLeadingZero = (BOOL) (lpIntl->iTLZero != 0); lpIntl->fMinuteLeadingZero = TRUE; lpIntl->fSecondLeadingZero = TRUE; lpIntl->iLZero = GetProfileInt(TEXT("intl"), TEXT("iLZero"), 0); GetProfileString(TEXT("intl"), TEXT("sDecimal"), TEXT("."), lpIntl->szDecimal, SIZEOFARRAY(lpIntl->szDecimal)); } if (!fSuccess) { IntlTerm(IntlGetHandle(lpIntl)); lpIntl = NULL; } return fSuccess ? IntlGetHandle(lpIntl) : NULL; } // IntlTerm - shut down intl engine // (i) handle returned from IntlInit // return 0 if success // int DLLEXPORT WINAPI IntlTerm(HINTL hIntl) { BOOL fSuccess = TRUE; LPINTL lpIntl; if ((lpIntl = IntlGetPtr(hIntl)) == NULL) fSuccess = TraceFALSE(NULL); else if ((lpIntl = MemFree(NULL, lpIntl)) != NULL) fSuccess = TraceFALSE(NULL); return fSuccess ? 0 : -1; } // IntlDateGetText - construct date text based on , , // (i) handle returned from IntlInit // (i) year // (i) month // (i) day // (o) buffer to copy date text // (i) size of buffer // (i) option flags // INTL_NOYEAR do not include year in text output // return 0 if success // int DLLEXPORT WINAPI IntlDateGetText(HINTL hIntl, int y, int m, int d, LPTSTR lpszText, size_t sizText, DWORD dwFlags) { BOOL fSuccess = TRUE; LPINTL lpIntl; if ((lpIntl = IntlGetPtr(hIntl)) == NULL) fSuccess = TraceFALSE(NULL); else if (lpszText != NULL) { TCHAR szYear[16]; TCHAR szMonth[16]; TCHAR szDay[16]; TCHAR szText[64]; *szYear = '\0'; if (!lpIntl->fYearCentury) y %= 100; if (y < 10) StrCat(szYear, TEXT("0")); StrItoA(y, StrChr(szYear, '\0'), 10); *szMonth = '\0'; if (lpIntl->fMonthLeadingZero && m < 10) StrCat(szMonth, TEXT("0")); StrItoA(m, StrChr(szMonth, '\0'), 10); *szDay = '\0'; if (lpIntl->fDayLeadingZero && d < 10) StrCat(szDay, TEXT("0")); StrItoA(d, StrChr(szDay, '\0'), 10); *szText = '\0'; if (lpIntl->iDate == IDATE_MDY) { StrCat(szText, szMonth); StrCat(szText, lpIntl->szDateSep); StrCat(szText, szDay); if (!(dwFlags & INTL_NOYEAR)) { StrCat(szText, lpIntl->szDateSep); StrCat(szText, szYear); } } else if (lpIntl->iDate == IDATE_DMY) { StrCat(szText, szDay); StrCat(szText, lpIntl->szDateSep); StrCat(szText, szMonth); if (!(dwFlags & INTL_NOYEAR)) { StrCat(szText, lpIntl->szDateSep); StrCat(szText, szYear); } } else if (lpIntl->iDate == IDATE_YMD) { if (!(dwFlags & INTL_NOYEAR)) { StrCat(szText, szYear); StrCat(szText, lpIntl->szDateSep); } StrCat(szText, szMonth); StrCat(szText, lpIntl->szDateSep); StrCat(szText, szDay); } StrNCpy(lpszText, szText, sizText); } return fSuccess ? 0 : -1; } // IntlTimeGetText - construct time text based on , , // (i) handle returned from IntlInit // (i) hour // (i) minute // (i) second // (o) buffer to copy time text // (i) size of buffer // (i) option flags // INTL_NOSECOND do not include second in text output // INTL_NOAMPM do not include am or pm in text output // INTL_NOAMPMSEPARATOR do not include space between time and am/pm // return 0 if success // int DLLEXPORT WINAPI IntlTimeGetText(HINTL hIntl, int h, int m, int s, LPTSTR lpszText, size_t sizText, DWORD dwFlags) { BOOL fSuccess = TRUE; LPINTL lpIntl; if ((lpIntl = IntlGetPtr(hIntl)) == NULL) fSuccess = TraceFALSE(NULL); else if (lpszText != NULL) { TCHAR szHour[16]; TCHAR szMinute[16]; TCHAR szSecond[16]; BOOL fPM = FALSE; TCHAR szText[64]; *szHour = '\0'; if (lpIntl->iTime == ITIME_12) { if (h > 11) fPM = TRUE; if (h > 12) h -= 12; if (h == 0) h = 12; } if (lpIntl->fHourLeadingZero && h < 10) StrCat(szHour, TEXT("0")); StrItoA(h, StrChr(szHour, '\0'), 10); *szMinute = '\0'; if (lpIntl->fMinuteLeadingZero && m < 10) StrCat(szMinute, TEXT("0")); StrItoA(m, StrChr(szMinute, '\0'), 10); *szSecond = '\0'; if (lpIntl->fSecondLeadingZero && s < 10) StrCat(szSecond, TEXT("0")); StrItoA(s, StrChr(szSecond, '\0'), 10); *szText = '\0'; StrCat(szText, szHour); StrCat(szText, lpIntl->szTimeSep); StrCat(szText, szMinute); if (!(dwFlags & INTL_NOSECOND)) { StrCat(szText, lpIntl->szTimeSep); StrCat(szText, szSecond); } if (!(dwFlags & INTL_NOAMPM)) { if (!(dwFlags & INTL_NOAMPMSEPARATOR)) StrCat(szText, lpIntl->szAMPMSep); StrCat(szText, fPM ? lpIntl->szPM : lpIntl->szAM); } StrNCpy(lpszText, szText, sizText); } return fSuccess ? 0 : -1; } // IntlTimeSpanGetText - construct time span text based on // (i) handle returned from IntlInit // (i) milleseconds // (i) 0, 1, 2, or 3 decimal places for fraction // (o) buffer to copy time span text // (i) size of buffer // (i) option flags // INTL_HOURS_LZ include hours, even if zero // INTL_MINUTES_LZ include minutes, even if zero // INTL_SECONDS_LZ include seconds, even if zero // // NOTE: below are some examples // // dwFlags ms=7299650 ms=1234 ms=0 // -------------------------------------------------------- // 0 "2:01:39.650" "1.234" "0" // INTL_HOURS_LZ "2:01:39.650" "0:00:01.234" "0:00:00.000" // INTL_MINUTES_LZ "2:01:39.650" "0:01.234" "0:00.000" // INTL_SECONDS_LZ "2:01:39.650" "1.234" "0.000" // // dwFlags ms=7299650 ms=1234 ms=0 // -------------------------------------------------------- // 3 "2:01:39.650" "1.234" ".000" // 2 "2:01:39.65" "1.23" ".00" // 1 "2:01:39.7" "1.2" ".0" // 0 "2:01:39" "1" "0" // // return 0 if success // int DLLEXPORT WINAPI IntlTimeSpanGetText(HINTL hIntl, DWORD ms, int nDecimalPlaces, LPTSTR lpszText, size_t sizText, DWORD dwFlags) { BOOL fSuccess = TRUE; LPINTL lpIntl; if ((lpIntl = IntlGetPtr(hIntl)) == NULL) fSuccess = TraceFALSE(NULL); else if (lpszText != NULL) { long h; long m; long s; long f; TCHAR szText[64]; // break ms into h, m, s, f // NOTE: rounding must occur before we break ms // if (nDecimalPlaces == 1) f = (long) ms + 50; else if (nDecimalPlaces == 2) f = (long) ms + 5; else f = (long) ms; s = f / 1000; f = f % 1000; m = s / 60; s = s % 60; h = m / 60; m = m % 60; // construct text // *szText = '\0'; if (h > 0 || (dwFlags & INTL_HOURS_LZ)) { if (lpIntl->fHourLeadingZero && h < 10) StrCat(szText, TEXT("0")); StrLtoA(h, StrChr(szText, '\0'), 10); } if (*szText != '\0' || m > 0 || (dwFlags & INTL_MINUTES_LZ)) { if (*szText != '\0') { StrCat(szText, lpIntl->szTimeSep); if (lpIntl->fMinuteLeadingZero && m < 10) StrCat(szText, TEXT("0")); } StrLtoA(m, StrChr(szText, '\0'), 10); } if (*szText != '\0' || s > 0 || (dwFlags & INTL_SECONDS_LZ) || (ms == 0 && nDecimalPlaces == 0)) { if (*szText != '\0') { StrCat(szText, lpIntl->szTimeSep); if (lpIntl->fSecondLeadingZero && s < 10) StrCat(szText, TEXT("0")); } StrLtoA(s, StrChr(szText, '\0'), 10); } switch (nDecimalPlaces) { case 3: if (*szText != '\0' || ms < 1000) { StrCat(szText, lpIntl->szDecimal); if (f < 100) StrCat(szText, TEXT("0")); if (f < 10) StrCat(szText, TEXT("0")); } StrLtoA(f, StrChr(szText, '\0'), 10); break; case 2: f = f / 10; if (*szText != '\0' || ms < 1000) { StrCat(szText, lpIntl->szDecimal); if (f < 10) StrCat(szText, TEXT("0")); } StrLtoA(f, StrChr(szText, '\0'), 10); break; case 1: f = f / 100; if (*szText != '\0' || ms < 1000) StrCat(szText, lpIntl->szDecimal); StrLtoA(f, StrChr(szText, '\0'), 10); break; default: break; } StrNCpy(lpszText, szText, sizText); } return fSuccess ? 0 : -1; } // IntlDateGetFormat - return current date format structure // (i) handle returned from IntlInit // (o) copy date format structure here // return 0 if success // int DLLEXPORT WINAPI IntlDateGetFormat(HINTL hIntl, LPINTLDATEFORMAT lpIntlDateFormat) { BOOL fSuccess = TRUE; LPINTL lpIntl; if ((lpIntl = IntlGetPtr(hIntl)) == NULL) fSuccess = TraceFALSE(NULL); else if (lpIntlDateFormat != NULL) { MemSet(lpIntlDateFormat, 0, sizeof(INTLDATEFORMAT)); MemCpy(lpIntlDateFormat->szShortDate, lpIntl->szShortDate, sizeof(lpIntl->szShortDate)); MemCpy(lpIntlDateFormat->szDateSep, lpIntl->szDateSep, sizeof(lpIntl->szDateSep)); lpIntlDateFormat->iDate = lpIntl->iDate; lpIntlDateFormat->fYearCentury = lpIntl->fYearCentury; lpIntlDateFormat->fMonthLeadingZero = lpIntl->fMonthLeadingZero; lpIntlDateFormat->fDayLeadingZero = lpIntl->fDayLeadingZero; } return fSuccess ? 0 : -1; } // IntlTimeGetFormat - return current time format structure // (i) handle returned from IntlInit // (o) copy time format structure here // return 0 if success // int DLLEXPORT WINAPI IntlTimeGetFormat(HINTL hIntl, LPINTLTIMEFORMAT lpIntlTimeFormat) { BOOL fSuccess = TRUE; LPINTL lpIntl; if ((lpIntl = IntlGetPtr(hIntl)) == NULL) fSuccess = TraceFALSE(NULL); else if (lpIntlTimeFormat != NULL) { MemSet(lpIntlTimeFormat, 0, sizeof(INTLDATEFORMAT)); MemCpy(lpIntlTimeFormat->szTimeSep, lpIntl->szTimeSep, sizeof(lpIntl->szTimeSep)); MemCpy(lpIntlTimeFormat->szAMPMSep, lpIntl->szAMPMSep, sizeof(lpIntl->szAMPMSep)); MemCpy(lpIntlTimeFormat->szAM, lpIntl->szAM, sizeof(lpIntl->szAM)); MemCpy(lpIntlTimeFormat->szPM, lpIntl->szPM, sizeof(lpIntl->szPM)); lpIntlTimeFormat->iTime = lpIntl->iTime; lpIntlTimeFormat->fHourLeadingZero = lpIntl->fHourLeadingZero; lpIntlTimeFormat->fMinuteLeadingZero = lpIntl->fMinuteLeadingZero; lpIntlTimeFormat->fSecondLeadingZero = lpIntl->fSecondLeadingZero; } return fSuccess ? 0 : -1; } //// // helper functions //// // IntlGetPtr - verify that intl handle is valid, // (i) handle returned from IntlInit // return corresponding intl pointer (NULL if error) // static LPINTL IntlGetPtr(HINTL hIntl) { BOOL fSuccess = TRUE; LPINTL lpIntl; if ((lpIntl = (LPINTL) hIntl) == NULL) fSuccess = TraceFALSE(NULL); else if (IsBadWritePtr(lpIntl, sizeof(INTL))) fSuccess = TraceFALSE(NULL); #ifdef CHECKTASK // make sure current task owns the intl handle // else if (lpIntl->hTask != GetCurrentTask()) fSuccess = TraceFALSE(NULL); #endif return fSuccess ? lpIntl : NULL; } // IntlGetHandle - verify that intl pointer is valid, // (i) pointer to INTL struct // return corresponding intl handle (NULL if error) // static HINTL IntlGetHandle(LPINTL lpIntl) { BOOL fSuccess = TRUE; HINTL hIntl; if ((hIntl = (HINTL) lpIntl) == NULL) fSuccess = TraceFALSE(NULL); return fSuccess ? hIntl : NULL; }