示例#1
0
/* Create an app info chunk if missing, return result from the database call */
static void InitPlkrAppInfo
    (
    DmOpenRef docRef    /* reference to document */
    )
    /* THROWS */
{
    UInt16              cardNo;
    MemHandle           handle;
    LocalID             dbID;
    LocalID             appInfoID;
    PlkrAppInfoType*    appInfoP;
    Err                 err;

    err = DmOpenDatabaseInfo( docRef, &dbID, NULL, NULL, &cardNo, NULL );
    THROW_IF( err != errNone, err );

    err = DmDatabaseInfo( cardNo, dbID, NULL, NULL, NULL, NULL, NULL,
            NULL, NULL, &appInfoID, NULL, NULL, NULL );
    THROW_IF( err != errNone, err );

    if ( appInfoID == 0 ) {
        handle = DmNewHandle( docRef, sizeof *appInfoP );
        THROW_IF( handle == NULL, dmErrMemError );

        appInfoID = MemHandleToLocalID( handle );
        DmSetDatabaseInfo( cardNo, dbID, NULL, NULL, NULL, NULL,
            NULL, NULL, NULL, &appInfoID, NULL, NULL, NULL );
    }
    appInfoP = MemLocalIDToLockedPtr( appInfoID, cardNo );
    DmSet( appInfoP, 0, sizeof *appInfoP, 0 );
    CategoryInitialize( ( AppInfoPtr ) appInfoP, strCatDefault );
    MemPtrUnlock( appInfoP );
}
示例#2
0
/* Finds and opens database,
 * calls plugin specific code to create new item,
 * then fills in GoTo parameters.
 */
static UInt16
PickBooger(KleenexPtr kleenexP)
{
    DmOpenRef dbR;
    UInt32 creatorID;
    UInt16 cardNo;
    LocalID dbID;
    Boolean closedb = false;
    UInt16 err, index;
    Char name[dmDBNameLength];

    /* Check for the correct version */
    if (!((kleenexP->version) & IBVERSION_PICTURE))
        return (boogerErrorVersionMismatch);

    /* Open the database */
    cardNo = 0;
    if (!(dbID = DmFindDatabase(cardNo, "DiddleIDB")))
        return 1;

    if ((dbR = DmOpenDatabase(cardNo, dbID, dmModeReadWrite))) {
        closedb = true;

    } else if (DmGetLastErr() == dmErrAlreadyOpenForWrites) {
        dbR = NULL;
        while ((dbR = DmNextOpenDatabase(dbR))) {
            DmOpenDatabaseInfo(dbR, &dbID, NULL, NULL, &cardNo, NULL);
            DmDatabaseInfo(cardNo, dbID, name, NULL, NULL, NULL, NULL, NULL,
                           NULL, NULL, NULL, NULL, &creatorID);
            if (!StrCompare(name, "DiddleIDB") && (creatorID == DB_CREATOR))
                break;
        }
        if (!dbR)
            return 1;
    }

    /* Call plugin specific routine to create item in database */
    err = DoTheBoogie(kleenexP, dbR, &index);

    /* Close the database */
    if (closedb)
        DmCloseDatabase(dbR);

    /* Did it work? */
    if (err)
        return (1);

    /* Load the GoTo parameters */
    if (!(kleenexP->booger.cmdPBP = MemPtrNew(sizeof(GoToParamsType))))
        return (1);
    MemSet(kleenexP->booger.cmdPBP, sizeof(GoToParamsType), 0);
    ((GoToParamsType *)(kleenexP->booger.cmdPBP))->dbCardNo = cardNo;
    ((GoToParamsType *)(kleenexP->booger.cmdPBP))->dbID = dbID;
    ((GoToParamsType *)(kleenexP->booger.cmdPBP))->recordNum = index;
    MemPtrSetOwner(kleenexP->booger.cmdPBP, 0);

    return (errNone);
}
示例#3
0
/* Finds and opens database,
 * calls plugin specific code to create new item,
 * then fills in GoTo parameters.
 */
