TweetFollow Us on Twitter

Bug Parser
Volume Number:7
Issue Number:8
Column Tag:C Forum

Bug Parser Debugging Aid

By Douglas W. Rinehart, Sunnyvale, CA

What it is!

The skill I exhibit when writing new programs generally leads to a vicious compile-link-bomb cycle. While my Macintosh is searching the hard disk during the reboot cycle I have time to ponder what I changed that could have caused the problem. Now, I don’t imagine that any of you would treat your creations this way but never-the-less you may find the following add-on features very useful, even with your carefully thought out programming methods. (Oh-brother!)

The debugger that comes with the Think-C package is very good but for simple chores it can take a lot of time to use. To more easily troubleshoot my programs it was necessary to add more and more debugger aids to my code. In the beginning it was sufficient to provide a method of tracing what procedure I had last called, but over time I found that I had added enough band-aids to cover a mummy. The following package can be added to any existing program you are writing to help you quickly pinpoint problems and verify its performance with the greatest of ease.

The Foundation

The basic building block is the procedure:

/* 1 */

ShowPro( wait,proTYPE,msg )

long  wait; /* number of seconds to delay display */
long  proTYPE; /* ‘TYPE’ code for procedure (discipline)
char  *msg; /* pascal message string to be displayed */

Once the environment variables have been initialized, this procedure will provide a method of displaying useful information without directly depending on any of your program’s environment variables. ShowPro() has its own grafPort in which to draw and provides a method of slowing down the rate at which the information is presented. Having its own grafPort keeps track of where the pen is, what font and font size is used and allows you to display your information anywhere you want. Apple has stated not to draw to the screen directly since it will cause disaster while running under MultiFinder, but since this is for the purpose of debugging and should not be included in any final versions I think exception is in order. To display information at strategic points in your program, you pass ShowPro() a string and poof you get the message without disturbing your programs pen location etc. If you add this call to the entry and exit points of every procedure in your program you can visually monitor where you are at all times, which makes it easy to find out where bombs occur since the last procedure entered will still be displayed on the screen. (unless it is a really bad bomb, DING)

Most of the time you will simply want ShowPro() to display where it is and do so as fast as possible. There are times however, that you will want to slow down this information to give your non-Evelyn Wood speed reading brain a chance to comprehend the messages. ShowPro() is passed a variable to indicate how long to delay before continuing on for this purpose. Defining a predetermined value of delay to be equivalent to BP_STOP informs ShowPro() to stop and wait for you to give the go ahead and allows you to change or examine information if you so desire. There are instances where you may wish to stop, independent of any calls, so a provision to check the state of the Command,Option,Shift, and CapsLock keys is included. By pressing the Command,Option, and Shift simultaneously you can stop within ShowPro() and process commands. Treat it as though it were a breakpoint, where the breakpoint is determined by the state of the keyboard. Since the display-overhead does slow down the throughput speed of your program a bit, ShowPro() checks the command key and if it is the only key being pressed it instantly returns ignoring the default or user defined delay times. This allows you to run at pseudo “full speed” when you have a temporary need for speed. You can always disable or enable the display by menu.

I was experimenting with methods to keep the display from constantly flashing even though the same information was being displayed over and over. You will see a commented out “#define BLINDTEST_ON”.(.c listing above ShowPro()) If it is defined, the display will only be updated when the information changes. Doing so greatly improves the throughput speed when information sent to ShowPro() remains constant and only slightly degrades throughput when sent constantly varied information. I left it for you to decide.

( #define or not #define, that is the question )

ShowPro() is also passed a parameter to be used as an indicator of what kind of message is coming in. In certain instances you may be interested in monitoring only procedures dealing with window functions. To do so you can change what type of message is to be intercepted during run time. An example would be that you are having trouble with the updating of numerous windows so you would set the procedure discipline to ‘WIND’. This tells ShowPro() to display only calls made with the proTYPE of ‘WIND’. This helps eliminate a lot of searching through your log files to find the information you are concentrating on.

The proTYPE discipline method is as follows. Upon initialization a static long global is set to the 4 character TYPE of ‘SHOW’. This tells ShowPro() to display all messages sent to it.(no discipline) You can change the comparison type from ‘SHOW’ to ‘test’ and then only the messages sent to ShowPro() with the proTYPE (procedure TYPE code) set to ‘test’ will be displayed. You may later change the type back to ‘SHOW’ to once again display all messages sent to ShowPro(). If the proTYPE passed to ShowPro() is ‘SHOW’, then the message sent will be displayed even if a discipline type has been entered. This ensures that commands of importance (error messages) always get displayed with or without procedure discipline being on.

Keep it simple

Something so simple can save an enormous amount of time with very few drawbacks. Well OK! It does slow your run-time down a bit but don’t give up yet, it is worth the time. Place

/* 2 */

#ifdef BP_Lives
ShowPro( delay time, TYPE code , message string )
#endif

just after the local variables declaration (entry) in each of your project’s procedures and just before the exit point of each ( see listing of AddedMenuProc() ). By using the #ifdef approach you can remove all debugging code with one header file change. Normally you will find that the extra time added by the debugger is tolerable if left in and you will only remove it when you get to the release stage of the game.

When you begin to structure a new program you need to keep in mind what procedures go with each other. i.e. event procedures, window procedures, file, drawing etc. Knowing these interaction priorities will make it easy to choose what code type should be used to ensure that you can monitor similar types of procedures more efficiently. You normally have a file for specific types of operations anyway, so use the first four letters of the file as the proTYPE.

If you do not mind the extra baggage in you compiled code you may wish to have a global flag, instead of the #ifdef, to determine if ShowPro() should be called. This will still allow a very fast runtime speed and with a special method of enabling the debugger you could always track down a surprise problem without recompiling your “final version”.

She just won’t listen

A sure sign you spend way to much time with your Mac is when you refer to it in the opposite sex.(my wife the Mac) No chauvinism intended! Anyway........the previous method alone was fine for some time until I noticed I was constantly recompiling just to change display times or changing which procedure types I wished to monitor. Thus was born the parser portion of the debugger. This allows you to interactively set (talk to the debugger routines) display time delays or display only certain types of calls in ShowPro() without recompiling. Now the debugging routines will listen to you. Getting better, Huh? You will notice that there are not a lot of commands available but you can easily add more. The primary commands for setting delay times and determining which calls are to be monitored are included along with a command to break into MacsBug and an ExitToShell command.

When ShowPro() receives a message string with the delay set equal to BP_STOP it will invert the debug display and wait for you to tell it what to do. At this time you can use the built in commands to change the ‘TYPE’ code to display only specific types of calls or you can change the time that the message is displayed. If you see a wrong answer ( like a NULL handle that you are about to write to ) you can ExitToShell by entering an ‘e’ or ‘es’.

To get the feeling of how this works choose CommandShowPro from the debug menu. All this does is call ShowPro() with the delay set to BP_STOP and the message string set to “\PMenu directed command”. The debug display is inverted and the computer is waiting on you to type a command. If you hit <return> or <enter> it will continue on, but if you type a command (ST) it will then prompt you to do that operation before continuing on.

Summary listing of available commands:

1) ‘ST<return>’ or ‘st<return>’ will prompt you to enter a 4 character TYPE code that will be used to determine if a message sent to ShowPro() should be displayed. (procedure discipline) Make sure you type the “ ‘ “ preceding 4 char text. [‘SHOW’]

The routine to get your input treats the entered string in the following manner:

$xxxxxxxx = hex entry
#xxxxxxxxxx or xxxxxxxxxx = decimal
‘xxxx = four character TYPE code

2) ‘SD<return>’ will prompt you for a number representing the delay time (seconds) to wait before continuing on. Naturally ‘0’ is the fastest display available.

