executor/src/iu.c
2009-06-16 14:55:37 -06:00

663 lines
17 KiB
C

/* 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 <ctype.h>
/*
* 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);
}