Upgrade Guide


Appendix A. JAM Documentation: Alternative Scrolling

By default, storage of scrolling arrays is handled internally by Panther, which stores them in its own memory buffers. It is also possible for this data to be stored by the application, external to Panther–for example, in memory or disk. In this case, the application must install a scrolling driver which is called by Panther with an interface defined by Panther. Installation of a scrolling driver replaces Panther's default scroll driver. The driver is called to initialize the array, get and put occurrences, and so on.

You can write your own scrolling function; an alternative scroll driver can reduce application memory usage when used to control the scrolling of large arrays. Scroll drivers can be freely mixed on a screen. Each driver can be specified to manage any number of arrays and any number of drivers can be used at once.

Panther Interaction with Scrolling Drivers

When Panther initializes an application, it calls all scrolling drivers, and installs them. Similarly, when the application exits, Panther calls the driver for clean up. While the driver is active, Panther calls the routine once for each new scrolling array that Panther creates–for example, on screen open–telling it to initialize the array.

While the array is active, Panther moves data back and forth between itself and the driver and informs the driver of other changes to the array–for example, insertion or deletion of occurrences.

When the array is destroyed–for example, its window closes–the driver is called to release all the data associated with the array.

Normally, a non-scrolling widget can hold as many occurrences of data as the display allows. In character mode, this corresponds to the number of lines the widget occupies onscreen. The data held in non-scrolling widgets is kept as part of the normal screen data structure. However, by setting the Scrolling property to Yes, you can enter a number of occurrences that is equal to or greater than the number of visible occurrences.

Because the amount of data kept in scrolling widgets can grow large, the data for offscreen occurrences is managed separately from onscreen. Management of offscreen data is handled either by Panther's default scroll driver, or by a custom-written driver, which you can specify in the Alt Scroll Func property. If this property is left blank or the name is invalid, Panther uses its own scroll driver.

Installation

You can bundle multiple scrolling drivers into a Panther application. Scrolling drivers are installed in funclist.c in sm_do_uinstalls. Two types installations are important:

The definition and installation of the default driver in funclist.c looks like this:

static struct fnc_data udfunc[] =
{
SM_OLDFNC("virtmem", sm_vmbscroll),
};
static int udcount =
sizeof (udfunc) / sizeof (struct fnc_data);
sm_install (DFLT_SCROLL_FUNC, udfunc, &udcount);

The definition and installation of the list of drivers in funclist.c looks like:

static struct fnc_data ufuncs[] =
{
SM_OLDFNC("virtmem", sm_vmbscroll),
SM_OLDFNC("dosmem", sm_mbscroll),
SM_OLDFNC("dummy", adummy),
};
static int ucount = 
sizeof (ufuncs) / sizeof (struct fnc_data);
sm_install (SCROLL_FUNC, ufuncs, &ucount);

If no default scrolling driver is installed, Panther uses its own scroll driver.

Scroll Driver Interface

All scroll drivers have a single entry point. Panther passes the driver two parameters. The first is a pointer to an altsc_t structure; the second parameter is an operation code, indicating what action Panther needs the scrolling driver to perform. Following is an example definition of a scrolling driver:

int
scroll_driver (as_ptr, action_code)
altsc_t *as_ptr;
int action_code;

The altsc_t Structure

A pointer to an altsc_t structure is the first parameter to a scroll driver. Table A-1 describes the altsc_t structure.

Table A-1 The altsc_t structure

Member name Description Type

Driver-maintained information:

scrolldata

Pointer to structure maintained by driver.

VOIDPTR

Scrolling information:*

luid

ID of the largest-used occurrence

unsigned int

max_items

Maximum number of occurrence

unsigned int

shs

Largest non-blank occurrence

unsigned int

Occurrence information:

item

Occurrence number

unsigned int

len

Length of the occurrence

unsigned char

attr

Occurrence attributes

attribute

valids[AS_VAL]

Occurrence validation bits

unsigned char

*text

Occurrence data

unsigned char

Other parameters:

number

Integer parameter

int

vptr

Pointer parameter–currently not used.

