TweetFollow Us on Twitter

Break-out Box
Volume Number:7
Issue Number:12
Column Tag:C Workshop

Go With the Flow

By Byron Miller, Minneapolis, MN

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

An Alternative to Expensive Protocol Analyzers

I had a problem that needed a solution. The device I was debugging was having trouble Kermiting files between it and the host. I first used a breakout box to check hardware handshaking (since the breakout box is specifically for testing the physical protocol layer, it is of no use for testing the stream or network protocol layer). As it turned out the handshaking lines behaved correctly. “Now what?”, I thought. I needed to look at the data coming over the line. My first thought was to use a file capture program and look at the data stream. I soon abandoned this idea because a file capture program displays the characters in an ASCII format and since control characters are used to control data flow, they do not have a corresponding printable character. What I really needed is a protocol analyzer. However protocol analyzers are expensive, and I could not justify the cost. So my other alternative is to develop my own. After weighing the pros and cons I decided it was in my own best interest to develop my own analyzer. The result of my effort is the Macintosh Break-Out Box (MBOB) protocol analyzer.

Mac Break Out Box Specification

Supports:
 xon, xoff, parity, overrun, framing errors, break detection.
 Single filter of operator choosing (editable text dialog).
 Clipboard access via resizable window.
 Baud rate and parity selection via an editable text dialog.

Menu Layout:

apple symbol | File | Edit | Options

about | Monito | Copy | Baud

| --------- | Clear | Parity

| Quit | Clipboard | Filter

| | | Stop Bits

Listing 1. Specification of MBOB's functionality along with the menu layout.

MBOB is an alternative to expensive logical analyzers. Often, vendors develop propriety RS232 protocols. Vendors may not have the need or resources to justify the expense of a protocol analyzer, and MBOB is the tool for filling the void. MBOB provides basic functionality, in that it filters for a single character which is user defined, and baud, parity and stop bits are selectable. It uses the modem port of the Mac and is written in Think C and tested on the Mac Plus through the II lines.

In this article I shall go through the software design process for developing MBOB. First I’ll generate a design specification, followed by a description of the functional sections, and then I’ll wrap it up with suggestions on how to improve MBOB.

Figure 2.

Background

Before I begin discussing how MBOB is implemented I would like to talk briefly about the methodology to produce it. I used a variation of the Yourdon methodology to produce this application. In a nutshell, the Yourdon design methodology is a formalized process and notation for developing quality software; quality software is defined as code which is maintainable, reliable, and thoroughly documented. Normally, this methodology is broken down into two phases; much like the moon’s only less! First is the analysis, followed by the design phase.

Usually, the analysis phase starts with a problem definition. During the analysis stage, designers look for the best solution to the problem. Furthermore, they also decide if they are focusing correctly on the right problem. In other words, problem definition starts with an analysis of a proposed solution. If designers discover that there is a problem with the solution, another is picked and the process is repeated until they are satisfied with the results of the analysis. Once problem definition is satisfied, the design phase kicks in.

The Design Phase consists of a statement of purpose, events list, data flow diagram (DFD), process specification, user interface considerations, and pseudo code. In the design phase each elements making up the design phase describes the system from different perspective. For instance, the statement of purpose and the process specification are often combined to describe in English what problem it satisfies, and how the system will interact. The event list defines what events the system recognizes and responds to. The user interface describes what the shell of the system will look like. DFD’s are used to represents how the system works from a data point of view. Finally, the designer distills each perspective into pseudo code. Once in pseudo code, the system is ready for mechanical process of language specific coding.

defaultSettings = 
 [baudSetting + paritySetting + stopBits + filterChar]

SelectionEvent = 
 [(menuSelection) + (command key equivalent for menu selection)]

WindowPtr = 
 [ptr to record that contains current window’s graphical attributes]

StatusRecord = 
 [serial status record + filter character count]

Figure 3.

The data dictionary for the top level structure chart. Data dictionary notation is as follows: An equal (“=”), means “is composed of”, plus (“+”) stands for logical and. Left and right parentheses (“()”) mean optional, while curly brackets and square brackets stand for iteration and select one respectively. Comments are denoted by double asterisks (“**”), and the @ sign means that what follows is part of an ID for a data store.

Analysis

Analysis for this problem is straight forward. The problem is understood and thus easily defined; a lot of times this is the most difficult part. To briefly restate the problem: There is no way to look at characters coming over the serial line on the fly. The solution is to monitor these characters. Part of the analysis is looking at existing products to see if they satisfy the problem. Additionally, sometimes cost analysis is necessary to decide whether to buy or produce your own application. In this case, the decision was made to produce an application. This was a result of analysis of required functionality versus cost of an existing protocol analyzer.

Design

MBOB’s process specification is similar to the one used by Apple computer in object oriented design. When this approach is used, several parts of the traditional methodology are combined. For instance, the statement of purpose, event list, and user interface are combined into a single document see figure 1. Under this approach, DFD’s are omitted from the design since they do not convey any new information. Next, the specification is broken up into areas of functionality or modules. Each function module is then organized, based on the event list and the user interface considerations to form a structure chart. Finally, individual modules within the structure chart are pseudo coded.

Implementation

Figures 2 and 3 shows a top level structure chart and its associated data dictionary of the core functions. The main loop is a typical Macintosh application shell which is event driven. It responds to events such as keyboard, rodent (mouse) input, and the serial ports. Main loop fetches events from the event queue and sends the event to the correct function; much the same as an object in the object oriented paradigm sends a message to a corresponding method. Initializing the serial port and loading default settings is handled by the function Init Serial. It is called from main loop, before it actually begins fetching events from the queue. Similarly, function shut down application is called from main loop just before it exits. Moreover, shut down application flushes the serial port’s buffer and frees the port, making it available for use by other applications. Handle serial selection is not a real function, but more of a functional block composed of several functions. It handles events from the keyboard and rodent that have to do with initiating some activity with the serial port. For instance, either a menu selection or an equivalent command sequence activates the change settings function. Change settings is used change port parameters like baud and parity. However, before it attempts to change parameters, it first calls reset ports. Function doSerial performs the job of monitoring the serial stream and display status keeps track of correctly updating the display window.

Once the structure charts are adequately defined, they are translated and fleshed out into pseudo code and then into source code. Often times pseudo code may look a lot like real code since enough information is available from other portions of the design process. Listing MBOB functs.c presents code corresponding to the structure charts.

Operation

Since most everyone is already familiar with the compile and debug stages of software development, it is omitted and instead I’ll proceed to operating the application. Operation is easy for anyone already familiar with a window based environment such as the Mac or Microsoft’s windows. Double clicking on the application’s icon invokes it. Once started, the file, edit and option menu bars are displayed. Choosing the monitor menu under the file menu bar begins parsing of the serial data stream. Terminating the application is as easy as choosing the quit menu which is also located under the file menu bar. And as you may have already guessed, the option menu bar controls changing serial port characteristics and the filter selection. In a typical session, the application is invoked, and the port characteristics are set. Next, the filter character is selected, followed by monitoring the data stream.

That’s a Wrap People

Currently, MBOB is adequate for my needs. However, as is the case in the software life cycle model, useful software should be evolved! With that in mind, I submit the following suggestions for evolving this application. First, more filters! One is OK, but it is a bit of a pain to debug protocols where more than one character is sought. Or, how about a counter to keep track of the number of filter characters encountered? Finally, how about adding file access. This feature gives the developer the option to post process the stream.

Most problems have solutions when attacked from them right angle. However, a solution is not always enough. Often a plan is needed, so that the problem is not attacked from the left. New analysis and design methodologies present software developers with the techniques not only to solve the problem, but to do it in a manner which produces quality software.

References

Mark, David.; and Reed, Cartwright. Macintosh Programming Primer, volume one. New York: Addison-Wesley, 1989.

Wilkerson, Brian. “How to Develop an Object Based Application.” Develop magazine, April, 1990.

Lecture notes from “Structured Analysis and Design for real time systems.” Edition 4.0. Yourdon, Inc 1501 Broadway, NY, NY 10036.

Listing: MBOB.h

#define FALSE    0
#define TRUE1

#define BASE_RES_ID400
#define NIL 0L
#define MOVE_TO_FRONT-1L
#define REMOVE_ALL_EVENTS 0

#define SLEEP    0L
#define NIL_MOUSE_REGION  0L
#define WNE_TRAP_NUM 0x60
#define UNIMPL_TRAP_NUM   0x9f

#define BANNER_OFFSET96
#define HORIZONTAL_OFFSET 0
#define INITIAL_ROW24
#define LEFT_MARGIN10
#define ROW_HEIGHT 15
#define SCROLL_BAR_PIXELS 16
#define START_ROW0

#define TEXT_FONT_SIZE    10
 /* in pixels */
#define GRAD_FONT_SIZE    6

#define APPLE_MENU_IDBASE_RES_ID
#define FILE_MENU_ID BASE_RES_ID+1
#define EDIT_MENU_ID BASE_RES_ID+2
#define OPTION_MENU_ID    BASE_RES_ID+3

#define OPEN_ITEM1
#define TRANSFER_ITEM3
#define LAUNCH_ITEM4
#define QUIT_ITEM6
#define ABOUT_ITEM 1
#define COPY_ITEM4
#define PASTE_ITEM 5
#define CLEAR_ITEM 6
#define CLIPBOARD_ITEM    7
#define BAUD_ITEM1
#define PARITY_ITEM2
#define STOP_ITEM3
#define FILTER_ITEM4

#define ABOUT_ALERT400
#define LAUNCH_ALERT 401
#define ENOUGH_ALERT 403
#define ERR_ALERT404
#define CLIPBOARD_ALERT   406
#define EMPTY_ALERT407

