/* Copyright 1989, 1990, 1994 by Abacus Research and * Development, Inc. All rights reserved. */ #if !defined (OMIT_RCSID_STRINGS) char ROMlib_rcsid_iu[] = "$Id: iu.c 63 2004-12-24 18:19:43Z ctm $"; #endif /* Forward declarations in IntlUtil.h (DO NOT DELETE THIS LINE) */ #include "rsys/common.h" #include "IntlUtil.h" #include "OSUtil.h" #include "ResourceMgr.h" #include "MemoryMgr.h" #include "BinaryDecimal.h" #include "rsys/glue.h" #include "rsys/resource.h" #include "rsys/hook.h" #include /* * outl adds the characters in the four bytes of a longint to the place * pointed to by the pointer pointed to by opp, the pointer pointed to * by opp is incremented for each character that is added. */ A2(PRIVATE, void, outl, LONGINT, l, char **, opp) { if (l & 0xFF000000) { *(*opp)++ = (l & 0xFF000000) >> 24; if (l & 0xFF0000) { *(*opp)++ = (l & 0xFF0000) >> 16; if (l & 0xFF00) { *(*opp)++ = (l & 0xFF00) >> 8; if (l & 0xFF) *(*opp)++ = (l & 0xFF); } } } } /* * outs is similar to outl, except it works with a string and has an additional * paramater that is used to specify that an exact number of characters are * transfered (used when doing abbreviations). */ /* * n is the number of characters to transfer, or 0 for entire string */ A3(PRIVATE, void, outs, StringPtr, p, INTEGER, n, char **, opp) { int ntocopy; ntocopy = n ? n : p[0]; /* This can lead to copying NUL characters */ /* which is prescribed in IMI-505 (ick) */ BlockMove((Ptr) (p+1), (Ptr) *opp, (Size) ntocopy); *opp += ntocopy; } /* * outn is similar to outl and outs but it converts a number to a set * of characters and adds them to *opp. If leading0 is TRUE and the number * is less than 10, a leading zero is output. */ A3(PRIVATE, void, outn, INTEGER, n, BOOLEAN, leading0, char **, opp) { Str255 s; NumToString((LONGINT) n, s); if (leading0 && n < 10) *(*opp)++ = '0'; BlockMove((Ptr) (s+1), (Ptr) *opp, (Size) s[0]); *opp += s[0]; } /* * month is similar to the outx routines but is used to print the numerical * form of the month and, if non-null, a separator. */ A4(PRIVATE, void, month, INTEGER, n, Intl0Ptr, int0p, char, sep, char **, opp) { outn(n, Cx(int0p->shrtDateFmt) & mntLdingZ, opp); if (sep) *(*opp)++ = sep; } /* * day is similar to month */ A4(PRIVATE, void, day, INTEGER, n, Intl0Ptr, int0p, char, sep, char **, opp) { outn(n, Cx(int0p->shrtDateFmt) & dayLdingZ, opp); if (sep) *(*opp)++ = sep; } /* * year is similar to month and day */ A4(PRIVATE, void, year, INTEGER, n, Intl0Ptr, int0p, char, sep, char **, opp) { outn(Cx(int0p->shrtDateFmt) & century ? n : n % 100, FALSE, opp); if (sep) *(*opp)++ = sep; } P4(PUBLIC pascal trap, void, IUDatePString, LONGINT, date, /* IMI-505 */ DateForm, form, StringPtr, p, Handle, h) { Intl1Ptr int1p; Intl0Ptr int0p; char *op; DateTimeRec dtr; int abbrev; if (!h) h = IUGetIntl (form == shortDate ? 0 : 1); Secs2Date(date, &dtr); op = (char *) p + 1; if (form == shortDate) { if (h && (int0p = (Intl0Ptr) STARH(h))) { switch (Cx(int0p->dateOrder)) { case mdy: month(CW(dtr.month), int0p, Cx(int0p->dateSep), &op); day (CW(dtr.day), int0p, Cx(int0p->dateSep), &op); year (CW(dtr.year), int0p, 0, &op); break; case dmy: day (CW(dtr.day), int0p, Cx(int0p->dateSep), &op); month(CW(dtr.month), int0p, Cx(int0p->dateSep), &op); year (CW(dtr.year), int0p, 0, &op); break; case ymd: year (CW(dtr.year), int0p, Cx(int0p->dateSep), &op); month(CW(dtr.month), int0p, Cx(int0p->dateSep), &op); day (CW(dtr.day), int0p, 0, &op); break; } } } else { if (h && (int1p = (Intl1Ptr) STARH(h))) { abbrev = form == longDate ? 0 : Cx(int1p->abbrLen); outl(Cx(int1p->st0), &op); if (!Cx(int1p->suppressDay)) { outs(int1p->days[CW(dtr.dayOfWeek)-1], abbrev, &op); outl(Cx(int1p->st1), &op); } if (Cx(int1p->lngDateFmt)) { outs(int1p->months[CW(dtr.month)-1], abbrev, &op); outl(Cx(int1p->st2), &op); outn(CW(dtr.day), Cx(int1p->dayLeading0), &op); } else { outn(CW(dtr.day), Cx(int1p->dayLeading0), &op); outl(Cx(int1p->st2), &op); outs(int1p->months[CW(dtr.month)-1], abbrev, &op); } outl(Cx(int1p->st3), &op); outn(CW(dtr.year), FALSE, &op); outl(Cx(int1p->st4), &op); } } p[0] = op - (char *) p - 1; } P1(PUBLIC pascal trap, Handle, IUGetIntl, INTEGER, id) /* IMI-505 */ { INTEGER oldres; Handle retval; oldres = CurResFile(); UseResFile(0); retval = ROMlib_getrestid(TICK("INTL"), id); UseResFile(oldres); if (!retval && id == 4) { static Handle h = 0; warning_unimplemented (NULL_STRING); if (!h) h = NewHandleClear (100); retval = h; } /* force dates to include century, otherwise we can run into y2k problems with programs like Quicken 6.0 */ if (id == 0 && retval) { Intl0Ptr int0p; int0p = (Intl0Ptr) STARH (retval); int0p->shrtDateFmt |= CBC(century); } return retval; } P3(PUBLIC pascal trap, void, IUDateString, LONGINT, date, /* IMI-504 */ DateForm, form, StringPtr, p) { IUDatePString(date, form, p, IUGetIntl(form == shortDate ? 0 : 1)); } P4(PUBLIC pascal trap, void, IUTimePString, LONGINT, date, /* IMI-505 */ BOOLEAN, secs, StringPtr, p, Handle, h) { Intl0Ptr int0p; char *op; DateTimeRec dtr; char *ip, *ep; if (!h) h = IUGetIntl (0); op = (char *) p + 1; if (h && (int0p = (Intl0Ptr) STARH(h))) { Secs2Date(date, &dtr); if (int0p->timeCycle) outn((CW(dtr.hour) % 12) == 0 ? 12 : CW(dtr.hour) % 12, Cx(int0p->timeFmt) & hrLeadingZ, &op); else outn(CW(dtr.hour), Cx(int0p->timeFmt) & hrLeadingZ, &op); *op++ = int0p->timeSep; outn(CW(dtr.minute), Cx(int0p->timeFmt) & minLeadingZ, &op); if (secs) { *op++ = int0p->timeSep; outn(CW(dtr.second), Cx(int0p->timeFmt) & secLeadingZ, &op); } /* IMI-499 is misleading about the timenSuff fields. The first four are used for AM, the second four for PM. Yes, that's dumb. But that's how the Mac works. Sigh. */ if (!int0p->timeCycle && CW(dtr.hour) < 12) for (ip = (char *) &int0p->time1Suff, ep = ip + 4; ip != ep && *ip;) *op++ = *ip++; else if (!int0p->timeCycle) /* dtr.hour >= 12 */ for (ip = (char *) &int0p->time5Suff, ep = ip + 4; ip != ep && *ip;) *op++ = *ip++; else if (CW(dtr.hour) < 12) outl(Cx(int0p->mornStr), &op); else outl(Cx(int0p->eveStr), &op); } p[0] = op - (char *) p - 1; } P3(PUBLIC pascal trap, void, IUTimeString, LONGINT, date, /* IMI-505 */ BOOLEAN, secs, StringPtr, p) { IUTimePString(date, secs, p, IUGetIntl(0)); } P0(PUBLIC pascal trap, BOOLEAN, IUMetric) /* IMI-505 */ { Handle h; h = IUGetIntl(0); return h ? ((Intl0Ptr) STARH(h))->metricSys : FALSE; } P3(PUBLIC pascal trap, void, IUSetIntl, INTEGER, rn, /* IMI-506 */ INTEGER, id, Handle, newh) { INTEGER oldcurmap; Handle h; oldcurmap = Cx(CurMap); UseResFile(rn); if (ResErr == noErr) { h = IUGetIntl(id); if (h && HomeResFile(h) == rn) { if (id == 0) * (Intl0Ptr) STARH(h) = * (Intl0Ptr) STARH(newh); else * (Intl1Ptr) STARH(h) = * (Intl1Ptr) STARH(newh); ChangedResource(h); } else AddResource(newh, TICK("INTL"), id, (StringPtr) 0); } UseResFile(oldcurmap); } typedef struct { unsigned char primary; unsigned char secondary; } sorttype; PRIVATE sorttype highsortvalues[] = { { 'A', 0x02 }, { 'A', 0x04 }, { 'C', 0x01 }, { 'E', 0x01 }, { 'N', 0x01 }, { 'O', 0x01 }, { 'U', 0x01 }, { 'A', 0x81 }, { 'A', 0x82 }, { 'A', 0x83 }, { 'A', 0x84 }, { 'A', 0x85 }, { 'A', 0x86 }, { 'C', 0x81 }, { 'E', 0x81 }, { 'E', 0x82 }, { 'E', 0x83 }, { 'E', 0x84 }, { 'I', 0x81 }, { 'I', 0x82 }, { 'I', 0x83 }, { 'I', 0x84 }, { 'N', 0x81 }, { 'O', 0x81 }, { 'O', 0x82 }, { 'O', 0x83 }, { 'O', 0x84 }, { 'O', 0x85 }, { 'U', 0x81 }, { 'U', 0x82 }, { 'U', 0x83 }, { 'U', 0x84 }, { 0xA0, 0x00 }, { 0xA1, 0x00 }, { 0xA2, 0x00 }, { 0xA3, 0x00 }, { 0xA4, 0x00 }, { 0xA5, 0x00 }, { 0xA6, 0x00 }, { 0xA7, 0x00 }, { 0xA8, 0x00 }, { 0xA9, 0x00 }, { 0xAA, 0x00 }, { 0xAB, 0x00 }, { 0xAC, 0x00 }, { 0xAD, 0x00 }, { 0xAE, 0x00 }, { 'O', 0x03 }, { 0xB0, 0x00 }, { 0xB1, 0x00 }, { 0xB2, 0x00 }, { 0xB3, 0x00 }, { 0xB4, 0x00 }, { 0xB5, 0x00 }, { 0xB6, 0x00 }, { 0xB7, 0x00 }, { 0xB8, 0x00 }, { 0xB9, 0x00 }, { 0xBA, 0x00 }, { 0xBB, 0x00 }, { 0xBC, 0x00 }, { 0xBD, 0x00 }, { 0xAE, 0x01 }, { 'O', 0x86 }, { 0xC0, 0x00 }, { 0xC1, 0x00 }, { 0xC2, 0x00 }, { 0xC3, 0x00 }, { 0xC4, 0x00 }, { 0xC5, 0x00 }, { 0xC6, 0x00 }, { 0x22, 0x01 }, { 0x22, 0x02 }, { 0xC9, 0x00 }, { 0x20, 0x01 }, { 'A', 0x01 }, { 'A', 0x03 }, { 'O', 0x02 }, { 0xAE, 0x02 }, { 0xAE, 0x03 }, { 0xD0, 0x00 }, { 0xD1, 0x00 }, { 0x22, 0x03 }, { 0x22, 0x04 }, { 0x27, 0x01 }, { 0x27, 0x02 }, { 0xD6, 0x00 }, { 0xD7, 0x00 }, { 'Y', 0x00 }, }; A3(PRIVATE, INTEGER, defaultorder, unsigned char *, cp, INTEGER, len, sorttype *, rp) /* i.e. U.S. order */ { int index; int c; c = *cp; if (c & 0x80) { index = (c & 0x7F); if (index < (int) NELEM(highsortvalues)) *rp = highsortvalues[index]; else { rp->primary = c; rp->secondary = 0; } } else { if (islower(c)) { rp->primary = toupper(c); rp->secondary = 0x80; } else { rp->primary = c; rp->secondary = 0; } } return 1; } A3(PRIVATE, INTEGER, germanylocalization, unsigned char *, cp, INTEGER, len, sorttype *, rp) { INTEGER retval; (void) defaultorder(cp, len, rp); retval = 1; switch (*cp) { case 'A': if (len > 1 && cp[1] == 'E') { /* A E */ retval = 2; rp->secondary = 0x02; } break; case 0x80: /* A-umlaut */ rp->secondary = 0x03; break; case 0xAE: /* AE */ rp->secondary = 0x04; break; case 0xCB: /* A~ */ rp->secondary = 0x05; break; case 0x81: /* A-jot */ rp->secondary = 0x06; break; case 'a': if (len > 1 && cp[1] == 'e') { /* a e */ retval = 2; rp->secondary = 0x84; } break; case 0x8A: /* a-umlaut */ rp->secondary = 0x85; break; case 0xBE: /* ae */ rp->secondary = 0x86; break; case 0x8B: /* a~ */ rp->secondary = 0x87; break; case 0x8C: /* a-jot */ rp->secondary = 0x88; break; case 'O': if (len > 1 && cp[1] == 'E') { /* O E */ retval = 2; rp->secondary = 0x01; } break; case 0x85: /* O-umlaut */ rp->secondary = 0x02; break; case 0xCE: /* OE */ rp->secondary = 0x03; break; case 0xCD: /* O~ */ rp->secondary = 0x04; break; case 0xAF: /* O-slash */ rp->secondary = 0x05; break; case 'o': if (len > 1 && cp[1] == 'e') { /* o e */ retval = 2; rp->secondary = 0x84; } break; case 0x9A: /* o-umlaut */ rp->secondary = 0x85; break; case 0xCF: /* oe */ rp->secondary = 0x86; break; case 0x9B: /* o~ */ rp->secondary = 0x87; break; case 0xBF: /* o-slash */ rp->secondary = 0x88; break; case 'U': if (len > 1 && cp[1] == 'E') { /* U E */ retval = 2; rp->secondary = 0x01; } break; case 0x86: /* U-umlaut */ rp->secondary = 0x02; break; case 'u': if (len > 1 && cp[1] == 'e') { /* u e */ retval = 2; rp->secondary = 0x84; } break; case 0x9F: /* u-umlaut */ rp->secondary = 0x85; break; case 's': if (len > 1 && cp[1] == 's') { /* s s */ retval = 2; rp->primary = 0xA7; rp->secondary = 0x00; } break; case 0xA7: /* Beta? */ rp->secondary = 0x01; break; } return retval; } A3(PRIVATE, INTEGER, britainlocalization, unsigned char *, cp, INTEGER, len, sorttype *, rp) { (void) defaultorder(cp, len, rp); if (rp->primary >= 0x23 && rp->primary <= 0xA3) { /* shift around so */ if (rp->primary == 0xA3) /* real pound sign comes before sharp */ rp->primary = 0x23; else rp->primary++; } return 1; } A3(PRIVATE, INTEGER, defaultlocalization, unsigned char *, cp, INTEGER, len, sorttype *, rp) { return 0; /* never consume anything */ } /* * NOTE: currently we can only use natively compiled localization routines * because we don't envoke syn68k below. However, since we don't know * the exact format of localization routines, we don't care, for now. */ #if !defined (__STDC__) typedef INTEGER (*locptype)(); #else /* __STDC__ */ typedef INTEGER (*locptype)( Ptr ptr, INTEGER len, sorttype *sp ); #endif /* __STDC__ */ A5(PRIVATE, INTEGER, iuhelper, Ptr, ptr1, Ptr, ptr2, INTEGER, len1, INTEGER, len2, BOOLEAN, ignoresec) { Intl0Hndl h; locptype locp; sorttype sort1, sort2; INTEGER ret1, ret2; int usesec = 0; #if !defined (LETGCCWAIL) locp = 0; #endif /* LETGCCWAIL */ if ((h = (Intl0Hndl) IUGetIntl(0)) && (*h).p) { switch ((Hx(h, intl0Vers) >> 8) & 0xFF) { case verBritain: locp = (locptype) britainlocalization; break; case verGermany: locp = (locptype) germanylocalization; break; default: locp = (locptype) defaultlocalization; break; } } else { gui_assert(0); } while (len1 > 0 && len2 > 0) { if (!(ret1 = (*locp)(ptr1, len1, &sort1))) ret1 = defaultorder((unsigned char *) ptr1, len1, &sort1); if (!(ret2 = (*locp)(ptr2, len2, &sort2))) ret2 = defaultorder((unsigned char *) ptr2, len2, &sort2); if (sort1.primary == sort2.primary) { if (!ignoresec && !usesec && sort1.secondary != sort2.secondary) { if (sort1.secondary < sort2.secondary) usesec = -1; else usesec = 1; } len1 -= ret1; ptr1 += ret1; len2 -= ret2; ptr2 += ret2; } else if (sort1.primary < sort2.primary) { len1 = 0; len2 = 1; } else { len1 = 1; len2 = 0; } } if (len1 == len2) return ignoresec ? 0 : usesec; else return (len1 < len2 ? -1 : 1); } P4(PUBLIC pascal trap, INTEGER, IUMagString, Ptr, ptr1, /* IMI-506 */ Ptr, ptr2, INTEGER, len1, INTEGER, len2) { return iuhelper(ptr1, ptr2, len1, len2, FALSE); } A2(PUBLIC, INTEGER, IUCompString, StringPtr, str1, StringPtr, str2) /* IMI-506 */ { return IUMagString((Ptr) (str1+1), (Ptr) (str2+1), str1[0], str2[0]); } P4(PUBLIC pascal trap, INTEGER, IUMagIDString, Ptr, ptr1, /* IMI-507 */ Ptr, ptr2, INTEGER, len1, INTEGER, len2) { return iuhelper(ptr1, ptr2, len1, len2, TRUE); } A2(PUBLIC, INTEGER, IUEqualString, StringPtr, str1, /* IMI-506 */ StringPtr, str2) { return IUMagIDString((Ptr) (str1+1), (Ptr) (str2+1), str1[0], str2[0]); } P4(PUBLIC pascal trap, /* INTEGER */ void, IUMystery, Ptr, arg1, Ptr, arg2, INTEGER, arg3, INTEGER, arg4) { /* Microsoft Excel calls Pack6 with a selector of 18. This is being done on the Mac+. Neither, Inside Macintosh, nor any of the .h and .a files help. This is here just to pop the arguments in a desperate hope that nothing important is being done anyway. */ } /* NOTE: none of the below are done yet */ /* #warning A bunch of IU routines are not implemented yet */ P4(PUBLIC pascal trap, void, IULDateString, LongDateTime *, datetimep, DateForm, longflag, Str255, result, Handle, intlhand) { warning_unimplemented (NULL_STRING); ROMlib_hook(iu_unimplementednumber); } P4(PUBLIC pascal trap, void, IULTimeString, LongDateTime *, datetimep, BOOLEAN, wantseconds, Str255, result, Handle, intlhand) { warning_unimplemented (NULL_STRING); ROMlib_hook(iu_unimplementednumber); } P0(PUBLIC pascal trap, void, IUClearCache) { } P5(PUBLIC pascal trap, INTEGER, IUMagPString, Ptr, ptra, Ptr, ptrb, INTEGER, lena, INTEGER, lenb, Handle, itl2hand) { warning_unimplemented (NULL_STRING); ROMlib_hook(iu_unimplementednumber); return 0; } P5(PUBLIC pascal trap, INTEGER, IUMagIDPString, Ptr, ptra, Ptr, ptrb, INTEGER, lena, INTEGER, lenb, Handle, itl2hand) { warning_unimplemented (NULL_STRING); ROMlib_hook(iu_unimplementednumber); return 0; } P2(PUBLIC pascal trap, INTEGER, IUScriptOrder, ScriptCode, script1, ScriptCode, script2) { warning_unimplemented (NULL_STRING); ROMlib_hook(iu_unimplementednumber); return 0; } P2(PUBLIC pascal trap, INTEGER, IULangOrder, LangCode, l1, LangCode, l2) { warning_unimplemented (NULL_STRING); ROMlib_hook(iu_unimplementednumber); return 0; } P8(PUBLIC pascal trap, INTEGER, IUTextOrder, Ptr, ptra, Ptr, ptrb, INTEGER, lena, INTEGER, lenb, ScriptCode, scripta, ScriptCode, bscript, LangCode, langa, LangCode, langb) { warning_unimplemented (NULL_STRING); ROMlib_hook(iu_unimplementednumber); return 0; } P5(PUBLIC pascal trap, void, IUGetItlTable, ScriptCode, script, INTEGER, tablecode, Handle *, itlhandlep, LONGINT *, offsetp, LONGINT *, lengthp) { warning_unimplemented (NULL_STRING); ROMlib_hook(iu_unimplementednumber); }