VOIDPTR

*This information is supplied on all calls except for INIT and RESET.

The altsc_t structure serves two purposes:

A scrolling driver can manage several arrays at once. The scrolldata member of the altsc_t structure serves the purpose of keeping tract of data for each array. When the driver is called to AS_INIT_FUNC, the driver should store a pointer in the scrolldata member, usually to an internal structure. Panther assumes that the driver uses the pointer in scrolldata to access the offscreen data. The scrolldata pointer can only be changed during the INIT call; all other calls pass back the same pointer saved from the INIT call.

The altsc_t structure also passes data into and out of the driver. The scrolling information parameters–luid, max_items, and shs–are passed so the driver knows the size of the array, current and potential. However, the luid and shs parameters are only completely accurate for the AS_INSRT_FUNC and AS_DEL_FUNC calls; otherwise, they are approximate. The occurrence information parameters–item, len, attr, valids and text–are used to pass information about specific occurrences into and out of the driver. The other parameters –number, vptr–are used only for specific calls.These members are discussed later in the description of each action.

Return Values

The scrolling driver generally returns 0 if the function is supported and it succeeds, -1 if the function is not supported, and non-zero value if the function fails. Exceptions are noted in the action code descriptions.

Scroll Driver Action Codes

The interface to the scrolling driver is through the mechanism of various action codes. Each action code represents one particular functionality. Many actions are required to update members of the altsc_t structure that is passed to the driver. Although the scrolling driver has one entry point, almost all drivers are implement ed as a giant switch statement that calls other routines.

For an example, refer to "Scrolling Driver Example."

The following sections describe the calling protocols and functionality expected for the routines associated with the action codes.

AS_CLEAR_FUNC
Not currently used. Function should return -1.

AS_DLT_FUNC, AS_INSRT_FUNC
AS_DLT_FUNC and AS_INSRT_FUNC expect routines to delete and insert array occurrences, respectively. The routines typically manipulate indexes or lists to implement the deletion/insertion.New entries that are inserted into the array, or trailing occurrences that are left blank when occurrences are deleted, should have their attr, valids, and text parameters set from the values that are passed in the structure. A NULL pointer for text indicates an empty string.

The return value is the number of lines actually inserted/deleted; should equal number.

Input parameters (and their descriptions) are:

scrolldata

Pointer to the driver's internal buffer.

item

Occurrence number to start at–the first deleted occurrence or first newly inserted occurrence.

number

Number of occurrences to delete or insert.

len

Length of the occurrence.

attr

Display attribute to give to new occurrences.

valids

Validation bits to give to new occurrences.

text

Text to put into new occurrences.

AS_GDATA_FUNC
AS_GDATA_FUNC expects a routine that gets the data of an occurrence in a scrolling array. The routine might be called because the occurrence scrolled onscreen, or in response to a request for data from a C or JPL routine, for example, a call by sm_getfield.

Occurrence data contains text, display attributes, and validation flags. Panther allocates a buffer to hold this data and passes a pointer to the buffer in the text member. The routine should update the attr, text, and valids members in the structure with values previously passed in by the AS_PDATA_FUNC routine, although a clever driver can manufacture them.

Return value of 0 indicates success; -1 indicates failure.

Note: An empty occurrence must be blank-filled.

Input parameters (and their descriptions) are:

scrolldata

Pointer to the driver's internal buffer.

item

Occurrence number to get.

len

Length of the occurrence. Represents the size of Panther's buffer; the scrolling driver should not overrun this length.

text

Buffer to get the text.

Output parameters (and their descriptions) are:

attr

Display attribute of the occurrence.

text

The routine should fill the buffer pointed to by text with the text of the occurrence as passed to the routine by PDATA.

valids

Occurrence's validation bits; these are packed into a unique form.

AS_GTSPC_FUNC
AS_GTSPC_FUNC expects a routine that tells the driver the largest occurrence, or luid, that it must keep track of. Any buffers or resources currently allocated for keeping track of data above number occurrences can be freed.

The return value is the number of occurrences it has resources allocated for. Usually, the return is the same as number.