#define DRAG_THRESHOLD    30

#define OK_BUTTON1
 /* dialog list items */
#define CANCEL_BUTTON2
#define FIRST_RADIO3
#define SECOND_RADIO 4
#define THIRD_RADIO5
#define FOURTH_RADIO 6
#define FIFTH_RADIO7
#define SIXTH_RADIO8
#define FIRST_FILTER 3

#define ONTRUE
#define OFF FALSE

#define FLOAT_CONST4
 /* floating pt numbers take up 4 bytes */

#define WATCH_ICON 4

#define WINDOW_HOME_LEFT  45
 /* global coords */
#define WINDOW_HOME_RIGHT 45
#define NEW_WINDOW_OFFSET 20
#define LEAVE_WHERE_IT_IS FALSE

typedef struct
{
 StringPtrpfName;
 /* ptr to the name of launchee */
 short intparam;
 char   LC[2];
 /* extended params: */
 long int extBlockLen;  /* number of bytes in extension == 6 */
 short intfFlags;/* finder file info flags */
 long int launchFlags;    /* bits 30, & 31 equal 1 for sublaunch */
}  LaunchStruct, *pLaunchStruct;

typedef struct
{
 int    baud;    /* 300 <= baud <= 57600 */
 int    parity;  /* 0 <= parity <= 2 {0 = none, 1 = even, 2 = odd} */
 int    stopBits;/* 0 <= stopBits <=1 {0 = 1 stop, 1 = 2 stop} */
 int    filter;  /* 0 <= filter <= 255 {ascii range} */
} dlogSettings, *dlogSettingsPtr;
Listing:  Dlogs.c

#include <QuickDraw.h>
#include <MacTypes.h>
#include <FontMgr.h>
#include <WindowMgr.h>
#include <MenuMgr.h>
#include <TextEdit.h>
#include <DialogMgr.h>
#include <EventMgr.h>
#include <DeskMgr.h>
#include <StdfilePkg.h>
#include <FileMgr.h>
#include <ToolboxUtil.h>
#include <ControlMgr.h>
#include <SerialDvr.h>

#include “MBOB.h”

extern  gEOL[];

/*
 Created by :  Byro
 Date   : 05/10/90
 Modified : 05/17/90
*/

HndlBaudDialog(settings)
 dlogSettingsPtr settings;
 