static UInt16
PickBooger(KleenexPtr kleenexP)
{
    DmOpenRef dbR;
    DmSearchStateType searchstate;
    UInt32 creatorID, dbtype;
    UInt16 cardNo;
    LocalID dbID;
    Boolean closedb = false;
    UInt16 err, index;

    /* Check for the correct version */
    if (!((kleenexP->version) & IBVERSION_ORIG))
        return (boogerErrorVersionMismatch);

    /* Open the database */
    if (DmGetNextDatabaseByTypeCreator(true, &searchstate, DB_TYPE,
                                       DB_CREATOR, true, &cardNo, &dbID))
        return (1);

    if ((dbR = DmOpenDatabase(cardNo, dbID, dmModeReadWrite))) {
        closedb = true;

    } else if (DmGetLastErr() == dmErrAlreadyOpenForWrites) {
        dbR = NULL;
        while ((dbR = DmNextOpenDatabase(dbR))) {
            DmOpenDatabaseInfo(dbR, &dbID, NULL, NULL, &cardNo, NULL);
            DmDatabaseInfo(cardNo, dbID, NULL, NULL, NULL, NULL, NULL, NULL,
                           NULL, NULL, NULL, &dbtype, &creatorID);
            if ((dbtype == DB_TYPE) && (creatorID == DB_CREATOR))
                break;
        }
        if (!dbR)
            return (1);
    }

    /* Call plugin specific routine to create item in database */
    err = DoTheBoogie(kleenexP, dbR, &index);

    /* Close the database */
    if (closedb)
        DmCloseDatabase(dbR);

    /* Did it work? */
    if (err)
        return (1);

    /* Load the GoTo parameters */
    if (!(kleenexP->booger.cmdPBP = MemPtrNew(sizeof(GoToParamsType))))
        return (1);
    MemSet(kleenexP->booger.cmdPBP, sizeof(GoToParamsType), 0);
    ((GoToParamsType *)(kleenexP->booger.cmdPBP))->dbCardNo = cardNo;
    ((GoToParamsType *)(kleenexP->booger.cmdPBP))->dbID = dbID;
    ((GoToParamsType *)(kleenexP->booger.cmdPBP))->recordNum = index;
    MemPtrSetOwner(kleenexP->booger.cmdPBP, 0);

    return (errNone);
}
示例#4
0
/*
** Add the Linker link to the plugin text. The calling
** function must free the returned pointer.
*/
static Char* GetLink(Char* orig_text) {
  UInt16 length = 0;
  Char* linked_text = NULL;
  LinkerCPB command_block;
  UInt32 result;

  /* Bail if there is no text */
  if (!orig_text)
    return 0;

  length = StrLen(orig_text) + 1;
  if (p.flags & PFLAGS_XFER_BACKLINK && d.linker_available) 
    length += 5;

  linked_text = MemPtrNew(length);
  ASSERT(linked_text);
  StrCopy(linked_text, orig_text);

  if (!(p.flags & PFLAGS_XFER_BACKLINK && d.linker_available))
    return linked_text;

  MemSet(&command_block, sizeof(LinkerCPB), 0);
  command_block.creator = 'Linx'; /* maybe this is overkill, but .... */
  command_block.message = LinkerNewLinkMessage;
  /* command_block.linkTag is empty and to be filled by Linker */
  command_block.gotoTargetAppCreator = AppType; /* DiddleBug is the target */
  DmOpenDatabaseInfo(d.dbR, &(command_block.gotoLinkParams.dbID), NULL, NULL,
		     &(command_block.gotoLinkParams.dbCardNo), NULL);
  command_block.gotoLinkParams.recordNum = p.dbI;
  
  /* Signal Linker */
  SysAppLaunch(d.cardNo, d.dbID, 0, linkerAppLaunchCmdSignalLinker,
	       &command_block, &result);

  /* Add the link text */
  command_block.linkTag[5] = 0x00; /* just to be sure */
  StrCat(linked_text, command_block.linkTag);

  return linked_text;
}
示例#5
0
/* Create database for list of documents */
static void CreateDocList( void )
    /* THROWS */
{
    UInt16  cardNo;
    Err     err;
    LocalID dbID;
    UInt16  version;

    /* list is always put on first card in RAM */
    cardNo  = 0;
    err     = errNone;

    err = DmCreateDatabase( cardNo, PlkrDocListName, ViewerAppID,
            PlkrDocListType, false );
    THROW_IF( err != errNone, memErrNotEnoughSpace );

    dbID    = DmFindDatabase( cardNo, PlkrDocListName );
    version = PlkrDocListVersion;
    err     = DmSetDatabaseInfo( cardNo, dbID, NULL, NULL, &version, 
                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );

    plkrDocList = DmOpenDatabaseByTypeCreator( PlkrDocListType, ViewerAppID,
                    dmModeReadWrite );

    ErrTry {
        InitPlkrAppInfo( plkrDocList );
    }
    ErrCatch( UNUSED_PARAM( err ) ) {
        LocalID dbID;

        DmOpenDatabaseInfo( plkrDocList, &dbID, NULL, NULL, &cardNo, NULL );
        CloseDatabase( plkrDocList );
        DmDeleteDatabase( cardNo, dbID );
        MSG( "Couldn't initialize Plkr document list [ appInfo ]\n" );
        ErrThrow( memErrNotEnoughSpace );
    } ErrEndCatch
}
示例#6
0
/***********************************************************************
 * handling for form and control actions
 * menu actions are forwarded to MainFormDoCommand
 ***********************************************************************/