Input parameters (and their descriptions) are:

scrolldata

Pointer to the driver's internal buffer.

number

New luid to use.

AS_INIT_FUNC
AS_INIT_FUNC expects a routine that is called when Panther starts handling scrolling data for an array. The max_items and len parameters provide the driver with approximately how much data the array can hold.

Return value of 0 indicates success; -1 indicates failure.

Input parameters (and their descriptions) are:

max_items

Maximum number of occurrences in the array. If the value of max_items subsequently changes, Panther calls the AS_GTSPC_FUNC function to inform the driver of new limits.

len

Maximum width of the text of each occurrence.

Output parameter is scrolldata. Set to point to a driver-specific data structure that keeps track of the data for the array. This value is associated with the array; all future calls to the scrolling driver that refer to this array get the scrolldata value passed in the altsc_t structure.

AS_INST_FUNC
AS_INST_FUNC expects a routine that is called once when Panther starts up. If an application causes Panther to initialize and reset more than once, the function is called repeatedly. No buffer is passed to the driver; instead, it gets NULL.

This routine usually initializes the driver's global properties, allocates buffers, initializes virtual memory, opens files. However, it cannot perform tasks, especially if the initialization is performed for each array by AS_INIT_FUNC.

Return value of 1 indicates success; 0 indicates failure–driver is not installed.

AS_NMUSD_FUNC
Not currently used. Function should return -1.

AS_PDATA_FUNC

AS_PDATA_FUNC expects a routine that is called when Panther wants to update offscreen data in the driver. The routine should save the contents of the attr, valids, and text members.

Return value of 0 indicates success; -1 indicates failure.

Note: The routine cannot assume that text is null-terminated; it should save all len bytes of it.

Input parameters (and their descriptions) are:

scrolldata

Pointer to the driver's internal buffer.

item

Occurrence number to save.

len

Length of the occurrence.

text

Buffer to get the text.

attr

Display attribute of the occurrence.

valids

Validation bits of the occurrence.

text

Text to save.

AS_RESET_FUNC
AS_RESET_FUNC expects a routine to call when Panther terminates with sm_resetcrt. The routine can perform any desired final clean up, such as deleting temporary files, freeing memory allocated in the INST function, and so on. The routine has no input or output parameters and returns no value. It should only be called by Panther when it has released all active arrays with AS_RLS_FUNC.

AS_RLS_FUNC
AS_RLS_FUNC expects a routine that is called when Panther destroys an array. The routine should then free any resources allocated for the array. The return value from this call is ignored. Thus, the scrolling driver must inform the user about any failure and take the appropriate action–for example, exit the program.

The input parameter is scrolldata, the pointer to the driver's internal buffer.

Return value of 0 indicates success; -1 indicates failure.

AS_SCMAX_FUNC
Not currently used. Function should return -1.

Scrolling Driver Example

The following code is an example of a scrolling driver:

/* Scroll buffers hold field data of scrolling. New buffers
are allocated as formerly empty offscreen elements are filled.
Each buffer can hold several items, determined by
i_per_buff = (SC_BUF_SIZE - SC_OVERHEAD) / (item_size + SC_BYTES) where item_size is the maximum (shifting) length of a field.
The extra SC_BYTES hold VALIDED, MDT, and attribute information
for a field scrolled offscreen. The constants are defined below */
/* A buffer is allocated contiguously with its sc_buf_s.*/
#define SC_BUF_SIZE 1024
#define SC_LEN 0 /* length of an item if var.*/
#define SC_ATTR 0 /* offset of saved attribute*/
#define SC_BITS 2 /* offset of saved bits*/
#define SC_BYTES SC_BITS+AS_VAL /* extra bytes per item*/
#define SC_DATA SC_BYTES /* offset of field data*/
/* bits stored are:
SELECTED (0x10)
VALIDED (0x20)
MDT (0x40)
OPROTECT (0x80)
PROTECT (0x0f) */
typedef
struct sc_buf_s
{
struct sc_buf_s *link; /* forward link */
struct sc_buf_s *back; /* backward link */
unsigned int first_item; /* first in this buffer */
unsigned int last_item; /* last in this buffer */
char item[SC_BYTES+1]; /* start of buffer */
} sc_buf_t;
#define SC_OVERHEAD							(int)(sizeof (sc_buf_t) - SC_BYTES - 1)
/* Every scroll header has an item altsc_id which is a pointer to a scroll_t. scroll_t has an item scrolldata. A structure of scrolldata depends on a scrolling method. If memory-based scrolling is used, the structure of scrolling data is: */
typedef
struct scr_data_s
{ 
sc_buf_t *first_buff;
sc_buf_t *cur_buff;
unsigned int i_per_buff;
} scr_data_t;
/* To store offscreen data, buffers are acquired as needed. Buffers are linked into a chain whose head is stored in the member first_buff in the structure above. Each buffer holds the same number of items, determined by the formula above. */
/* FUNCTIONS IN THIS MODULE */
int sm_mbscroll PROTO((altsc_t *, int));
static int SMLOCAL mb_initscr PROTO((altsc_t *));
static int SMLOCAL mb_getitem PROTO((altsc_t *));
static int SMLOCAL mb_putitem PROTO((altsc_t *));
static int SMLOCAL mb_insitem PROTO((altsc_t *));
static int SMLOCAL mb_delitem PROTO((altsc_t *));
static int SMLOCAL mb_setluid PROTO((altsc_t *));
static int SMLOCAL mb_rlsscrl PROTO((altsc_t *));
static char * SMLOCAL mb_getptr PROTO((altsc_t *));
static sc_buf_t * SMLOCAL mb_addscbuf PROTO((altsc_t *,
sc_buf_t *));
static int SMLOCAL mb_incluid PROTO((altsc_t *, scr_data_t *,
unsigned int));
static sc_buf_t * SMLOCAL mb_getscbuf PROTO((scr_data_t *,
int));
static void SMLOCAL mb_free_sc_bufs PROTO((sc_buf_t *));
int sm_mbscroll (as_ptr, option) altsc_t *as_ptr;
int option;
{
switch (option)
{
case AS_INIT_FUNC:
return mb_initscr (as_ptr);

case AS_GDATA_FUNC:
return mb_getitem (as_ptr);

case AS_PDATA_FUNC:
return mb_putitem (as_ptr);

case AS_INSRT_FUNC:
return mb_insitem (as_ptr);

case AS_DLT_FUNC:
return mb_delitem (as_ptr);

case AS_GTSPC_FUNC:
return mb_setluid (as_ptr);

case AS_RLS_FUNC:
return mb_rlsscrl (as_ptr);
default:
return 1;
}
}
static int SMLOCAL
mb_initscr (as_ptr)
altsc_t *as_ptr;
{
scr_data_t *scr_data;
int retcode;
scr_data = (scr_data_t *) sm_fmalloc (sizeof /
(scr_data_t));
if (scr_data && as_ptr->len > 0)
{
scr_data->first_buff = 0;
scr_data->cur_buff = 0;
scr_data->i_per_buff =
(unsigned)(SC_BUF_SIZE - SC_OVERHEAD) /
(as_ptr->len + SC_BYTES);
retcode = 0;
}
	else
{
sm_qui_msg ("Memory based scrolling method
cannot be initialized");
retcode = -1;
}
as_ptr->scrolldata = (VOIDPTR)scr_data;
return retcode;
}
static int SMLOCAL
mb_getitem (as_ptr)
altsc_t *as_ptr;
{
char *ptr;
if (!(ptr = mb_getptr (as_ptr)))
{
return -1;
}
memcpy ((VOIDPTR)as_ptr->valids, (VOIDPTR)&ptr[SC_BITS],
AS_VAL);
as_ptr->attr = UGET (ptr, SC_ATTR);
memcpy ((VOIDPTR)as_ptr->text, (VOIDPTR)&ptr[SC_DATA],
as_ptr->len);
return 0;
}
static int SMLOCAL
mb_putitem (as_ptr)
altsc_t *as_ptr;
{
char *ptr;
if (!(ptr = mb_getptr (as_ptr)))
{
return -1;
}
memcpy ((VOIDPTR)&ptr[SC_BITS], (VOIDPTR)as_ptr->valids,
AS_VAL);
UPUT (ptr, SC_ATTR, as_ptr->attr);
memcpy ((VOIDPTR)&ptr[SC_DATA], (VOIDPTR)as_ptr->text,
as_ptr->len);
return 0;
}
static int SMLOCAL 
mb_insitem (as_ptr)
altsc_t *as_ptr;
{
unsigned char *ptr;
unsigned char valids[AS_VAL];
attrib_t attr;
int item;
int item_to;
int item_from;
item = (int)as_ptr->item;
if ((unsigned int)as_ptr->number >
(as_ptr->luid - as_ptr->shs))
{
as_ptr->number = (int)(as_ptr->luid - as_ptr->shs);
}
item_from = (int)as_ptr->shs;
item_to = item_from + as_ptr->number;
ptr = as_ptr->text;
attr = as_ptr->attr;
memcpy ((VOIDPTR)valids, (VOIDPTR)as_ptr->valids, AS_VAL);
as_ptr->text = (unsigned char *)sm_fmalloc (as_ptr->len);
if (!as_ptr->text)
{
return -3;
}
for (; item_to >= item; item_to--)
{
if (item_from >= item)
{
as_ptr->item = item_from;
if (mb_getitem (as_ptr))
{
if (ptr)
{
sm_ffree (as_ptr->text);
as_ptr->text = ptr;
}
return -1;
}
item_from--;
}
else if (ptr)
{
sm_ffree (as_ptr->text);
as_ptr->text = ptr;
as_ptr->attr = attr;
memcpy((VOIDPTR)as_ptr->valids,(VOIDPTR)valids,
AS_VAL);
ptr = 0;
}
as_ptr->item = item_to;
if (mb_putitem (as_ptr))
{
if (ptr)
{
sm_ffree (as_ptr->text);
as_ptr->text = ptr;
}
return -2;
}
}
if (ptr)
{
sm_ffree (as_ptr->text);
as_ptr->text = ptr;
}
return as_ptr->number;
}
static int SMLOCAL
mb_delitem (as_ptr)
altsc_t *as_ptr;
{
unsigned char *ptr;
unsigned char valids[AS_VAL];
attrib_t attr;
unsigned int item_to;
unsigned int item_from;
item_to = as_ptr->item;
if (as_ptr->number > (int)(as_ptr->luid - item_to + 1))
{
as_ptr->number = (int)(as_ptr->luid - item_to + 1);
}
item_from = item_to + (unsigned int)as_ptr->number;
ptr = as_ptr->text;
attr = as_ptr->attr;
memcpy ((VOIDPTR)valids, (VOIDPTR)as_ptr->valids, AS_VAL);
as_ptr->text = (unsigned char *)sm_fmalloc (as_ptr->len);
if (!as_ptr->text)
{
return -3;
}
for (; item_to <= as_ptr->shs; item_to++)
{
if (item_from <= as_ptr->shs)
{
as_ptr->item = item_from;
if (mb_getitem (as_ptr))
{
if (ptr)
{
sm_ffree (as_ptr->text);
as_ptr->text = ptr;
}
return -1;
}
item_from++;
}
else if (ptr)
{
sm_ffree (as_ptr->text);
as_ptr->text = ptr;
as_ptr->attr = attr;
memcpy((VOIDPTR)as_ptr->valids,(VOIDPTR)valids,
AS_VAL);
ptr = 0;
}
as_ptr->item = item_to;
if (mb_putitem (as_ptr))
{
if (ptr)
{
sm_ffree (as_ptr->text);
as_ptr->text = ptr;
}
return -2;
}
}
if (ptr)
{
sm_ffree (as_ptr->text);
as_ptr->text = ptr;
}
return as_ptr->number;
}
static int SMLOCAL
mb_setluid (as_ptr)
altsc_t *as_ptr;
{
sc_buf_t *sc_buf;
scr_data_t *scroll;
unsigned int new_luid;
unsigned int old_fuid;
scroll = (scr_data_t *) as_ptr->scrolldata;
if (!scroll)
return 0;
new_luid = as_ptr->number;
if (!new_luid)
{
mb_free_sc_bufs(scroll->first_buff);
scroll->first_buff = scroll->cur_buff = 0;
return 0;
}
sc_buf = mb_getscbuf (scroll, (int)new_luid);
if (!sc_buf)
new_luid = mb_incluid(as_ptr, scroll, new_luid);
else if (sc_buf->link)
{
mb_free_sc_bufs(sc_buf->link);
sc_buf->link = 0;
scroll->cur_buff = sc_buf;
}
old_fuid = as_ptr->luid;
as_ptr->luid = new_luid;
while (++old_fuid <= new_luid)
{
as_ptr->item = old_fuid;
mb_putitem (as_ptr);
}
return (int)new_luid;
}

/*
NAME: mb_rlsscrl - Free scroll buffers
SYNOPSIS: 	mb_rlsscrl (as_ptr)
altsc_t *as_ptr;
DESCRIPTION: Loops through field's scroll buffers, freeing them. Then frees altsc_id and sets it to 0.
*/
static int SMLOCAL 
mb_rlsscrl (as_ptr)
altsc_t *as_ptr;
{
sc_buf_t *sc_buf;
scr_data_t *scroll;
scroll = (scr_data_t *) as_ptr->scrolldata;
sc_buf = scroll->first_buff;
mb_free_sc_bufs(sc_buf);
sm_ffree ((VOIDPTR) scroll);
return 0;
}
/*
NAME: mb_getptr - Get a pointer to offscreen item in memory buffer
SYNOPSIS:
	ptr = mb_getptr (as_ptr);
char *ptr;
altsc_t *as_ptr;
DESCRIPTION: Searches forward or backward from current scroll buffer to find buffer that contains specified occurrence. If the occurrence previously existed, returns pointer to data.
RETURNS: ptr = pointer to offscreen data; 0 if occurrence could not be found.
*/
static char * SMLOCAL
mb_getptr(as_ptr)
altsc_t *as_ptr;
{
scr_data_t *scroll;
unsigned int occur;
sc_buf_t *sc_buf;
if (!(scroll = (scr_data_t *)as_ptr->scrolldata) ||
!(sc_buf = mb_getscbuf(scroll, (int)(occur =
as_ptr->item))))
return 0;
return sc_buf->item + ((unsigned)occur -
sc_buf->first_item) * (as_ptr->len + SC_BYTES);
}
/*
NAME: mb_addscbuf - Add another sc_buf_s to the list specified.
SYNOPSIS:
	new_scroll_buffer = mb_addscbuf (as_ptr, scroll_buffer);
sc_buf_t *new_scroll_buffer;
altsc_t *as_ptr;
sc_buf_t *scroll_buffer;
DESCRIPTION: Mallocs and initializes new scroll buffer. If scroll buffer passed is null, the first_buff and cur_buff entries of scroll header are set to the new buffer.
RETURNS: new_scroll_buffer = pointer to new buffer; 0 if malloc failed.
*/
static sc_buf_t * SMLOCAL 
mb_addscbuf (as_ptr, sc_buf)
altsc_t *as_ptr;
sc_buf_t *sc_buf;
{ 
unsigned int f_item;
unsigned int l_item;
unsigned int buf_size;
sc_buf_t *new_buf;
scr_data_t *scroll;
scroll = (scr_data_t *) as_ptr->scrolldata;
l_item = 0;
if (sc_buf)
l_item = sc_buf->last_item;
f_item = l_item + 1;
l_item += scroll->i_per_buff;
if (l_item > as_ptr->max_items)
l_item = as_ptr->max_items;
buf_size = (l_item - f_item + 1) * (as_ptr->len +
SC_BYTES) + SC_OVERHEAD;
new_buf = (sc_buf_t *)sm_fmalloc(buf_size);
if (new_buf == 0)
{
char buf[80];
sprintf (buf, "There is no more memory for new
occurrence # %i", as_ptr->number);
sm_qui_msg (buf);
return 0;
}
memset((VOIDPTR)new_buf, 0, buf_size);
new_buf->link = 0;
new_buf->first_item = f_item;
new_buf->last_item = l_item;
new_buf->back = sc_buf;
if (sc_buf)
sc_buf->link = new_buf;
else
{
scroll->first_buff = new_buf;
scroll->cur_buff = new_buf;
}
return(new_buf);
}
/* 
NAME: mb_getscbuf - Get pointer to scroll buf that contains the specified item.

SYNOPSIS:
scroll_buffer = mb_getscbuf (sc_data, item);
sc_buf_t *scroll_buffer;
scr_data_t *sc_data;
int item;
DESCRIPTION: Searches scroll buffers for specified item. Uses the cur_buff pointer to save time. Updates cur_buff pointer (to save time next time). If desired item is in first buffer, don't bother with cur_buff.
RETURNS: scroll_buffer = pointer to desired buffer; 0 if item is not in any buffer.
*/
static sc_buf_t * SMLOCAL
mb_getscbuf(sc_data, item)
scr_data_t *sc_data;
int item;
{
sc_buf_t *sc_buf;
sc_buf_t *ret_buf;
if (!(sc_buf = sc_data->cur_buff))
return 0;
if (item <= (int)sc_buf->last_item)
{
sc_buf_t *f_buf;
if (item >= (int)sc_buf->first_item)
return sc_buf;
f_buf = sc_data->first_buff;
if (item <= (int)f_buf->last_item)
{
if (item < (int)f_buf->first_item)
return 0;
return f_buf;
}
if (item >= (int)((sc_buf->first_item + \
f_buf->last_item) / 2))
{
while ((ret_buf = sc_buf->back) &&
item < (int)(sc_buf = ret_buf)->first_item)
{
}
sc_data->cur_buff = sc_buf;
return ret_buf;
}
sc_buf = f_buf;
}
while ((ret_buf = sc_buf->link) &&
item > (int)(sc_buf = ret_buf)->last_item)
{
}
sc_data->cur_buff = sc_buf;
return ret_buf;
/*
NAME: mb_incluid - Ensures sufficient allocated space to hold desired item.
SYNOPSIS:
	new_luid = mb_incluid (as_ptr, scroll, desired_new_luid)
int new_luid;
altsc_t *as_ptr;
scr_data_t *scroll;
unsigned int desired_new_luid;
DESCRIPTION: Calls mb_addscbuf in a loop to increase largest_used_item_id until it 						meets or surpasses desired value.
RETURNS: new_luid = smaller of desired_new_luid and amount of space which could be allocated.
*/
static int SMLOCAL 
mb_incluid (as_ptr, scroll, new_luid)
altsc_t *as_ptr;
scr_data_t *scroll;
unsigned int new_luid;
{
sc_buf_t *new_buf;
sc_buf_t *last_buf;
unsigned int retval;
retval = new_luid;
last_buf = scroll->cur_buff;
do
{
if (!(new_buf = mb_addscbuf(as_ptr, last_buf)))
{
if (last_buf)
retval = last_buf->last_item;
else
retval = 0;
break;
}
}
while (new_luid > (last_buf = new_buf)->last_item);
scroll->cur_buff = last_buf;
return (int)retval;
}
/*
NAME: mb_free_sc_bufs - Frees scrolling buffers starting with one passed.
SYNOPSIS:	
	mb_free_sc_bufs (scroll_buffer)
sc_buf_t *scroll_buffer;
DESCRIPTION: Loops through on link freeing buffers. Caller is responsible for valid arguments and setting pointers to the freed buffer to NULL. Argument can be NULL.
RETURNS: None.
*/
static void SMLOCAL
mb_free_sc_bufs(sc_buf)
sc_buf_t *sc_buf;
{
char *ptr;
while (sc_buf)
{
ptr = (char *)sc_buf;
sc_buf = sc_buf->link;
sm_ffree(ptr);
}
}