/***************************************************************************
 *                         var_args_mod.c -  description
 *                            -------------------
 *   begin                : Mon 26 Dec 2005 12:02:33 PM EST
 *   copyright            : (C) 2005 by Terry D. Boldt
 *   email                : fastsnip-wm1@yahoo.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
/*
 *
 *   QTAwk plugin function to demonstrate variable argument function
 */

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

/* Note QTAwk_plugins.h header file depeneds on "string.h" header file.
 * ALWAYS include "string.h" before QTAwk_plugins
 */
#include "QTAwk_plugins.h"

/* define some useful constants
 */
#define TRUE  1
#define FALSE 0

/* define End Of String marker
 */
#define EOS '\x000'

/* define initialization function
 */
unsigned QTAwk_init_load_module(
void)
{
    /* array of pointers to string with argument names for loaded functions
     * Here both functions take a single string function
     */
    unsigned char *arguments[] = {
                    "count",
                    NULL
                    };

    /* declare error return variable
     */
    unsigned char *reg_err;

    /* call function to initialize for installing dynamic function(s)
     */
    QTAwk_register_function_count(3);

    /* now call function to register each dynamic function to load
     *
     * Note that 'QTAwk_register_function' returns a pointer to a string or NULL
     * if no error in registering function. Here we are ignoring the return value
     * until returning from the call.
     * We "should" examine the return value for every call to 'QTAwk_register_function'
     * and report any errors.
     */
    reg_err = QTAwk_register_function("vararg_mod_version",NULL,FALSE);
    reg_err = QTAwk_register_function("variable_arg_c",NULL,TRUE);
    reg_err = QTAwk_register_function("variable_arg_s",NULL,TRUE);

    QTAwk_set_module_exit_function("var_args_mod_exit");

    return reg_err ? -1 : 0;
} /* QTAwk_init_load_module */

/* function registered to accomplish actual work.
 *
 * All dynamically loaded functions have the following prototype form:
 *
 *      Variable_ptr loaded_function(unsigned argument_count);
 *
 * Where 'Variable_ptr' is a QTAwk variable defined in the QTAwk plugin
 *  header file "QTAwk_plugins.h"
 *  Do NOT manipulate the fields in the structure directly. Use the function
 *  calls defined in "QTAwk_plugins.h" for that purpose.
 *
 *
 *
 */

/* version string
 */
static unsigned char vararg_mod_version_string[] = "Variable Argument Demo. Version 1.00";

/* function to return module version string
 */
Variable_ptr  vararg_mod_version(
void)
{
    Variable_ptr   retval;

    retval = QTAwk_get_variable_set((void *)vararg_mod_version_string,STRING_VAL);

    return retval;
} /* vararg_mod_version */

/* sequence through array elements and find largest value
 * this could be done in QTAwk with the following user defined function:
 *
 *      function variable_arg_s(...)
 *      {
 *          local i;
 *          local cmp1 = 0, cmp2;
 *
 *          for ( i in vargv ) {
 *              cmp2 = vargv[i];
 *              if ( cmp2 > cmp1 ) cmp1 = cmp2;
 *          } ## endfor
 *          return cmp1;
 *      }
 *
 *
 * You will also note that the function parameter, arg_cnt paased to the
 * function contains the actual number of arguments specified in the
 * call. Since all of the arguments for this function are optional,
 * arg_cnt will be equal to the value passed in the QTAwk variable vargc
 */
Variable_ptr variable_arg_s(
unsigned     arg_cnt)
{
    Variable_ptr     arg_element;
    Variable_ptr     vararg_count;
    Variable_ptr     vararg_array;
    Variable_ptr     return_val;
    unsigned         vcnt;
    unsigned         vtype;
    unsigned         seqstate;
    qta_long         cmp1 = 0LL,
                     cmp2;

    /* get arguments
     * first the vargc argument with the count of variable arguments
     * then the vargv argument as a one-dimensional array of the variable arguments
     * For this example we are assuming all variable arguments are integers and
     * returning the maximum value.
     */
    vararg_count = QTAwk_get_argument(1,NULL);
    vararg_array = QTAwk_get_argument(2,NULL);

    vtype = LONG_VAL;
    vcnt = *(qta_long *)QTAwk_get_value(vararg_count,&vtype);

    /* check that variable indexed, then now sequence through array elements,
     * retrieving values and comparing to previous value.
     */
    for ( arg_element = QTAwk_first_array_element(vararg_array,&seqstate,NULL) ;
          arg_element ;
          arg_element = QTAwk_next_array_element(seqstate,NULL) ) {
        vtype = LONG_VAL;
        cmp2 = *(qta_long *)QTAwk_get_value(arg_element,&vtype);
        if ( cmp2 > cmp1 ) cmp1 = cmp2;
    } /* endfor */

    /* now tidy up array sequence function - ALWAYS call this function when done
     * sequencing through array elements
     */
    QTAwk_array_finish(seqstate);

    return_val = QTAwk_get_variable_set((void *)&cmp1,LONG_VAL);

    return return_val;
} /* variable_arg */

/* sequence through array elements and find largest value
 * this could be done in QTAwk with the following user defined function:
 *
 *      function variable_arg_s(...)
 *      {
 *          local i;
 *          local cmp1 = 0, cmp2;
 *
 *          for ( i = 0 ; i < vargc ; i++ ) {
 *              cmp2 = vargv[i];
 *              if ( cmp2 > cmp1 ) cmp1 = cmp2;
 *          } ## endfor
 *          return cmp1;
 *      }
 *
 *
 * You will also note that the function parameter, arg_cnt paased to the
 * function contains the actual number of arguments specified in the
 * call. Since all of the arguments for this function are optional,
 * arg_cnt will be equal to the value passed in the QTAwk variable vargc
 */
Variable_ptr variable_arg_c(
unsigned     arg_cnt)
{
    Variable_ptr     arg_element;
    Variable_ptr     vararg_count;
    Variable_ptr     vararg_array;
    Variable_ptr     return_val;
    unsigned         vcnt;
    unsigned         lcnt;
    unsigned         vtype;
    qta_long         cmp1 = 0LL,
                     cmp2;

    /* get arguments
     * first the vargc argument with the count of variable arguments
     * then the vargv argument as a one-dimensional array of the variable arguments
     * For this example we are assuming all variable arguments are integers and
     * returning the maximum value.
     */
    vararg_count = QTAwk_get_argument(1,NULL);
    vararg_array = QTAwk_get_argument(2,NULL);

    vtype = LONG_VAL;
    vcnt = *(qta_long *)QTAwk_get_value(vararg_count,&vtype);

    /* now loop through array elements
     *
     * NOTE: array elements start numbering at ONE, 1, NOT zero.
     */
    for ( lcnt = 1 ; lcnt <= vcnt ; lcnt++ ) {
        if ( arg_element = QTAwk_get_array_element(vararg_array,"n",lcnt) ) {
            vtype = LONG_VAL;
            cmp2 = *(qta_long *)QTAwk_get_value(arg_element,&vtype);
            if ( cmp2 > cmp1 ) cmp1 = cmp2;
        } /* endif */
    } /* endfor */

    return_val = QTAwk_get_variable_set((void *)&cmp1,LONG_VAL);

    return return_val;
} /* variable_arg */
/* exit function - executed before unloading module
 * Using default function name here.
 */
unsigned var_args_mod_exit(
void)
{
    printf("Unloading Variable Argument module.\n");
} /* var_args_mod_exit */