3) ‘B<return>’ will break into MacsBug for you.

4) ‘E<return>’ or ‘e<return>’ will call ExitToShell() to rudely quit your program. (no saves)

5) <return>,<enter> or <option> will simply tell the debugger to continue on normally.

Note: <xxxx> indicates pressing the key ‘xxxx’.

No memory?

If your memory is as bad as mine it would only make sense to include a method of saving the displays chronologically away to a file so that you could read them when the smoke clears. ShowPro() has all the information necessary, so why not just send this on to MacsBug? Lucky for us, Apple provided us with an outstanding debugger called MacsBug, so lets use it. (By now you may think you should just use MacsBug and forget this all together. NO!!!! )

LogMacsBug() first checks to see if it has been enabled (menu selectable) and if so, passes a command string containing the information on to MacsBug via the stack. The string is received by MacsBug and then interpreted as if you had typed the command from within the debugger. Apple also gave us the capability to DX (display exchange) how MacsBug will react when sent a string via the DebugStr() trap. The DX command in MacsBug toggles the manner in which it deals with $ABFF and $A9FF debugger traps. If DX is ON and you break into MacsBug with either of the two debugger traps, MacsBug will stop and display a window of information about the current stack, register values etc. and then waits for a command to be entered. This allows the user to check memory or set breakpoints before returning to the calling program. If MacsBug receives a break entry with DX OFF, it prints the break information, but without switching the screen display away from your program. Once DX is off, all commands via the debugger traps are ignored (not processed). This presents a problem since you can not send a DX ON command via the DebugStr() once it has been turned off. The only way to turn DX back on is to use the debugger switch provided with your computer (NMI). Maybe Apple will fix this in future releases.

Using the MacsBug “log” function, you can send to a file (or printer) the same text string sent to the screen. By telling MacsBug to begin logging to a file with DX OFF, your messages will be sent (invisible to your program) to a text file for later viewing. A thorough check of your program’s call chain is to log the calls made to a file and then examine the flow for redundancy and order. Invariably you will find routines that are called many times when you thought they were only being called once.

Let’s talk technical to APPLE

The bugsDM() procedure is a somewhat more technical routine that allows you to send an address in memory to MacsBug along with a typecast string. If the typecast template exists in the MacsBug resource file “Debugger Prefs” the information for that memory location will be displayed accordingly. In order to create a template for MacsBug to use, you must add a resource of type ‘mxwt’ to the “Debugger Prefs” file. After adding the resource definitions you must reboot before MacsBug will be able to use them. I generally add an ‘mxwt’ resource for each project I am working on. If you are employing a linked list data structure for a database, or whatever, it is cumbersome to try and find the values at any particular time with MacsBug alone. By having your template installed and defined, you can send the address of the structure and let MacsBug show you all the parameters at any step along the way. Other methods would require a special window and routine to display the information or you could use an elaborate menu driven debugger and double-click you fingers raw.

Provisions of the typecasting feature allows sending pointers as well as the actual address of the variable you wish to examine. The definition in your template will determine if you send a pointer to, or the address of, your variable. For instance: In AddedMenuProc(case of item 4) you will notice the two methods being used. In one instance the address of the global variable BP_Port is sent and in the other case the value of the variable BP_Port is sent. The definition of the GrafPtr template uses the hex address entered as the location in memory that contains the GrafPort structure’s information. The interaction with bugsDM() will definitely test your understanding of pointers.

Is it soup yet?

Once you begin to use these routines you will start to appreciate their usefulness and will wonder why you didn’t do it before now. Ha! Aside from the foundation routines mentioned earlier, the other routines in the listing are pretty straight forward. Some of the utility routines provided may be redundant but in order to keep this package self contained I have included them. Keep in mind that there are no external resources that must be added to your project so try to keep it that way. In doing so you will be able to use this package with any project you wish without worrying about what resources need to be copied over each time. As far as adding structure templates to your “Debugger Prefs” file, you have probably already been doing that. (Oh, right!)

My own version of this package contains many floating point procedures that I borrowed from my Manx Aztec-C development program so I can not freely give them out. I switched over to Think-C when Manx decided to stray from the K&R standards in order to more conveniently interact with MPW. Try to (in’C’) remember when it is ok to pass a pascal string that requires the \P and when to use a string without the \P, even though it is a pascal string. If you think that is confusing, try to program with those rules. Think-C is much easier to maintain in my case, and when they decide to include floating point routines they will, by far, be the best choice. Think-C is very true to K&R definitions of C and with the latest inclusion of prototypes you will be glad you used them.

(author’s opinion)

INSTALLATION

The best way to demonstrate this method of debugging is to add this package to a commonly available project such as MiniEdit which is included in Think-C’s 4.0 release. If you do not have 4.0 the instructions are very similar when adding it to any version of the MiniEdit example.

1) Add [InitBP();] to the end of “SetUpMenus()” procedure in “MiniEdit.c”. This sets up the environment and menus for BP. NOTE: It must follow the routines that set up the menus for MiniEdit!

2) Add to “DoCommand()” of “MiniEdit.c”:

/* 3 */

 case BP_MENU_ID:
 BPMenuChooser( theItem);
 break;

This allows menu interaction with BP.

3) Add [#include “BugParser.h”] to the beginning of

MiniEdit.h so that it is included in all files.

4) Optional. Add #ifdef and ShowPro() to some of the more useful procedures. i.e. the eventLoop and activate procedures.

MiniEdit is such a basic little program that it was chosen only to demonstrate how this package works, for more complex programs you will be amazed at how much debugging time it saves you. It would be interesting to learn how the elite programming professionals handle debugging. Maybe they don’t need to. (HaHa)

When you have reached the point at which you are going to freeze the design and release, you simply comment out the definition of BP_Level in the BugParser.h header file and all is removed.

Cross fingers, YOU ARE READY TO GO

Beauty is in the code of the beholder

When you look at the listing of AddedMenuProc() please do not be too harsh in your judgement. This method was chosen in order to keep the procedure self contained and easier to add items to later without having to remember what other procedure must be changed each time. I keep a file of archived tests that I have tried and can easily add them back in when I find the need.

I used the TestProcedure routine to make timing tests and found that using BlockMove for the CopyString() routine was faster, for strings with a typical length of 15 characters or more than the pStrCopy() routine found in MiniEdit.

Some Hints/Advice

Use #ifdef or #if preprocessor commands often. This allows you to leave in place any test code or additions which will serve as a reminder of what you have tried. Also read up on MacsBug. It is very powerful and allows a great deal of program interaction through the use of DebugStr(). In bugsDM() you can see how to display many different types of structures. The key is to create a template resource for MacsBug so you can display structures specific to your program. Maybe another installation will expand on how to interface with MacsBug on a much greater level.

I found this package’s routines great for understanding how MultiFinder unfriendly one of my earlier programs was. I placed ShowStrStr() in my window activate and update procedures along with a call to GetWTitle() so I could make sure which window was being updated and in what order etc.

I was having a problem with a routine that created a window, read in some data and then calculated the results. It was to calculate only after the WaitNextEvent loop encountered a NULL event (spare time). ShowPro kept informing me that the dataHandle for the window was NULL. Using the ShowStrL() routine in my event loop to display events as they happened, it was easy to see that an idle event came through after the Deactivate but before the next Activate, even though they were back to back. To attack that kind of problem with most debuggers would require a great deal of time to monitor each event, while flashing your window to the front and then the debugger’s etc. etc.

OPTIONAL MACSBUG MODIFICATIONS

Yeah, yeah, always use a copy to try these modifications. If you do not know this by now then you probably do not know how to turn your Mac on.