{
 int    dialDone = FALSE, itemHit, itemType;
 Rect   itemRect;
 Handle itemHandle;
 DialogPtrBaudDialog;
 dlogSettings  oldSettings; /* used to restore in case of cancel */
 
 
 oldSettings = *settings;
 BaudDialog = GetNewDialog(BASE_RES_ID, NIL, MOVE_TO_FRONT);
 if (BaudDialog == NIL)
 {
 StopAlert(ENOUGH_ALERT, NIL);
 return(TRUE);
 }

 SelectWindow(BaudDialog);
 SetBaud(settings, BaudDialog);  /* load current settings */
 ShowWindow(BaudDialog);  /* initially invisible */
 
 while (dialDone == FALSE)
 {
 ModalDialog(NIL, &itemHit);
 switch(itemHit)
 {
 case OK_BUTTON :
 HideWindow(BaudDialog);
 DisposDialog(BaudDialog);
 dialDone = TRUE;
 break;
 case CANCEL_BUTTON :
 HideWindow(BaudDialog);
 DisposDialog(BaudDialog);
 *settings = oldSettings; /* load old values */
 dialDone = TRUE;
 return(CANCEL_BUTTON);
 break;
 case FIRST_RADIO :
 
 /* turn on 300 baud radio dial */
 
 GetDItem(BaudDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(BaudDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 settings->baud = baud300;
 
 break;
 case SECOND_RADIO :
 
 /* turn on 1200 baud radio dial */
 
 GetDItem(BaudDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);

 GetDItem(BaudDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 settings->baud = baud1200; 
 
 break;
 case THIRD_RADIO :
 
 /* turn on 4800 baud radio dial */
 
 GetDItem(BaudDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);

 GetDItem(BaudDialog, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 settings->baud = baud4800; 
 
 break;
 case FOURTH_RADIO :
 
 /* turn on 9600 baud radio dial */
 
 GetDItem(BaudDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(BaudDialog, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 settings->baud = baud9600; 
 
 break;
 case FIFTH_RADIO :
 
 /* turn on 19200 baud radio dial */
 
 GetDItem(BaudDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(BaudDialog, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 settings->baud = baud19200;
 
 break;
 case SIXTH_RADIO :
 
 /* turn on 57600 baud radio dial */
 
 GetDItem(BaudDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(BaudDialog, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(BaudDialog, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 settings->baud = baud57600;
 
 break;
 default :
 break;
 }
 }
 return(NIL);  /* all ok */
}

HndlParityDialog(settings)
 dlogSettingsPtr settings;
 
{
 int    dialDone = FALSE, itemHit, itemType;
 Rect   itemRect;
 Handle itemHandle;
 DialogPtrParityDialog;
 dlogSettings  oldSettings; /* used to restore in case of cancel */
 
 oldSettings = *settings;
 
 ParityDialog = GetNewDialog(BASE_RES_ID + 1, NIL, MOVE_TO_FRONT);
 if (ParityDialog == NIL)
 {
 StopAlert(ENOUGH_ALERT, NIL);
 return(TRUE);
 }
 
 SelectWindow(ParityDialog);
 SetParity(settings, ParityDialog);
 ShowWindow(ParityDialog);/* initially invisible */
 
 while (dialDone == FALSE)
 {
 ModalDialog(NIL, &itemHit);
 switch(itemHit)
 {
 case OK_BUTTON :
 HideWindow(ParityDialog);
 DisposDialog(ParityDialog);
 dialDone = TRUE;
 break;
 case CANCEL_BUTTON :
 HideWindow(ParityDialog);
 DisposDialog(ParityDialog);
 *settings = oldSettings; /* load old values */
 dialDone = TRUE;
 return(CANCEL_BUTTON);
 break;
 case FIRST_RADIO :
 
 /* turn on even parity radio dial */
 
 GetDItem(ParityDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(ParityDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(ParityDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 settings->parity = evenParity;
 
 break;
 case SECOND_RADIO :
 
 /* turn on no parity radio dial */
 
 GetDItem(ParityDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(ParityDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);

 GetDItem(ParityDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 settings->parity = noParity;
 
 break;
 case THIRD_RADIO :
 
 /* turn on odd parity radio dial */
 
 GetDItem(ParityDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(ParityDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(ParityDialog, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);

 settings->parity = oddParity;
 
 break;
 default :
 break;
 }
 }
 return(NIL);  /* all ok */
}

HndlStopBitsDialog(settings)
 dlogSettingsPtr settings;
 
{
 int    dialDone = FALSE, itemHit, itemType;
 Rect   itemRect;
 Handle itemHandle;
 DialogPtrStopBitsDialog;
 dlogSettings  oldSettings; /* used to restore in case of cancel */
 
 oldSettings = *settings;
 
 StopBitsDialog = GetNewDialog(BASE_RES_ID + 2, NIL, MOVE_TO_FRONT);
 if (StopBitsDialog == NIL)
 {
 StopAlert(ENOUGH_ALERT, NIL);
 return(TRUE);
 }
 
 SelectWindow(StopBitsDialog);
 SetStopBits(settings, StopBitsDialog);
 ShowWindow(StopBitsDialog);/* initially invisible */
 
 while (dialDone == FALSE)
 {
 ModalDialog(NIL, &itemHit);
 switch(itemHit)
 {
 case OK_BUTTON :
 HideWindow(StopBitsDialog);
 DisposDialog(StopBitsDialog);
 dialDone = TRUE;
 break;
 case CANCEL_BUTTON :
 HideWindow(StopBitsDialog);
 DisposDialog(StopBitsDialog);
 *settings = oldSettings; /* load old values */
 dialDone = TRUE;
 return(CANCEL_BUTTON);
 break;
 case FIRST_RADIO :
 
 /* turn on 1 stop bit radio dial */
 
 GetDItem(StopBitsDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(StopBitsDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 settings->stopBits = stop10;
 
 break;
 case SECOND_RADIO :
 
 /* turn on 2 stop bits radio dial */
 
 GetDItem(StopBitsDialog, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(StopBitsDialog, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);

 settings->stopBits = stop20;
 
 break;
 
 default :
 break;
 }
 }
 return(NIL);  /* all ok */
}

HndlFilterDialog(settings)
 dlogSettingsPtr settings;
 
{
 int    dialDone = FALSE, filterChar, itemHit, itemType;
 Rect   itemRect;
 Handle itemHandle;
 DialogPtrFilterDialog;
 Str255 CfilterString, filterString;
 
 settings->filter = 0;
 FilterDialog = GetNewDialog(BASE_RES_ID + 3, NIL, MOVE_TO_FRONT);
 if (FilterDialog == NIL)
 {
 StopAlert(ENOUGH_ALERT, NIL);
 return(TRUE);
 }
 
 SelectWindow(FilterDialog);
 ShowWindow(FilterDialog);/* initially invisible */
 
 while (dialDone == FALSE)
 {
 ModalDialog(NIL, &itemHit);
 switch(itemHit)
 {
 case OK_BUTTON :
 HideWindow(FilterDialog);
 DisposDialog(FilterDialog);
 
 /* be sure and check this for valid input */
 
 if (*filterString != *gEOL)
 {
 if (isItADigit(filterString) == TRUE)
 {
 
 /* string ok */
 
 P2Cstr(filterString, CfilterString);
 filterChar = atoi(CfilterString);
 
 /* range check */
 
 if (filterChar < 256)
 settings->filter = filterChar;
 else
 {
 ; /* display error dialog */
 }
 }
 else
 return(TRUE); /* err condition */
 }
 dialDone = TRUE;
 break;
 case CANCEL_BUTTON :
 HideWindow(FilterDialog);
 DisposDialog(FilterDialog);
 dialDone = TRUE;
 return(CANCEL_BUTTON);
 break;
 case FILTER_ITEM :
 
 /* get filter value from dialog */
 
 GetDItem(FilterDialog, FILTER_ITEM, &itemType,
 &itemHandle, &itemRect);
 GetIText(itemHandle, filterString);
 break;
 default :
 break;
 }
 }
 return(NIL);  /* all ok */
}

SetBaud(Settings, dlogPtr)
 dlogSettingsPtr Settings;
 DialogPtrdlogPtr;
 
/*
 sets radio buttons in baud rate dialog according to values in
 the settings structure.
*/

{
 int    itemHit, itemType;
 Rect   itemRect;
 Handle itemHandle;

 switch (Settings->baud)
 {
 case baud300 :
 
 /* turn on 300 baud radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 break;
 
 case baud1200 :
 
 /* turn on 1200 baud radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 break;
 
 case baud4800 :
 
 /* turn on 4800 baud radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);

 GetDItem(dlogPtr, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 break;
 
 case baud9600 :
 
 /* turn on 9600 baud radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(dlogPtr, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 break;
 
 case baud19200 :
 
 /* turn on 19200 baud radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(dlogPtr, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 break;
 
 case baud57600 :
 
 /* turn on 57600 baud radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, FOURTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, FIFTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SIXTH_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON); 
 break;
 
 default :
 break;
 }
}

SetParity(settings, dlogPtr)
 dlogSettingsPtr settings;
 DialogPtrdlogPtr;
 
/*
 Sets Parity defaults in input dialog.
*/

{
 int    itemHit, itemType;
 Rect   itemRect;
 Handle itemHandle;

 switch (settings->parity)
 {
 case evenParity :
 
 /* turn on even parity radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 break;
 
 case noParity :
 
 /* turn on no parity radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 break;
 
 case oddParity :
 
 /* turn on odd parity radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);

 GetDItem(dlogPtr, THIRD_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 break;
 
 default :
 break;
 }
}

SetStopBits(settings, dlogPtr)
 dlogSettingsPtr settings;
 DialogPtrdlogPtr;
 
/*
 Sets Stop Bit(s) defaults in input dialog.
*/

{
 int    itemHit, itemType;
 Rect   itemRect;
 Handle itemHandle;

 switch (settings->stopBits)
 {
 case stop10 :
 
 /* turn on 1 stop bit radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 break;
 
 case stop20 :
 
 /* turn on 2 stop bits radio dial */
 
 GetDItem(dlogPtr, FIRST_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, OFF);
 
 GetDItem(dlogPtr, SECOND_RADIO, &itemType, &itemHandle, &itemRect);
 SetCtlValue(itemHandle, ON);
 break;
 
 default :
 break;
 }
}

Continued in next frame
Volume Number:7
Issue Number:12
Column Tag:C Workshop

Go With the Flow (code)


Listing:  Utils.c

extern  gEOL[];
extern  gSP[];
extern  gTAB[];


C2Pstr(src, dst)
 unsigned char src[], dst[];

/* C 2 Pascal String converts a  C string into a pascal string */

{
 int  i = 0;
 unsigned char j;

 /* put length at start of destination string */

 j = (unsigned char) strlen(src);
 dst[0] = j;

 /* copy chars until delimiter encountered */

 while (src[i] != *gEOL)
 {
 dst[i + 1] = src[i];
 i++;
 }
}

i2a(n, s)
 int    n;
 char s[];
 
/*
 convert n to character string in array s.  Taken from pp.60 k & r.
*/

{
 int i, sign;
 
 if((sign = n) < 0)/* record sign */
 n = -n;/* make n positive */
 i = 0;
 
 /* generate digits in reverse order */
 
 do
 {
 s[i++] = n % 10 + ‘0’;   /* get next digit */
 } while ((n /= 10) > 0); /* delete it */
 
 if (sign < 0)
 s[i++] = ‘-’;
 s[i] = *gEOL;
 reverse(s);
}

reverse(s)
 char s[];
 
/*
 reverse string s in place
*/

{
 int c, i, j;
 
 for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
 {
 c = s[i];
 s[i] = s[j];
 s[j] = c;
 }
}

double a2f(s)
 char s[];
 
/* 
 convert a string s to double.  lifted from k & r pp. 69 
*/

{
 double val, power;
 int    i, sign;
 
 for (i = 0; s[i] == *gSP || s[i] == ‘\n’ || s[i] == *gTAB; i++)
 ; /* blow off white spaces */
 
 sign = 1;
 
 if (s[i] == ‘+’ || s[i] == ‘-’) /* sign */
 sign = (s[i++] == ‘+’) ? 1 : -1;
 for (val = 0; s[i] >= ‘0’ && s[i] <= ‘9’; i++)
 val = 10 * val + s[i] - ‘0’;
 if (s[i] == ‘.’)
 i++;
 for (power = 1; s[i] >= ‘0’ && s[i] <= ‘9’; i++)
 {
 val = 10 * val + s[i] - ‘0’;
 power *= 10;
 }
 return(sign * val / power);
}

P2Cstr(source, dest)

/* This function converts a Pascal string into a C string */

char  source[], dest[];
 
{
 char ch;
 int i, j;
 
 ch = source[0]; /* get string length; from 1st ele of pascal string 
*/
 j = (int) ch; /* convert to integer */
 
 
 for (i = 0; i < j; i++)
 dest[i] = source[i + 1];
 
 while (i < 256)
 {
 dest[i] = ‘\0’; /* tack on delimiter to end of string */
 i++;
 }
 
 return(j); /* ret it length */
 
}

pStrCpy(src, dst)
 char *src,
 *dst;
 
/* pascal string copy function */

{
 int  i,
 length;
 
 length = *src;
 
 for (i = 0; i <= length + 1; i++)
 {
 *dst = *src;
 src++; dst++;
 }
}

ZeroStruct(a, b)
 Ptr  a;/* ptr to structure */
 int  b;/* iteration index */

/*
 Zero Structure does just that with the two parameters passed to it. 
 The
  first, is the ptr to the structure and the second is the loop index.
*/

{
 int i;

 for(i = 0; i < b; i++)
 ((unsigned char *) a) [i] = 0;

}

a2i(s)
 char s[];
 
/*
 convert s to integer.  Taken from K & R pp. #58.
*/

{
 int  i, n, sign;
 
 for (i = 0; s[i] == ‘ ‘ || s[i] == ‘\n’ || s[i] == ‘\t’; i++)
 ; /* skip white spaces */
 
 sign = 1;
 if (s[i] == ‘+’ || s[i] ==’-’)  /* sign */
 sign = (s[i++] == ‘+’) ? 1 : -1;
 for (n = 0; s[i] >= ‘0’ && s[i] <= ‘9’; i++)
 n = 10 * n + s[i] - ‘0’;
 return(sign * n);
}

isItADigit(cPtr)
 char *cPtr;
 
/* 
 checks pascal strings for non-numeric characters and returns true 
 value if no invalid characters are detected.
*/

{
 char ch;
 int    i,
 length = 0;
 
 length = *cPtr; /* extract length of pascal string */
 
 if (length == 0)
 return(FALSE);  /* zero length string */
 
 for (i = 1; i <= length; i++)
 {
 ch = *(cPtr + i);
 if ((ch >= ‘0’) && (ch <= ‘9’))
 ;
 else
 return(FALSE);
 }
 return(TRUE);
}

cmpStruct(strct1, strct2, length)
 unsigned char *strct1,
 *strct2;
 int    length;
 
/*
 compares structures returning a true if they are equal or a false
 if they are not.
*/

{
 int  i;
 
 for (i = 0; i < length; i++)
 {
 if (*strct1 == *strct2)
 {
 strct1++;
 strct2++;
 }
 else
 return(FALSE);  /* not equal */
 }
 return(TRUE);   /* equal */
}

Adigit(c)
 char *c;
 
/*
 returns true | false.  This function works for integers and the
 integer portion of a floating point number.
*/

{
 /* look at first char to see if it is +ive | -ive */
 
 if (*c == ‘-’ || *c ==’+’)
 {
 c++;
 
 /* look at next char to determine if digit */
 
 if (*c >= ‘0’ && *c <= ‘9’)
 return(TRUE);
 else
 return(FALSE);
 }
 
 /* otherwise look only at first char */
 if (*c >= ‘0’ && *c <= ‘9’)
 return(TRUE);
 else
 return(FALSE);
}

f2a(aNumber, aStr, precision)
 float  aNumber;
 char *aStr;
 int    precision;
 
/*
 converts a float number to an ascii string with n digits of precision
 to the right of the decimal point;ie, a precision of zero generates 
an
 long and a precistion of two generates an integer with a mantissa of 
two
 digits.
 
 Note:
 The variable The variable aStr must be cleared before entry to this 
routine or the funct
 returns strange results.
*/

{
 float  sign;
 int  i = 0, l;
 long tmp = 0;
 
 if (precision < 0)/* range check */
 precision = 0;
 
 if ((sign = aNumber) < 0)/* record sign */
 {
 aStr[i++] = ‘-’;
 aNumber = - aNumber;/* make n positive */
 }
 
 /* generate long portion */
 
 do
 { /* generate digits in reverse order */
 aStr[i++] = (long) aNumber % 10 + ‘0’;/* get next digit */
 aNumber /= 10;
 tmp = aNumber;
 } while ((tmp) > 0);/* delete it */
 
 if (sign < 0)   /* reverse long portion */
 reverse(aStr + 1);
 else
 reverse(aStr);
 
 /* create mantissa */
 
 if (precision != 0)
 {
 aStr[i] = ‘.’;
 i++;
 
 /* make mantissa a long with the precision of n decimal places */
 
 aNumber = sign;
 tmp = aNumber;  /* trunc mantissa */
 aNumber -= tmp; /* restore only mantissa */
 
 
 if (aNumber < 0)/* make +ive */
 aNumber = - aNumber;
 
 for (l = 1; l <= precision; l++)
 {
 aNumber *= 10;
 
 aStr[i++] = (long) aNumber % 10 + ‘0’;/* get next digit */
 tmp = aNumber;
 aNumber -= tmp; /* rotate left one place */
 }
 }
 
 aStr[i] = *gEOL;/* tack on delimiter */

}

cmpss(s1, s2)
 char *s1, *s2;
 
/*
 compares for occurance of substring s1 in s2 and returns either a
 zero value of match found, or a minus one value if no match found.
*/

{
 int  i,
 s1Length = 0,
 s2Length = 0;
 
 s1Length = strlen(s1);
 s2Length = strlen(s2);
 
 /* compare for substring inc’ing s2 and only chking for s1 length chars 
*/
 
 for (i = 0; i < s2Length; i++)
 {
 if (strncmp(s1, s2 + i, s1Length) == 0)
 return(0);
 }
 
 return(-1);
}
Listing:  MBOB Functs.c

#include <MacTypes.h>
#include <FontMgr.h>
#include <WindowMgr.h>
#include <MenuMgr.h>
#include <TextEdit.h>
#include <DialogMgr.h>
#include <EventMgr.h>
#include <DeskMgr.h>
#include <StdfilePkg.h>
#include <FileMgr.h>
#include <ToolboxUtil.h>
#include <ControlMgr.h>
#include <SerialDvr.h>

#include “MBOB.h”

/*
 Created by :  Byro
 Date   : 05/14/90
 Modified : 06/21/90
*/


InitSerial(defaultSettings)
 dlogSettingsPtr defaultSettings;
 
/*
 Initialize Serial drivers does just that.  Furthermore, it also loads
 the default values into the settings structure.
*/

{
 int    AinRefNumber = AinRefNum, AoutRefNumber = AoutRefNum, Config, 
Err = noErr;
 Str255 ErrStrng;
 
 
 if ((Err = OpenDriver(“\p.Ain”, &AinRefNumber)) != noErr)
 {
 /* error dialog and exit to shell */
 
 NumToString((long) Err, ErrStrng);/* load err val into dlog */
 ParamText(ErrStrng, NIL, NIL, NIL);
 StopAlert(ERR_ALERT, NIL);
 ExitToShell();
 }
 
 if ((Err = OpenDriver(“\p.Aout”, &AoutRefNumber)) != noErr)
 {
 /* error dialog and exit to shell */
 
 NumToString((long) Err, ErrStrng);/* load err val into dlog */
 ParamText(ErrStrng, NIL, NIL, NIL);
 StopAlert(ERR_ALERT, NIL);
 ExitToShell();
 }

 Config = baud9600 + data8 + stop20 + noParity;
 
 ResetPorts(Config); /* reconfigure modem port */
 
 /* load defaults settings structure */
 
 defaultSettings->baud = baud9600;
 defaultSettings->parity = noParity;
 defaultSettings->stopBits = stop20;
 defaultSettings->filter = (int) NIL;
}

shutdownAppl()

/*
 This function closes application by flushing I/O buffer and closing
 the serial drvrs before exiting to the shell.
*/

{
 int    Err = noErr;
 Str255 ErrStrng;
 
 /* flush drvrs */
 
 if ((Err = KillIO(AinRefNum)) != noErr)     /* modem input/output port 
*/
 {
 NumToString((long) Err, ErrStrng);/* load err val into dlog */
 ParamText(ErrStrng, NIL, NIL, NIL);
 StopAlert(ERR_ALERT, NIL);
 }
 
 if ((Err = KillIO(AoutRefNum)) != noErr)
 {
 NumToString((long) Err, ErrStrng);/* load err val into dlog */
 ParamText(ErrStrng, NIL, NIL, NIL);
 StopAlert(ERR_ALERT, NIL);
 }
 
 RAMSDClose(sPortA);
 
 ExitToShell();
}

doSerial(Awindow, settings, serStatPtr, filterKountPtr)
 WindowPtr*Awindow;
 dlogSettingsPtr settings;
 SerStaRec*serStatPtr;
 int    *filterKountPtr;
 
/*
 Reads serial input parses status record looking for changes since 
 last iteration.  Additionally, it also parses input buffer looking for
 filter character.
*/

{
 BooleaninvalidRect = FALSE;
 char   serBuf[64];/* serial input buffer */
 int    i;
 long   bufKount = NIL; /* I.M. II-178 */
 static SerStaRecoldSerStat;
 
 /* read buffer once */

 SerGetBuf(AinRefNum, &bufKount);  /* get # of bytes currently in input 
buffer */
 if ((bufKount < 0) || (bufKount > 63))
 bufKount = NIL;
 if (FSRead(AinRefNum, &bufKount, serBuf) == noErr)
 {
 if (bufKount != NIL)
 {
 for (i = 0; i < bufKount; i++)
 {
 if (serBuf[i] == settings->filter)
 *filterKountPtr += 1;  /* inc filter count */
 }
 SerStatus(AinRefNum, serStatPtr); /* read status */
 if (cmpStruct(&oldSerStat, serStatPtr, sizeof(oldSerStat)) != TRUE)
 invalidRect = TRUE;
 if ((invalidRect == TRUE) || (*filterKountPtr > 0))
 {
 InvalRect(&(*Awindow)->portRect); /* generate update evnt */
 }
 oldSerStat = *serStatPtr;
 }
 }
}

displayStatus(SerStatPtr, filterCount)
 SerStaRec*SerStatPtr;
 int    filterCount;
 
/*
 display all vitals from port status
*/

{
 Byte SWOverruns, HWOverruns, Parity, Framing;
 int    CursorRow = INITIAL_ROW;   /* current cursor row position */
 
 TextSize(TEXT_FONT_SIZE);
 
 /* mask values */
 
 SWOverruns = swOverrunErr & SerStatPtr->cumErrs;
 HWOverruns = hwOverrunErr & SerStatPtr->cumErrs;
 Parity = parityErr & SerStatPtr->cumErrs;
 Framing = framingErr & SerStatPtr->cumErrs;
 
 /* display status using conditionals coupled with movetos and drawstrings. 
*/
 
 MoveTo(LEFT_MARGIN, CursorRow);
 if (SWOverruns != FALSE)
 DrawString(“\pSoftware Overrun error(s) detected   “);
 else
 DrawString(“\pno Software Overrun errors detected  “);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 
 if (HWOverruns != FALSE)
 DrawString(“\pHardware Overrun error(s) detected   “);
 else
 DrawString(“\pno Hardware Overrun errors detected  “);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 
 if (Parity != FALSE)
 DrawString(“\pParity error(s) detected   “);
 else
 DrawString(“\pno Parity errors detected  “);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 
 if (Framing != FALSE)
 DrawString(“\pFraming error(s) detected   “);
 else
 DrawString(“\pno Framing errors detected  “);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 
 if (SerStatPtr->ctsHold != FALSE)
 DrawString(“\pCTS disabled   “);
 else
 DrawString(“\pCTS enabled    “);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 
 if (SerStatPtr->xOffHold != FALSE)
 DrawString(“\pStream suspended   “);
 else
 DrawString(“\pStream  enabled    “);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 MoveTo(LEFT_MARGIN, CursorRow += ROW_HEIGHT);
 
 if (filterCount > 0)
 DrawString(“\pfilter Character detected   “);
 else
 DrawString(“\p                            “);
 /* don’t display */
}

ChangeSettings(settingPtr)
 dlogSettingsPtr    settingPtr;
 
/*
 changes serial port A settings to values in setting structure.
*/

{
 int  Config, Err = noErr;
 
 Config = settingPtr->baud + data8 + settingPtr->parity + settingPtr->stopBits;
 ResetPorts(Config); /* reconfigure modem port */
}

ResetPorts(config)
 int config;
 
/* resets/reconfigures modem port to value specified by config param 
*/

{
 int  Err = noErr;
 Str255 ErrStrng;
 
 /* reset modem input serial port */
 
 if ((Err = SerReset(AinRefNum, config)) != noErr)
 {
 /* error dialog and exit to shell */
 
 NumToString((long) Err, ErrStrng);/* load err val into dlog */
 ParamText(ErrStrng, NIL, NIL, NIL);
 StopAlert(ERR_ALERT, NIL);
 ExitToShell();  
 }
 
 /* reset modem output serial port */
 
 if ((Err = SerReset(AoutRefNum, config)) != noErr)
 {
 /* error dialog and exit to shell */
 
 NumToString((long) Err, ErrStrng);/* load err val into dlog */
 ParamText(ErrStrng, NIL, NIL, NIL);
 StopAlert(ERR_ALERT, NIL);
 ExitToShell();  
 }
}
Listing:  MBOB.c

#include <QuickDraw.h>
#include <MacTypes.h>
#include <FontMgr.h>
#include <WindowMgr.h>
#include <MenuMgr.h>
#include <TextEdit.h>
#include <DialogMgr.h>
#include <EventMgr.h>
#include <DeskMgr.h>
#include <StdfilePkg.h>
#include <FileMgr.h>
#include <ToolboxUtil.h>
#include <ControlMgr.h>
#include <SerialDvr.h>

#include “MBOB.h”


/* Mac Break Out Box is an application that allows the Mac to act as 
a
 logical breakout box.
 The following are included as part of the project:
 
 mactraps lib
 strings lib
 serd resources
 mbob.c
 mbob functs.c
 dlogs.c
 utils.c
 
 
 Written by :  Byro
 Date : 05/07/90
 Modified : 06/22/90
 
 
 Version Log:
 1.0 initial release
*/

/************* globals  ***************/

char gCR[] = “\r”;
char gTAB[] = “\t”;
char gSP[] = “ “;/* space */
char gEOL[] = “\0”;

main()

{

 BooleandoneFlag = FALSE, WNEImplemented;
 dlogSettings  mySettings;
 EventRecordmyEvent;
 Handle ClipHandle;
 MenuHandle AppleMenu;
 Rect   DragRect;
 WindowPtrStatWindow,
 ClipboardWindow;

 ToolBoxInit();
 WindowInit(&StatWindow, “\pStatus Window”);
 SetUpDragRect(&DragRect);
 MenuBarInit(&AppleMenu);
 CreateClipBoardWindow(&ClipboardWindow);
 ClipHandle = NewHandle(NIL);
 InitSerial(&mySettings);
 MainLoop(&doneFlag, &myEvent, &WNEImplemented, &DragRect, &AppleMenu,
 &StatWindow, &ClipboardWindow, &ClipHandle, &mySettings);

}

/*******************************************************/

ToolBoxInit()  
 
 /* initialization */

{
 InitGraf(&thePort);
 InitFonts();
 FlushEvents( everyEvent, REMOVE_ALL_EVENTS );
 InitWindows();
 InitMenus();
 TEInit();
 InitDialogs(NIL);
 InitCursor();
}

/*******************************************************/

WindowInit(aWindow, windowTitle)
 WindowPtr*aWindow;
 Str255 *windowTitle;
 
{
 /* init window ptr */
 
 *aWindow = GetNewWindow(BASE_RES_ID, NIL, MOVE_TO_FRONT);
 
 /* if can’t open window let user know */
 
 if (*aWindow == NIL)
 {
 /* system dialog goes here */
 
 StopAlert(EMPTY_ALERT, NIL);
 ExitToShell();  /* ciao */
 }
 
 if (**windowTitle != NIL)
 SetWTitle(*aWindow, windowTitle);
 
 SetPort(*aWindow);/* make current graf port */

}

/*******************************************************/

SetUpDragRect(DragRect)
 Rect *DragRect;
 
{
 *DragRect = screenBits.bounds;
 (*DragRect).left += DRAG_THRESHOLD;
 (*DragRect).right -= DRAG_THRESHOLD;
 (*DragRect).bottom -= DRAG_THRESHOLD;
}

/*******************************************************/
MenuBarInit(AppleMenu)
 MenuHandle *AppleMenu;
 
{
 Handle myMenuBar;
 
 myMenuBar = GetNewMBar(BASE_RES_ID);
 SetMenuBar(myMenuBar);
 *AppleMenu = GetMHandle(APPLE_MENU_ID);
 AddResMenu(*AppleMenu, ‘DRVR’);
 DrawMenuBar();
}

/*******************************************************/
CreateClipBoardWindow(ClipBoardWindow)
 WindowPtr*ClipBoardWindow;
 
{

 if (( *ClipBoardWindow = GetNewWindow(BASE_RES_ID, NIL, MOVE_TO_FRONT)) 
 == NIL)
 {
 NoteAlert(CLIPBOARD_ALERT, NIL);
 /* ExitToShell(); */
 }
 
 /* set window title */
 
 SetWTitle(*ClipBoardWindow, “\p ClipBoard”);
 
 MoveWindow(*ClipBoardWindow, WINDOW_HOME_LEFT, WINDOW_HOME_RIGHT, 
 LEAVE_WHERE_IT_IS);
}

/*******************************************************/
MainLoop(doneFlag, myEvent, WNEImplemented, DragRect, AppleMenu, 
 StatWindow, CBWindow, clipHandle, MySettings)
 Boolean*doneFlag;
 EventRecord*myEvent;
 Boolean*WNEImplemented;
 Rect   *DragRect;
 MenuHandle *AppleMenu;
 WindowPtr*StatWindow,
 *CBWindow;
 Handle *clipHandle;
 dlogSettingsPtr MySettings;
 
{
 int    filterKount = 0;
 SerStaRecserStat; /* serial status record */

 /* check to see if multifinder running */
 
 *WNEImplemented = (NGetTrapAddress(WNE_TRAP_NUM, ToolTrap) != 
 NGetTrapAddress(UNIMPL_TRAP_NUM, ToolTrap));
 
 /* main program/Event loop */
 
 do
 {
 /* check serial port for input and process if necessary */
 
 doSerial(StatWindow, MySettings, &serStat, &filterKount);
 
 HandleEvent(doneFlag, myEvent, WNEImplemented, DragRect,
 AppleMenu, StatWindow, CBWindow, clipHandle,
 MySettings, &serStat, &filterKount);
 } 
 while (*doneFlag == FALSE);
 shutdownAppl(); /* ciao */
}

/*******************************************************/
HandleEvent(doneFlag, myEvent, WNEImplemented, DragRect, AppleMenu, 
 StatWindow, CbWindow, clipHandl, meSettings,
 serStatPtr, fKountPtr)
 Boolean*doneFlag;
 EventRecord*myEvent;
 Boolean*WNEImplemented;
 Rect   *DragRect;
 MenuHandle *AppleMenu;
 WindowPtr*StatWindow,
 *CbWindow;
 Handle *clipHandl;
 dlogSettingsPtr meSettings;
 SerStaRec*serStatPtr;
 int    *fKountPtr;
 
{
 char   theChar;
 Rect   myClip, oldClip;
 WindowPtroldPort; /* contains current graph port */
 static Boolean  monitorStream = FALSE;
 
 /* multifinder check */
 
 if (*WNEImplemented)
 WaitNextEvent(everyEvent, myEvent, SLEEP, NIL_MOUSE_REGION);
 else
 {
 SystemTask(); /* time slice for OS */
 GetNextEvent(everyEvent, myEvent);
 }
 
 switch ((*myEvent).what)
 {
 case mouseDown:
 HandleMouseDown(doneFlag, myEvent,WNEImplemented, DragRect, AppleMenu,
 &monitorStream, StatWindow, CbWindow, meSettings);
 break;

 case nullEvent:
 case mouseUp:
 case keyUp:
 case updateEvt:

 /* 
 see if update is for this window or monitor stream menu selected 
 & redraw window if either condition true.
 */
 
 if (((WindowPtr) (*myEvent).message == *StatWindow) || (monitorStream 
== TRUE))
 { 
 
 /* reset filter counter when monitoring starts */
 
 if (monitorStream == TRUE)
 {
 *fKountPtr = 0;
 ZeroStruct(serStatPtr, sizeof(SerStaRec));
 SelectWindow(*StatWindow);
 ShowWindow(*StatWindow);
 }
 
 SysBeep(4);
 BeginUpdate(*StatWindow);
 
 GetPort(&oldPort);/* save current graph port */
 SetPort(*StatWindow);
 EraseRect(&(*StatWindow)->portRect);
 displayStatus(serStatPtr, *fKountPtr);
 SetPort(oldPort); /* restore old graph port */
 EndUpdate(*StatWindow);
 monitorStream = FALSE; /* reset after use */
 }
 
 /* chk if update for clip board window */
 
 if ((WindowPtr) (*myEvent).message == *CbWindow)
 {
 BeginUpdate(*CbWindow);
 GetPort(&oldPort);/* save current graph port */
 SetPort(*CbWindow);
 EraseRect(&(*CbWindow)->portRect);
 
 /* clip scrollbar sections of clipboard */
 
 SetRect(&myClip, (*CbWindow)->portRect.left, (*CbWindow)->portRect.top,
 (*CbWindow)->portRect.right, (*CbWindow)->portRect.bottom);
 oldClip = myClip; /* save old portrect  */
 myClip.bottom -= SCROLL_BAR_PIXELS;
 myClip.right -= SCROLL_BAR_PIXELS;
 ClipRect(&myClip); 
 
 DisplayClipboard(CbWindow, clipHandl);
 ClipRect(&oldClip); /* restore old clip region */
 DrawGrowIcon(*CbWindow);
 ShowWindow(*CbWindow);
 SetPort(oldPort); /* restore old graph port */
 EndUpdate(*CbWindow);
 }
 break;
 case keyDown:
 case autoKey:
 theChar = (*myEvent).message & charCodeMask;
 if (((*myEvent).modifiers & cmdKey) != 0)
 HandleMenuChoice(MenuKey(theChar), doneFlag, AppleMenu, 
 &monitorStream, CbWindow, meSettings);
 break;
 case activateEvt:
 break;
 default:
 break;
 }
}

/*******************************************************/

HandleMouseDown(doneFlag, myEvent, WNEImplemented, DragRect, AppleMenu, 

 monStreamPtr, statWindow, cBwindow, MeSettings)
 Boolean*doneFlag;
 EventRecord*myEvent;
 Boolean*WNEImplemented;
 Rect   *DragRect;
 MenuHandle *AppleMenu;
 Boolean*monStreamPtr;
 WindowPtr*statWindow,
 *cBwindow;
 dlogSettingsPtr MeSettings;
 
{
 BooleanStillInGoAway, updateBackdrop = FALSE;
 WindowPtrwhichWindow;
 short intthePart;
 long int menuChoice;
 MenuHandle disableHandle;
 long   nuSize;
 Rect   limitRect;
 
 WindowPtroldPort;
 
 thePart = FindWindow((*myEvent).where, &whichWindow);
 GetPort(&oldPort);/* save current graph port  */
 switch(thePart)
 {
 case inContent:
 /* activate the window that was pt’d @  */
 
 SetPort(whichWindow);
 SelectWindow(whichWindow);
 break;
 case inMenuBar:
 menuChoice = MenuSelect((*myEvent).where);
 HandleMenuChoice(menuChoice, doneFlag, AppleMenu, 
 monStreamPtr, cBwindow, MeSettings);
 break;
 case inSysWindow:
 SystemClick(myEvent, whichWindow);
 break;
 case inDrag:
 DragWindow(whichWindow, (*myEvent).where, DragRect);
 updateBackdrop = TRUE;
 break;
 case inGoAway:
 /* highlight close box when clicked */
 
 StillInGoAway = TrackGoAway(whichWindow, (*myEvent).where);
 if (StillInGoAway)
 {
 /* re-enable menu selection when window closed */
 
 if (whichWindow == *statWindow)
 {
 disableHandle = GetMHandle(FILE_MENU_ID);
 EnableItem(disableHandle, OPEN_ITEM);
 }
 
 if (whichWindow == *cBwindow)
 {
 disableHandle = GetMHandle(EDIT_MENU_ID);
 EnableItem(disableHandle, CLIPBOARD_ITEM);
 }
 
 updateBackdrop = TRUE;
 
 /* restore old graph port */
 
 SetPort(oldPort);
 HideWindow(whichWindow);
 SendBehind(whichWindow, NIL);
 }
 break;
 case inGrow:
 if (whichWindow == *cBwindow)
 {
 /* determine min, max dimensions, based on screen here */
 
 SetRect(&limitRect, 80, 80, screenBits.bounds.right,
 screenBits.bounds.bottom);
 
 /* get nu dimensions of window */
 
 nuSize = GrowWindow(whichWindow, (*myEvent).where,
 &limitRect);
 
 /* resize window */
 
 SizeWindow(whichWindow, LoWord(nuSize), HiWord(nuSize), TRUE);
 GetPort(&oldPort);/* save current graph port  */
 SetPort(whichWindow);
 InvalRect(&whichWindow->portRect);/* generate update evnt */
 
 /* restore old graph port */
 
 SetPort(oldPort);
 updateBackdrop = TRUE;
 }
 break;
 default:
 break;
 }
 
 /* generate update evnt for back ground window if condition met */
 
 if (updateBackdrop == TRUE)
 InvalRect(&(*statWindow)->portRect);
}

/*******************************************************/
HandleMenuChoice(menuChoice, doneFlag, AppleMenu, monSptr, cbWindow, 
MySetngs)
 long   menuChoice;
 Boolean*doneFlag;
 MenuHandle *AppleMenu;
 Boolean*monSptr;
 WindowPtr*cbWindow;
 dlogSettingsPtr MySetngs;

{
 int theMenu;
 int theItem;
 
 if (menuChoice != FALSE)
 {
 theMenu = HiWord(menuChoice);
 theItem = LoWord(menuChoice);
 switch (theMenu)
 {
 case APPLE_MENU_ID:
 HandleAppleChoice(theItem, AppleMenu);
 break;
 case EDIT_MENU_ID:
 HandleEditChoice(theItem, cbWindow);
 break;
 case FILE_MENU_ID:
 HandleFileChoice(theItem, doneFlag, monSptr);
 break;
 case OPTION_MENU_ID:
 HandleOptionsChoice(theItem, MySetngs);
 break;
 default:
 break;
 }
 HiliteMenu(0);
 }
}

/*******************************************************/

HandleAppleChoice(theItem, AppleMenu)
 int theItem;
 MenuHandle *AppleMenu;

{
 Str255 accName;
 int    accNumber;
 short intitemNumber;
 DialogPtrAboutDialog;
 
 switch (theItem)
 {
 case ABOUT_ITEM:
 NoteAlert(ABOUT_ALERT, NIL);
 break;
 default: 
 GetItem(*AppleMenu, theItem, accName);
 accNumber = OpenDeskAcc(accName);
 break;
 }
}

/*******************************************************/
HandleEditChoice(theItem, theCbWindow)
 int    theItem;
 WindowPtr*theCbWindow;
 
{
 int Err;
 long *myPtr, Ptr = 0;
 MenuHandle editHandle;
 
 myPtr = &Ptr;
 
 /* generate update evnt for clipboard window */
 
 switch (theItem)
 {
 case COPY_ITEM:
 /* defined by application */
 break;
 case PASTE_ITEM:
 /* defined by application */
 break;
 case CLEAR_ITEM:
 /* clear clipboard; refer to I.M. I:385-386, I:461 */
 
 ZeroScrap();
 PutScrap(4, ‘PAT’, myPtr);
 InvalRect(&(*theCbWindow)->portRect);
 break;
 case CLIPBOARD_ITEM:
 /* disable item when selected */
 
 editHandle = GetMHandle(EDIT_MENU_ID);
 DisableItem(editHandle, CLIPBOARD_ITEM);
 
 SelectWindow(*theCbWindow);
 ShowWindow(*theCbWindow);
 break;
 default:
 break;
 }
}

/*******************************************************/

HandleFileChoice(theItem, doneFlag, mSPtr)
 int  theItem;
 Boolean*doneFlag,
 *mSPtr;/* monitor stream ptr */

{
 OSErr  DoLaunch();/* forward declaration */
 Boolean  SubLaunch; /* sublaunch if true and launch if false */
 int    Err = noErr;
 MenuHandle fileHandle;
 
 switch (theItem)
 {
 case OPEN_ITEM:
 /* disable item when selected */
 
 fileHandle = GetMHandle(FILE_MENU_ID);
 DisableItem(fileHandle, OPEN_ITEM);
 
 *mSPtr = TRUE;
 break;
 case TRANSFER_ITEM:
 /* quits current routine after launch */
 
 SubLaunch = FALSE;
 Err = DoLaunch(SubLaunch); 
 break;
 case LAUNCH_ITEM:
 SubLaunch = TRUE; /* doesn’t quit after launch */
 Err = DoLaunch(SubLaunch);
 break;
 case QUIT_ITEM:
 *doneFlag = TRUE;
 break;
 }
 
 /* handle launch failure */
 
 if (Err != noErr)
 NoteAlert(LAUNCH_ALERT, NIL);
}

/*******************************************************/
HandleOptionsChoice(theItem, mySetngs)
 int  theItem;
 dlogSettingsPtr mySetngs;

{
 int    Err = noErr;
 
 /* load default settings here */
 
 switch (theItem)
 {
 case BAUD_ITEM :
 Err = HndlBaudDialog(mySetngs);
 break;
 case PARITY_ITEM :
 Err = HndlParityDialog(mySetngs);
 break;
 case STOP_ITEM :
 Err = HndlStopBitsDialog(mySetngs);
 break;
 case FILTER_ITEM :
 Err = HndlFilterDialog(mySetngs);
 break;
 default :
 break;
 }
 
 /* exit program if memory exhausted */
 
 if (Err == TRUE)
 {
 shutdownAppl();  /* close serial drvr and exit*/
 }

 if (Err != CANCEL_BUTTON)
 {
 /* reset serial drvrs and load nu settings vals */
 
 ChangeSettings(mySetngs);
 }
 
}

/*******************************************************/
DisplayClipboard(BoardWindow, ClipHandle)
 WindowPtr*BoardWindow;
 Handle *ClipHandle;
 
/* displays either text or pict clipboard item */

{
 Rect myRect;
 long length,
 offset;
 
 if ((length = GetScrap(*ClipHandle, ‘TEXT’, &offset)) < 0)
 {
 if ((length = GetScrap(*ClipHandle, ‘PICT’, &offset)) < 0)
 ;/* NoteAlert(CLIPBOARD_ALERT, NIL); */
 else
 {
 /* display pict data */
 
 myRect = (*BoardWindow)->portRect;
 CenterPict(*ClipHandle, &myRect);
 DrawPicture(*ClipHandle, &myRect);
 }
 }
 else
 {
 /* display text data */
 
 HLock(*ClipHandle);
 TextBox(**ClipHandle, length, &(thePort->portRect), teJustLeft);
 HUnlock(*ClipHandle);
 }
}

/*******************************************************/

OSErr LaunchIt(pLnch)
 pLaunchStruct pLnch;

/*
 This function is pascal call back routine.  It lanches nu apps; refer
 to pp. 118 & 119 in the ls c manual for more info.
 note:  result code < 0 means error
*/

{
 asm
 {
 move.l 8(sp),a0 /* pops ptr into a0 */
 _Launch/* calls launch */
 /* OSErr ret’d in d0 */
 }
}

/*******************************************************/

OSErr DoLaunch(subLaunch)
 BooleansubLaunch; /* sublaunch if true & launch if false */
 
{
 LaunchStruct  myLaunch;
 Point  where;   /* where to display dialog */
 SFReplyreply;   /* reply record */
 SFTypeList myFileTypes;  /* we only want appls */
 short intnumFileTypes = 1;
 HFileInfomyPB;
 StringPtrdirNameStr;
 OSErr  err;
 OSErr  LaunchIt();/* forward declare funct */
 
 where.h = 80;
 where.v = 90;
 myFileTypes[0] = ‘APPL’; /* only appls */
 
 /* let the user choose the file to launch */
 
 SFGetFile(where, “”, NIL, numFileTypes, myFileTypes, NIL, &reply);
 
 if (reply.good)
 {
 dirNameStr = (StringPtr) &reply.fName;/* init to file selected */
 
 /* get finder flags */
 
 myPB.ioCompletion = NIL;
 myPB.ioNamePtr = dirNameStr;
 myPB.ioVRefNum = reply.vRefNum;
 myPB.ioFDirIndex = 0;
 myPB.ioDirID = 0;
 err = PBGetCatInfo((CInfoPBPtr) &myPB, FALSE);
 if (err != noErr)
 return(err);  /* how to handle this? */
 
 /* set the current volume to where the target appl is */
 
 err = SetVol(NIL, reply.vRefNum);
 if (err != noErr)
 return(err);  /* ditto */
 
 /* set up the launch params */
 
 myLaunch.pfName = (StringPtr) &reply.fName;       /* ptr to our filename 
*/
 myLaunch.param = 0; /* we don’t want alt screen or sound buffs */
 
 /* set up LC so as to tell launch that htere is non-junk next */
 
 myLaunch.LC[0] = ‘L’;  myLaunch.LC[1] = ‘C’;
 myLaunch.extBlockLen = 6;/* len of param blk past this long word */
 
 /* copy flags; set bit 6 of low byte to 1 for RO access: */
 
 myLaunch.fFlags = myPB.ioFlFndrInfo.fdFlags;      /* from _GetCatInfo 
*/
 
 /* test sublaunch & set launch flags accordingly */
 
 if (subLaunch)
 myLaunch.launchFlags = 0xC0000000;/* set 2 high bit for sublaunch */
 else
 myLaunch.launchFlags = 0x00000000;/* launch & quit */
 /* Debugger(); */
 err = LaunchIt(&myLaunch); /* call _Launch */
 if (err < 0)
 {
 /* launch failed, put up alert to tell user */
 /* LaunchFailed();*/
 return(err);
 }
 else
 return(noErr);
 }
}

/*******************************************************/

CenterPict(thePicture, myRectPtr)
 PicHandlethePicture;
 Rect   *myRectPtr;
 
{
 Rect windRect, 
 pictureRect;
 
 windRect = *myRectPtr;
 pictureRect = (**(thePicture)).picFrame;
 myRectPtr->top = (windRect.bottom - windRect.top - (pictureRect.bottom
 - pictureRect.top)) / 2 + windRect.top;
 myRectPtr->bottom = myRectPtr->top + (pictureRect.bottom - pictureRect.top);
 myRectPtr->left = (windRect.right - windRect.left - (pictureRect.right 

 - pictureRect.left)) / 2 + windRect.left;
 myRectPtr->right = myRectPtr->left + (pictureRect.right - pictureRect.left);
}

Listing:  MBOB.R

resource ‘DLOG’ (400, “Baud”) {
 {40, 40, 240, 280},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 408,
 “Baud Rate Dialog”
};

resource ‘DLOG’ (401, “Parity”) {
 {40, 40, 200, 240},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 409,
 “New Dialog”
};

resource ‘DLOG’ (402, “Stop”) {
 {60, 80, 180, 280},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 410,
 “Stop Bits Dialog”
};

resource ‘DLOG’ (403, “Filter”) {
 {100, 100, 260, 380},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 411,
 “Filter Dialog”
};

resource ‘WIND’ (400) {
 {48, 23, 332, 470},
 documentProc,
 invisible,
 goAway,
 0x0,
 “App Window”
};

resource ‘MENU’ (400, “Apple”) {
 400,
 textMenuProc,
 0x7FFFFFFD,
 enabled,
 apple,
 { /* array: 2 elements */
 /* [1] */
 “About MacBreak Out Box”, noIcon, noKey, noMark, plain,
 /* [2] */
 “-”, noIcon, noKey, noMark, 16
 }
};

resource ‘MENU’ (401, “File”) {
 401,
 textMenuProc,
 0x7FFFFFED,
 enabled,
 “File”,
 { /* array: 6 elements */
 /* [1] */
 “Monitor Stream”, noIcon, “O”, noMark, plain,
 /* [2] */
 “-”, noIcon, noKey, noMark, plain,
 /* [3] */
 “Transfer...”, noIcon, “T”, noMark, plain,
 /* [4] */
 “Launch...”, noIcon, “L”, noMark, plain,
 /* [5] */
 “-”, noIcon, noKey, noMark, plain,
 /* [6] */
 “Quit”, noIcon, “Q”, noMark, plain
 }
};

resource ‘MENU’ (402, “Edit”) {
 402,
 textMenuProc,
 0x60,
 enabled,
 “Edit”,
 { /* array: 7 elements */
 /* [1] */
 “Undo”, noIcon, “Z”, noMark, plain,
 /* [2] */
 “-”, noIcon, noKey, noMark, plain,
 /* [3] */
 “Cut”, noIcon, “X”, noMark, plain,
 /* [4] */
 “Copy”, noIcon, “C”, noMark, plain,
 /* [5] */
 “Paste”, noIcon, “V”, noMark, plain,
 /* [6] */
 “Clear”, noIcon, noKey, noMark, plain,
 /* [7] */
 “Show Clip Board”, noIcon, noKey, noMark, plain
 }
};

resource ‘MENU’ (403, “Options”) {
 403,
 textMenuProc,
 0xF,
 enabled,
 “Options”,
 { /* array: 4 elements */
 /* [1] */
 “Baud”, noIcon, noKey, noMark, plain,
 /* [2] */
 “Parity”, noIcon, noKey, noMark, plain,
 /* [3] */
 “Stop Bits”, noIcon, noKey, noMark, plain,
 /* [4] */
 “Filter”, noIcon, noKey, noMark, plain
 }
};

resource ‘MBAR’ (400) {
 { /* array MenuArray: 4 elements */
 /* [1] */
 400,
 /* [2] */
 401,
 /* [3] */
 402,
 /* [4] */
 403
 }
};

resource ‘DITL’ (400, “About”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {140, 138, 160, 198},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {81, 33, 133, 314},
 StaticText {
 enabled,
 “This is the MacBreak out Box application”
 }
 }
};

resource ‘DITL’ (401, “Launch”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {171, 84, 191, 144},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {60, 24, 168, 216},
 StaticText {
 enabled,
 “Unable to launch application\n      Check”
 “ the following:\n\n          1. Path name\n”
 “          2. File name\n          3. Avai”
 “lable memory”
 }
 }
};

resource ‘DITL’ (402, “Free”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {106, 65, 126, 125},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {68, 1, 95, 254},
 StaticText {
 enabled,
 “  Unable to release memory”
 }
 }
};

resource ‘DITL’ (404, “Err”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {108, 85, 128, 145},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {55, 0, 95, 259},
 StaticText {
 enabled,
 “An unexpected value of ^0 was returned f”
 “rom the program”
 }
 }
};

resource ‘DITL’ (405, “Hosed”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {121, 94, 141, 154},
 Button {
 enabled,
 “Thpt!”
 },
 /* [2] */
 {58, 8, 119, 234},
 StaticText {
 enabled,
 “Logic fault, this file is returning a ne”
 “gitive file length!”
 }
 }
};

resource ‘DITL’ (407, “Empty”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {116, 97, 136, 157},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {57, 0, 110, 267},
 StaticText {
 enabled,
 “Not enough memory to allocate storage fo”
 “r application window\n        Check avail”
 “able free memory”
 }
 }
};

resource ‘DITL’ (403, “Enough”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {116, 97, 136, 157},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {63, 1, 103, 271},
 StaticText {
 enabled,
 “Not enough memory to allocate storage\n  “
 “      Check available free memory”
 }
 }
};

resource ‘DITL’ (406, “ClipBoard”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {116, 97, 136, 157},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {57, 0, 110, 267},
 StaticText {
 enabled,
 “Not enough memory to allocate storage fo”
 “r clipboard window\n        Check availab”
 “le free memory”
 }
 }
};

resource ‘DITL’ (408, “Baud”) {
 { /* array DITLarray: 9 elements */
 /* [1] */
 {153, 27, 173, 87},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {152, 148, 172, 208},
 Button {
 enabled,
 “Cancel”
 },
 /* [3] */
 {45, 40, 65, 100},
 RadioButton {
 enabled,
 “300”
 },
 /* [4] */
 {78, 40, 98, 100},
 RadioButton {
 enabled,
 “1200”
 },
 /* [5] */
 {108, 40, 128, 100},
 RadioButton {
 enabled,
 “4800”
 },
 /* [6] */
 {47, 149, 67, 209},
 RadioButton {
 enabled,
 “9600”
 },
 /* [7] */
 {77, 149, 97, 209},
 RadioButton {
 enabled,
 “19200”
 },
 /* [8] */
 {107, 149, 127, 209},
 RadioButton {
 enabled,
 “57600”
 },
 /* [9] */
 {8, 53, 31, 192},
 StaticText {
 disabled,
 “Baud Rate Selection”
 }
 }
};

resource ‘DITL’ (409, “Parity”) {
 { /* array DITLarray: 6 elements */
 /* [1] */
 {126, 23, 146, 83},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {127, 113, 147, 173},
 Button {
 enabled,
 “Cancel”
 },
 /* [3] */
 {42, 66, 62, 126},
 RadioButton {
 enabled,
 “Even”
 },
 /* [4] */
 {66, 66, 86, 126},
 RadioButton {
 enabled,
 “None”
 },
 /* [5] */
 {93, 66, 113, 126},
 RadioButton {
 enabled,
 “Odd”
 },
 /* [6] */
 {10, 43, 30, 163},
 StaticText {
 disabled,
 “Parity Selection”
 }
 }
};

resource ‘DITL’ (410, “Stop”) {
 { /* array DITLarray: 5 elements */
 /* [1] */
 {36, 124, 56, 184},
 Button {
 enabled,
 “Ok”
 },
 /* [2] */
 {82, 124, 102, 184},
 Button {
 enabled,
 “Cancel”
 },
 /* [3] */
 {36, 8, 56, 104},
 RadioButton {
 enabled,
 “1 Stop Bit”
 },
 /* [4] */
 {83, 9, 103, 102},
 RadioButton {
 enabled,
 “2 Stop Bits”
 },
 /* [5] */
 {6, 27, 28, 167},
 StaticText {
 disabled,
 “Stop Bits Selection”
 }
 }
};

resource ‘DITL’ (411, “Filter”) {
 { /* array DITLarray: 4 elements */
 /* [1] */
 {118, 47, 138, 107},
 Button {
 enabled,
 “Ok”
 },
 /* [2] */
 {118, 179, 138, 239},
 Button {
 enabled,
 “Cancel”
 },
 /* [3] */
 {18, 4, 59, 276},
 StaticText {
 disabled,
 “                    Character Filter\nEnt”
 “er an 8 bit decimal number for filter”
 },
 /* [4] */
 {80, 113, 100, 173},
 EditText {
 enabled,
 “”
 }
 }
};

resource ‘ALRT’ (400, “About”) {
 {40, 40, 240, 380},
 400,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘ALRT’ (401, “Launch”) {
 {40, 140, 240, 380},
 401,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘ALRT’ (402, “Free”) {
 {80, 80, 240, 280},
 402,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘ALRT’ (403, “Enough”) {
 {80, 80, 220, 340},
 403,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘ALRT’ (404, “Err”) {
 {76, 128, 206, 368},
 404,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘ALRT’ (405, “Hosed”) {
 {58, 118, 208, 358},
 405,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘ALRT’ (407, “Empty”) {
 {40, 40, 240, 310},
 407,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘ALRT’ (406, “ClipBoard”) {
 {40, 40, 240, 310},
 406,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Things 2.5.4 - Elegant personal task man...
Things is a task management solution that helps to organize your tasks in an elegant and intuitive way. Things combines powerful features with simplicity through the use of tags and its intelligent... Read more
NeoOffice 2014.10 - Mac-tailored, OpenOf...
NeoOffice is a complete office suite for OS X. With NeoOffice, users can view, edit, and save OpenOffice documents, PDF files, and most Microsoft Word, Excel, and PowerPoint documents. NeoOffice 3.x... Read more
iPhoto Library Manager 4.2 - Manage mult...
iPhoto Library Manager allows you to organize your photos among multiple iPhoto libraries, rather than having to store all of your photos in one giant library. You can browse the photos in all your... Read more
Web Snapper 3.3.8 - Capture entire Web p...
Web Snapper lets you capture Web pages exactly as they appear in your browser. You can send them to a file as images or vector-based, multi-page PDFs. It captures the whole Web page - eliminating the... Read more
TeamViewer 10.0.41404 - Establish remote...
TeamViewer gives you remote control of any computer or Mac over the Internet within seconds, or can be used for online meetings. Find out why more than 200 million users trust TeamViewer! Free for... Read more
Ableton Live 9.1.8 - Record music using...
Ableton Live lets you create and record music on your Mac. Use digital instruments, pre-recorded sounds, and sampled loops to arrange, produce, and perform your music like never before. Ableton Live... Read more
VOX 2.5 - Music player that supports man...
VOX is a beautiful music player that supports many filetypes. The beauty is in its simplicity, yet behind the minimal exterior lies a powerful music player with a ton of features & support for... Read more
OmniFocus 2.1.2 - GTD task manager with...
OmniFocus helps you manage your tasks the way that you want, freeing you to focus your attention on the things that matter to you most. Capturing tasks and ideas is always a keyboard shortcut away in... Read more
Adobe Flash Player 17.0.0.169 - Plug-in...
Adobe Flash Player is a cross-platform, browser-based application runtime that provides uncompromised viewing of expressive applications, content, and videos across browsers and operating systems.... Read more
iMazing 1.1.3 - Complete iOS device mana...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more

Chainsaw Warrior: Lords of the Night has...
It's time to put the Darkness back in its place now that Chainsaw Warrior: Lords of the Night has officially made it to iOS. | Read more »
A World of Ice and Fire Lets You Stalk 2...
George R. R. Martin’s A World of Ice and Fire, by Random House, is a mobile guide to the epic series. The new update gives you the Journeys map feture that will let you track the movements of 25 different characters. But don't worry, you can protect... | Read more »
Gameloft Announces Battle Odyssey, a New...
Battle Odyssey, Gameloft's newest puzzle RPG, is coming to the App Store next week. Set in the world of Pondera, you will need to control the power of the elements to defend the world from evil. You'll be able to entlist over 500 allies to aid you... | Read more »
Fusion - HDR Camera (Photography)
Fusion - HDR Camera 1.0.0 Device: iOS Universal Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Fusion creates HDR (high dynamic range) photos by capturing different exposures and then combining them into one... | Read more »
Sago Mini Toolbox (Education)
Sago Mini Toolbox 1.1 Device: iOS Universal Category: Education Price: $2.99, Version: 1.1 (iTunes) Description: Come build with the Sago Mini friends! Use a wrench, try a saw, or hammer some nails. From sewing hand puppets to... | Read more »
You Should Probably Grab Hitman GO While...
Hitman GO is a surprisingly cool (yet also incredibly drastic) departure from the Hitman series. It's well worth playing for any puzzle game fans out there, and at the moment you can get your hands - or garrotte if you will - on it for a mere $0.99... | Read more »
IFTTT is Bringing Do Button and Do Note...
IFTTT has announced Do Button and Do Note for the Apple Watch. Do Button lets you make your own personalized button that can connect to things like your Google Drive, control the temperature in your home with Nest Thermostat, or turn the lights on... | Read more »
How Many Days, Hours, and Minutes Are Le...
Countdown, by Yves Tscherry, is now available on the App Store. The app keeps track of countdowns to your favorite things such as someones birthday or days till the New Year. You can display the time in seconds, minutes, hours, days, weeks, months,... | Read more »
The All-New Misfit 2.0 App is Available...
Misfit has just given their app a complete overhaul. Misfit 2.0 now has a brand new interface with a sleek design and is easier to navigate. You'll be able to sync your Misfit device and look up health and fitness information faster than ever before... | Read more »
Halo: Spartan Strike (Games)
Halo: Spartan Strike 1.0 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0 (iTunes) Description: Delve into 30 challenging missions through cities and jungles using a devastating arsenal of weapons, abilities and... | Read more »

Price Scanner via MacPrices.net

Clearance 13-inch 2.6GHz Retina MacBook Pro a...
B&H Photo has clearance 2014 13″ 2.6GHz/128GB Retina MacBook Pros now available for $1099, or $200 off original MSRP. Shipping is free, and B&H charges NY sales tax only. Read more
Apple refurbished 2014 13-inch Retina MacBook...
The Apple Store has Apple Certified Refurbished 2014 13″ Retina MacBook Pros available for up to $400 off original MSRP, starting at $979. An Apple one-year warranty is included with each model, and... Read more
iMacs on sale for up to $205 off MSRP, NY tax...
B&H Photo has 21″ and 27″ iMacs on sale for up to $205 off MSRP including free shipping plus NY sales tax only: - 21″ 1.4GHz iMac: $1019 $80 off - 21″ 2.7GHz iMac: $1189 $110 off - 21″ 2.9GHz... Read more
Sale! 16GB iPhone 5S for $1 with service
Best Buy is offering 16GB iPhone 5Ss for $1.00 with 2-year activation at a participating cellular provider. Choose free home shipping and activation, or buy online and activate during in-store pickup... Read more
Apple refurbished 2014 MacBook Airs available...
The Apple Store has Apple Certified Refurbished 2014 MacBook Airs available starting at $679. An Apple one-year warranty is included with each MacBook, and shipping is free. These are currently the... Read more
27-inch 3.5GHz 5K iMac on sale for $2349, sav...
 Adorama has the 27″ 3.5GHz 5K iMac in stock today and on sale for $2349 including free shipping plus NY & NJ sales tax only. Their price is $150 off MSRP. For a limited time, Adorama will... Read more
Save up to $380 on an iMac with Apple refurbi...
The Apple Store has Apple Certified Refurbished iMacs available for up to $380 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 27″ 3.5GHz 5K iMac – $2119 $... Read more
iFixIt Teardown Awards 12-IInch Retina MacBoo...
iFixIt has posted its illustrated teardown of the new 12-inch MacBook Retina. They note that this new MacBook is less than half the thickness of the last Apple notebook called just “MacBook” back in... Read more
13-inch 2.5GHz MacBook Pro (refurbished) avai...
The Apple Store has Apple Certified Refurbished 13″ 2.5GHz MacBook Pros available for $829, or $270 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.... Read more
Faithful iPad 2 Gets A Second Career In Retir...
Finally, after four months’ transition, I handed my faithful old 2011 iPad 2 off to my wife at the end of March and switched whole-hog to using the iPad Air 2 I bought back in November. I’d found... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* TV Live Streaming Frameworks Test En...
**Job Summary** Work and contribute towards the engineering of Apple 's state-of-the-art products involving video, audio, and graphics in Interactive Media Group (IMG) at Read more
Event Director, *Apple* Retail Marketing -...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global engagement strategy and team. Delivering an overarching brand Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.