@z --- breakpt.web ---

THIS CODE SERVES AS AN EXAMPLE OF A C CODE WRITTEN IN WEB.
HOWEVER, ITS CONTENTS IS FOR ADVANCED PROGRAMMERS ONLY! See the
discussion of breakpointing/debugging in the user's manual.

@x-----------------------------------------------------------------------------

@c

\Title{BREAKPT.WEB}

@* DEBUGGING. This sample program shows how to write module breakpointing
functions that work in conjunction with the general |_BP| macro mechanism.

@d NO 0
@d YES 1

@ We begin by defining a structure~|_BP| that contains information about each
breakpoint---a flag |on| to indicate whether that breakpoint is active or
not, and a pointer to the name of the module. We will have an array |bps|
of such structures, one for each possible section.

@a
typedef struct
        {
        char on; /* Flag to indicate active or not. */
        char *name; /* Name of the module. */
        } BP;

/* The following illustrates use of the built-in macros |_MODULES|,
|_SECTIONS|, ANd |_eval|. */
BP bps0[_MODULES]; /* This array corresponds to all the independent module
		names, with 0~corresponding to the unnamed module. */
BP bps[_EVAL(_SECTIONS+1)]; /* These correspond to the \.{@@\ } or~\.{@@*}
		sections, 
		numbered as in \.{WEAVE}'s output. The zeroth section does
		not exist. */ 

@ We shall add a module number to the breakpoint list by calling~|bp|
\It{from the debugger} with a positive argument; we remove one from the
list by calling with a negative argument.

@a
int bp(int m)
{
/*  Check for |m| out-of-bounds. */
if(abs(m) > _SECTIONS)
	{
	printf("Section number %d too large; must be < %d\n",
		m,_SECTIONS);
	return NO;
	}

if(m > 0)
	{
	printf("Setting breakpoint at section %d\n",m);
	 return bps[m].on = YES;
	}
else if(m < 0)
	{
	printf("Removing breakpoint at section %d\n",-m);
	 return bps[-m].on = NO;
	}
else
	{
	puts("Removing all breakpoints");
	for(; m<=_SECTIONS; m++)
		bps[m].on = NO;
	return NO;
	}
}

@ We can initialize all breakpoints by calling the following routine from
the debugger. To make it easier for us in this demo, we do that explicitly
in |main|.
@a
void init_bp(void)
{
int m;

puts("Initializing all breakpoints");
for(m=0; m<=_SECTIONS; m++) bps[m].on = YES;
}

@ The actual breakpoint macro should in general be defined as follows:
\.{-m"\_BP(m,name)=trap(m,name);"}, where |trap|~is a function that is to
be called at the beginning of each module.  If the module is in the
breakpoint list, then |trap| will call the null function~|_bp|, on which
one can set a debugger breakpoint. (This might be put into an
initialization file.) Thus, for an active module breakpoint, the |trap|
routine will print the name of the module, then stop in the debugger.

@a
void _bp(void)
{}

void trap(int m,char *name)
{
if(bps[m].on)
        {
        printf("Entering section %d, module \"%s\"\n",
		m,bps[m].name = name);
        _bp();
        }
}

@ Here is a test program.
@a
main()
{
int k = 50; /* To prevent an infinite loop if you run this without any
		breakpoints set. */

init_bp(); /* Initialize all breakpoints. */

while(k-- > 0)
        {
        @<A@>;
        @<B@>;
        @<This is a very, very long module whose name seems never to end@>;
        }
}

@ A simple named section.
@<A@>=
{
puts("A");
}

@ This section has no braces, so the breakpointing mechanism won't work.
@<B@>=
puts("B");

@ This section starts off with a C~declaration. We must use the
\.{@@\{}~command to prevent the debugging statement from being inserting
before the declaration, and the \.{@@b}~command to say where to actually put
the debugging statement.
@<This...@>=
@{
int i;

@b
puts("Testing");
}