For version 6.1a4 of MacsBug, search for the following hex string in the DATA FORK, not the resource fork.

487A 002C 4EBA FF68 and replace with

4E71 4E71 4E71 4E71

For version 6.0 search for 487A 0030 4EBA FF62 and replace. If you have some other version you will have to improvise. Search the DATA FORK for the first occurrence of ascii “User break”. Then go back about 48 Bytes and look for 487A 00?? 4EBA FF??. This will most likely be it.

This will remove the unnecessary “User break at blah blah” so that log history files are not filled with redundant information. If you want the text file created by MacsBug to be for QUED then search MacsBug for the ASCII String of “MPS ”(space after S) and change to “QED1” or replace with “KAHL” for Think-C’s editor.

FUTURE

I am currently writing an application that calculates the combination of “linear” cascaded elements to be used for system level design and analysis in the analog world. The combined gain, noise figure, intercept points, compression, and dynamic range is calculated. After that, I plan on writing an external function for ResEdit that will call MacsBug to disassemble various resource types such as INITs,CDEFs etc.

MacTutor had a good article on adding procedures to ResEdit but you needed MPW to create the routines.

Let me know what you would like to see next.

/* LISTING: BugParser.h */
/* include file for BugParser.c, to be “#included”
in each of your project’s files or in an “#include”
file that is called from each file */

#define BP_MENU_ID 777

/*------------ DELAY modes------------*/
#define BP_CONTINUE0L
#define BP_STOP  32L
#define BP_PAUSE 2L

/*------------ DeBug Levels ----------*/
#define BP_Lives TRUE

/***********************************
***USAGE of BP_Lives ***
**************************************************
**************************************************
#ifdef  BP_Lives     ***
ShowPro( BP_CONTINUE,’CODE’,”\P->Procedure()” ) **
#endif      ***
**************************************************
**************************************************/

/* PROTOYPES are always a good idea */
extern Init_BP(void);
extern int BP_Parser( char*,long );
extern ShowPro(long,long,char*);
extern AddedMenuProc( long,int );
extern BPMenuChooser( int );
extern TestProcedure(void);
extern bugsDM( char*,char*,long,char* );
extern int BugInput( char*,char* );
extern SetLong( long*,char* );
extern TE_to_String( char*,TEHandle );
extern OptionWait(void);
extern MakeChrsVisible( char* );
extern int CheckAbort(void);
extern HexString( char*,int,char* );
extern CopyString( char*,char* );
extern ApString( char*,char* );
extern ShowStrL(long,long,char*,long);
extern ShowStrStrL(long,long,char*,char*,long);
extern ShowStrStr( long,long,char*,char* );
extern ShowStrR(long,long,char*,Rect*);
extern ShowStrPnt( long,long,char*,Point );
extern CodeToString( long,char* );
extern ApLongString( char*,long );
extern StringToLong( long*,char* );
extern LogMacsBug( char* );
extern SetBugsFlag(void);
extern SetDisplayRect( long );
extern int CheckOption( int );
/* LISTING: BugParser.c */
/*********FILE_DESCRIPTION****  
Handy debugger file to be added to a project to aid in test and integration. 
 It provides procedures to be called at entry and at exit of each procedure 
so that you can trace the flow during the program.  A MacsBug interface 
also allows logging of any messages sent to these debugging aids and 
display of memory directly.

USAGE:
  You must add [ Init_BP(); ]
 after SetUpMenus to install the menu for BP.
  You must add the following to your programs
  MenuChoice(??) or DoCommand(??) or wherever the 
  program’s menu selection decision is made.
 [ case BP_MENU_ID:]
 [ BPMenuChooser( theItem );]
 [ break; ] */
/*********BP_INTERNAL_GLOBALS ******** */
/*---- TRUE or FALSE */
 static int bp_runStatus;
/*---- level of interrupt */
 static longbp_TYPE;
/*---- delay code for display time */
 static longbp_delay;
/*-  capsLock delay for added display time */
 static longcap_delay;
/*---- TRUE to log */
 static int logEnabled;
/*---- TRUE to show*/
 static int showEnabled;
/*---- TRUE is so*/
 static int MacsBugExists;
/*---- Rect where to display*/
 static RectBPdisplayRect;
/*---- port for interfacing */
 static GrafPtr  BP_Port;
/*---- TextEdit handle for BP intfc*/
 static TEHandle BP_TEH;
/*---- set when menu is installed  */
 static MenuHandle BP_menuHndl = 0L;
/*---- to test for MacsBug*/
 extern longMacJumpGlobal : 0x0120;

/*********DEFINITIONS/INCLUDE ******** */
#define in_main_BP TRUE
#include “MiniEdit.h”
/* “#include” must follow #define of in_main_BP */
/* When using program specific structures you may
want to include program specific include files here */
/*----KEY_MAP_DEFINITIONS----*/
#define BP_CommandKey48L
#define BP_OptionKey 61L
#define BP_CapsLockKey  62L
#define BP_ShiftKey63L

/*********EXTERNAL_GLOBALS********
Fill in with externals as needed to let 
BP know types and global values */
extern  TEHandle TEH;

