1198 lines
40 KiB
C
1198 lines
40 KiB
C
############################################################# -*- c -*-
|
|
## generic include for XXX. Do not use directly.
|
|
##
|
|
########################################################################
|
|
##
|
|
@eval $mfd_aue_wrap_param = "wrap_ctx"@
|
|
@eval $mfd_aue_wrap_param_type = "${context}_interface_ctx *"@
|
|
@eval $mfd_aue_wrap_param_decl = "$mfd_aue_wrap_param_type $mfd_aue_wrap_param"@
|
|
##
|
|
@eval $mfd_aue_param = "${context}_reg"@
|
|
@eval $mfd_aue_param_type = "${context}_registration *"@
|
|
@eval $mfd_aue_param_decl = "$mfd_aue_param_type $mfd_aue_param"@
|
|
@eval $mfd_aue_param_cmt = "$mfd_aue_param Pointer to a $mfd_aue_param_type"
|
|
##
|
|
@if $m2c_mark_boundary == 1@
|
|
/** START code generated by mfd-access-unsorted-external-defines.m2i */
|
|
@end@
|
|
##//####################################################################
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@if $m2c_processing_type eq 'h'@
|
|
##
|
|
@if $m2c_include_examples == 1@
|
|
$example_start
|
|
/* *********************************************************************
|
|
* Since we have no idea how you really access your data, we'll go with
|
|
* a worst case example: a flat text file.
|
|
@ if $m2c_data_transient != 2@
|
|
@ print Example code is for fully transient data. Either turn off@
|
|
@ print m2c_include_examples or set m2c_data_transient to 2.@
|
|
@ exit@
|
|
@ end@
|
|
*/
|
|
#define MAX_LINE_SIZE 256
|
|
$example_end
|
|
|
|
@end@
|
|
/**
|
|
* loop context
|
|
*
|
|
* ToDo:
|
|
* define loop context structure
|
|
*
|
|
* Since the actual loop is in the MFD handler, a loop contex parameter
|
|
* is provided to help you keep track of where you are in between calls
|
|
* to functions that you wrote and the master MFD handler calls. The
|
|
* structure of this context is user defineable, and is defined in the
|
|
* file ${table}_data_access.h.
|
|
*
|
|
* E.G., if your data is stored in a linked list, the obvious thing you
|
|
* want to know from one function call to the next is your current
|
|
* position in the linked list. Thus the easiest context to use is a
|
|
* pointer within the linked list. For an array, the current index to
|
|
* that array would be easiest.
|
|
*
|
|
* The funtion calls are actually passed a reference to the loop
|
|
* context, to allow the loop context to be allocated memory. Here are
|
|
* some simple examples definitions for various data formats. These
|
|
* definitions are used in examples later on.
|
|
*
|
|
*/
|
|
typedef struct ${context}_loop_context_s {
|
|
/*
|
|
* temporary context used during iteration
|
|
*/
|
|
${context}_rowreq_ctx *rowreq_ctx;
|
|
@if $m2c_include_examples == 1@
|
|
|
|
/*
|
|
* this example code is based on a data source that is a
|
|
* text file to be read and parsed.
|
|
*/
|
|
FILE *filep;
|
|
char line[MAX_LINE_SIZE];
|
|
@end@
|
|
} ${context}_loop_context;
|
|
|
|
/*
|
|
* define a reference to the loop context
|
|
*
|
|
* NOTE: DO NOT ADD ITEMS TO THIS STRUCTURE!
|
|
*/
|
|
typedef struct ${context}_ref_loop_ctx_s {
|
|
${context}_loop_context *loop_ctx;
|
|
} ${context}_ref_loop_ctx;
|
|
|
|
int ${context}_loop_get_first( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx *rowreq_ctx_ref);
|
|
int ${context}_loop_get_next( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx *rowreq_ctx_ref);
|
|
int ${context}_loop_get_data( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx *rowreq_ctx_ref);
|
|
int ${context}_loop_save_position($mfd_aue_param_decl,
|
|
${context}_ref_loop_ctx *loop_ctx_ref,
|
|
${context}_ref_loop_ctx *save_loop_ctx_ref, int reuse);
|
|
int ${context}_loop_cleanup_context( $mfd_aue_param_decl, ${context}_ref_loop_ctx *ref);
|
|
|
|
##
|
|
@end@ // m2c_processing_type eq 'h'
|
|
########################################################################
|
|
##//####################################################################
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@if $m2c_processing_type eq 'i'@
|
|
/**
|
|
* @internal
|
|
* wrapper around clean up a loop reference
|
|
*/
|
|
static int
|
|
_${context}_loop_cleanup_context( $mfd_aue_wrap_param_decl,
|
|
${context}_ref_loop_ctx *ref)
|
|
{
|
|
DEBUGMSGTL(("internal:${context}:_${context}_loop_cleanup_context","called\n"));
|
|
|
|
return ${context}_loop_cleanup_context($mfd_aue_wrap_param->user_ctx, ref);
|
|
} /* _${context}_loop_cleanup_context */
|
|
|
|
/**
|
|
* @internal
|
|
* wrapper around save position
|
|
*/
|
|
static int
|
|
_${context}_loop_save_position( $mfd_aue_wrap_param_decl, ${context}_ref_loop_ctx *ref,
|
|
${context}_ref_loop_ctx *ref_copy, int reuse)
|
|
{
|
|
DEBUGMSGTL(("internal:${context}:_${context}_loop_save_position","called\n"));
|
|
|
|
return ${context}_loop_save_position($mfd_aue_wrap_param->user_ctx, ref,
|
|
ref_copy, reuse);
|
|
} /* _${context}_loop_save_position */
|
|
|
|
/**
|
|
* @internal
|
|
* wrapper around user get_first to setup the index oid
|
|
*/
|
|
static int
|
|
_${context}_loop_get_first_wrapper($mfd_aue_wrap_param_decl,
|
|
${context}_ref_loop_ctx * loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx * rowreq_ctx_ref)
|
|
{
|
|
int rc;
|
|
DEBUGMSGTL(("internal:${context}:_${context}_loop_get_first_wrapper","called\n"));
|
|
|
|
rc = ${context}_loop_get_first($mfd_aue_wrap_param->user_ctx, loop_ctx_ref,
|
|
rowreq_ctx_ref);
|
|
/*
|
|
* convert index to OID
|
|
*/
|
|
if(SNMPERR_SUCCESS == rc ) {
|
|
netsnmp_assert((NULL != rowreq_ctx_ref) &&
|
|
(rowreq_ctx_ref->rowreq_ctx->oid_idx.oids == rowreq_ctx_ref->rowreq_ctx->oid_tmp));
|
|
rowreq_ctx_ref->rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp);
|
|
rc = ${context}_index_to_oid(&rowreq_ctx_ref->rowreq_ctx->oid_idx,
|
|
&rowreq_ctx_ref->rowreq_ctx->tbl_idx);
|
|
netsnmp_assert(rowreq_ctx_ref->rowreq_ctx->oid_idx.len !=
|
|
sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp));
|
|
}
|
|
|
|
return rc;
|
|
} /* _${context}_loop_get_first_wrapper */
|
|
|
|
/**
|
|
* @internal
|
|
* wrapper around user get_next to setup the index oid
|
|
*/
|
|
static int
|
|
_${context}_loop_get_next_wrapper($mfd_aue_wrap_param_decl,
|
|
${context}_ref_loop_ctx * loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx * rowreq_ctx_ref)
|
|
{
|
|
int rc;
|
|
DEBUGMSGTL(("internal:${context}:_${context}_loop_get_next_wrapper","called\n"));
|
|
|
|
rc = ${context}_loop_get_next($mfd_aue_wrap_param->user_ctx, loop_ctx_ref,
|
|
rowreq_ctx_ref);
|
|
/*
|
|
* convert index to OID
|
|
*/
|
|
if(SNMPERR_SUCCESS == rc ) {
|
|
netsnmp_assert((NULL != rowreq_ctx_ref) &&
|
|
(rowreq_ctx_ref->rowreq_ctx->oid_idx.oids == rowreq_ctx_ref->rowreq_ctx->oid_tmp));
|
|
rowreq_ctx_ref->rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp);
|
|
rc = ${context}_index_to_oid(&rowreq_ctx_ref->rowreq_ctx->oid_idx,
|
|
&rowreq_ctx_ref->rowreq_ctx->tbl_idx);
|
|
netsnmp_assert(rowreq_ctx_ref->rowreq_ctx->oid_idx.len !=
|
|
sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp));
|
|
}
|
|
|
|
return rc;
|
|
} /* _${context}_loop_get_next_wrapper */
|
|
|
|
@if $m2c_data_transient != 0@ #
|
|
/**
|
|
* @internal
|
|
* get data wrapper to allocate context for the user
|
|
*/
|
|
static int
|
|
_${context}_loop_get_data_wrapper($mfd_aue_wrap_param_decl,
|
|
${context}_ref_loop_ctx * loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx * rowreq_ctx_ref)
|
|
{
|
|
// ${context}_rowreq_ctx *orig_ctx = rowreq_ctx_ref->rowreq_ctx;
|
|
|
|
DEBUGMSGTL(("internal:${context}:_${context}_loop_get_data_wrapper","called\n"));
|
|
|
|
return ${context}_loop_get_data($mfd_aue_wrap_param->user_ctx, loop_ctx_ref, rowreq_ctx_ref);
|
|
} /* _${context}_loop_get_data_wrapper */
|
|
|
|
@end@ // transient != 0
|
|
/**
|
|
* @internal
|
|
* initialize the iterator container with functions or wrappers
|
|
*/
|
|
void
|
|
_${context}_container_init(${context}_interface_ctx *if_ctx)
|
|
{
|
|
DEBUGMSGTL(("internal:${context}:_${context}_container_init","called\n"));
|
|
|
|
if_ctx->container = netsnmp_container_iterator_get(/** registration */
|
|
if_ctx,
|
|
/** compare */
|
|
NULL,
|
|
/** get_first */
|
|
(Netsnmp_Iterator_Loop_Key*)_${context}_loop_get_first_wrapper,
|
|
/** get_next */
|
|
(Netsnmp_Iterator_Loop_Key*)_${context}_loop_get_next_wrapper,
|
|
/** get_data */
|
|
@if $m2c_data_transient != 0@ #
|
|
(Netsnmp_Iterator_Loop_Data*)_${context}_loop_get_data_wrapper,
|
|
@else@
|
|
NULL,
|
|
@end@
|
|
/** save_pos */
|
|
(Netsnmp_Iterator_Ctx_Dup*)_${context}_loop_save_position,
|
|
/** init_context */
|
|
(Netsnmp_Iterator_Ctx*)NULL,
|
|
/** cleanup_context */
|
|
(Netsnmp_Iterator_Ctx*)_${context}_loop_cleanup_context,
|
|
/** free_user_ctx */
|
|
NULL,
|
|
/** sorted */
|
|
0);
|
|
} /* _${context}_container_init */
|
|
|
|
##
|
|
@end@ // m2c_processing_type eq 'i'
|
|
########################################################################
|
|
##//####################################################################
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@if $m2c_processing_type eq 'c'@
|
|
/**
|
|
* unsorted-external overview
|
|
*
|
|
* The unsorted external data access code works by calling a few simple
|
|
* functions to get the index value for each row. Once the agent determines
|
|
* which row is needed to process an incoming request, another function
|
|
* is called to retrieve the data for that row.
|
|
*
|
|
* A simplified version of the pseudo-code looks like this:
|
|
*
|
|
* ${context}_loop_get_first(loop,data)
|
|
* while( no_error ) {
|
|
* if( best_match(data, key)
|
|
* ${context}_loop_save_position(loop,pos);
|
|
* ${context}_loop_get_next(loop,data)
|
|
* }
|
|
* ${context}_loop_get_data(pos,data)
|
|
* ${context}_loop_cleanup_context(loop)
|
|
*/
|
|
|
|
/***********************************************************************
|
|
*
|
|
* ITERATION
|
|
*
|
|
***********************************************************************/
|
|
|
|
/**
|
|
* get the first data index
|
|
*
|
|
* Summary
|
|
* -------
|
|
* This function is called to initialize the iterator loop context for a
|
|
* new iteration loop and return the index(es) for the first
|
|
* ${context}_data in the data set.
|
|
*
|
|
* Note that during the loop, the only important thing is the indexes.
|
|
* If access to your data is cheap/fast (e.g. you have a pointer to a
|
|
* structure in memory), it would make sense to update the data here.
|
|
* If, however, the accessing the data involves more work (e.g. parsing
|
|
* some other existing data, or peforming calculations to derive the data),
|
|
* then you should limit yourself to setting the indexes. Extracting the
|
|
* can be put off until the desired row is found. See the notes on
|
|
* ${context}_loop_get_data().
|
|
*
|
|
* Note that this function does not correspond to a SNMP GET pdu, and
|
|
* you should return data items in whatever order they are already in.
|
|
* (In fact, if your data is already ordered in the same order as the
|
|
* SNMP indexes, you shouldn't be using the unsorted-access code).
|
|
*
|
|
* This function should update the table index (rowreq_ctx_ref->rowreq_ctx->tbl_idx)
|
|
* values for the raw data (rowreq_ctx_ref->rowreq_ctx->data).
|
|
*
|
|
* More Details
|
|
* ------------
|
|
* If there is currently no data available, return MFD_END_OF_DATA.
|
|
* Otherwise, you should set rowreq_ctx_ref->rowreq_ctx and its indexes.
|
|
*
|
|
* rowreq_ctx_ref->rowreq_ctx will be NULL. You should allocate a new context
|
|
* for this loop. [Alternatively, you could allocate one in
|
|
* ${context}_loop_init_context, save it in your
|
|
* ${context}_ref_loop_ctx, and use it here.]
|
|
*
|
|
* Once you have your context pointer, you should set the index (or indexes)
|
|
* in rowreq_ctx_ref->rowreq_ctx->tbl_idx to the appropriate value for this row. [If you
|
|
* use your loop_ctx_ref cleverly, you might be able to put this work in
|
|
* ${context}_loop_get_next, and simply call that function.]
|
|
*
|
|
* @param $mfd_aue_param_cmt
|
|
* @param loop_ctx_ref Pointer to your loop reference.
|
|
* @param rowreq_ctx_ref Pointer to a context reference.
|
|
*
|
|
* @retval MFD_SUCCESS : success.
|
|
* @retval MFD_END_OF_DATA : no data available
|
|
* @retval MFD_ERROR : error.
|
|
*/
|
|
int
|
|
${context}_loop_get_first( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx *rowreq_ctx_ref)
|
|
{
|
|
DEBUGMSGTL(("verbose:${context}:${context}_loop_get_first","called\n"));
|
|
|
|
netsnmp_assert(rowreq_ctx_ref);
|
|
netsnmp_assert(loop_ctx_ref);
|
|
|
|
/*
|
|
* allocate memory for new structure
|
|
*/
|
|
loop_ctx_ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context);
|
|
if(NULL == loop_ctx_ref->loop_ctx)
|
|
return MFD_ERROR;
|
|
|
|
/*
|
|
* allocate a temporary context to use during iteration
|
|
*/
|
|
@ eval $m2c_tmp = ""@
|
|
@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@
|
|
@ eval $m2c_tmp = "NULL"@
|
|
@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@
|
|
@ eval $m2c_tmp = "$m2c_tmp, NULL"@
|
|
@ @end@
|
|
@ end@
|
|
loop_ctx_ref->loop_ctx->rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp);
|
|
if(NULL == loop_ctx_ref->loop_ctx->rowreq_ctx) {
|
|
SNMP_FREE(loop_ctx_ref->loop_ctx);
|
|
return MFD_RESOURCE_UNAVAILABLE;
|
|
}
|
|
|
|
/*
|
|
* ToDo:
|
|
* set up loop context
|
|
*/
|
|
@if $m2c_include_examples == 1@
|
|
$example_start
|
|
/*
|
|
* open our data file.
|
|
*/
|
|
loop_ctx_ref->loop_ctx->filep = fopen("/etc/dummy.conf", "r");
|
|
if(NULL == loop_ctx_ref->loop_ctx->filep) {
|
|
return MFD_RESOURCE_UNAVAILABLE;
|
|
}
|
|
|
|
$example_end
|
|
@end@
|
|
|
|
@ifconf ${table}_update_idx.m2i@
|
|
@ include ${table}_update_idx.m2i@
|
|
@else@
|
|
@ if $m2c_include_examples == 1@
|
|
$example_start
|
|
/*
|
|
* in this example, after opening the file, get next does the same thing
|
|
* as get first, we let's just call get next...
|
|
*/
|
|
return ${context}_loop_get_next($mfd_aue_param, loop_ctx_ref, rowreq_ctx_ref);
|
|
$example_end
|
|
@ else@
|
|
/*
|
|
* we just need the index for now. Reuse the one in the loop context's
|
|
* temporary row request context. (rowreq_ctx_ref->rowreq_ctx->tbl_idx)
|
|
*/
|
|
rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
|
|
|
|
/*
|
|
* ToDo:
|
|
* set local vars for index from loop_ctx_ref->loop_ctx
|
|
* this can be done in one of two ways:
|
|
*/
|
|
|
|
/*
|
|
* 1) individually
|
|
*/
|
|
@ foreach $node index@
|
|
@ include m2c_setup_node.m2i@
|
|
/*
|
|
* ToDo:
|
|
* set rowreq_ctx_ref->rowreq_ctx->tbl_idx->$node
|
|
@ if $m2c_node_needlength == 1@
|
|
* and rowreq_ctx_ref->tbl_idx->${node}_len
|
|
@ end@
|
|
*/
|
|
@ end@ #foreach
|
|
|
|
/*
|
|
* OR
|
|
*/
|
|
|
|
/*
|
|
* 2) by calling ${context}_indexes_set()
|
|
* ${context}_indexes_set(rowreq_ctx_ref->tbl_idx,
|
|
@ foreach $node index@
|
|
@ include m2c_setup_node.m2i@
|
|
@ if $m2c_node_needlength == 1@
|
|
* ${node}_ptr, ${node}_len
|
|
@ else@
|
|
* $node
|
|
@ end@
|
|
@ end@ # foreach index
|
|
* );
|
|
*/
|
|
@ end@ # example
|
|
@end@ #ifconf
|
|
|
|
return MFD_SUCCESS;
|
|
} /* ${context}_loop_get_first */
|
|
|
|
/**
|
|
* get the next data index
|
|
*
|
|
* Summary
|
|
* -------
|
|
* This function returns the next data item in the data set. The same
|
|
* caveat applies here as did above. The indexes are the important parts
|
|
* during loop processing.
|
|
*
|
|
* Note that this function does not correspond to a SNMP GET-NEXT pdu, and
|
|
* you should return data items in whatever order they are already in.
|
|
* (In fact, if your data is already ordered in the same order as the
|
|
* SNMP indexes, you shouldn't be using the unsorted-access code).
|
|
*
|
|
* More Details
|
|
* ------------
|
|
* rowreq_ctx_ref->rowreq_ctx will have been set in ${context}_loop_get_first.
|
|
*
|
|
* If there is currently no data available, return MFD_END_OF_DATA.
|
|
* Otherwise, you should set the indexes in rowreq_ctx_ref->rowreq_ctx->tbl_idx.
|
|
*
|
|
* You should set the index (or indexes) in rowreq_ctx_ref->rowreq_ctx->tbl_idx to the
|
|
* appropriate value for this row.
|
|
*
|
|
* @param $mfd_aue_param_cmt
|
|
* @param loop_ctx_ref Pointer to your loop reference.
|
|
* @param rowreq_ctx_ref Pointer to a context reference.
|
|
*
|
|
* @retval MFD_SUCCESS : success.
|
|
* @retval MFD_END_OF_DATA : no more data available
|
|
* @retval MFD_ERROR : error.
|
|
*/
|
|
int
|
|
${context}_loop_get_next( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx *rowreq_ctx_ref)
|
|
{
|
|
DEBUGMSGTL(("verbose:${context}:${context}_loop_get_next","called\n"));
|
|
|
|
netsnmp_assert(loop_ctx_ref && loop_ctx_ref->loop_ctx);
|
|
netsnmp_assert(rowreq_ctx_ref);
|
|
|
|
/*
|
|
* we just need the index for now. Reuse the one in the loop context's
|
|
* temporary row request context. (rowreq_ctx_ref->rowreq_ctx->tbl_idx)
|
|
*/
|
|
rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
|
|
|
|
@ if $m2c_include_examples == 1@
|
|
$example_start
|
|
/*
|
|
* get a line (skip blank lines)
|
|
*/
|
|
do {
|
|
if (!fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line),
|
|
loop_ctx_ref->loop_ctx->filep)) {
|
|
/* we're done */
|
|
fclose(loop_ctx_ref->loop_ctx->filep);
|
|
loop_ctx_ref->loop_ctx->filep = NULL;
|
|
}
|
|
} while (loop_ctx_ref->loop_ctx->filep && (loop_ctx_ref->loop_ctx->line[0] == '\n'));
|
|
|
|
/*
|
|
* check for end of data
|
|
*/
|
|
if(NULL == loop_ctx_ref->loop_ctx->filep)
|
|
return MFD_END_OF_DATA;
|
|
|
|
/*
|
|
* ToDo:
|
|
* set local vars for index from loop_ctx_ref->loop_ctx
|
|
* this can be done in one of two ways:
|
|
*/
|
|
|
|
/*
|
|
* 1) individually
|
|
*/
|
|
@ foreach $node index@
|
|
@ include m2c_setup_node.m2i@
|
|
/*
|
|
* ToDo:
|
|
* set rowreq_ctx_ref->rowreq_ctx->tbl_idx->$node
|
|
@ if $m2c_node_needlength == 1@
|
|
* and rowreq_ctx_ref->tbl_idx->${node}_len
|
|
@ end@
|
|
*/
|
|
@ end@ #foreach
|
|
|
|
/*
|
|
* OR
|
|
*/
|
|
|
|
/*
|
|
* 2) by calling ${context}_indexes_set()
|
|
* ${context}_indexes_set(rowreq_ctx_ref->tbl_idx,
|
|
@ foreach $node index@
|
|
@ include m2c_setup_node.m2i@
|
|
@ if $m2c_node_needlength == 1@
|
|
* ${node}_ptr, ${node}_len
|
|
@ else@
|
|
* $node
|
|
@ end@
|
|
@ end@ # foreach index
|
|
* );
|
|
*/
|
|
$example_end
|
|
@ end@ # example
|
|
|
|
return MFD_SUCCESS;
|
|
} /* ${context}_loop_get_next */
|
|
|
|
/**
|
|
* duplicate the current loop reference
|
|
*
|
|
* Summary
|
|
* -------
|
|
* During loop iteration, the iterator keeps track of the row that
|
|
* is the current best match. This function is called when the
|
|
* current row is a better match than any previous row.
|
|
*
|
|
* You should save any information you need to be able to locate this row
|
|
* again from the current loop context to a new loop context.
|
|
*
|
|
* At the end of the loop, when the best match has been found, the saved
|
|
* loop context will be used to get the data for the row by calling
|
|
* ${context}_loop_get_data().
|
|
@if $m2c_data_transient != 0@ # persistent
|
|
*
|
|
* Since your data is transient, you need to make a copy of it before
|
|
* the iterator moves on to the next row.
|
|
@end@
|
|
*
|
|
@if $m2c_data_transient != 0@ # persistent
|
|
* More Details
|
|
* ------------
|
|
@ if $m2c_data_transient == 1@ # short term
|
|
* Since your data is semi-TRANSIENT data, you could just keep a pointer
|
|
* to the data in the loop reference. The data should then be copied in
|
|
* ${context}_loop_get_data().
|
|
@ else@ # $m2c_data_transient == 2@ # copy immediately
|
|
* One idea would be to copy it space allocated in the loop reference
|
|
* structure. Another would be to simply have a pointer in the loop
|
|
* reference structure, and allocate memory here.
|
|
*
|
|
@ end@
|
|
@end@
|
|
* @param $mfd_aue_param_cmt
|
|
* @param loop_ctx_ref Reference to current loop context.
|
|
* @param save_loop_ctx_ref Reference to a loop context for saving the current
|
|
* position. If reuse is not set or
|
|
* save_loop_ctx_ref->loop_ctx is NULL, allocate
|
|
* a new one. If reuse is set, you may reuse the existing
|
|
* loop_ctx.
|
|
* @param reuse Indicates if an existing save_loop_ctx_ref->loop_ctx
|
|
* may be reused.
|
|
*
|
|
* @retval MFD_SUCCESS : success.
|
|
* @retval MFD_ERROR : error.
|
|
*/
|
|
int
|
|
${context}_loop_save_position($mfd_aue_param_decl,
|
|
${context}_ref_loop_ctx *loop_ctx_ref,
|
|
${context}_ref_loop_ctx *save_loop_ctx_ref,
|
|
int reuse)
|
|
{
|
|
DEBUGMSGTL(("verbose:${context}:${context}_loop_save_position","called\n"));
|
|
|
|
netsnmp_assert(loop_ctx_ref && save_loop_ctx_ref);
|
|
|
|
/*
|
|
* ToDo:
|
|
* 1) allocate new loop context, unless you can reuse a previous pointer.
|
|
* 2) save information for the position of loop_ctx_ref in save_loop_ctx_ref.
|
|
*/
|
|
if((0 == reuse) || (NULL == save_loop_ctx_ref->loop_ctx))
|
|
save_loop_ctx_ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context);
|
|
if(NULL == save_loop_ctx_ref->loop_ctx) {
|
|
snmp_log(LOG_ERR, "could not allocate memory\n");
|
|
return MFD_ERROR;
|
|
}
|
|
|
|
/*
|
|
* if you can reuse a previously saved contex, just swap
|
|
* it out with the loop iterator
|
|
*/
|
|
if(reuse && save_loop_ctx_ref->loop_ctx->rowreq_ctx) {
|
|
${context}_rowreq_ctx * tmp_rowreq_ctx = save_loop_ctx_ref->loop_ctx->rowreq_ctx;
|
|
save_loop_ctx_ref->loop_ctx->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
|
|
loop_ctx_ref->loop_ctx->rowreq_ctx = tmp_rowreq_ctx;
|
|
}
|
|
else {
|
|
/*
|
|
* take the current pointer
|
|
*/
|
|
save_loop_ctx_ref->loop_ctx->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
|
|
|
|
/*
|
|
* allocate a new context to replace the one you just took.
|
|
*/
|
|
@ eval $m2c_tmp = ""@
|
|
@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@
|
|
@ eval $m2c_tmp = "NULL"@
|
|
@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@
|
|
@ eval $m2c_tmp = "$m2c_tmp, NULL"@
|
|
@ @end@
|
|
@ end@
|
|
loop_ctx_ref->loop_ctx->rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp);
|
|
if(NULL == loop_ctx_ref->loop_ctx->rowreq_ctx) {
|
|
SNMP_FREE(loop_ctx_ref->loop_ctx);
|
|
return MFD_ERROR;
|
|
}
|
|
}
|
|
|
|
@if $m2c_data_transient == 0@ # persistent
|
|
/** non-TRANSIENT data: no need to copy */
|
|
@elsif $m2c_data_transient == 1@ # short term
|
|
/** semi-TRANSIENT data: will copy data when index found */
|
|
/** only need to copy pertinent data from loop context */
|
|
@elsif $m2c_data_transient == 2@ # copy immediately
|
|
/*
|
|
* TRANSIENT data: copy all the data.
|
|
*/
|
|
@end@
|
|
@if $m2c_include_examples == 1@
|
|
$example_start
|
|
@ if $m2c_data_transient == 1@ # short term
|
|
/** save line to do that */
|
|
memcpy(save_loop_ctx_ref->loop_ctx->line, loop_ctx_ref->loop_ctx->line,
|
|
sizeof(loop_ctx_ref->loop_ctx->line));
|
|
@ elsif $m2c_data_transient == 2@ # copy immediately
|
|
@ foreach $node nonindex@
|
|
@ include m2c_setup_node.m2i@
|
|
/*
|
|
* ToDo:
|
|
* set rowreq_ctx_ref->${m2c_data_item}$node
|
|
* from the loop context
|
|
*/
|
|
@ end@
|
|
@ end@
|
|
$example_end
|
|
@end@ # example
|
|
|
|
return MFD_SUCCESS;
|
|
} /* ${context}_loop_save_position */
|
|
|
|
@if $m2c_data_transient != 0@ # semi-transient
|
|
/**
|
|
* set ${context}_data from a data context
|
|
*
|
|
* Summary
|
|
* -------
|
|
* At the end of the loop, when the best match has been found, the saved
|
|
* loop context will be used to get the data for the row by calling
|
|
* ${context}_loop_get_data().
|
|
*
|
|
* You should return a fully populated row request context in
|
|
* rowreq_ctx_ref->rowreq_ctx.
|
|
*
|
|
* More Details
|
|
* ------------
|
|
* @param $mfd_aue_param_cmt
|
|
* @param loop_ctx_ref pointer to your loop reference.
|
|
* @param rowreq_ctx_ref pointer to a context reference.
|
|
*/
|
|
int
|
|
${context}_loop_get_data( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref,
|
|
${context}_ref_rowreq_ctx *rowreq_ctx_ref)
|
|
{
|
|
DEBUGMSGTL(("verbose:${context}:${context}_loop_get_data","called\n"));
|
|
|
|
netsnmp_assert((NULL != loop_ctx_ref) && (NULL != loop_ctx_ref->loop_ctx));
|
|
netsnmp_assert(NULL != rowreq_ctx_ref);
|
|
netsnmp_assert(NULL != rowreq_ctx_ref->rowreq_ctx);
|
|
|
|
/*
|
|
* take temporary row request context from loop context
|
|
*/
|
|
rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx;
|
|
loop_ctx_ref->loop_ctx->rowreq_ctx = NULL;
|
|
|
|
/*
|
|
* copy data to the data context (rowreq_ctx_ref->${m2c_data_item})
|
|
@ if $m2c_include_examples == 1@
|
|
* in loop_save_position, we saved line to do that
|
|
@ end@
|
|
*/
|
|
@ foreach $node nonindex@
|
|
@ include m2c_setup_node.m2i@
|
|
/*
|
|
* $m2c_node_summary
|
|
*/
|
|
@ eval $m2c_ctx_lh = "rowreq_ctx_ref->$m2c_ctx_rh"@
|
|
@ eval $m2c_ctx_lhs = "rowreq_ctx_ref->$m2c_ctx_rhs"@
|
|
@ eval $m2c_ctx_rh = "loop_ctx_ref->loop_ctx->$node"@
|
|
@ eval $m2c_ctx_rhs = "loop_ctx_ref->loop_ctx->${node}_len"@
|
|
@ include generic-value-map.m2i@
|
|
|
|
@ end@
|
|
|
|
return MFD_SUCCESS;
|
|
} /* ${context}_loop_get_data */
|
|
|
|
@end@ // if $m2c_data_transient != 0
|
|
|
|
/**
|
|
* clean up a loop reference
|
|
*
|
|
* Summary
|
|
* -------
|
|
* This function will be called once the loop iteration has completed
|
|
* to release any memory or resources allocated for the loop context.
|
|
*
|
|
* More Details
|
|
* ------------
|
|
* @param $mfd_aue_param_cmt
|
|
* @param loop_ctx_ref Pointer to your loop reference.
|
|
*
|
|
* @retval MFD_SUCCESS : success.
|
|
* @retval MFD_ERROR : error.
|
|
*/
|
|
int
|
|
${context}_loop_cleanup_context( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref)
|
|
{
|
|
DEBUGMSGTL(("verbose:${context}:${context}_loop_cleanup_context","called\n"));
|
|
|
|
netsnmp_assert(loop_ctx_ref);
|
|
|
|
if(!loop_ctx_ref->loop_ctx)
|
|
return MFD_ERROR;
|
|
|
|
/*
|
|
* release the row request context, if it wasn't taken
|
|
*/
|
|
if(loop_ctx_ref->loop_ctx->rowreq_ctx)
|
|
${context}_release_rowreq_ctx(loop_ctx_ref->loop_ctx->rowreq_ctx);
|
|
|
|
/*
|
|
* ToDo:
|
|
* release resources
|
|
*/
|
|
@if $m2c_include_examples == 1@
|
|
$example_start
|
|
/*
|
|
* close file
|
|
*/
|
|
if(loop_ctx_ref->loop_ctx->filep)
|
|
fclose(loop_ctx_ref->loop_ctx->filep);
|
|
$example_end
|
|
|
|
@end@
|
|
/*
|
|
* free loop context
|
|
*/
|
|
free(loop_ctx_ref->loop_ctx);
|
|
|
|
return MFD_SUCCESS;
|
|
} /* ${context}_loop_cleanup_context */
|
|
|
|
@end@ // m2c_processing_type eq 'c'
|
|
########################################################################
|
|
##//####################################################################
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@if $m2c_processing_type eq 'r'@
|
|
##
|
|
unsorted-external summary
|
|
-------------------------
|
|
The unsorted-external data access code is for cases when you data is
|
|
kept UNSORTED and EXTERNAL to the agent/sub-agent.
|
|
|
|
This code was generated based on the following assumptions or settings:
|
|
|
|
1) The raw data for this table is UNSORTED.
|
|
@if $mfd_readme_verbose != 0@
|
|
|
|
UNSORTED data is data that is not kept in the same order as the way
|
|
SNMP expects the index(es) for the table to be kept. [It could very
|
|
well be sorted in some other order, but for the purpose of SNMP, the
|
|
order is incorrect.] If you're not sure if your data is sorted
|
|
in an SNMP compliant way, its likely not.
|
|
|
|
Because the raw data is unsorted, to satisfy a particular request, the
|
|
entire data set must be examined to find the apropriate index. This
|
|
is done via a simple loop. The MFD handler will call your get_first
|
|
function and the call the get_next function repeatedly, until it
|
|
returns SNMPERR_NO_VARS.
|
|
@end@
|
|
|
|
2) The raw data for this table is EXTERNAL.
|
|
@if $mfd_readme_verbose != 0@
|
|
|
|
EXTERNAL data is data that is owned by some other process,
|
|
device, file or mechanism. The agent must use some interface to
|
|
read or modify the data. An external process may modify the data
|
|
without the agent's knowledge. For example, the Net-SNMP agent
|
|
implements the interface table (ifTable), which reports on
|
|
network interfaces. The host operating system owns this data, and
|
|
Net-SNMP must use system calls to report or manipulate the data.
|
|
Examples of external data include data stored in kernel space, in
|
|
files, in another non-memory shared process, and data stored in
|
|
devices.
|
|
@end@
|
|
|
|
3) The raw data for this table is TRANSIENT.
|
|
@if $mfd_readme_verbose != 0@
|
|
|
|
TRANSIENT data is data that may be overwritten by another funtion
|
|
or process. For example, many OS functions return data in a
|
|
static buffer that will be reused the next time the function is
|
|
called. Because of this, we will assume that you will copy the
|
|
raw data retrieved from these other sources to a generated
|
|
structure for use within the Net-SNMP agent. (Don't worry, we'll
|
|
help you)
|
|
@end@
|
|
|
|
|
|
##
|
|
## this should be syncronized with master version of comments in
|
|
## mfd-access-unsorted-external-body.m2i You should be able to copy
|
|
## the comments here and replace " * " with " ".
|
|
##
|
|
The unsorted external data access code works by calling a few simple
|
|
functions to get the index value for each row. Once the agent determines
|
|
which row is needed to process an incoming request, another function
|
|
is called to retrieve the data for that row.
|
|
|
|
A simplified version of the pseudo-code looks like this:
|
|
|
|
${context}_loop_init_context(loop)
|
|
${context}_loop_get_first(loop,data)
|
|
while( no_error ) {
|
|
if( best_match(data, key)
|
|
${context}_loop_save_position(loop,pos);
|
|
${context}_loop_get_next(loop,data)
|
|
}
|
|
${context}_loop_get_data(pos,data)
|
|
${context}_loop_cleanup_context(loop)
|
|
##
|
|
## end sync
|
|
##
|
|
|
|
We will talk about each individual step below.
|
|
|
|
|
|
########################################################################
|
|
Defining context for the loop
|
|
-----------------------------
|
|
ToDo : typedef ${context}_loop_context
|
|
WHERE: ${table}_data_access.h
|
|
|
|
@if $mfd_readme_verbose != 0@
|
|
##
|
|
## this should be syncronized with master version of comments in
|
|
## mfd-access-unsorted-external-body.m2i You should be able to copy
|
|
## the comments here and replace " * " with " ".
|
|
##
|
|
Since the actual loop is in the MFD handler, a loop contex parameter
|
|
is provided to help you keep track of where you are in between calls
|
|
to functions that you wrote and the master MFD handler calls. The
|
|
structure of this context is user defineable, and is defined in the
|
|
file ${table}_data_access.h.
|
|
|
|
E.G., if your data is stored in a linked list, the obvious thing you
|
|
want to know from one function call to the next is your current
|
|
position in the linked list. Thus the easiest context to use is a
|
|
pointer within the linked list. For an array, the current index to
|
|
that array would be easiest.
|
|
|
|
The funtion calls are actually passed a reference to the loop
|
|
context, to allow the loop context to be allocated memory. Here are
|
|
some simple examples definitions for various data formats. These
|
|
definitions are used in examples later on.
|
|
##
|
|
## end sync
|
|
##
|
|
|
|
Linked list
|
|
-----------
|
|
typedef list_node ${context}_loop_context;
|
|
|
|
Array
|
|
-----
|
|
typedef integer ${context}_loop_context;
|
|
|
|
File
|
|
----
|
|
typedef struct ${context}_loop_context_s {
|
|
char * file_name;
|
|
FILE * f;
|
|
char line[128];
|
|
} ${context}_loop_context;
|
|
|
|
@end@
|
|
|
|
########################################################################
|
|
Initialization
|
|
--------------
|
|
ToDo : Initialization
|
|
FUNC : ${context}_loop_init_data
|
|
WHERE: ${table}_data_access.c
|
|
|
|
@if $mfd_readme_verbose != 0@
|
|
The ${context}_loop_init_data function will be called during startup to
|
|
allow for any initialization needed for the data access routines.
|
|
|
|
@end@
|
|
|
|
########################################################################
|
|
Preparing for the loop
|
|
----------------------
|
|
ToDo : initialize loop context
|
|
FUNC : ${context}_loop_init_context
|
|
WHERE: ${table}_data_access.c
|
|
|
|
@if $mfd_readme_verbose != 0@
|
|
##
|
|
## this should be syncronized with master version of comments in
|
|
## mfd-access-unsorted-external-body.m2i You should be able to copy
|
|
## the comments here and replace " * " with " ".
|
|
##
|
|
This function will be called before the start of a new itertion over
|
|
the data. The loop context that is initialized here will be passed to
|
|
${context}_loop_get_first and ${context}_loop_get_next.
|
|
|
|
Set the loop context variable ref->loop_ctx so that the iteration
|
|
functions (get_first and get_next) can locate the apropriate data
|
|
context.
|
|
##
|
|
## end sync
|
|
##
|
|
|
|
The primary purpose of the loop_init_context call is to initialize
|
|
the loop context data (ref). Here are some simple examples, based on the
|
|
earlier example loop contexts.
|
|
|
|
Linked list
|
|
-----------
|
|
ref->loop_ctx = my_table_head_ptr;
|
|
|
|
Array
|
|
-----
|
|
/* instead of actually allocating memory, just use the pointer */
|
|
/* as an integer */
|
|
(integer)(ref->loop_ctx) = 0;
|
|
|
|
File
|
|
----
|
|
ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context);
|
|
/* error checking here */
|
|
ref->loop_ctx->file_name = (char*) reg->mfd_user_ctx;
|
|
ref->loop_ctx->f = fopen( ref->loop_ctx->file_name, "r+" );
|
|
|
|
@end@
|
|
|
|
########################################################################
|
|
The Loop
|
|
--------
|
|
ToDo : return raw data
|
|
FUNC : ${context}_loop_get_first
|
|
WHERE: ${table}_data_access.c
|
|
|
|
@if $mfd_readme_verbose != 0@
|
|
##
|
|
## this should be syncronized with master version of comments in
|
|
## mfd-access-unsorted-external-body.m2i You should be able to copy
|
|
## the comments here and replace " * " with " ".
|
|
##
|
|
This function is called to return set the index(es) for the first
|
|
${context}_data in the data set.
|
|
|
|
Note that during the loop, the only important thing is the indexes.
|
|
If access to your data is cheap/fast (e.g. you have a pointer to a
|
|
structure in memory), it would make sense to update the data here.
|
|
If, however, the accessing the data involves more work (e.g. parsing
|
|
some other existing data, or peforming calculations to derive the data),
|
|
then you should limit yourslef to setting the indexes. Extracting the
|
|
can be put off until the desired row is found See the notes on
|
|
${context}_loop_get_data().
|
|
|
|
Note that this function does not correspond to a SNMP GET pdu, and
|
|
you should return data items in whatever order they are already in.
|
|
(In fact, if your data is already ordered in the same order as the
|
|
SNMP indexes, you shouldn't be using the unsorted-access code).
|
|
|
|
This function should update the table index (rowreq_ctx_ref->rowreq_ctx->tbl_idx)
|
|
values for the raw data (rowreq_ctx_ref->rowreq_ctx->data).
|
|
##
|
|
## end sync
|
|
##
|
|
|
|
Linked list
|
|
-----------
|
|
rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx;
|
|
|
|
Array
|
|
-----
|
|
/* assuming registration has array of pointers */
|
|
rowreq_ctx_ref->rowreq_ctx->data = reg->mfd_user_ctx[(integer)(ref->loop_ctx)];
|
|
|
|
File
|
|
----
|
|
fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line),
|
|
loop_ctx_ref->loop_ctx->f);
|
|
rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx->line;
|
|
|
|
@end@
|
|
|
|
ToDo : return raw data
|
|
FUNC : ${context}_loop_get_next
|
|
WHERE: ${table}_data_access.c
|
|
|
|
@if $mfd_readme_verbose != 0@
|
|
##
|
|
## this should be syncronized with master version of comments in
|
|
## mfd-access-unsorted-external-body.m2i You should be able to copy
|
|
## the comments here and replace " * " with " ".
|
|
##
|
|
This function returns the next data item in the data set. The same
|
|
caveat applies here as did above. The indexes are the important parts
|
|
during loop processing.
|
|
|
|
Note that this function does not correspond to a SNMP GET-NEXT pdu, and
|
|
you should return data items in whatever order they are already in.
|
|
(In fact, if your data is already ordered in the same order as the
|
|
SNMP indexes, you shouldn't be using the unsorted-access code).
|
|
##
|
|
## end sync
|
|
##
|
|
|
|
Linked list
|
|
-----------
|
|
loop_ctx_ref->loop_ctx = loop_ctx_ref->loop_ctx->next;
|
|
rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx;
|
|
|
|
Array
|
|
-----
|
|
++((integer)(ref->loop_ctx));
|
|
/* assuming registration has array of pointers */
|
|
rowreq_ctx_ref->rowreq_ctx->data = reg->mfd_user_ctx[(integer)(ref->loop_ctx)];
|
|
|
|
File
|
|
----
|
|
fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line),
|
|
loop_ctx_ref->loop_ctx->f);
|
|
rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx->line;
|
|
|
|
@end@
|
|
|
|
########################################################################
|
|
Updating the Index
|
|
------------------
|
|
ToDo : update index for the raw data
|
|
FUNC : ${context}_indexes_set
|
|
WHERE: ${table}_data_access.c
|
|
|
|
This is a convenience function for setting the index context from
|
|
the native C data. Where necessary, value mapping should be done.
|
|
|
|
@if $mfd_readme_verbose == 1@
|
|
This function should update the table index values (found in
|
|
tbl_idx) for the given raw data.
|
|
|
|
@end@
|
|
|
|
########################################################################
|
|
Saving a position in the loop
|
|
-----------------------------
|
|
ToDo : Saving a position in the loop
|
|
FUNC : ${context}_loop_save_position
|
|
WHERE: ${table}_data_access.c
|
|
|
|
@if $mfd_readme_verbose != 0@
|
|
##
|
|
## this should be syncronized with master version of comments in
|
|
## mfd-access-unsorted-external-body.m2i You should be able to copy
|
|
## the comments here and replace " * " with " ".
|
|
##
|
|
During loop iteration, the iterator keeps track of the row that
|
|
is the current best match. This function is called when the
|
|
current row is a better match than any previous row.
|
|
|
|
You should save any information you need to be able to locate this row
|
|
again from the current loop context to a new loop context.
|
|
|
|
At the end of the loop, when the best match has been found, the saved
|
|
loop context will be used to get the data for the row by calling
|
|
${context}_loop_get_data().
|
|
@if $m2c_data_transient != 0@ # persistent
|
|
|
|
Since your data is transient, you need to make a copy of it before
|
|
the iterator moves on to the next row.
|
|
@end@
|
|
##
|
|
## end sync
|
|
##
|
|
|
|
@end@
|
|
|
|
########################################################################
|
|
Returning Data For an Index
|
|
---------------------------
|
|
ToDo : copy transient raw data to generated structure
|
|
FUNC : ${context}_loop_get_data
|
|
WHERE: ${table}_data_access.c
|
|
|
|
@if $mfd_readme_verbose != 0@
|
|
##
|
|
## this should be syncronized with master version of comments in
|
|
## mfd-access-unsorted-external-body.m2i You should be able to copy
|
|
## the comments here and replace " * " with " ".
|
|
##
|
|
At the end of the loop, when the best match has been found, the saved
|
|
loop context will be used to get the data for the row by calling
|
|
${context}_loop_get_data().
|
|
##
|
|
## end sync
|
|
##
|
|
|
|
@end@
|
|
|
|
########################################################################
|
|
Cleaning up after the loop
|
|
--------------------------
|
|
ToDo : release any allocated memory
|
|
FUNC : ${context}_loop_cleanup_context
|
|
WHERE: ${table}_data_access.c
|
|
|
|
@if $mfd_readme_verbose != 0@
|
|
##
|
|
## this should be syncronized with master version of comments in
|
|
## mfd-access-unsorted-external-body.m2i You should be able to copy
|
|
## the comments here and replace " * " with " ".
|
|
##
|
|
This function will be called once the loop iteration has completed
|
|
to release any memory allocated for loop reference.
|
|
##
|
|
## end sync
|
|
##
|
|
The purpose of the loop_cleanup_context call is to release any memory
|
|
allocated for the loop context data. Here are some simple examples, based
|
|
on the earlier example loop contexts.
|
|
|
|
Linked list
|
|
-----------
|
|
/* nothing to do */
|
|
|
|
Array
|
|
-----
|
|
/* nothing to do */
|
|
|
|
File
|
|
----
|
|
free(ref->loop_ctx);
|
|
|
|
@end@
|
|
|
|
##
|
|
@end@ // m2c_processing_type eq 'r
|
|
########################################################################
|
|
@if $m2c_mark_boundary == 1@
|
|
/** END code generated by mfd-access-unsorted-external-defines.m2i */
|
|
@end@
|