static Boolean
MainFormHandleEvent (EventPtr event)
{
  FormType *frm;
  Boolean handled = false;
  Boolean categoryEdited, reDraw=false;
  UInt16 category, numRecords;
  ControlType *ctl;
  UInt32 *recordList;

  
  if (event->eType == ctlSelectEvent) {
    // button handling
    handled = true;
    switch (event->data.ctlSelect.controlID) {
      // the ok button - this leaves the application

      case LIST_cat_trigger:
        frm = FrmGetActiveForm();
        category=DatabaseGetCat();
        numRecords=DmNumRecordsInCategory(DatabaseGetRef(), DELETE_CATEGORY);
        recordList=(UInt32 *)MemPtrNew(numRecords * sizeof(UInt32));
        CatPreEdit(numRecords, recordList);
        categoryEdited = CategorySelect(DatabaseGetRef(), frm,
                                        LIST_cat_trigger, LIST_cat, false,
                                        &category, gCategoryName, 0,
                                        STRING_cat_edit); // categoryDefaultEditCategoryString
        if (categoryEdited || (category != DatabaseGetCat())) {
          reDraw=true;
          DatabaseSetCat(category);
          ctl = GetObjectPtr(LIST_cat_trigger);
          CategoryGetName(DatabaseGetRef(), DatabaseGetCat(), gCategoryName); 
          CategorySetTriggerLabel(ctl, gCategoryName); 
        }
        CatPostEdit(numRecords, recordList);
        if (reDraw)  {
          GadgetSetNeedsCompleteRedraw(true);
          FrmDrawForm(frm);
        }
        if (recordList != NULL)    MemPtrFree((MemPtr)recordList);
        break;

      case BUTTON_beam:
        BeamCourse(GadgetGetHintCourseIndex());
        break;

      case BUTTON_edit:
        gMenuCurrentForm=FORM_main;
        EditTime();
        break;

      case BUTTON_next:
        GadgetDrawHintNext();
        break;

      default:
        break;
      }
    } else if (event->eType == keyDownEvent) {
      // We have a hard button assigned and it was pressed
      if (TxtCharIsHardKey(event->data.keyDown.modifiers, event->data.keyDown.chr)) {
        if (! (event->data.keyDown.modifiers & poweredOnKeyMask)) {
          GadgetDrawHintNext();
          handled = true;
        }
      } else if (EvtKeydownIsVirtual(event)) {
        // Up or down keys pressed
        switch (event->data.keyDown.chr) {
          case vchrPageUp:
            if (event->data.keyDown.modifiers & autoRepeatKeyMask) {
              if (! gMainRepeat) {
                GadgetSwitchScreen();
                gMainRepeat = true;
              }
            } else {
              GadgetDrawStep(winUp);
              gMainRepeat = false;
            }
            handled=true;
            break;

          case vchrPageDown:
            if (event->data.keyDown.modifiers & autoRepeatKeyMask) {
              if (! gMainRepeat) {
                GadgetSwitchScreen();
                gMainRepeat = true;
              }
            } else {
              GadgetDrawStep(winDown);
              gMainRepeat = false;
            }
            handled=true;
            break;

          case vchrSendData:
            BeamCourse(GadgetGetHintCourseIndex());
            handled=true;
            break;

          default:
            break;
        }
      }
    } else if (event->eType == menuEvent) {
      // forwarding of menu events
      return HandleMenuEvent(event->data.menu.itemID);
    } else if (event->eType == menuOpenEvent) {
      return HandleMenuOpenEvent(event);
    } else if (event->eType == frmUpdateEvent) {
      // redraws the form if needed
      frm = FrmGetActiveForm();
      FrmDrawForm(frm);
      // GadgetDrawHintNext();
      handled = true;
    } else if (event->eType == frmOpenEvent) {
      ControlType *ctl;
      LocalID dbID;
      UInt16 cardNo;
      Boolean newKeyP4=false;
      UInt16 newKeyP2=0xFFFF;

      // initializes and draws the form at program launch
      frm = FrmGetActiveForm();

      GadgetSet(frm, GADGET_main, GADGET_hint);
      FrmSetGadgetHandler(frm, FrmGetObjectIndex(frm, GADGET_main), GadgetHandler);
      FrmSetGadgetHandler(frm, FrmGetObjectIndex(frm, GADGET_hint), GadgetHintHandler);

      FrmDrawForm(frm);
      GadgetDrawHintNext();

      ctl = GetObjectPtr(LIST_cat_trigger);
      CategoryGetName (DatabaseGetRef(), DatabaseGetCat(), gCategoryName); 
      CategorySetTriggerLabel (ctl, gCategoryName); 

      DmOpenDatabaseInfo(DatabaseGetRefN(DB_MAIN), &dbID, NULL, NULL, &cardNo, NULL);
      SysNotifyRegister(cardNo, dbID, sysNotifyLateWakeupEvent, HandleNotification, sysNotifyNormalPriority, NULL);

    	KeyRates(false,&gKeyP1, &gKeyP2, &gKeyP3, &gKeyP4);
	    KeyRates(true, &gKeyP1, &newKeyP2, &gKeyP3, &newKeyP4);

      handled = true;
    } else if (event->eType == frmCloseEvent) {
      // this is done if program is closed
      LocalID dbID;
      UInt16 cardNo;
      DmOpenDatabaseInfo(DatabaseGetRefN(DB_MAIN), &dbID, NULL, NULL, &cardNo, NULL);
      SysNotifyUnregister(cardNo, dbID, sysNotifyLateWakeupEvent, sysNotifyNormalPriority);
      // Restore original key rates
	    KeyRates(true, &gKeyP1, &gKeyP2, &gKeyP3, &gKeyP4);
    }

  return (handled);
}
示例#7
0
// Save preferences previously set via ErrSet*() calls to a database.
// If something goes wrong, returns an error
// Possible errors:
//   memErrNotEnoughSpace - not enough memory to allocate needed structures
//   errors from Dm*() calls
Err PrefsStoreWriter::ErrSavePreferences()
{
    Err     err = errNone;
    long    blobSize;
    void *  prefsBlob = SerializeItems(_items, _itemsCount, &blobSize);
    if ( NULL == prefsBlob ) 
        return memErrNotEnoughSpace;

    DmOpenRef db = DmOpenDatabaseByTypeCreator(_dbType, _dbCreator, dmModeReadWrite);
    if (!db)
    {
        err = DmCreateDatabase(0, _dbName, _dbCreator, _dbType, false);
        if ( err)
            return err;

        db = DmOpenDatabaseByTypeCreator(_dbType, _dbCreator, dmModeReadWrite);
        if (!db)
            return DmGetLastErr();
    }

    // set backup bit on the database. code adapted from DataStore.cpp
    // DataStore::open()
    if (errNone == err)
    {
        LocalID localId;
        UInt16 cardNo;
        UInt16 attribs;
        err = DmOpenDatabaseInfo(db, &localId, NULL, NULL, &cardNo, NULL);
        if (errNone != err)
            goto Continue;
        err = DmDatabaseInfo(cardNo, localId, NULL, &attribs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
        if (errNone != err)
            goto Continue;
        if (0 != attribs & dmHdrAttrBackup)
            goto Continue;
        attribs |= dmHdrAttrBackup;
        err = DmSetDatabaseInfo(cardNo, localId, NULL, &attribs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
Continue:
        err = errNone;
    }

    UInt16    recNo = 0;
    UInt16    recsCount = DmNumRecords(db);
    MemHandle recHandle;
    Boolean   fRecordBusy = false;
    Boolean   fRecFound = false;
    void *    recData;
    long      recSize;
    while (recNo < recsCount)
    {
        recHandle = DmGetRecord(db, recNo);
        fRecordBusy = true;
        recData = MemHandleLock(recHandle);
        recSize = MemHandleSize(recHandle);
        if (IsValidPrefRecord(recData))
        {
            fRecFound = true;
            break;
        }
        MemPtrUnlock(recData);
        DmReleaseRecord(db, recNo, true);
        fRecordBusy = false;
        ++recNo;
    }

    if (fRecFound && blobSize>recSize)
    {
        /* need to resize the record */
        MemPtrUnlock(recData);
        DmReleaseRecord(db,recNo,true);
        fRecordBusy = false;
        recHandle = DmResizeRecord(db, recNo, blobSize);
        if ( NULL == recHandle )
            return DmGetLastErr();
        recData = MemHandleLock(recHandle);
        Assert( MemHandleSize(recHandle) == blobSize );        
    }

    if (!fRecFound)
    {
        recNo = 0;
        recHandle = DmNewRecord(db, &recNo, blobSize);
        if (!recHandle)
        {
            err = DmGetLastErr();
            goto CloseDbExit;
        }
        recData = MemHandleLock(recHandle);
        fRecordBusy = true;
    }

    err = DmWrite(recData, 0, prefsBlob, blobSize);
    MemPtrUnlock(recData);
    if (fRecordBusy)
        DmReleaseRecord(db, recNo, true);
CloseDbExit:
    // if had error before - preserve that error
    // otherwise return error code from DmCloseDatabase()
    if (err)
        DmCloseDatabase(db);
    else
        err = DmCloseDatabase(db);
    new_free( prefsBlob );
    return err;
}
示例#8
0
void IntlInit(void)
{
	Err result;
	MemHandle localeCodeH;
	MemHandle tableListH;
	MemHandle featureTableH;
	ROMFtrTableType* featureTableP;
	ROMFtrCreatorType* creatorTableP;
	UInt16 creators;
	Boolean fastSort = true;
	Boolean fastSearch = true;
	Boolean fastAttr = true;
	UInt16 index;
	UInt32 intlFtrFlags;

#if (EMULATION_LEVEL == EMULATION_NONE)
	UInt16 systemCard;
	LocalID systemID;
	DmSearchStateType* searchStateP;
	MemHandle localeNameH;
	LocalID moduleID;
	DmOpenRef moduleRef;

	// Locate the system DB, so that we know where to look (which card)
	// for the locale module.
	searchStateP = (DmSearchStateType*)MemPtrNew(sizeof(DmSearchStateType));
	result = DmGetNextDatabaseByTypeCreator(	true,
															searchStateP,
															sysFileTSystem,
															sysFileCSystem,
															true,					// onlyLatestVers
															&systemCard,
															&systemID);
	ErrNonFatalDisplayIf((result != errNone) || (systemID == 0), "Can't find system DB");
	MemPtrFree((MemPtr)searchStateP);
	
	localeNameH = DmGetResource(strRsc, localeModuleNameStrID);
	ErrNonFatalDisplayIf(localeNameH == NULL, "Missing locale module name string");
	
	moduleID = DmFindDatabaseWithTypeCreator(	systemCard,
															(Char*)MemHandleLock(localeNameH),
															sysFileTLocaleModule,
															sysFileCSystem);
	MemHandleUnlock(localeNameH);
	
	if (moduleID != 0)
	{
		moduleRef = DmOpenDatabase(systemCard, moduleID, dmModeReadOnly | dmModeLeaveOpen);
		ErrNonFatalDisplayIf(moduleRef == 0, "Can't open locale module");
		
		if (ResLoadConstant(kIntlLMVersResID) != kIntlLMVersion)
		{
			DmCloseDatabase(moduleRef);
			moduleID = 0;
		}
	}
	
	// If we couldn't find the locale module, or it has the wrong version, then
	// default to the ROM locale's locale module.
	if (moduleID == 0)
	{
		SysNVParamsType* romParamsP;
		OmLocaleType romLocale;
		Char* overlayName;
		LocalID overlayID;
		DmOpenRef overlayRef;
		Char* systemName;
		
		// Open up the system overlay that corresponds to the ROM's locale.
		// Note that (assuming the ROM locale != current locale) we have to
		// try to open up the overlay explicitly, since the Overlay Mgr
		// won't be opening it automatically. We also have to handle the case
		// of a ROM built without overlays, in which case the ROM locale's
		// locale module name string is located in the base, which means we
		// have to make a low-level resource call to get it (otherwise we'll
		// get the string from the system overlay).
		romParamsP = (SysNVParamsType*)MemPtrNew(sizeof(SysNVParamsType));
		MemGetRomNVParams(romParamsP);
		romLocale.country = romParamsP->localeCountry;
		romLocale.language = romParamsP->localeLanguage;
		MemPtrFree((MemPtr)romParamsP);
		
		// Get the name of the system DB, so that we can construct the overlay
		// name.
		systemName = (Char*)MemPtrNew(dmDBNameLength);
		overlayName = (Char*)MemPtrNew(dmDBNameLength);

		result = DmDatabaseInfo(systemCard, systemID, systemName,
						NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
		ErrNonFatalDisplayIf(result != errNone, "Can't get system DB info");
		
		result = OmLocaleToOverlayDBName(systemName, &romLocale, overlayName);
		ErrNonFatalDisplayIf(result != errNone, "Can't make ROM locale system overlay name");
		
		overlayID = DmFindDatabaseWithTypeCreator(systemCard,
																overlayName,
																sysFileTOverlay,
																sysFileCSystem);
		MemPtrFree(systemName);
		MemPtrFree((MemPtr)overlayName);
		
		if (overlayID != 0)
		{
			overlayRef = DmOpenDatabase(systemCard, overlayID, dmModeReadOnly);
			ErrNonFatalDisplayIf(overlayRef == 0, "Can't open system overlay");
			
			// Now load the locale module name string from this overlay, and use
			// it to find the locale module.
			localeNameH = DmGet1Resource(strRsc, localeModuleNameStrID);
			ErrNonFatalDisplayIf(localeNameH == NULL, "Missing locale module name string");
			moduleID = DmFindDatabaseWithTypeCreator(	systemCard,
																	(Char*)MemHandleLock(localeNameH),
																	sysFileTLocaleModule,
																	sysFileCSystem);
			MemHandleUnlock(localeNameH);
			DmCloseDatabase(overlayRef);
		}
		else
		{
			// Assume it's a ROM built without overlays, in which case we need to
			// get the locale name handle from the system base.
			DmOpenRef sysRef = NULL;
			Int16 index;
			
			do
			{
				LocalID dbID;
				
				sysRef = DmNextOpenResDatabase(sysRef);
				
				if ((sysRef != NULL)
				 && (DmOpenDatabaseInfo(sysRef, &dbID, NULL, NULL, NULL, NULL) == errNone)
				 && (dbID == systemID))
				{
				 	break;
				}
			} while (sysRef != NULL);

			ErrNonFatalDisplayIf(sysRef == NULL, "Can't find system DB");
			index = DmFindResource(sysRef, strRsc, localeModuleNameStrID, NULL);
			ErrNonFatalDisplayIf(index == -1, "Missing locale module name string");
			localeNameH = DmGetResourceIndex(sysRef, index);
			ErrNonFatalDisplayIf(localeNameH == NULL, "Missing locale module name string");
			moduleID = DmFindDatabaseWithTypeCreator(	systemCard,
																	(Char*)MemHandleLock(localeNameH),
																	sysFileTLocaleModule,
																	sysFileCSystem);
		}
		
		// If we found the locale module DB, open it up and make sure it has
		// the right version.
		if (moduleID != 0)
		{
			moduleRef = DmOpenDatabase(systemCard, moduleID, dmModeReadOnly | dmModeLeaveOpen);
			if ((moduleRef == 0)
			 || (ResLoadConstant(kIntlLMVersResID) != kIntlLMVersion))
			{
				// Trigger fatal alert below. No need to close the DB in that case.
				moduleID = 0;
			}
			else
			{
				// We found a valid locale module, using the ROM locale, so set
				// the current locale to be the ROM locale.
				result = FtrSet(sysFtrCreator, sysFtrNumLanguage, romLocale.language);
				
				if (result == errNone)
				{
					result = FtrSet(sysFtrCreator, sysFtrNumCountry, romLocale.country);
				}
				
				ErrNonFatalDisplayIf(result != errNone, "Can't switch current locale to ROM locale");
			}
		}
		
		ErrFatalDisplayIf(moduleID == 0, "No valid locale module");
	}
	
	result = DmDatabaseProtect(systemCard, moduleID, true);
	if (result != dmErrROMBased)
	{
		ErrNonFatalDisplayIf(result != errNone, "Can't protect locale module");
	}
#else
	// Give the locale module code in the Simulator a chance to
	// initialize itself. If there's no such code (e.g. with latin) then the
	// routine in SimStubs.cp does nothing.
	StubPalmOSInitLocaleModule();
#endif

	// If there's a locale module code resource, load & call it now.
	localeCodeH = DmGet1Resource(kIntlLMCodeType, kIntlLMCodeResID);
	if (localeCodeH != NULL)
	{
		ProcPtr localeCodeP = (ProcPtr)MemHandleLock(localeCodeH);
		(*localeCodeP)();
		MemHandleUnlock(localeCodeH);
	}
	
	// If the IntlMgr data ptr hasn't been set up by the locale module code,
	// allocate it now.
	if (GIntlMgrGlobalsP == NULL)
	{
		UInt16 numCustomTransTables;
		MemPtr globalPtr;

		numCustomTransTables = ResLoadConstant(kIntlLMCustomTransCountID);
		ErrNonFatalDisplayIf(numCustomTransTables > kIntlMaxCustomTransliterations,
									"Too many custom transliterations");
		
		globalPtr = MemPtrNew(sizeof(IntlGlobalsType) + (numCustomTransTables * sizeof(void*)));
		ErrNonFatalDisplayIf(globalPtr == NULL, "Out of memory");
		
		MemSet(globalPtr, sizeof(IntlGlobalsType) + (numCustomTransTables * sizeof(void*)), 0);
		GIntlMgrGlobalsP = globalPtr;
		
		GIntlData->numCustomTransliterations = numCustomTransTables;
	}
	else
	{
		// If any of the sorting tables are already configured, we can't do
		// our fast sorting optimization.
		for (index = 0; index < kIntlMaxSortLevels; index++)
		{
			if (GIntlData->sortTables[index] != NULL)
			{
				fastSort = false;
				break;
			}
		}
		
		// If the word start or word match tables are already configured, we
		// can't do our fast word search optimization.
		
		if ((GIntlData->findWordStartTable != NULL)
		 || (GIntlData->findWordMatchTable != NULL))
		{
			fastSearch = false;
		}
		
		// If the character attribute table is already configured, we can't do
		// our fast attribute optimization.
		if (GIntlData->charAttrTable != NULL)
		{
			fastAttr = false;
		}
	}
	
	// Loop over all of the table resources, locking & setting up pointers in
	// the IntlMgr global data structure.
	tableListH = DmGet1Resource(kIntlLMTableListType, kIntlLMTableListResID);
	if (tableListH != NULL)
	{
		IntlLMTableEntryType* curTable;
		UInt8* globalsP = (UInt8*)GIntlMgrGlobalsP;
		IntlLMTableResType* tableListP = (IntlLMTableResType*)MemHandleLock(tableListH);
		
		for (index = 0, curTable = tableListP->resources; index < tableListP->numResources; index++, curTable++)
		{
			void** ptrLocation;
			MemHandle tableH;
			
			tableH = DmGet1Resource(curTable->resType, curTable->resID);
			ErrFatalDisplayIf(tableH == NULL, "Missing table resource from locale module");
			ErrFatalDisplayIf(curTable->tableIndex >= intlLMNumTableIndexes, "Invalid table index");
			
			ptrLocation = (void**)(globalsP + kIntlGlobalOffsets[curTable->tableIndex]);
			ErrFatalDisplayIf(*ptrLocation != NULL, "Resource overriding existing table ptr");
			*ptrLocation = MemHandleLock(tableH);
		}
		
		MemHandleUnlock(tableListH);
	}

	// Note that we can't check for the presence of tables here, as a table that
	// is required by a Text Mgr routine might be NULL if the locale module has
	// patched out that routine.
	
	// As an optimization, see if all of the sorting tables are byte-indexed 8-bit
	// values. If so, then replace the table ptrs with ptrs to the actual data,
	// and set the fast sorting intl mgr flag.
	for (index = 0; (index < kIntlMaxSortLevels) && fastSort; index++)
	{
		void* sortTable = GIntlData->sortTables[index];
		if (sortTable == NULL)
		{
			break;
		}
		else if (PrvGetByteIndexedTable(sortTable, 8) == NULL)
		{
			fastSort = false;
		}
	}
	
	if (fastSort)
	{
		GIntlData->intlFlags |= kByteSortingFlag;
		
		for (index = 0; index < kIntlMaxSortLevels; index++)
		{
			GIntlData->sortTables[index] = PrvGetByteIndexedTable(GIntlData->sortTables[index], 8);
		}
	}
	
	// As an optimization, see if all of the searching tables are byte-indexed 8-bit
	// values. If so, then replace the table ptrs with ptrs to the actual data,
	// and set the fast searching intl mgr flag. Note that PrvGetByteIndexedTable
	// will return NULL if findWordMatchTable is NULL, which is OK because then
	// TxtFindString must be patched out anyway. The findWordStartTable is optional,
	// and thus it can either be NULL or a byte indexed byte table.
	if ((fastSearch)
	 && ((GIntlData->findWordStartTable == NULL)
	  || (PrvGetByteIndexedTable(GIntlData->findWordStartTable, 8) != NULL))
	 && (PrvGetByteIndexedTable(GIntlData->findWordMatchTable, 8) != NULL))
	{
		GIntlData->intlFlags |= kByteSearchingFlag;

		GIntlData->findWordStartTable = PrvGetByteIndexedTable(GIntlData->findWordStartTable, 8);
		GIntlData->findWordMatchTable = PrvGetByteIndexedTable(GIntlData->findWordMatchTable, 8);
	}
	
	// As an optimization, see if the character attribute table is a byte-indexed
	// table of 16-bit values. If so, then replace the table ptr with a ptr to
	// the data, and set the kByteCharAttrFlag flag.
	if (fastAttr && (PrvGetByteIndexedTable(GIntlData->charAttrTable, 16) != NULL))
	{
		GIntlData->intlFlags |= kByteCharAttrFlag;
		GIntlData->charAttrTable = PrvGetByteIndexedTable(GIntlData->charAttrTable, 16);
	
	// As an optimization, see if the character attribute table is a stage index map
	// table of 16-bit values. If so, then replace the table ptr with a ptr to
	// the sub-table offsets, set up the result table ptr, and set the
	// kStageCharAttrFlag flag.
	}
	else if (fastAttr && PrvGetStageIndexMapTable(GIntlData->charAttrTable, 16))
	{
		GIntlData->intlFlags |= kStageCharAttrFlag;
		GIntlData->charAttrTable = PrvGetStageIndexMapTable(GIntlData->charAttrTable, 16);
	}
	
	// If there's a doubleCharTable, we want to (a) verify that it's a byte-indexed
	// byte table, and (b) set up the pointer now.
	if (GIntlData->doubleCharTable != NULL)
	{
		void* tableP = PrvGetByteIndexedTable(GIntlData->doubleCharTable, 8);
		ErrNonFatalDisplayIf(tableP == NULL, "Double-char table isn't byte-indexed byte table");
		GIntlData->doubleCharTable = tableP;
	}
	
	// Load the 'feat' resource from the locale module, and use it to initialize
	// various locale-specific features. Typically this includes sysFtrNumCharEncodingFlags,
	// sysFtrNumEncoding, sysFtrDefaultFont, and sysFtrDefaultBoldFont.
	// Try to load the 'feat' resource.
	featureTableH = DmGet1Resource(sysResTFeatures, kIntlLMFeatureResID);
	ErrFatalDisplayIf(featureTableH == NULL, "Missing feature table");
	featureTableP = (ROMFtrTableType*)MemHandleLock(featureTableH);
	creatorTableP = featureTableP->creator;
	
	for (creators = 0; creators < featureTableP->numEntries; creators++)
	{
		UInt16 features;
		
		for (features = 0; features < creatorTableP->numEntries; features++)
		{
			result = FtrSet(	creatorTableP->creator,
									creatorTableP->feature[features].num,
									creatorTableP->feature[features].value);
			ErrNonFatalDisplayIf(result != errNone, "Can't set locale feature");
		}
		
		// Advance to next creator table.
		creatorTableP = (ROMFtrCreatorType*)((UInt8*)creatorTableP
								+ sizeof(ROMFtrCreatorType)
								+ (creatorTableP->numEntries * sizeof(ROMFtrFeatureType)));
	}
	
	MemHandleUnlock(featureTableH);
	
	// Now, set up our internal kByteSearchingFlag flag based on the sysFtrNumCharEncodingFlags
	// feature value. This means that sysFtrNumCharEncodingFlags is read-only, since if
	// anybody uses FtrSet to change the settings of the flags, that won't update
	// our internal flag(s).
	if ((FtrGet(sysFtrCreator, sysFtrNumCharEncodingFlags, &intlFtrFlags) == errNone)
	 && ((intlFtrFlags & charEncodingOnlySingleByte) != 0))
	{
		GIntlData->intlFlags |= kSingleByteOnlyFlag;
	}
	
	// Finally set the bit that tells everybody we're ready to support IntlMgr/TextMgr calls.
	FtrSet(sysFtrCreator, sysFtrNumIntlMgr, intlMgrExists);
} // IntlInit