/*----  Init_BP(void)----*/
/************************************************
usage: called from SetUpMenus() to set up the debugger’s menus and environment 
variables etc.
************************************************/
Init_BP()
{
intmenuItem;
GrafPtr orig_port;
Rect  dr,vr;

 /* Set up the Debug Menu */
 BP_menuHndl = NewMenu( BP_MENU_ID,”\PBP” );
 InsertMenu( BP_menuHndl,0 );
 AppendMenu( BP_menuHndl,
 “\PlogEnable” );/* 1 */
 AppendMenu( BP_menuHndl,
 “\PshowEnable” ); /* 2 */
 AppendMenu( BP_menuHndl,
 “\PBP_in_MENU” ); /* 3 */
 AppendMenu( BP_menuHndl,
 “\PBP_in_TITLEBAR” );    /* 4 */
 AppendMenu( BP_menuHndl,
 “\PBP_in_ScrnBOTTOM” );  /* 5 */
 AppendMenu( BP_menuHndl,
 “\PMacsBugExists” );/* 6 */
 AppendMenu( BP_menuHndl,
 “\PEngage Parser[ ]” );  /* 7 */
 AppendMenu( BP_menuHndl,
 “\PTestProcedure[ ]” );  /* 8 */
 AppendMenu( BP_menuHndl,
 “\P(-” );/* 9 */
 DrawMenuBar();

 /* set up a method for interface  */
 BP_Port = (GrafPtr )
 NewPtr( (long )sizeof(GrafPort) );
 if( BP_Port )
 {
 /* save the original port*/
 orig_port = thePort;
 /* set up interface port */
 OpenPort( BP_Port );
 /* set font to monaco    */
 TextFont( 4 );
 TextSize( 9 );
 /* Rect set to bottom  */
 SetDisplayRect( ‘BOTM’ );
 vr = BPdisplayRect;
 dr = BPdisplayRect;
 /* adjust visible rect */
 InsetRect( &vr,1,1 );
 InsetRect( &dr,2,2 );  dr.left += 4;
 BP_TEH = TENew( &dr,&vr ); 
 if( BP_TEH == 0L )
 DebugStr(“\PNULL BP_TEH [exit]” );
 /* set back to original  */
 SetPort( orig_port );
 }
 else
 DebugStr(“\Pno memory for BP_Port [exit]”);
 SetBugsFlag();
 logEnabled = FALSE;
 showEnabled= TRUE;
 bp_runStatus = TRUE;
 /* set no delay initially */
 bp_delay = 0L;
 /* capsLock == 2 seconds initially */
 cap_delay = 2L;
 /* ‘SHOW’ = do not censor any */
 bp_TYPE = ‘SHOW’;
 /* update checkmarks for menuItems */
 if( logEnabled )
 { CheckItem( BP_menuHndl,1,TRUE );}
 else
 { CheckItem( BP_menuHndl,1,FALSE ); }
 if( showEnabled )
 { CheckItem( BP_menuHndl,2,TRUE );}
 else
 { CheckItem( BP_menuHndl,2,FALSE ); }
 if( MacsBugExists )
 { CheckItem( BP_menuHndl,6,TRUE );}
 else
 { CheckItem( BP_menuHndl,6,FALSE ); }

 /* install extra menu items after all set-up */
 AddedMenuProc( ‘INIT’,10 );
}

/*----  int BP_Parser( char*,long )----*/
/*************************************************
usage: msg is the string passed to ShowPro().  If proTYPE is ‘STOP’, 
then BP_Parser() will read the msg as a command to set levels, pause 
time etc.  If the command is invalid it will return 0 = FALSE. Available 
Commands: ST,SD,B,E - it then prompts for the new value
*************************************************/
intBP_Parser( msg,proTYPE )
char  *msg;
long  proTYPE;
{
long    numLong;
intrtn,indx,dotindx;
char    cmdStr[255],numStr[255],str[255],*mymsg;

 rtn = FALSE;

/* Get command input from user */
 if( proTYPE == ‘STOP’ )
 { 
 if( !BugInput( msg,cmdStr ) )
 return( FALSE );
 }

/* crude parser to interpret the command */
 switch( cmdStr[1] )
 {
 case ‘b’:case ‘B’:/* break to MacsBug */
 DebugStr(“\PCommand Parser came here.”);
 rtn = TRUE;
 break;
 case ‘s’:case ‘S’:/* set */
 switch( cmdStr[2] )
 {
 /* ST=set type of interupts->’XXXX’ */
 case ‘t’:case ‘T’:
 SetLong( &bp_TYPE,”\Pbp_TYPE” );
 break;
 case ‘d’:case ‘D’:
 /* SD = Set delay time of display */
 SetLong( &bp_delay,
 “\Pbp_delay(seconds)” );
 /*verify if longer that 10 seconds*/
 if(  bp_delay > 10L && 
 bp_delay < BP_STOP )
 ShowPro( BP_STOP,’SHOW’,
 “\PAre you sure? Thats a long time!” );
 break;
 default:
 break;
 }
 rtn = TRUE;
 break;
 case ‘e’:case ‘E’:/* exit */
 ExitToShell();
 break;
 default: rtn = FALSE;  break;
 }
 return( rtn );
}
/* #define BLINDTEST_ON TRUE */
/* remove comment around above to only update the display when the information 
changes, also remove comments around the matching #endif in ShowPro()*/
/*----  ShowPro(long,long,char*) ----*/
/*************************************************
usage:[->entry <-exit DEVELOP A STANDARD]
#ifdef BP_Lives
ShowPro( BP_STOP,’XXXX’,”\P->ProcedureName()” );
#endif
set ‘XXXX’ to a 4 char code to be used to determine if the call should 
be intercepted.  Place above code at the begining and end of every procedure
 to monitor program flow continuously.  You may wish to call   ShowStrL() 
instead to monitor parameters passed such as eventMessages or ShowStrPnt() 
to determine the mouse coordinates used in deciding PtInRect()  etc.
**************************************************
NOTE: proTYPE == ‘SHOW’ is reserved
DO NOT use register variables since it is recursive
*************************************************/
ShowPro( wait,proTYPE,msg )
long  wait;
long  proTYPE;
char  *msg;
{
static  charoldStr[255];
long    ignore,trickKeys[4];
char    str[255];
GrafPtr orig_Port;
Boolean cmnd_Keydn,opt_Keydn;
Boolean shift_Keydn,capslock_Keydn;

 /* make sure InitBP() has been called */
 if( BP_menuHndl == 0L )  return;
/* even if showEnabled is off you should still show anyway if wait == 
STOP or if bp_delay == STOP used to display errors sent via BP_STOP */
 if( !showEnabled && proTYPE != ‘SHOW’ )
 {
 if( wait < BP_STOP && bp_delay < BP_STOP )              return;
 }
 else/* check proTYPE for match */
 if( bp_TYPE != ‘SHOW’)
 if(  proTYPE != bp_TYPE && proTYPE != ‘SHOW’ )
 return;
 /* Handle trick keys early */
 GetKeys( trickKeys );
 cmnd_Keydn = BitTst(trickKeys,BP_CommandKey );
 opt_Keydn= BitTst(trickKeys,BP_OptionKey );
 shift_Keydn= BitTst(trickKeys,BP_ShiftKey );
 capslock_Keydn=
 BitTst( trickKeys,BP_CapsLockKey );

/* check for KEY NOSHOW COMBINATION */
 if( cmnd_Keydn && !opt_Keydn && !shift_Keydn )
 if( wait < BP_STOP )return;

/* check for KEY STOP COMBINATION */
 if( cmnd_Keydn && opt_Keydn && shift_Keydn )
 wait = BP_STOP;

 /* save original setup */
 orig_Port = thePort;
 SetPort( BP_Port );

#ifdef  BLINDTEST_ON
 /* only if msg is different from last */
 if( IUCompString( msg,oldStr ) || 
 wait == BP_STOP )
 {
 CopyString( oldStr,msg );
#endif

 if( logEnabled )LogMacsBug( msg );
 /* make a copy before modifying it*/
 CopyString( str,msg );
 /* convert invisible characters to visible */
 MakeChrsVisible( str );
 if( wait >= BP_STOP || bp_delay >= BP_STOP )
 /* allow command entry */
 ignore = (int )BP_Parser( str,’STOP’ );
 else   /* just display the msg */
 {
 FrameRect( &BPdisplayRect );
 TESetSelect( 0L,32767L,BP_TEH );
 TEDelete( BP_TEH );
 TEInsert( &str[1],(long )str[0],BP_TEH );
 }
 SetPort( orig_Port );
#ifdef  BLINDTEST_ON
 }
#endif

 /* delay returning according to bp_delay */
 if( wait < BP_STOP && bp_delay < BP_STOP )
 Delay( (wait + bp_delay) * 60L,&ignore );

/* if caps lock was down upon entry then slow down the display time even 
more than usual */
 if( capslock_Keydn )
 Delay( cap_delay * 60L,&ignore );
}

/*----  AddedMenuProc( long,int )  ----*/
/*************************************************
usage: Installs added menus if code == ‘INIT’ starting with theItem.
If code == ‘MENU’ then do theItem function.
*************************************************/
AddedMenuProc( code,theItem )
register long  code;
inttheItem;
{
static  int firstItem;
intlastItem,indx;
char    str[255];
WindowPeektwp;
long    keys[4],oldKeys[4];
EventRecord er;
#ifdef BP_Lives
ShowStrL( BP_CONTINUE,’MENU’,
 “\P->AddedMenuProc(item->)”,(long )theItem );
#endif

 /* save away the first item for adjustment */
 if( code == ‘INIT’ )firstItem = theItem;
 theItem -= firstItem;
 lastItem = FALSE;
 do {
 switch( ++theItem )
 {
 case 1:if( code == ‘INIT’ )/* key test */
 AppendMenu( BP_menuHndl,”\Pkey TEST” );
 else
 {
 while( !Button() )
 {
 if( GetNextEvent( 
 autoKeyMask + keyDownMask,&er ) )
 /* through away the event */ ;
 GetKeys( keys );
 for( indx = 0;indx < 4;indx++ )
 if( keys[indx] != oldKeys[indx] )
 {
 oldKeys[indx] = keys[indx];
 HexString( (char *)keys,16,str );
 oldKeys[indx] = keys[indx];
 /* remember cmd-key will not show */
 ShowStrStr( BP_CONTINUE,’SHOW’,
 “\P[Button exits]  keyMap->”,str );
 }
 }
 }
 break;
 case 2:if( code == ‘INIT’ )
 /* window lister */
 AppendMenu( BP_menuHndl,”\PwindowLister” );
 else
 {
 twp = (WindowPeek )FrontWindow();
 while( twp )
 {
 GetWTitle( twp,str );
 ShowStrStr( BP_STOP,’SHOW’, “\Ptitle ->”,str );
 twp = (WindowPeek )twp->nextWindow;
 }
 }
 break;
 case 3:if(code ==’INIT’)/* bugs window */
 AppendMenu(BP_menuHndl,”\PBugs Window”);
 else
 {/* invoke MacsBug to show windowData*/
 DebugStr(“\P;dm (a5^^ + 98)^^ windowData”);
 /*where windowData template must be
 defined in “Debugger Prefs” file  */
 }
 break;
 case 4:if( code == ‘INIT’ )
 /* bugsDM tests */
 AppendMenu( BP_menuHndl,”\PbugsDM Tests” );
 else
 {
 CopyString(str,
 “\PPascal array of chrs.” );
 bugsDM( “\Ptest of string[] display”,
 (char *)str,’TYPE’,”\PpString” );
 bugsDM( “\Ptest of pString display”,
 “\PPascal_TestString”,’TYPE’,”\PpString” );
 bugsDM( “\Ptest of cString display”,
 “C_TestString”,’TYPE’,”\PcString” );
 bugsDM( “\Ptest of port grafPtr”,
 (char *)BP_Port,’TYPE’,”\PGrafPort” );
 bugsDM( “\Ptest of port &grafPtr”,
 (char *)&BP_Port,’PTR ‘,”\PGrafPort” );
 }
 break;
 default: lastItem = TRUE;break;
 }
 } while( code == ‘INIT’ && !lastItem );

#ifdef BP_Lives
ShowPro( BP_CONTINUE,’MENU’,
 “\P<-AddedMenuProc()” );
#endif
}

/*----  BPMenuChooser( int )----*/
/*************************************************
usage: is passed an int containing theItem.
*************************************************/
BPMenuChooser( theItem )
inttheItem;
{
char  str[255],tstr[255];
#ifdef BP_Lives
ShowStrL( BP_CONTINUE,’MENU’,
 “\P->BPMenuChooser(theItem->)”,(long )theItem );
#endif

 switch( theItem )
 {
 case 1:/*__________logEnable_____________*/
 if( logEnabled )
 {
 logEnabled = FALSE;
 DebugStr( “\P;log” );
 ShowPro(BP_STOP,’SHOW’,
“\PYou must go into MacsBug and type log;dx;g” );
 CheckItem( BP_menuHndl,theItem,FALSE );
 }
 else
 {
 logEnabled = TRUE;
 CopyString( str,”\P;dx;log “ );
 if( !BugInput(
 “\PEnter name for LOG File”,tstr ))
 return;
 ApString( str,tstr );
 ApString( str,”\P;g” );
 DebugStr( str );
 CheckItem( BP_menuHndl,theItem,TRUE );
 }
 break;
 case 2:/*__________showEnable____________*/
 if( showEnabled )
 { showEnabled = FALSE;
 CheckItem( BP_menuHndl,theItem,FALSE ); }
 else
 { showEnabled = TRUE;
 CheckItem( BP_menuHndl,theItem,TRUE ); }
 break;
 case 3:/*__________BP_in_MENU____________*/
 SetDisplayRect( ‘MENU’ );
 break;
 case 4:/*__________BP_in_TITLEBAR________*/
 SetDisplayRect( ‘TITL’ );
 break;
 case 5:/*__________BP_in_ScrnBOTTOM______*/
 SetDisplayRect( ‘BOTM’ );
 break;
 case 6:/*__________MacsBugExists_________*/
 break;
 case 7:/*__________CommandShowPro________*/
 ShowPro( BP_STOP,’SHOW’,
 “\PMenu directed command” );
 break;
 case 8:/*__________TestProcedure_________*/
 TestProcedure();
 break;
 case 9:/*__________----------------______*/
 break;
 default: AddedMenuProc( ‘MENU’,theItem ); break;
 }
#ifdef BP_Lives
ShowPro( BP_CONTINUE,’MENU’,”\P<-BPMenuChooser” );
#endif
}

/*----  TestProcedure(void) ----*/
/*************************************************
usage: For testing of knew unkown functions.
*************************************************/
TestProcedure()
{
Point   pnt;
Rect    r;
WindowPeekfWindow;
long    num,strtTime;
intindx;
char    str[255];

 if(!BugInput( “\PEnter ## to run.(1,2,3, etc)”,str))
 return;

 StringToNum( str,&num );
 indx = (int )num;

 switch( indx )
 {
 case 1:/* Demo ShowStrPnt() */
 ShowPro( BP_STOP,’TEST’,
 “\PDemo of ShowStrPnt()” );
 GetMouse( &pnt );
 ShowStrPnt( BP_STOP,’TEST’,
 “\Plocal mouseLocation ->”,pnt );
 break;
 case 2:/* Demo ShowStrR() */
 ShowPro( BP_STOP,’TEST’,
 “\PDemo of ShowStrR()” );
 fWindow = (WindowPeek )FrontWindow();
 if( fWindow )
 {
 r = (*fWindow->strucRgn)->rgnBBox;
 ShowStrR( BP_STOP,’TEST’,
 “\PFrontWindows strucRect ->”,&r );
 }
 else
 ShowPro( BP_STOP,’TEST’,
 “\PSorry, NULL FrontWindow()” );
 break;
 case 3:/* Demo ShowStrStr() */
 ShowPro( BP_STOP,’TEST’,
 “\PDemo of ShowStrStr()” );
 ShowStrStr( BP_STOP,’TEST’,
 “\PString #1 followed by”,”\PString#2" );
 break;
 case 4:/* Demo HexString() */
 ShowPro( BP_STOP,’TEST’,
 “\PDemo of HexString()” );
 HexString( &str[1], 8 /* Bytes */, str );
 ShowStrStr(BP_STOP,’TEST’,
 “\Phex dump of str[]”,str );
 break;
 case 5:/* Demo port advantage */
 MoveTo( 10,10 );
 for(indx=0;indx<40;indx++)
 {
 Line( 2,2 );
 ShowPro(NULL,’TEST’,
 “\Pdid the pen move?” );
 }
 break;
 case 6:/* Demo time test */
 /* timing test for ShowPro() */
 strtTime = TickCount();
 for(indx=0;indx<200;indx++)
 {
 ShowPro(NULL,’TEST’,
 “\P25 characters.xxxxxxxxxxx” );
 ShowPro(NULL,’TEST’,
 “\P25 characters:xxxxxxxxxxx” );
 }
 strtTime = TickCount() - strtTime;
 ShowStrL(BP_STOP,’TEST’,
 “\P1/60ths ->”,strtTime );
 break;
 case 7:
 break;
 default: break;
 }

#ifdef BP_Lives
ShowPro( BP_CONTINUE,’TEST’,
 “\P<-TestProcedure” );
#endif
}

/*----  bugsDM( char*,char*,long,char* )     ----*/
/*************************************************
usage: Sent a pointer and the type bugsDM sends the info to MacsBug for 
a lower level display
*************************************************/
bugsDM( msg,pntr,code,type )
char  *msg;
char  *pntr;
long  code;
char  *type;
{
char  str[255],hexStr[65],*typeCast;

 /* return if no MacsBug */
 if( !MacsBugExists )return;

/* place the command in str */
 CopyString( str,”\P;dm “ );

/* convert address to ascii */
 HexString( (char *)&pntr,4L,hexStr );
/* pointers need the ‘@’(indirection) */
 if( code == ‘PTR ‘ )
 str[++str[0]] = 64;
 /* @ character + offset */
 ApString( str,hexStr );
 if( code == ‘STAK’ )
 CopyString( str,”\P;dm A6 Stack” );
 else
 ApString( str,type );
 LogMacsBug( msg );
 LogMacsBug( str );
}

/*----  BugParser.c UTILITY PROCEDURES ----*/
/*************************************************
usage: some duplicated procedures just to ensure they exist
*************************************************/

/*----  int BugInput( char*,char* )----*/
/*************************************************
usage: returns the entered command line in str
NOTE: storage must be allocated by the caller
XXX DO NOT USE ShowPro() IN HERE XXX
*************************************************/
int BugInput( msg,str )
char  *msg,*str;
{
EventRecord BPEvent;
GrafPtr orig_Port;
long    cmdLength;
intlineFeed,keyHit,optionFlag;
char    eventChar;

 orig_Port = thePort;/* save original */
 SetPort( BP_Port );
 FrameRect( &BPdisplayRect );
 TEActivate( BP_TEH );
 TESetSelect( 0L,32767L,BP_TEH );
 TEDelete( BP_TEH );
 TEInsert( &msg[1],(long )msg[0],BP_TEH );
 TESetSelect( 0L,32767L,BP_TEH );
 SysBeep(1);
 keyHit = 0;
 optionFlag = FALSE;
 lineFeed = FALSE;
 do {
 if(GetNextEvent(keyDownMask + 
 autoKeyMask,&BPEvent))
 {
 eventChar = 
 (char )( BPEvent.message & 
 charCodeMask );
 if( eventChar==0x0D || eventChar==0x03 )
 lineFeed = TRUE;
 else
 {
 /* keep track of chars entered */
 if(eventChar != 8) keyHit = TRUE;
 TEKey( eventChar,BP_TEH );
 }
 }
 TEIdle( BP_TEH );
 optionFlag = 
 CheckOption((BPEvent.modifiers & optionKey) );
 if( optionFlag && Button() )
 ExitToShell();
 } while( !lineFeed && !optionFlag );

/* Extract the string for command interpretation */
 TE_to_String( str,BP_TEH );
 TEDeactivate( BP_TEH );
 TESetSelect( 0L,32767L,BP_TEH );
 SetPort( orig_Port );
 return( keyHit );
}

/*----  SetLong( long*,char* )----*/
/*************************************************
usage: uses BugInput() to interactively set a long number
*************************************************/
SetLong( theLong,msg )
long  *theLong;
char  *msg;
{
char  str[255],tstr[7],numStr[255];

 CopyString( str,”\PChange current val of “ );
 ApString( str,msg );
 ApString( str,”\P from “ );
 ApLongString( str,*theLong );
 MakeChrsVisible( str );
 if( BugInput( str,str ) )
 StringToLong( theLong,str );
 CopyString( str,msg );
 ApString( str,”\P is now “ );
 ApLongString( str,*theLong );
 ShowPro( BP_STOP,’SHOW’,str );
}

/*----  TE_to_String( char*,TEHandle ) ----*/
/*************************************************
usage: Extract TE chars and copy to str.
*************************************************/
TE_to_String( str,TEH )
char    *str;
TEHandleTEH;
{
long    cmdLength;
Handle  TEText;

 /* get the length of entered text */
 cmdLength = (*TEH)->teLength;
 /* make sure not to overwrite str’s storage */
 if( cmdLength >= 255 ) cmdLength = 254;
 TEText = (*TEH)->hText;
 HLock( TEText );
 BlockMove(*TEText,&str[1],cmdLength);
 str[0] = cmdLength;
 HUnlock( TEText );
}

/*----  OptionWait() ----*/
/************************************************
usage:  Wait till optionKey is pressed but make sure it is not still 
down from a previous check
************************************************/
OptionWait()
{
long  trickKeys[4];

 InvertRect( &BPdisplayRect );
 SysBeep(1);

 do {
 GetKeys( trickKeys );
 TEIdle( BP_TEH );
 } while( !CheckOption( (int )
 BitTst( trickKeys,BP_OptionKey ) ) );

 /* if mouse was down when pressed then exit */
 if( Button() )  ExitToShell();

 /* re-invert the rect and go home */
 InvertRect( &BPdisplayRect );
}

/*----  MakeChrsVisible( char* ) ----*/
/*************************************************
usage: converts nonvisible chars to visible representations
use ‘_’ for a real space to be displayed blank
*************************************************/
MakeChrsVisible( str )
register char  *str;
{
register intindx;
register char  chr;

 for( indx = 1; indx <= str[0]; indx++ )
 {
 chr = str[indx];
 /* invisible + options default */
 if( chr < 32 )  str[indx] = ‘º’;
 if( chr > 126 ) str[indx] = ‘ª’;
 /* SPACE */
 if( chr == 32 ) str[indx] = ‘ ’;
 /* _ becomes spc */
 if( chr == 95 ) str[indx] = ‘ ‘;
 /* RETURN */
 if( chr == 13 ) str[indx] = ‘®’;
 /* TAB */
 if( chr == 9 )  str[indx] = ‘Ý’;
 /* ENTER */
 if( chr == 3 )  str[indx] = ‘ ’;
 /* infinity is an option but accept it */
 if( chr == ‘ ’ ) str[indx] = ‘ ’;
 }
}

/*----  int CheckAbort()  ----*/
/*************************************************
usage: scans the low-level event queue for Cmd-’.’
Each is removed  when found. Return zero if none.  Source found in MacTutor
*************************************************/
intCheckAbort()
{
EvQElPtreq_p;
intfound;
QHdrPtr qhp;

 found = 0;
 qhp = GetEvQHdr();
 eq_p = (EvQElPtr )qhp->qHead;
 while(TRUE)/* loop till break */
 {
 if( ((eq_p->evtQWhat == keyDown) ||
 (eq_p->evtQWhat == autoKey)) &&
 (eq_p->evtQModifiers & cmdKey) &&
 (eq_p->evtQMessage & charCodeMask) == ‘.’ )
 {
 /* remove the event from the queue */
 Dequeue( (QElemPtr )eq_p, qhp );
 found = 1;
 }
 /* test for end of queue */
 if( eq_p == (EvQElPtr )qhp->qTail)break;
 /* only escape here */

 /* continue with next queue entry */
 eq_p = (EvQElPtr )(eq_p->qLink);
 }
 return( found );
}

/*----  HexString( char*,int,char* ) ----*/
/*************************************************
usage: returns an ascii string representing buffer’s hex
*************************************************/
HexString( buffer,length,str )
register char  *buffer;
intlength;
register char  *str;
{
intindx,cindx,lownib,highnib,brk;
register char  *hexit;

 if( length > 112 )length = 112;
/* 112 (252 chars) is used since there will be spaces added and we are 
allowed only 255 char storage
*/
 hexit = “0123456789ABCDEF”;
 cindx = 0; brk = 0;
 for( indx = 0; indx < length; indx++ )
 {
 lownib =0x000F & (buffer[indx] &0x0F);
 highnib=0x000F & ((buffer[indx] &0xF0) >> 4);
 str[ ++cindx ] = hexit[highnib];
 str[ ++cindx ] = hexit[lownib];
 /* ########_########_######## format */
 if( (cindx - brk) >= 8 && indx <= length)
 { str[ ++cindx ] = ‘ ‘;  brk = cindx; }
 }
 str[0] = cindx;
}

/*----  CopyString( char*,char* )  ----*/
/*************************************************
usage: srcStr replaces destStr (makes a copy)
NOTE: destStr must have 255 Bytes available for storage
*************************************************/
CopyString( destStr,srcStr )
register char  *destStr,*srcStr;
{
register intindx;

if( srcStr[0] > 254 )srcStr[0] = 254;
BlockMove(srcStr,destStr,(long )(srcStr[0] + 1) );
}

/*----  ApString( char*,char* )  ----*/
/*************************************************
usage: endStr is appended to strtStr
NOTE: strtStr must have 255 Bytes available for safety
*************************************************/
ApString( strtStr,endStr )
register char  *strtStr,*endStr;
{
register inti;

 if( ( strtStr[0] + endStr[0] ) < 254 )
 {
 BlockMove(
 &endStr[1],&strtStr[strtStr[0]+1],
 (long )endStr[0] );
 strtStr[0] += endStr[0];
 }
 else
 CopyString( strtStr,
 “\Pillegal ApString() length” );
}

/*----  ShowStrL(long,long,char*,long) ----*/
/*************************************************
usage: Use ShowPro() to display a long in decimal and hex
*************************************************/
ShowStrL(wait,proTYPE,str,num)
long  wait;
long  proTYPE;
char  *str;
long  num;
{
char  newStr[256],numStr[256];

 CopyString( newStr,str );
 ApLongString( newStr,num );
 ShowPro( wait,proTYPE,newStr );
}

/*--ShowStrStrL(long,long,char*,char*,long)--*/
/*************************************************
usage: Use ShowPro() to display two msgs and a long (d,h)
*************************************************/
ShowStrStrL(wait,proTYPE,str1,str2,num)
long  wait;
long  proTYPE;
char  *str1;
char  *str2;
long  num;
{
char  newStr[256],numStr[256];

 CopyString( newStr,str1 );
 ApString( newStr,str2 );
 ApLongString( newStr,num );
 ShowPro( wait,proTYPE,newStr );
}

/*----  ShowStrStr( long,long,char*,char* )  ----*/
/*************************************************
usage: Use ShowPro() to display to msg strings
*************************************************/
ShowStrStr( wait,proTYPE,str1,str2 )
long  wait;
long  proTYPE;
char  *str1;
char  *str2;
{
char  localStr[256];

 CopyString( localStr,str1 );/* make a copy */
 ApString( localStr,”\P_” );
 /* add a seperator */
 ApString( localStr,str2 );
 ShowPro( wait,proTYPE,localStr );
}

/*----  ShowStrR(long,long,char*,Rect*)----*/
/*************************************************
usage: Use ShowPro() to display a msg and Rect coordinates
*************************************************/
ShowStrR(wait,proTYPE,str,r)
long  wait;
long  proTYPE;
char  *str;
Rect  *r;
{
char  newStr[256],numStr[256];

 CopyString( newStr,str );
 ApString( newStr,”\P_t.” );
 NumToString( (long)r->top,numStr );
 ApString( newStr,numStr );
 ApString( newStr,”\P,_l.” );
 NumToString( (long)r->left,numStr );
 ApString( newStr,numStr );
 ApString( newStr,”\P,_b.” );
 NumToString( (long)r->bottom,numStr );
 ApString( newStr,numStr );
 ApString( newStr,”\P,_r.” );
 NumToString( (long)r->right,numStr );
 ApString( newStr,numStr );
 ShowPro( wait,proTYPE,newStr );
}

/*----  ShowStrPnt( long,long,char*,Point )  ----*/
/*************************************************
usage: Use ShowPro() to display msg and Point coordinates
*************************************************/
ShowStrPnt( wait,proTYPE,str,pnt )
long  wait;
long  proTYPE;
char  *str;
Point pnt;
{
char  newStr[255],numStr[255];

 CopyString( newStr,str );
 ApString( newStr,”\P_x =_” );
 NumToString( (long )pnt.h,numStr );
 ApString( newStr, numStr );
 ApString( newStr,”\P,_y =_” );
 NumToString( (long )pnt.v,numStr );
 ApString( newStr, numStr );

 ShowPro( wait,proTYPE,newStr );
}

/*----  CodeToString( long,char* ) ----*/
/*************************************************
usage: Convert long ‘TYPE’ to string in brackets
*************************************************/
CodeToString( code,str )
long  code;
char  *str;
{
 str[0] = 6;
 str[1] = ‘[‘;
 *(long *)(&str[2] ) = code;
 str[6] = ‘]’;
}

/*----  ApLongString( char*,long ) ----*/
/*************************************************
usage: Append long decimal,hex,char to str
*************************************************/
ApLongString( str,theLong )
char  *str;
long  theLong;
{
char  tstr[255];

 ApString( str,”\P_#” );
 NumToString( theLong,tstr );
 ApString( str,tstr );
 ApString( str,”\P_$” );
 HexString( (char *)&theLong,4,tstr );
 ApString( str,tstr );
 CodeToString( theLong,tstr );
 ApString( str,tstr );
}

/*----  StringToLong( long*,char* )----*/
/*************************************************
usage: Convert string to long value using typecasts #,$,’’
*************************************************/
StringToLong( code,str )
long  *code;
char  *str;
{
intindx;
char  chr,nibble;

 switch( str[1] )
 {
 case ‘$’:
 *code = 0L;
 if( str[0] > 9 )str[0] = 9;
 for( indx = 2;indx <= str[0]; indx++ )
 {
 chr = str[indx];
 if( chr >= ‘a’ && chr <= ‘f’ )
 nibble = chr - ‘a’ + 10;
 else if(chr >= ‘A’ && chr <= ‘F’)
 nibble = chr - ‘A’ + 10;
 else if(chr >= ‘0’ && chr <= ‘9’)
 nibble = chr - ‘0’;
 else break;
 *code = (*code << 4);
 *code |= nibble;
 }
 break;
 case 39: /* single quote */
 BlockMove( &str[2],code,4L );
 break;
 case 35: /* # */
 /* space so StringToNum() works right */
 str[1] = 32;  
 default: /* decimal default */
 StringToNum( str,code );
 break;
 }
}

/*----  LogMacsBug( char* ) ----*/
/*************************************************
usage: logEnabled will have set MacsBug up for logging
*************************************************/
LogMacsBug( str )
char  *str;
{
 if( MacsBugExists ) DebugStr( str );
}

/*----  SetBugsFlag(void) ----*/
/*************************************************
usage: sets the global MacsBugExists according to MacsBug
*************************************************/
SetBugsFlag()
{
/* bit  = debugger is running 
 bit 6= debugger can handle system errors
 bit 5= debugger is installed
 bit 4= debugger can support discipline utility 
*/
 MacsBugExists = FALSE; /* default is no */
 if( MacJumpGlobal & 0x40000000 )/* bit 6 */
 if( MacJumpGlobal & 0x20000000 )/* bit 5 */
 MacsBugExists = TRUE;
}

/*----  SetDisplayRect( long )----*/
/*************************************************
usage: set global BPDisplayRect according to code
*************************************************/
SetDisplayRect( code )
long  code;
{
Rect  dr,vr;

 BPdisplayRect = screenBits.bounds;
 switch( code )
 {
 case ‘MENU’:
 BPdisplayRect = screenBits.bounds;
 /* offset from the edge */
 BPdisplayRect.left += 10;
 /* leave room for text */
 BPdisplayRect.bottom = 
 BPdisplayRect.top + 15;
 /* don’t need it all ( bigScrns ) */
 BPdisplayRect.right = 
 BPdisplayRect.left + 500;
 CheckItem( BP_menuHndl,3,TRUE );
 CheckItem( BP_menuHndl,4,FALSE );
 CheckItem( BP_menuHndl,5,FALSE );
 break;
 case ‘TITL’:
 /*To set the display rect to the title
 bar of a window, the rect would
 need to be set for each call since
 the window could have moved.  The
 procedures ShowPro(),BugInput()
 would need to call 
 SetDisplayRect() upon entry.Or you
 could add to your MoveWindow()
 handling the same call to do it
 only when a window moves.  This
 does not permit BugParser.c
 to be as portable so I left it out
 and default to the bottom. */
 case ‘BOTM’:
 default:
 /* offset from the edge */
 BPdisplayRect.left += 10;
 /* leave room for text */
 BPdisplayRect.top = 
 BPdisplayRect.bottom - 15;
 /* don’t need it all (bigScrns) */
 BPdisplayRect.right = 
 BPdisplayRect.left + 500;
 CheckItem( BP_menuHndl,5,TRUE );
 CheckItem( BP_menuHndl,3,FALSE );
 CheckItem( BP_menuHndl,4,FALSE );
 CheckItem( BP_menuHndl,5,TRUE );
 break;
 }
 if( BP_TEH )  /* adjust TEdit rects */
 {
 vr = BPdisplayRect;
 dr = BPdisplayRect;
 /* adjust visible rect */
 InsetRect( &vr,1,1 );
 InsetRect( &dr,2,2 );  dr.left += 4;
 (*BP_TEH)->destRect = dr;
 (*BP_TEH)->viewRect = vr;
 }
 DrawMenuBar();  /* in case menu is unchosen */
}

/*----  int CheckOption( int )----*/
/*************************************************
usage: Returns true when optionKey changes last state
*************************************************/
int CheckOption( current )
intcurrent;
{
static  oldFlag;

 if( !current )
 { oldFlag = FALSE;return( FALSE );}

 if( !oldFlag )
 { oldFlag = TRUE; return( TRUE ); }
 else
 return( FALSE );
}

 
AAPL
$116.47
Apple Inc.
+0.16
MSFT
$47.98
Microsoft Corpora
-0.72
GOOG
$537.50
Google Inc.
+2.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

Cobook 3.0.7 - Intelligent address book....
Cobook Contacts is an intuitive, engaging address book. Solve the problem of contact management with Cobook Contacts and its simple interface and powerful syncing and integration possibilities.... Read more
StatsBar 1.9 - Monitor system processes...
StatsBar gives you a comprehensive and detailed analysis of the following areas of your Mac: CPU usage Memory usage Disk usage Network and bandwidth usage Battery power and health (MacBooks only)... Read more
Cyberduck 4.6 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Evernote 6.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 2.11 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital... Read more
Herald 5.0.1 - Notification plugin for M...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), and 4.0.8 (for OS X 10.9) are no longer supported by the developer. Herald is a notification plugin for Mail.app, Apple's Mac OS X email... Read more
Firetask 3.7 - Innovative task managemen...
Firetask uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask's "Today" view shows all relevant... Read more
TechTool Pro 7.0.6 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PhotoDesk 3.0.1 - Instagram client for p...
PhotoDesk lets you view, like, comment, and download Instagram pictures/videos! (NO Uploads! / Image Posting! Instagram forbids that! AND you *need* an *existing* Instagram account). But you can do... Read more

Latest Forum Discussions

See All

Ubisoft Gives Everyone Two New Ways to E...
Ubisoft Gives Everyone Two New Ways to Earn In-Game Stuff for Far Cry 4 Posted by Jessica Fisher on November 21st, 2014 [ permalink ] | Read more »
Golfinity – Tips, Tricks, Strategies, an...
Dig this: Would you like to know what we thought of being an infinite golfer? Check out our Golfinity review! Golfinity offers unlimited ways to test your skills at golf. Here are a few ways to make sure your score doesn’t get too high and your... | Read more »
Dark Hearts, The Sequel to Haunting Meli...
Dark Hearts, The Sequel to Haunting Melissa, is Available Now Posted by Jessica Fisher on November 21st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Meowza! Toyze Brings Talking Tom to Life...
Meowza! | Read more »
Square Enix Announces New Tactical RPG f...
Square Enix Announces New Tactical RPG for Mobile, Heavenstrike Rivals. Posted by Jessica Fisher on November 21st, 2014 [ permalink ] With their epic stories and gorgeous graphics, | Read more »
Quest for Revenge (Games)
Quest for Revenge 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: The great Kingdom of the west has fallen. The gods ignore the prayers of the desperate. A dark warlord has extinguished... | Read more »
Threadz is a New Writing Adventure for Y...
Threadz is a New Writing Adventure for You and Your Friends Posted by Jessica Fisher on November 21st, 2014 [ permalink ] In the tradition of round-robin storytelling, | Read more »
SteelSeries Stratus XL Hardware Review
Made by: SteelSeries Price: $59.99 Hardware/iOS Integration Rating: 4 out of 5 stars Usability Rating: 4.5 out of 5 stars Reuse Value Rating: 4.25 out of 5 stars Build Quality Rating: 4.5 out of 5 stars Overall Rating: 4.31 out of 5 stars | Read more »
ACDSee (Photography)
ACDSee 1.0.0 Device: iOS iPhone Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Capture, perfect, and share your photos with ACDSee. The ACDSee iPhone app combines an innovative camera, a powerful photo... | Read more »
ProTube for YouTube (Entertainment)
ProTube for YouTube 2.0.2 Device: iOS Universal Category: Entertainment Price: $1.99, Version: 2.0.2 (iTunes) Description: ProTube is the ultimate, fully featured YouTube app. With it's highly polished design, ProTube offers ad-free... | Read more »

Price Scanner via MacPrices.net

Save up to $400 with Apple refurbished 2014 1...
The Apple Store has restocked Apple Certified Refurbished 2014 15″ Retina MacBook Pros for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and shipping... Read more
New 13-inch 1.4GHz MacBook Air on sale for $8...
 Adorama has the 2014 13″ 1.4GHz/128GB MacBook Air on sale for $899.99 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. B&H Photo has the 13″ 1.4GHz/128GB MacBook... Read more
Apple Expected to Reverse Nine-Month Tablet S...
Apple and Samsung combined accounted for 62 percent of the nearly 36 million branded tablets shipped in 3Q 2014, according to early vendor shipment share estimates from market intelligence firm ABI... Read more
Stratos: 30 Percent of US Smartphone Owners t...
Stratos, Inc., creator of the Bluetooth Connected Card Platform, has announced results from its 2014 Holiday Mobile Payments Survey. The consumer survey found that nearly one out of three (30 percent... Read more
2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has lowered their price on the new 1.4GHz Mac mini to $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
64GB iPod touch on sale for $249, save $50
Best Buy has the 64GB iPod touch on sale for $249 on their online store for a limited time. Their price is $50 off MSRP. Choose free shipping or free local store pickup (if available). Sale price for... Read more
15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale for $1799.99 for a limited time. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of... Read more
New Logitech AnyAngle Case/Stand Brings Flexi...
Logitec has announced the newest addition to its suite of tablet products — the Logitech AnyAngle. A protective case with an any-angle stand for iPad Air 2 and all iPad mini models, AnyAngle is the... Read more
Notebook PC Shipments Rise Year-Over-Year as...
According to preliminary results from the upcoming DisplaySearch Quarterly Mobile PC Shipment and Forecast Report, the global notebook PC market grew 10 percent year-over-year in Q3’14 to 49.4... Read more

Jobs Board

*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Store Leader Program - College Gradu...
Job Description: Job Summary As an Apple Store Leader Program agent, you can continue your education as you major in the art of leadership at the Apple Store. You'll Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.