/* serial.c - basis of SimpleTerm 0.5, a simple Pilot terminal */ /* Feel free to use this code as you wish, no guarantees are given or implied. The code was not designed to be seen by others, it just turned out that way! Excuse the mess, it was quick and dirty, but fun! Whilst I'll endeavour to help when I can, I can't promise to reply to all email or give detailed explanations of the code. Let me know if anything interesting arises - especially that elusive VT100 terminal! Have fun, Iain - isb@pobox.com Hints ----- I never got this to run under the emulator, all my debugging had to be done after loading to the Pilot. Please distribute anything interesting that comes of this, people really seem to appreciate it! */ /* This code was once... */ /*********************************************************************** * * Copyright (c) Palm Computing 1995 -- All Rights Reserved * * PROJECT: Memo Pad Sample Application * * FILE: MemoPad.c (Phase 1) * * DESCRIPTION: Sample application to demonstrate the various * features available. * * OBJECTIVE: Create an initial main form with a title and an * exit button. * * REVISION HISTORY: * 9/1/95 David Initial version * **********************************************************************/ #include // all the system toolbox headers #include #include "serialRsc.h" // application resource defines //Code for Doc database logging typedef struct trecord0 { Word compression_type; Word spare; DWord story_length; Word num_records; Word reclen; // normall 0x1000; } Record0Type; typedef struct { Int baud; Int bits; Int parity; Int xon; Int rts; Int version; } SimplePreferenceType; SimplePreferenceType prefs; // Application database management defines. #define JDocAppType 'JDoc' // P5. type for application. J-DOC #define JDocDBCreator 'REAd' // P5. name for application 'DOC' #define JDocDBType 'TEXt' // P5. type for application 'DOC' #define JDocVersionNum 1 #define null 0 /*********************************************************************** * Prototypes for internal functions **********************************************************************/ static Err StartApplication(void); static void StopApplication(void); static Boolean MainFormHandleEvent(EventPtr event); static Boolean SetFormHandleEvent(EventPtr event); static void SetCurrentMenu(Word rscID); // P2. set new current menu static void EventLoop(void); static Boolean RxData(); static void ClrScreen(); static void SetSerialSettings(); static void OptionsApply(); void WriteDB( CharPtr, int); void CloseDB(void); Boolean CreateLogDB(CharPtr); FieldPtr GetFocusObjectPtr (void); extern void YieldTime(); void YieldTime() {return;} static MenuBarPtr CurrentMenu = NULL; // P2. ptr to current menu UInt SerialRef; static SerSettingsType SerialSettings; static DmOpenRef CurrentDB; Int Bits = 8; Int Parity = 0; //Use 0 for none, 1 for odd and 2 for even! Int Baud = 19200; Int Xon = 1; Int Rts = 1; Int Version = 5; static char InputStr[80]; char OutputStr[4200] = ""; char newBuff[1001] = ""; Handle bufferHandle; static Boolean portClosed; /*********************************************************************** * * FUNCTION: StartApplication * * DESCRIPTION: This routine sets up the initial state of the application. * * PARAMETERS: None. * * RETURNED: Nothing. * ***********************************************************************/ static Err StartApplication(void) { FormPtr frm; ControlPtr closePtr; ControlPtr openPtr; ControlPtr sendPtr; FieldPtr opPtr; Err error; //Try to open the serial port... error = SysLibFind("Serial Library", &SerialRef); if (error) ErrDisplay("Error trying to load the serial library"); // Initialize and draw the main form. frm = FrmInitForm(mainForm); FrmSetActiveForm(frm); closePtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainCloseButton)))); CtlSetEnabled(closePtr, false); sendPtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainSendButton)))); CtlSetEnabled(sendPtr, false); openPtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOpenButton)))); CtlSetEnabled(openPtr, true); FrmDrawForm(frm); SetCurrentMenu(mainMenu); // P2. set the current menu to the main menu bufferHandle = MemHandleNew(10); portClosed = true; opPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOPField)))); FldSetTextPtr(opPtr, "Welcome to SimpleTerm - V0.5\rConnect the Pilot to a modem via the cradle (with NullModem) or cable, tap 'Online' to connect. Enter AT commands to dial the modem - tap \'Send\' to transmit data. The checkbox toggles whether a Return is sent. To send an Escape type \'esc\', to send a control character (eg.x) type \'ctlx\'\r Have fun... isb@pobox.com"); FldRecalculateField(opPtr, true); if (PrefGetAppPreferences('Seri', 1, &prefs, sizeof(SimplePreferenceType)) != NULL) { Baud = prefs.baud; Parity = prefs.parity; Rts = prefs.rts; Xon = prefs.xon; Bits = prefs.bits; } CurrentDB = 0; return 0; } static void StopApplication (void) { //ErrDisplay("Stop App called!"); if (!portClosed) { SerClose(SerialRef); } if ( CurrentDB !=0) CloseDB(); } /*********************************************************************** * * FUNCTION: SetCurrentMenu * * DESCRIPTION: P2. This routine loads the specified menu resource and makes * it the current menu. * * PARAMETERS: rscID - resource id of the new menu * * RETURNED: nothing * ***********************************************************************/ static void SetCurrentMenu(Word rscID) { // Dispose of an existing current menu. if (CurrentMenu) MenuDispose(CurrentMenu); // Set the current menu and remember it. CurrentMenu = MenuInit(rscID); } static Boolean RxData() { FormPtr frm; FieldPtr opPtr; ULong numBytes = 0; CharPtr buffer; Err error; int i, attempt; int lineCnt = 0; Boolean success; Handle textHandle; if (portClosed) return false; // Get the text from the send box... frm = FrmGetFormPtr(mainForm); opPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOPField)))); error = SerReceiveCheck(SerialRef, &numBytes); if (error) { SerClearErr(SerialRef); //ErrNonFatalDisplayIf(true, "Could not read the number of bytes in the receive queue"); StrCat(OutputStr, "Error reading number of bytes"); FldSetTextPtr(opPtr, OutputStr); FldRecalculateField(opPtr, true); FldScrollField(opPtr, lineCnt+100, down); return false; } else if (numBytes <= 0) return false; if (numBytes > 1000) numBytes = 1000; MemHandleResize(bufferHandle, numBytes+10); // Lock down the handle and get a pointer to the memory chunk. buffer = MemHandleLock(bufferHandle); attempt = 0; success = false; StrCopy(buffer, ""); error = SerReceive(SerialRef, buffer, numBytes, -1); if (error) //failed to get the data { //What's the error? if (error == serErrTimeOut) { StrCopy(buffer, "timeout"); } else if (error == serErrLineErr) { Boolean x; Boolean y; Word err; // The next line causes the Mac linker to fail, but works // with the 'real' linker err = SerGetStatus(SerialRef, &x, &y); if (err==serLineErrorParity) { StrCopy(buffer, "parity"); } else if (err==serLineErrorHWOverrun) { StrCopy(buffer, "HW overrun"); } else if (err==serLineErrorFraming) { StrCopy(buffer, "framing"); } else if (err==serLineErrorBreak) { StrCopy(buffer, "break"); } else if (err==serLineErrorHShake) { StrCopy(buffer, "handshake"); } else if (err==serLineErrorSWOverrun) { StrCopy(buffer, "SW overrun"); } } SerClearErr(SerialRef); } buffer[numBytes] = '\0'; for (i=0; i= 4000) { StrCopy(OutputStr, ""); // A bit crap, as it just blasts the array away. FldSetScrollPosition(opPtr, 0); } //Set the OPText field to show the buffer StrCat(OutputStr, buffer); FldSetTextPtr(opPtr, OutputStr); FldRecalculateField(opPtr, true); FldScrollField(opPtr, lineCnt+100, down); if ( CurrentDB != 0) WriteDB( buffer, strlen(buffer) ); // Unlock the new memory chunk. MemHandleUnlock(bufferHandle); return true; } void SetSerialSettings() { Err error; SerialSettings.baudRate = Baud; SerialSettings.flags = 0; SerialSettings.ctsTimeout = serDefaultCTSTimeout; if (Xon == 1) SerialSettings.flags = serSettingsFlagXonXoffM; if (Bits == 7) { SerialSettings.flags = serSettingsFlagStopBits1 | serSettingsFlagBitsPerChar7; } else { SerialSettings.flags = (SerialSettings.flags) | serSettingsFlagStopBits1 | serSettingsFlagBitsPerChar8; } if (Rts == 1) SerialSettings.flags = (SerialSettings.flags) | serSettingsFlagCTSAutoM | serSettingsFlagRTSAutoM; if (Parity == 1) { SerialSettings.flags = (SerialSettings.flags) | serSettingsFlagParityOnM; } else if (Parity == 2) { SerialSettings.flags = (SerialSettings.flags) | serSettingsFlagParityOnM | serSettingsFlagParityEvenM; } error = SerSetSettings(SerialRef, &SerialSettings); if (error) { SerClearErr(SerialRef); ErrDisplay("Error when setting serial port values"); } prefs.baud = Baud; prefs.rts = Rts; prefs.xon = Xon; prefs.bits = Bits; prefs.parity = Parity; prefs.version = Version; PrefSetAppPreferences('Seri', 1, &prefs, sizeof(SimplePreferenceType)); } /*********************************************************************** * * FUNCTION: MainFormHandleEvent * * DESCRIPTION: Handles processing of events for the ÒmainÓ form. * * PARAMETERS: event - the most recent event. * * RETURNED: True if the event is handled, false otherwise. * ***********************************************************************/ static Boolean MainFormHandleEvent(EventPtr event) { Boolean handled = false; Err error; if (event->eType == ctlSelectEvent) { // P3. If the new button is pressed, go to the edit form. if (event->data.ctlEnter.controlID == mainOpenButton) { FormPtr frm; ControlPtr closePtr; ControlPtr openPtr; ControlPtr sendPtr; if (!portClosed) return false; // Port is already open! error = SerOpen(SerialRef, 0, Baud); // Best do something if there's an error! if (error) { ErrNonFatalDisplayIf( (error == serErrAlreadyOpen), "Another application is using the serial port"); ErrNonFatalDisplayIf( (error == memErrNotEnoughSpace), "Not enough memory to open the serial port"); ErrNonFatalDisplayIf( (error == serErrBadParam), "The serial port could not be opened"); return true; } SetSerialSettings(); //Set the open button not usable and close and send usable frm = FrmGetFormPtr(mainForm); closePtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainCloseButton)))); CtlSetEnabled(closePtr, true); sendPtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainSendButton)))); CtlSetEnabled(sendPtr, true); openPtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOpenButton)))); CtlSetEnabled(openPtr, false); portClosed = false; CreateLogDB("SimpleTerm-log"); handled = true; } else if (event->data.ctlEnter.controlID == mainCloseButton) { FormPtr frm; ControlPtr closePtr; ControlPtr openPtr; ControlPtr sendPtr; if (portClosed) return false; CloseDB(); error = SerClose(SerialRef); if (error) { ErrNonFatalDisplayIf(true, "The serial port could not be closed"); return true; } frm = FrmGetFormPtr(mainForm); closePtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainCloseButton)))); CtlSetEnabled(closePtr, false); sendPtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainSendButton)))); CtlSetEnabled(sendPtr, false); openPtr = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOpenButton)))); CtlSetEnabled(openPtr, true); portClosed = true; handled = true; } else if (event->data.ctlEnter.controlID == mainSendButton) { FormPtr frm; FieldPtr ipPtr; ControlPtr ctl; if (portClosed) return false; // Get the text from the send box... frm = FrmGetFormPtr(mainForm); ipPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainIPField)))); if (FldGetTextPtr(ipPtr) != NULL) StrCopy(InputStr, FldGetTextPtr(ipPtr)); else return false; if (!StrCaselessCompare("esc", InputStr)) { //Send an escape character //Copy char(27) to InputStr StrCopy(InputStr, " "); InputStr[0] = (char)27; } else if (StrLen(InputStr)==4) //It could be ctlx - need to check the first three chars { //Do a check //If the first bit matches, then subtract 96 to make it a CTRL-x //Be wary that this is case sensitive! char temp[5] = ""; StrCopy(temp, InputStr); temp[3] = '\0'; if (!StrCaselessCompare("ctl", temp)) { //We're in business! StrToLower(temp, InputStr); StrCopy(InputStr, " "); InputStr[0] = (char)((Word)temp[3] - 96); } //Not ctl - never mind! } error = SerSend(SerialRef, InputStr, StrLen(InputStr)); ErrNonFatalDisplayIf( (error!=0), "Handshaking timed out when trying to send data (use CTS/RTS)"); if (error) SerClearErr(SerialRef); //Lets see if the user wants a CR appended... ctl = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainCRBox)))); if (CtlGetValue (ctl)) { error = SerSend(SerialRef, "\n", StrLen("\n")); ErrNonFatalDisplayIf( (error!=0), "Handshaking timed out when trying to send CR character"); } //Clear the field if (!error) FldDelete(ipPtr, 0, FldGetTextLength(ipPtr)); //Just pause until the send buffer clears... SerSendWait(SerialRef, -1); handled = true; RxData(); //Check for anything received } else if (event->data.ctlEnter.controlID == mainClearButton) { //Clear all the boxes FormPtr frm; FieldPtr opPtr; frm = FrmGetFormPtr(mainForm); opPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOPField)))); StrCopy(OutputStr, ""); // A bit crap, as it just blasts the array away. FldSetTextPtr(opPtr, OutputStr); FldDrawField(opPtr); FldSetScrollPosition(opPtr, 0); handled = true; } } else if (event->eType == nilEvent) { while (RxData()); handled = true; } else if (event->eType == keyDownEvent) { // Scroll up key presed? if (event->data.keyDown.chr == pageUpChr) { FormPtr frm; FieldPtr opPtr; // Get the text from the send box... frm = FrmGetFormPtr(mainForm); opPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOPField)))); FldScrollField( opPtr, 1, up); handled = true; } // Scroll down key presed? else if (event->data.keyDown.chr == pageDownChr) { FormPtr frm; FieldPtr opPtr; // Get the text from the send box... frm = FrmGetFormPtr(mainForm); opPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOPField)))); FldScrollField( opPtr, 1, down); handled = true; } else if (event->data.keyDown.chr != 0) { FormPtr frm; FieldPtr ipPtr; // Get the text from the send box... frm = FrmGetFormPtr(mainForm); ipPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainIPField)))); if (GetFocusObjectPtr () != ipPtr) { // A cool idea from yamada@mm.rd.nttdata.co.jp (YAMADA Tatsushi) StrCopy(InputStr, " "); InputStr[0] = event->data.keyDown.chr; if ( event->data.keyDown.chr == '\r') InputStr[0] = '\n'; InputStr[1] = 0; error = SerSend(SerialRef, InputStr, StrLen(InputStr)); ErrNonFatalDisplayIf( (error!=0), "Handshaking timed out when trying to send data (use CTS/RTS)"); //Just pause until the send buffer clears... SerSendWait(SerialRef, -1); handled = true; RxData(); } } } else if (event->eType == menuEvent) // P2. process menu events for this form { FormPtr frm; int i; ListPtr listP; // A menu item was selected. // The ÒprefsÓ being the only menu item, display the info form. // First clear the menu status from the display. if (event->data.menu.itemID == settingsCmd) { ControlPtr ctl; MenuEraseStatus(CurrentMenu); // Load the info form, then display it. frm = FrmInitForm(setForm); //FrmDoDialog(frm); FrmDrawForm(frm); FrmSetActiveForm(frm); ctl = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, setXonBox)))); if (Xon == 1) CtlSetValue (ctl, 1); else CtlSetValue (ctl, 0); ctl = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, setRtsBox)))); if (Rts == 1) CtlSetValue (ctl, 1); else CtlSetValue (ctl, 0); if (Bits == 7) FrmSetControlGroupSelection(frm, 1, set7); else FrmSetControlGroupSelection(frm, 1, set8); if (Parity == 1) FrmSetControlGroupSelection(frm, 2, setO); else if (Parity == 2) FrmSetControlGroupSelection(frm, 2, setE); else FrmSetControlGroupSelection(frm, 2, setN); if (Baud == 1200) FrmSetControlGroupSelection(frm, 3, setBaud1); else if (Baud == 2400) FrmSetControlGroupSelection(frm, 3, setBaud2); else if (Baud == 4800) FrmSetControlGroupSelection(frm, 3, setBaud4); else if (Baud == 9600) FrmSetControlGroupSelection(frm, 3, setBaud9); else FrmSetControlGroupSelection(frm, 3, setBaud19); } else { //This is one from the edit menu... if (event->data.menu.itemID == copyCmd) { FormPtr frm; FieldPtr opPtr; Word len; // Copy the output text to the clipboard // The clipboard is only 1k big :^( //Lets go for the top of the screen + 1000 chars frm = FrmGetFormPtr(mainForm); opPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainOPField)))); len = FldGetTextLength(opPtr); if (len>1000) len = 1000; FldSetSelection(opPtr, 0, len); FldCopy(opPtr); FldSetSelection(opPtr, 0, 0); handled = true; } else if (event->data.menu.itemID == pasteCmd) { FormPtr frm; FieldPtr ipPtr; // Copy the output text to the clipboard frm = FrmGetFormPtr(mainForm); ipPtr = (FieldPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, mainIPField)))); FldPaste(ipPtr); handled = true; } else if (event->data.menu.itemID == keybdCmd) { SysKeyboardDialog(); handled = true; } MenuEraseStatus(CurrentMenu); } handled = true; } return handled; } static Boolean SetFormHandleEvent(EventPtr event) { Boolean handled = false; Err error; FormPtr frm; //ErrDisplay("Set form Handler came thru top"); if (event->eType == ctlSelectEvent) { switch (event->data.ctlSelect.controlID) { case setOK: { //OptionsApply (); Byte sel; Word ctl; ListPtr listP; ControlPtr chk; int i=0; frm = FrmGetFormPtr(setForm); chk = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, setXonBox)))); if (CtlGetValue (chk)) Xon = 1; else Xon = 0; chk = (ControlPtr)(FrmGetObjectPtr(frm, (FrmGetObjectIndex(frm, setRtsBox)))); if (CtlGetValue (chk)) Rts = 1; else Rts = 0; sel = FrmGetControlGroupSelection(frm, 1); ctl = FrmGetObjectId (frm, sel); if (ctl == set7) { //ErrDisplay("7 bits set"); Bits = 7; } else Bits = 8; sel = FrmGetControlGroupSelection(frm, 2); if (sel == -1) ErrDisplay("No parity selected"); ctl = FrmGetObjectId (frm, sel); if (ctl == setO) { Parity = 1; } else if (ctl == setE) { Parity = 2; } else Parity = 0; sel = FrmGetControlGroupSelection(frm, 3); ctl = FrmGetObjectId (frm, sel); if (ctl == setBaud1) Baud = 1200; else if (ctl == setBaud2) Baud = 2400; else if (ctl == setBaud4) Baud = 4800; else if (ctl == setBaud9) Baud = 9600; else Baud = 19200; SetSerialSettings(); FrmReturnToForm (mainForm); FrmUpdateForm (mainForm, frmRedrawUpdateCode); handled = true; break; } case setCancel: FrmReturnToForm (mainForm); handled = true; break; } } return handled; } /*********************************************************************** * * FUNCTION: EventLoop * * DESCRIPTION: A simple loop that obtains events from the Event * Manager and passes them on to various applications and * system event handlers before passing them on to * FrmHandleEvent for default processing. * * PARAMETERS: None. * * RETURNED: Nothing. * ***********************************************************************/ static void EventLoop(void) { EventType event; Word error; do { // Get the next available event. if (portClosed) //ie. we are not listening for serial events EvtGetEvent(&event, evtWaitForever); else // We are so need to react quickly... EvtGetEvent(&event, 1); // Give the system a chance to handle the event. if (! SysHandleEvent (&event)) // P2. Give the menu bar a chance to update and handle the event. if (! MenuHandleEvent(CurrentMenu, &event, &error)) // Give the application a chance to handle the event. if (! MainFormHandleEvent(&event)) if (! SetFormHandleEvent(&event)) // Let the form object provide default handling of the event. FrmHandleEvent(FrmGetActiveForm(), &event); } while (event.eType != appStopEvent); // ** SPECIAL NOTE ** // In order for the Emulator to exit // cleanly when the File|Quit menu option is // selected, the running application // must exit. The emulator will generate an // ÒappStopEventÓ when Quit is selected. } static FieldPtr GetFocusObjectPtr (void) { FormPtr frm; Word focus; FormObjectKind objType; frm = FrmGetActiveForm (); focus = FrmGetFocus (frm); if (focus == noFocus) return (NULL); objType = FrmGetObjectType (frm, focus); if (objType == frmFieldObj) return (FrmGetObjectPtr (frm, focus)); else if (objType == frmTableObj) return (TblGetCurrentField (FrmGetObjectPtr (frm, focus))); return (NULL); } //Again some great code given by yamada@mm.rd.nttdata.co.jp (YAMADA Tatsushi) static int dbID; static long total_length; static Word current_record; static int current_pos; static CharPtr current_record_ptr; static Handle current_record_handle; Boolean CreateLogDB(CharPtr dbname) { LocalID dbID; Handle h; Record0Type rec0; VoidPtr p; Err error; Word recnum; CurrentDB = 0; return true; //Not working yet - will log in 'corrupt' Doc format at present dbID = DmFindDatabase( 0, dbname); if (dbID) //Delete and replace the database DmDeleteDatabase(0, dbID); error = DmCreateDatabase(0, dbname, JDocDBCreator, JDocDBType, false); if (error) return false; dbID = DmFindDatabase ( 0,dbname); CurrentDB = DmOpenDatabase(0, dbID, dmModeReadWrite); //Make header in record 0 rec0.compression_type = 1; // no compression rec0.spare = 0x5555; rec0.num_records = 1; rec0.story_length = total_length = 0; rec0.reclen = 0x1000; recnum = 0; h = DmNewRecord( CurrentDB, &recnum, sizeof( Record0Type)); p = (Record0Type *)MemHandleLock(h); DmWrite( p, 0L, &rec0, sizeof( rec0)); MemHandleUnlock( h); DmReleaseRecord( CurrentDB, recnum, true); // Make first record for log current_record = 1; current_record_handle = DmNewRecord( CurrentDB, ¤t_record, 0x1000); current_record_ptr = (CharPtr)MemHandleLock(current_record_handle); current_pos=0; //WinDrawChars("Log opened",10, 100,148); return true; } void CloseDB(void){ Record0Type rec0; Word recnum; Handle h; VoidPtr p; // compact and release last record if ( CurrentDB == 0 ) return; MemHandleUnlock( current_record_handle); MemHandleResize( current_record_handle, current_pos); DmReleaseRecord( CurrentDB, current_record, true); rec0.compression_type = 1; // no compression rec0.spare = 0x5555; rec0.num_records = current_record; rec0.story_length = total_length; rec0.reclen = 0x1000; recnum = 0; h = DmGetRecord( CurrentDB, recnum); p = (Record0Type *)MemHandleLock(h); DmWrite( p, 0L, &rec0, sizeof( rec0)); MemHandleUnlock( h); DmReleaseRecord( CurrentDB, recnum, true); DmCloseDatabase(CurrentDB); // WinDrawChars("Log closed",10, 100,148); CurrentDB = 0; } void WriteDB( CharPtr c, int len) { int temp_len; int tmp; char buf[16]; Record0Type rec0; Word recnum; Handle h; VoidPtr p; if ( CurrentDB == 0 ) return; /* buf[0] = '0'+ current_record / 10; buf[1] = '0'+ current_record % 10; buf[2] = ':'; tmp = current_pos; buf[3] = '0'+ tmp / 1000; tmp = tmp % 1000; buf[4] = '0'+ tmp / 100; tmp = tmp % 100; buf[5] = '0'+ tmp / 10; tmp = tmp % 10; buf[6] = '0'+ tmp ; WinDrawChars( buf, 7, 100,124); */ while (len){ if ( current_pos + len <= 0x1000){ temp_len = len; } else { temp_len = 0x1000-current_pos; } DmWrite( current_record_ptr , current_pos, c , temp_len); current_pos += temp_len; if ( current_pos >= 0x1000){ // release current record; MemHandleUnlock( current_record_handle); DmReleaseRecord( CurrentDB, current_record, true); // make new record current_record++; current_record_handle = DmNewRecord( CurrentDB, ¤t_record, 0x1000); current_record_ptr = (CharPtr)MemHandleLock(current_record_handle); current_pos=0; rec0.compression_type = 1; // no compression rec0.spare = 0x5555; rec0.num_records = current_record; rec0.story_length = total_length; rec0.reclen = 0x1000; recnum = 0; h = DmGetRecord( CurrentDB, recnum); p = (Record0Type *)MemHandleLock(h); DmWrite( p, 0L, &rec0, sizeof( rec0)); MemHandleUnlock( h); DmReleaseRecord( CurrentDB, recnum, true); } total_length += temp_len; len -= temp_len; c += temp_len; /* buf[0] = '0'+ current_record / 10; buf[1] = '0'+ current_record % 10; buf[2] = ':'; tmp = current_pos; buf[3] = '0'+ tmp / 1000; tmp = tmp % 1000; buf[4] = '0'+ tmp / 100; tmp = tmp % 100; buf[5] = '0'+ tmp / 10; tmp = tmp % 10; buf[6] = '0'+ tmp ; //WinDrawChars( buf, 7, 100,136); */ } } /*********************************************************************** * * FUNCTION: PilotMain * * DESCRIPTION: This function is the equivalent of a main() function * in standard ÒCÓ. It is called by the Emulator to begin * execution of this application. * * PARAMETERS: cmd - command specifying how to launch the application. * cmdPBP - parameter block for the command. * launchFlags - flags used to configure the launch. * * RETURNED: Any applicable error code. * ***********************************************************************/ DWord PilotMain(Word cmd, Ptr cmdPBP, Word launchFlags) { Err error; if (cmd == sysAppLaunchCmdNormalLaunch) { // Set up initial form. error = StartApplication(); if (error) return error; // Start up the event loop. EventLoop(); StopApplication (); } return(0); }