"Fossies" - the Fresh Open Source Software Archive

Member "gawk-5.1.0/gawkapi.h" (6 Feb 2020, 40645 Bytes) of package /linux/misc/gawk-5.1.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gawkapi.h" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.0.1_vs_5.1.0.

    1 /*
    2  * gawkapi.h -- Definitions for use by extension functions calling into gawk.
    3  */
    4 
    5 /*
    6  * Copyright (C) 2012-2019 the Free Software Foundation, Inc.
    7  *
    8  * This file is part of GAWK, the GNU implementation of the
    9  * AWK Programming Language.
   10  *
   11  * GAWK is free software; you can redistribute it and/or modify
   12  * it under the terms of the GNU General Public License as published by
   13  * the Free Software Foundation; either version 3 of the License, or
   14  * (at your option) any later version.
   15  *
   16  * GAWK is distributed in the hope that it will be useful,
   17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19  * GNU General Public License for more details.
   20  *
   21  * You should have received a copy of the GNU General Public License
   22  * along with this program; if not, write to the Free Software
   23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   24  */
   25 
   26 /*
   27  * The following types and/or macros and/or functions are referenced
   28  * in this file.  For correct use, you must therefore include the
   29  * corresponding standard header file BEFORE including this file.
   30  *
   31  * FILE         - <stdio.h>
   32  * NULL         - <stddef.h>
   33  * memset(), memcpy()   - <string.h>
   34  * size_t       - <sys/types.h>
   35  * struct stat      - <sys/stat.h>
   36  *
   37  * Due to portability concerns, especially to systems that are not
   38  * fully standards-compliant, it is your responsibility to include
   39  * the correct files in the correct way. This requirement is necessary
   40  * in order to keep this file clean, instead of becoming a portability
   41  * hodge-podge as can be seen in the gawk source code.
   42  *
   43  * To pass reasonable integer values for ERRNO, you will also need to
   44  * include <errno.h>.
   45  */
   46 
   47 #ifndef _GAWK_API_H
   48 #define _GAWK_API_H
   49 
   50 /*
   51  * General introduction:
   52  *
   53  * This API purposely restricts itself to ISO C 90 features.  In particular, no
   54  * bool, no // comments, no use of the restrict keyword, or anything else,
   55  * in order to provide maximal portability.
   56  *
   57  * Exception: the "inline" keyword is used below in the "constructor"
   58  * functions. If your compiler doesn't support it, you should either
   59  * -Dinline='' on your command line, or use the autotools and include a
   60  * config.h in your extensions.
   61  *
   62  * Additional important information:
   63  *
   64  * 1. ALL string values in awk_value_t objects need to come from api_malloc().
   65  * Gawk will handle releasing the storage if necessary.  This is slightly
   66  * awkward, in that you can't take an awk_value_t that you got from gawk
   67  * and reuse it directly, even for something that is conceptually pass
   68  * by value.
   69  *
   70  * 2. Due to gawk internals, after using sym_update() to install an array
   71  * into gawk, you have to retrieve the array cookie from the value
   72  * passed in to sym_update().  Like so:
   73  *
   74  *  new_array = create_array();
   75  *  val.val_type = AWK_ARRAY;
   76  *  val.array_cookie = new_array;
   77  *  sym_update("array", & val); // install array in the symbol table
   78  *
   79  *  new_array = val.array_cookie;   // MUST DO THIS
   80  *
   81  *  // fill in new array with lots of subscripts and values
   82  *
   83  * Similarly, if installing a new array as a subarray of an existing
   84  * array, you must add the new array to its parent before adding any
   85  * elements to it.
   86  *
   87  * You must also retrieve the value of the array_cookie after the call
   88  * to set_element().
   89  *
   90  * Thus, the correct way to build an array is to work "top down".
   91  * Create the array, and immediately install it in gawk's symbol table
   92  * using sym_update(), or install it as an element in a previously
   93  * existing array using set_element().
   94  *
   95  * Thus the new array must ultimately be rooted in a global symbol. This is
   96  * necessary before installing any subarrays in it, due to gawk's
   97  * internal implementation.  Strictly speaking, this is required only
   98  * for arrays that will have subarrays as elements; however it is
   99  * a good idea to always do this.  This restriction may be relaxed
  100  * in a subsequent revision of the API.
  101  */
  102 
  103 /* Allow use in C++ code.  */
  104 #ifdef __cplusplus
  105 extern "C" {
  106 #endif
  107 
  108 /* This is used to keep extensions from modifying certain fields in some structs. */
  109 #ifdef GAWK
  110 #define awk_const
  111 #else
  112 #define awk_const const
  113 #endif
  114 
  115 typedef enum awk_bool {
  116     awk_false = 0,
  117     awk_true
  118 } awk_bool_t;   /* we don't use <stdbool.h> on purpose */
  119 
  120 /*
  121  * If an input parser would like to specify the field positions in the input
  122  * record, it may populate an awk_fieldwidth_info_t structure to indicate
  123  * the location of each field. The use_chars boolean controls whether the
  124  * field lengths are specified in terms of bytes or potentially multi-byte
  125  * characters. Performance will be better if the values are supplied in
  126  * terms of bytes. The fields[0].skip value indicates how many bytes (or
  127  * characters) to skip before $1, and fields[0].len is the length of $1, etc.
  128  */
  129 
  130 typedef struct {
  131     awk_bool_t  use_chars;  /* false ==> use bytes */
  132     size_t      nf;
  133     struct awk_field_info {
  134         size_t  skip;   /* amount to skip before field starts */
  135         size_t  len;    /* length of field */
  136     } fields[1];        /* actual dimension should be nf */
  137 } awk_fieldwidth_info_t;
  138 
  139 /*
  140  * This macro calculates the total struct size needed. This is useful when
  141  * calling malloc or realloc.
  142  */
  143 #define awk_fieldwidth_info_size(NF) (sizeof(awk_fieldwidth_info_t) + \
  144             (((NF)-1) * sizeof(struct awk_field_info)))
  145 
  146 /* The information about input files that input parsers need to know: */
  147 typedef struct awk_input {
  148     const char *name;   /* filename */
  149     int fd;         /* file descriptor */
  150 #define INVALID_HANDLE (-1)
  151     void *opaque;           /* private data for input parsers */
  152     /*
  153      * The get_record function is called to read the next record of data.
  154      *
  155      * It should return the length of the input record or EOF, and it
  156      * should set *out to point to the contents of $0. The rt_start
  157      * and rt_len arguments should be used to return RT to gawk.
  158      * If EOF is not returned, the parser must set *rt_len (and
  159      * *rt_start if *rt_len is non-zero).
  160      *
  161      * Note that gawk will make a copy of the record in *out, so the
  162      * parser is responsible for managing its own memory buffer.
  163      * Similarly, gawk will make its own copy of RT, so the parser
  164      * is also responsible for managing this memory.
  165      *
  166      * It is guaranteed that errcode is a valid pointer, so there is
  167      * no need to test for a NULL value.  Gawk sets *errcode to 0,
  168      * so there is no need to set it unless an error occurs.
  169      *
  170      * If an error does occur, the function should return EOF and set
  171      * *errcode to a positive value.  In that case, if *errcode is greater
  172      * than zero, gawk will automatically update the ERRNO variable based
  173      * on the value of *errcode (e.g., setting *errcode = errno should do
  174      * the right thing).
  175      *
  176      * If field_width is non-NULL, then *field_width will be initialized
  177      * to NULL, and the function may set it to point to a structure
  178      * supplying field width information to override the default
  179      * gawk field parsing mechanism. Note that this structure will not
  180      * be copied by gawk; it must persist at least until the next call
  181      * to get_record or close_func. Note also that field_width will
  182      * be NULL when getline is assigning the results to a variable, thus
  183      * field parsing is not needed.
  184      */
  185     int (*get_record)(char **out, struct awk_input *iobuf, int *errcode,
  186             char **rt_start, size_t *rt_len,
  187             const awk_fieldwidth_info_t **field_width);
  188 
  189     /*
  190      * No argument prototype on read_func to allow for older systems
  191      * whose headers are not up to date.
  192      */
  193     ssize_t (*read_func)();
  194 
  195     /*
  196      * The close_func is called to allow the parser to free private data.
  197      * Gawk itself will close the fd unless close_func first sets it to
  198      * INVALID_HANDLE.
  199      */
  200     void (*close_func)(struct awk_input *iobuf);
  201 
  202     /* put last, for alignment. bleah */
  203     struct stat sbuf;       /* stat buf */
  204 
  205 } awk_input_buf_t;
  206 
  207 typedef struct awk_input_parser {
  208     const char *name;   /* name of parser */
  209 
  210     /*
  211      * The can_take_file function should return true if the parser
  212      * would like to parse this file.  It should not change any gawk
  213      * state!
  214      */
  215     awk_bool_t (*can_take_file)(const awk_input_buf_t *iobuf);
  216 
  217     /*
  218      * If this parser is selected, then take_control_of will be called.
  219      * It can assume that a previous call to can_take_file was successful,
  220      * and no gawk state has changed since that call.  It should populate
  221      * the awk_input_buf_t's get_record, close_func, and opaque values as needed.
  222      * It should return true if successful.
  223      */
  224     awk_bool_t (*take_control_of)(awk_input_buf_t *iobuf);
  225 
  226     awk_const struct awk_input_parser *awk_const next;  /* for use by gawk */
  227 } awk_input_parser_t;
  228 
  229 /*
  230  * Similar for output wrapper.
  231  */
  232 
  233 /* First the data structure */
  234 typedef struct awk_output_buf {
  235     const char *name;   /* name of output file */
  236     const char *mode;   /* mode argument to fopen */
  237     FILE *fp;       /* stdio file pointer */
  238     awk_bool_t redirected;  /* true if a wrapper is active */
  239     void *opaque;       /* for use by output wrapper */
  240 
  241     /*
  242      * Replacement functions for I/O.  Just like the regular
  243      * versions but also take the opaque pointer argument.
  244      */
  245     size_t (*gawk_fwrite)(const void *buf, size_t size, size_t count,
  246                 FILE *fp, void *opaque);
  247     int (*gawk_fflush)(FILE *fp, void *opaque);
  248     int (*gawk_ferror)(FILE *fp, void *opaque);
  249     int (*gawk_fclose)(FILE *fp, void *opaque);
  250 } awk_output_buf_t;
  251 
  252 /* Next the output wrapper registered with gawk */
  253 typedef struct awk_output_wrapper {
  254     const char *name;   /* name of the wrapper */
  255 
  256     /*
  257      * The can_take_file function should return true if the wrapper
  258      * would like to process this file.  It should not change any gawk
  259      * state!
  260      */
  261     awk_bool_t (*can_take_file)(const awk_output_buf_t *outbuf);
  262 
  263     /*
  264      * If this wrapper is selected, then take_control_of will be called.
  265      * It can assume that a previous call to can_take_file was successful,
  266      * and no gawk state has changed since that call.  It should populate
  267      * the awk_output_buf_t function pointers and opaque pointer as needed.
  268      * It should return true if successful.
  269      */
  270     awk_bool_t (*take_control_of)(awk_output_buf_t *outbuf);
  271 
  272     awk_const struct awk_output_wrapper *awk_const next;  /* for use by gawk */
  273 } awk_output_wrapper_t;
  274 
  275 /* A two-way processor combines an input parser and an output wrapper. */
  276 typedef struct awk_two_way_processor {
  277     const char *name;   /* name of the two-way processor */
  278 
  279     /*
  280      * The can_take_file function should return true if the two-way
  281      * processor would like to parse this file.  It should not change
  282      * any gawk state!
  283      */
  284     awk_bool_t (*can_take_two_way)(const char *name);
  285 
  286     /*
  287      * If this processor is selected, then take_control_of will be called.
  288      * It can assume that a previous call to can_take_file was successful,
  289      * and no gawk state has changed since that call.  It should populate
  290      * the awk_input_buf_t and awk_otuput_buf_t structures as needed.
  291      * It should return true if successful.
  292      */
  293     awk_bool_t (*take_control_of)(const char *name, awk_input_buf_t *inbuf,
  294                     awk_output_buf_t *outbuf);
  295 
  296     awk_const struct awk_two_way_processor *awk_const next;  /* for use by gawk */
  297 } awk_two_way_processor_t;
  298 
  299 #define gawk_api_major_version 3
  300 #define gawk_api_minor_version 0
  301 
  302 /* Current version of the API. */
  303 enum {
  304     GAWK_API_MAJOR_VERSION = gawk_api_major_version,
  305     GAWK_API_MINOR_VERSION = gawk_api_minor_version
  306 };
  307 
  308 /* A number of typedefs related to different types of values. */
  309 
  310 /*
  311  * A mutable string. Gawk owns the memory pointed to if it supplied
  312  * the value. Otherwise, it takes ownership of the memory pointed to.
  313  *
  314  * The API deals exclusively with regular chars; these strings may
  315  * be multibyte encoded in the current locale's encoding and character
  316  * set. Gawk will convert internally to wide characters if necessary.
  317  *
  318  * Note that a string provided by gawk will always be terminated
  319  * with a '\0' character.
  320  */
  321 typedef struct awk_string {
  322     char *str;  /* data */
  323     size_t len; /* length thereof, in chars */
  324 } awk_string_t;
  325 
  326 enum AWK_NUMBER_TYPE {
  327     AWK_NUMBER_TYPE_DOUBLE,
  328     AWK_NUMBER_TYPE_MPFR,
  329     AWK_NUMBER_TYPE_MPZ
  330 };
  331 
  332 typedef struct awk_number {
  333     double d;   /* always populated in data received from gawk */
  334     enum AWK_NUMBER_TYPE type;
  335     void *ptr;  /* either NULL or mpfr_ptr or mpz_ptr */
  336 } awk_number_t;
  337 
  338 /* Arrays are represented as an opaque type. */
  339 typedef void *awk_array_t;
  340 
  341 /* Scalars can be represented as an opaque type. */
  342 typedef void *awk_scalar_t;
  343 
  344 /* Any value can be stored as a cookie. */
  345 typedef void *awk_value_cookie_t;
  346 
  347 /*
  348  * This tag defines the type of a value.
  349  *
  350  * Values are associated with regular variables and with array elements.
  351  * Since arrays can be multidimensional (as can regular variables)
  352  * it's valid to have a "value" that is actually an array.
  353  */
  354 typedef enum {
  355     AWK_UNDEFINED,
  356     AWK_NUMBER,
  357     AWK_STRING,
  358     AWK_REGEX,
  359     AWK_STRNUM,
  360     AWK_ARRAY,
  361     AWK_SCALAR,     /* opaque access to a variable */
  362     AWK_VALUE_COOKIE    /* for updating a previously created value */
  363 } awk_valtype_t;
  364 
  365 /*
  366  * An awk value. The val_type tag indicates what
  367  * is in the union.
  368  */
  369 typedef struct awk_value {
  370     awk_valtype_t   val_type;
  371     union {
  372         awk_string_t    s;
  373         awk_number_t    n;
  374         awk_array_t a;
  375         awk_scalar_t    scl;
  376         awk_value_cookie_t vc;
  377     } u;
  378 #define str_value   u.s
  379 #define strnum_value    str_value
  380 #define regex_value str_value
  381 #define num_value   u.n.d
  382 #define num_type    u.n.type
  383 #define num_ptr     u.n.ptr
  384 #define array_cookie    u.a
  385 #define scalar_cookie   u.scl
  386 #define value_cookie    u.vc
  387 } awk_value_t;
  388 
  389 /*
  390  * A "flattened" array element. Gawk produces an array of these
  391  * inside the awk_flat_array_t.
  392  * ALL memory pointed to belongs to gawk. Individual elements may
  393  * be marked for deletion. New elements must be added individually,
  394  * one at a time, using the separate API for that purpose.
  395  */
  396 
  397 typedef struct awk_element {
  398     /* convenience linked list pointer, not used by gawk */
  399     struct awk_element *next;
  400     enum {
  401         AWK_ELEMENT_DEFAULT = 0,    /* set by gawk */
  402         AWK_ELEMENT_DELETE = 1      /* set by extension if
  403                            should be deleted */
  404     } flags;
  405     awk_value_t index;
  406     awk_value_t value;
  407 } awk_element_t;
  408 
  409 /*
  410  * A "flattened" array. See the description above for how
  411  * to use the elements contained herein.
  412  */
  413 typedef struct awk_flat_array {
  414     awk_const void *awk_const opaque1;  /* private data for use by gawk */
  415     awk_const void *awk_const opaque2;  /* private data for use by gawk */
  416     awk_const size_t count;         /* how many elements */
  417     awk_element_t elements[1];      /* will be extended */
  418 } awk_flat_array_t;
  419 
  420 /*
  421  * A record describing an extension function. Upon being
  422  * loaded, the extension should pass in one of these to gawk for
  423  * each C function.
  424  *
  425  * Each called function must fill in the result with either a scalar
  426  * (number, string, or regex). Gawk takes ownership of any string memory.
  427  *
  428  * The called function must return the value of `result'.
  429  * This is for the convenience of the calling code inside gawk.
  430  *
  431  * Each extension function may decide what to do if the number of
  432  * arguments isn't what it expected.  Following awk functions, it
  433  * is likely OK to ignore extra arguments.
  434  *
  435  * 'min_required_args' indicates how many arguments MUST be passed.
  436  * The API will throw a fatal error if not enough are passed.
  437  *
  438  * 'max_expected_args' is more benign; if more than that are passed,
  439  * the API prints a lint message (IFF lint is enabled, of course).
  440  *
  441  * In any case, the extension function itself need not compare the
  442  * actual number of arguments passed to those two values if it does
  443  * not want to.
  444  */
  445 typedef struct awk_ext_func {
  446     const char *name;
  447     awk_value_t *(*const function)(int num_actual_args,
  448                     awk_value_t *result,
  449                     struct awk_ext_func *finfo);
  450     const size_t max_expected_args;
  451     const size_t min_required_args;
  452     awk_bool_t suppress_lint;
  453     void *data;     /* opaque pointer to any extra state */
  454 } awk_ext_func_t;
  455 
  456 typedef void *awk_ext_id_t; /* opaque type for extension id */
  457 
  458 /*
  459  * The API into gawk. Lots of functions here. We hope that they are
  460  * logically organized.
  461  *
  462  * !!! If you make any changes to this structure, please remember to bump !!!
  463  * !!! gawk_api_major_version and/or gawk_api_minor_version.              !!!
  464  */
  465 typedef struct gawk_api {
  466     /* First, data fields. */
  467 
  468     /* These are what gawk thinks the API version is. */
  469     awk_const int major_version;
  470     awk_const int minor_version;
  471 
  472     /* GMP/MPFR versions, if extended-precision is available */
  473     awk_const int gmp_major_version;
  474     awk_const int gmp_minor_version;
  475     awk_const int mpfr_major_version;
  476     awk_const int mpfr_minor_version;
  477 
  478     /*
  479      * These can change on the fly as things happen within gawk.
  480      * Currently only do_lint is prone to change, but we reserve
  481      * the right to allow the others to do so also.
  482      */
  483 #define DO_FLAGS_SIZE   6
  484     awk_const int do_flags[DO_FLAGS_SIZE];
  485 /* Use these as indices into do_flags[] array to check the values */
  486 #define gawk_do_lint        0
  487 #define gawk_do_traditional 1
  488 #define gawk_do_profile     2
  489 #define gawk_do_sandbox     3
  490 #define gawk_do_debug       4
  491 #define gawk_do_mpfr        5
  492 
  493     /* Next, registration functions: */
  494 
  495     /*
  496      * Add a function to the interpreter, returns true upon success. 
  497      * Gawk does not modify what func points to, but the extension
  498      * function itself receives this pointer and can modify what it
  499      * points to, thus it's not const.
  500      */
  501     awk_bool_t (*api_add_ext_func)(awk_ext_id_t id, const char *name_space,
  502             awk_ext_func_t *func);
  503 
  504     /* Register an input parser; for opening files read-only */
  505     void (*api_register_input_parser)(awk_ext_id_t id,
  506                     awk_input_parser_t *input_parser);
  507 
  508     /* Register an output wrapper, for writing files */
  509     void (*api_register_output_wrapper)(awk_ext_id_t id,
  510                     awk_output_wrapper_t *output_wrapper);
  511 
  512     /* Register a processor for two way I/O */
  513     void (*api_register_two_way_processor)(awk_ext_id_t id,
  514                 awk_two_way_processor_t *two_way_processor);
  515 
  516     /*
  517      * Add an exit call back.
  518      *
  519      * arg0 is a private data pointer for use by the extension;
  520      * gawk saves it and passes it into the function pointed
  521      * to by funcp at exit.
  522      *
  523      * Exit callback functions are called in LIFO order.
  524      */
  525     void (*api_awk_atexit)(awk_ext_id_t id,
  526             void (*funcp)(void *data, int exit_status),
  527             void *arg0);
  528 
  529     /* Register a version string for this extension with gawk. */
  530     void (*api_register_ext_version)(awk_ext_id_t id, const char *version);
  531 
  532     /* Functions to print messages */
  533     void (*api_fatal)(awk_ext_id_t id, const char *format, ...);
  534     void (*api_warning)(awk_ext_id_t id, const char *format, ...);
  535     void (*api_lintwarn)(awk_ext_id_t id, const char *format, ...);
  536     void (*api_nonfatal)(awk_ext_id_t id, const char *format, ...);
  537 
  538     /* Functions to update ERRNO */
  539     void (*api_update_ERRNO_int)(awk_ext_id_t id, int errno_val);
  540     void (*api_update_ERRNO_string)(awk_ext_id_t id, const char *string);
  541     void (*api_unset_ERRNO)(awk_ext_id_t id);
  542 
  543     /*
  544      * All of the functions that return a value from inside gawk
  545      * (get a parameter, get a global variable, get an array element)
  546      * behave in the same way.
  547      *
  548      * For a function parameter, the return is false if the argument
  549      * count is out of range, or if the actual parameter does not match
  550      * what is specified in wanted. In that case,  result->val_type
  551      * will hold the actual type of what was passed.
  552      *
  553      * Similarly for symbol table access to variables and array elements,
  554      * the return is false if the actual variable or array element does
  555      * not match what was requested, and result->val_type will hold
  556      * the actual type.
  557 
  558     Table entry is type returned:
  559 
  560 
  561                             +-------------------------------------------------------+
  562                             |                   Type of Actual Value:               |
  563                             +--------+--------+--------+--------+-------+-----------+
  564                             | String | Strnum | Number | Regex  | Array | Undefined |
  565     +-----------+-----------+--------+--------+--------+--------+-------+-----------+
  566     |           | String    | String | String | String | String | false | false     |
  567     |           +-----------+--------+--------+--------+--------+-------+-----------+
  568     |           | Strnum    | false  | Strnum | Strnum | false  | false | false     |
  569     |           +-----------+--------+--------+--------+--------+-------+-----------+
  570     |           | Number    | Number | Number | Number | false  | false | false     |
  571     |           +-----------+--------+--------+--------+--------+-------+-----------+
  572     |           | Regex     | false  | false  | false  | Regex  | false | false     |
  573     |           +-----------+--------+--------+--------+--------+-------+-----------+
  574     |   Type    | Array     | false  | false  | false  | false  | Array | false     |
  575     | Requested +-----------+--------+--------+--------+--------+-------+-----------+
  576     |           | Scalar    | Scalar | Scalar | Scalar | Scalar | false | false     |
  577     |           +-----------+--------+--------+--------+--------+-------+-----------+
  578     |           | Undefined | String | Strnum | Number | Regex  | Array | Undefined |
  579     |           +-----------+--------+--------+--------+--------+-------+-----------+
  580     |           | Value     | false  | false  | false  | false  | false | false     |
  581     |           | Cookie    |        |        |        |        |       |           |
  582     +-----------+-----------+--------+--------+--------+--------+-------+-----------+
  583     */
  584 
  585     /* Functions to handle parameters passed to the extension. */
  586 
  587     /*
  588      * Get the count'th parameter, zero-based.
  589      * Returns false if count is out of range, or if actual parameter
  590      * does not match what is specified in wanted. In that case,
  591      * result->val_type is as described above.
  592      */
  593     awk_bool_t (*api_get_argument)(awk_ext_id_t id, size_t count,
  594                       awk_valtype_t wanted,
  595                       awk_value_t *result);
  596 
  597     /*
  598      * Convert a parameter that was undefined into an array
  599      * (provide call-by-reference for arrays).  Returns false
  600      * if count is too big, or if the argument's type is
  601      * not undefined.
  602      */
  603     awk_bool_t (*api_set_argument)(awk_ext_id_t id,
  604                     size_t count,
  605                     awk_array_t array);
  606 
  607     /*
  608      * Symbol table access:
  609      *  - Read-only access to special variables (NF, etc.)
  610      *  - One special exception: PROCINFO.
  611      *  - Use sym_update() to change a value, including from UNDEFINED
  612      *    to scalar or array.
  613      */
  614     /*
  615      * Lookup a variable, fill in value. No messing with the value
  616      * returned.
  617      * Returns false if the variable doesn't exist or if the wrong type
  618      * was requested.  In the latter case, vaule->val_type will have
  619      * the real type, as described above.
  620      *
  621      *  awk_value_t val;
  622      *  if (! api->sym_lookup(id, name, wanted, & val))
  623      *      error_code_here();
  624      *  else {
  625      *      // safe to use val
  626      *  }
  627      */
  628     awk_bool_t (*api_sym_lookup)(awk_ext_id_t id,
  629                 const char *name_space,
  630                 const char *name,
  631                 awk_valtype_t wanted,
  632                 awk_value_t *result);
  633 
  634     /*
  635      * Update a value. Adds it to the symbol table if not there.
  636      * Changing types (scalar <--> array) is not allowed.
  637      * In fact, using this to update an array is not allowed, either.
  638      * Such an attempt returns false.
  639      */
  640     awk_bool_t (*api_sym_update)(awk_ext_id_t id,
  641                 const char *name_space,
  642                 const char *name,
  643                 awk_value_t *value);
  644 
  645     /*
  646      * A ``scalar cookie'' is an opaque handle that provide access
  647      * to a global variable or array. It is an optimization that
  648      * avoids looking up variables in gawk's symbol table every time
  649      * access is needed.
  650      *
  651      * This function retrieves the current value of a scalar cookie.
  652      * Once you have obtained a scalar_cookie using sym_lookup, you can
  653      * use this function to get its value more efficiently.
  654      *
  655      * Return will be false if the value cannot be retrieved.
  656      *
  657      * Flow is thus
  658      *  awk_value_t val;
  659      *  awk_scalar_t cookie;
  660      *  api->sym_lookup(id, "variable", AWK_SCALAR, & val); // get the cookie
  661      *  cookie = val.scalar_cookie;
  662      *  ...
  663      *  api->sym_lookup_scalar(id, cookie, wanted, & val);  // get the value
  664      */
  665     awk_bool_t (*api_sym_lookup_scalar)(awk_ext_id_t id,
  666                 awk_scalar_t cookie,
  667                 awk_valtype_t wanted,
  668                 awk_value_t *result);
  669 
  670     /*
  671      * Update the value associated with a scalar cookie.
  672      * Flow is
  673      *  sym_lookup with wanted == AWK_SCALAR
  674      *  if returns false
  675      *      sym_update with real initial value to install it
  676      *      sym_lookup again with AWK_SCALAR
  677      *  else
  678      *      use the scalar cookie
  679      *
  680      * Return will be false if the new value is not one of
  681      * AWK_STRING, AWK_NUMBER, AWK_REGEX.
  682      *
  683      * Here too, the built-in variables may not be updated.
  684      */
  685     awk_bool_t (*api_sym_update_scalar)(awk_ext_id_t id,
  686                 awk_scalar_t cookie, awk_value_t *value);
  687 
  688     /* Cached values */
  689 
  690     /*
  691      * Create a cached string,regex, or numeric value for efficient later
  692      * assignment. This improves performance when you want to assign
  693      * the same value to one or more variables repeatedly.  Only
  694      * AWK_NUMBER, AWK_STRING, AWK_REGEX and AWK_STRNUM values are allowed.
  695      * Any other type is rejected.  We disallow AWK_UNDEFINED since that
  696      * case would result in inferior performance.
  697      */
  698     awk_bool_t (*api_create_value)(awk_ext_id_t id, awk_value_t *value,
  699             awk_value_cookie_t *result);
  700 
  701     /*
  702      * Release the memory associated with a cookie from api_create_value.
  703      * Please call this to free memory when the value is no longer needed.
  704      */
  705     awk_bool_t (*api_release_value)(awk_ext_id_t id, awk_value_cookie_t vc);
  706 
  707     /* Array management */
  708 
  709     /*
  710      * Retrieve total number of elements in array.
  711      * Returns false if some kind of error.
  712      */
  713     awk_bool_t (*api_get_element_count)(awk_ext_id_t id,
  714             awk_array_t a_cookie, size_t *count);
  715 
  716     /*
  717      * Return the value of an element - read only!
  718      * Use set_array_element() to change it.
  719      * Behavior for value and return is same as for api_get_argument
  720      * and sym_lookup.
  721      */
  722     awk_bool_t (*api_get_array_element)(awk_ext_id_t id,
  723             awk_array_t a_cookie,
  724             const awk_value_t *const index,
  725             awk_valtype_t wanted,
  726             awk_value_t *result);
  727 
  728     /*
  729      * Change (or create) element in existing array with
  730      * index and value.
  731      *
  732      * ARGV and ENVIRON may not be updated.
  733      */
  734     awk_bool_t (*api_set_array_element)(awk_ext_id_t id, awk_array_t a_cookie,
  735                     const awk_value_t *const index,
  736                     const awk_value_t *const value);
  737 
  738     /*
  739      * Remove the element with the given index.
  740      * Returns true if removed or false if element did not exist.
  741      */
  742     awk_bool_t (*api_del_array_element)(awk_ext_id_t id,
  743             awk_array_t a_cookie, const awk_value_t* const index);
  744 
  745     /* Create a new array cookie to which elements may be added. */
  746     awk_array_t (*api_create_array)(awk_ext_id_t id);
  747 
  748     /* Clear out an array. */
  749     awk_bool_t (*api_clear_array)(awk_ext_id_t id, awk_array_t a_cookie);
  750 
  751     /*
  752      * Flatten out an array with type conversions as requested.
  753      * This supersedes the earlier api_flatten_array function that
  754      * did not allow the caller to specify the requested types.
  755      * (That API is still available as a macro, defined below.)
  756      */
  757     awk_bool_t (*api_flatten_array_typed)(awk_ext_id_t id,
  758             awk_array_t a_cookie,
  759             awk_flat_array_t **data,
  760             awk_valtype_t index_type, awk_valtype_t value_type);
  761 
  762     /* When done, delete any marked elements, release the memory. */
  763     awk_bool_t (*api_release_flattened_array)(awk_ext_id_t id,
  764             awk_array_t a_cookie,
  765             awk_flat_array_t *data);
  766 
  767     /*
  768      * Hooks to provide access to gawk's memory allocation functions.
  769      * This ensures that memory passed between gawk and the extension
  770      * is allocated and released by the same library.
  771      */
  772     void *(*api_malloc)(size_t size);
  773     void *(*api_calloc)(size_t nmemb, size_t size);
  774     void *(*api_realloc)(void *ptr, size_t size);
  775     void (*api_free)(void *ptr);
  776 
  777     /*
  778      * A function that returns mpfr data should call this function
  779      * to allocate and initialize an mpfr_ptr for use in an
  780      * awk_value_t structure that will be handed to gawk.
  781      */
  782     void *(*api_get_mpfr)(awk_ext_id_t id);
  783 
  784     /*
  785      * A function that returns mpz data should call this function
  786      * to allocate and initialize an mpz_ptr for use in an
  787      * awk_value_t structure that will be handed to gawk.
  788      */
  789     void *(*api_get_mpz)(awk_ext_id_t id);
  790 
  791         /*
  792      * Look up a file.  If the name is NULL or name_len is 0, it returns
  793      * data for the currently open input file corresponding to FILENAME
  794      * (and it will not access the filetype argument, so that may be
  795      * undefined).
  796      *
  797      * If the file is not already open, try to open it.
  798      *
  799      * The "filetype" argument should be one of:
  800      *
  801      *    ">", ">>", "<", "|>", "|<", and "|&"
  802      *
  803      * If the file is not already open, and the fd argument is non-negative,
  804      * gawk will use that file descriptor instead of opening the file
  805      * in the usual way.
  806      *
  807      * If the fd is non-negative, but the file exists already, gawk
  808      * ignores the fd and returns the existing file.  It is the caller's
  809      * responsibility to notice that the fd in the returned
  810      * awk_input_buf_t does not match the requested value.
  811      *
  812      * Note that supplying a file descriptor is currently NOT supported
  813      * for pipes. It should work for input, output, append, and two-way
  814      * (coprocess) sockets.  If the filetype is two-way, we assume that
  815      * it is a socket!
  816      *
  817      * Note that in the two-way case, the input and output file descriptors
  818      * may differ.  To check for success, one must check that either of
  819      * them matches.
  820      *
  821      * ibufp and obufp point at gawk's internal copies of the
  822      * awk_input_buf_t and awk_output_t associated with the open
  823      * file.  Treat these data structures as read-only!
  824      */
  825     awk_bool_t (*api_get_file)(awk_ext_id_t id,
  826             const char *name,
  827             size_t name_len,
  828             const char *filetype,
  829             int fd,
  830             /*
  831              * Return values (on success, one or both should
  832              * be non-NULL):
  833              */
  834             const awk_input_buf_t **ibufp,
  835             const awk_output_buf_t **obufp);
  836 } gawk_api_t;
  837 
  838 #ifndef GAWK    /* these are not for the gawk code itself! */
  839 /*
  840  * Use these if you want to define "global" variables named api
  841  * and ext_id to make the code a little easier to read.
  842  * See the sample boilerplate code, below.
  843  */
  844 #define do_lint     (api->do_flags[gawk_do_lint])
  845 #define do_traditional  (api->do_flags[gawk_do_traditional])
  846 #define do_profile  (api->do_flags[gawk_do_profile])
  847 #define do_sandbox  (api->do_flags[gawk_do_sandbox])
  848 #define do_debug    (api->do_flags[gawk_do_debug])
  849 #define do_mpfr     (api->do_flags[gawk_do_mpfr])
  850 
  851 #define get_argument(count, wanted, result) \
  852     (api->api_get_argument(ext_id, count, wanted, result))
  853 #define set_argument(count, new_array) \
  854     (api->api_set_argument(ext_id, count, new_array))
  855 
  856 #define fatal       api->api_fatal
  857 #define nonfatal    api->api_nonfatal
  858 #define warning     api->api_warning
  859 #define lintwarn    api->api_lintwarn
  860 
  861 #define register_input_parser(parser)   (api->api_register_input_parser(ext_id, parser))
  862 #define register_output_wrapper(wrapper) (api->api_register_output_wrapper(ext_id, wrapper))
  863 #define register_two_way_processor(processor) \
  864     (api->api_register_two_way_processor(ext_id, processor))
  865 
  866 #define update_ERRNO_int(e) (api->api_update_ERRNO_int(ext_id, e))
  867 #define update_ERRNO_string(str) \
  868     (api->api_update_ERRNO_string(ext_id, str))
  869 #define unset_ERRNO()   (api->api_unset_ERRNO(ext_id))
  870 
  871 #define add_ext_func(ns, func)  (api->api_add_ext_func(ext_id, ns, func))
  872 #define awk_atexit(funcp, arg0) (api->api_awk_atexit(ext_id, funcp, arg0))
  873 
  874 #define sym_lookup(name, wanted, result) \
  875     sym_lookup_ns("", name, wanted, result)
  876 #define sym_update(name, value) \
  877     sym_update_ns("", name, value)
  878 
  879 #define sym_lookup_ns(name_space, name, wanted, result) \
  880     (api->api_sym_lookup(ext_id, name_space, name, wanted, result))
  881 #define sym_update_ns(name_space, name, value) \
  882     (api->api_sym_update(ext_id, name_space, name, value))
  883 
  884 #define sym_lookup_scalar(scalar_cookie, wanted, result) \
  885     (api->api_sym_lookup_scalar(ext_id, scalar_cookie, wanted, result))
  886 #define sym_update_scalar(scalar_cookie, value) \
  887     (api->api_sym_update_scalar)(ext_id, scalar_cookie, value)
  888 
  889 #define get_array_element(array, index, wanted, result) \
  890     (api->api_get_array_element(ext_id, array, index, wanted, result))
  891 
  892 #define set_array_element(array, index, value) \
  893     (api->api_set_array_element(ext_id, array, index, value))
  894 
  895 #define set_array_element_by_elem(array, elem) \
  896     (api->api_set_array_element(ext_id, array, & (elem)->index, & (elem)->value))
  897 
  898 #define del_array_element(array, index) \
  899     (api->api_del_array_element(ext_id, array, index))
  900 
  901 #define get_element_count(array, count_p) \
  902     (api->api_get_element_count(ext_id, array, count_p))
  903 
  904 #define create_array()      (api->api_create_array(ext_id))
  905 
  906 #define clear_array(array)  (api->api_clear_array(ext_id, array))
  907 
  908 #define flatten_array_typed(array, data, index_type, value_type) \
  909     (api->api_flatten_array_typed(ext_id, array, data, index_type, value_type))
  910 
  911 #define flatten_array(array, data) \
  912     flatten_array_typed(array, data, AWK_STRING, AWK_UNDEFINED)
  913 
  914 #define release_flattened_array(array, data) \
  915     (api->api_release_flattened_array(ext_id, array, data))
  916 
  917 #define gawk_malloc(size)       (api->api_malloc(size))
  918 #define gawk_calloc(nmemb, size)    (api->api_calloc(nmemb, size))
  919 #define gawk_realloc(ptr, size)     (api->api_realloc(ptr, size))
  920 #define gawk_free(ptr)          (api->api_free(ptr))
  921 
  922 #define create_value(value, result) \
  923     (api->api_create_value(ext_id, value,result))
  924 
  925 #define release_value(value) \
  926     (api->api_release_value(ext_id, value))
  927 
  928 #define get_file(name, namelen, filetype, fd, ibuf, obuf) \
  929     (api->api_get_file(ext_id, name, namelen, filetype, fd, ibuf, obuf))
  930 
  931 #define get_mpfr_ptr() (api->api_get_mpfr(ext_id))
  932 #define get_mpz_ptr() (api->api_get_mpz(ext_id))
  933 
  934 #define register_ext_version(version) \
  935     (api->api_register_ext_version(ext_id, version))
  936 
  937 #define emalloc(pointer, type, size, message) \
  938     do { \
  939         if ((pointer = (type) gawk_malloc(size)) == 0) \
  940             fatal(ext_id, "%s: malloc of %d bytes failed", message, size); \
  941     } while(0)
  942 
  943 #define ezalloc(pointer, type, size, message) \
  944     do { \
  945         if ((pointer = (type) gawk_calloc(1, size)) == 0) \
  946             fatal(ext_id, "%s: calloc of %d bytes failed", message, size); \
  947     } while(0)
  948 
  949 #define erealloc(pointer, type, size, message) \
  950     do { \
  951         if ((pointer = (type) gawk_realloc(pointer, size)) == 0) \
  952             fatal(ext_id, "%s: realloc of %d bytes failed", message, size); \
  953     } while(0)
  954 
  955 /* Constructor functions */
  956 
  957 /* r_make_string_type --- make a string or strnum or regexp value in result from the passed-in string */
  958 
  959 static inline awk_value_t *
  960 r_make_string_type(const gawk_api_t *api,   /* needed for emalloc */
  961            awk_ext_id_t ext_id,     /* ditto */
  962            const char *string,
  963            size_t length,
  964            awk_bool_t duplicate,
  965            awk_value_t *result,
  966            awk_valtype_t val_type)
  967 {
  968     char *cp = NULL;
  969 
  970     memset(result, 0, sizeof(*result));
  971 
  972     result->val_type = val_type;
  973     result->str_value.len = length;
  974 
  975     if (duplicate) {
  976         emalloc(cp, char *, length + 1, "r_make_string");
  977         memcpy(cp, string, length);
  978         cp[length] = '\0';
  979         result->str_value.str = cp;
  980     } else {
  981         result->str_value.str = (char *) string;
  982     }
  983 
  984     return result;
  985 }
  986 
  987 /* r_make_string --- make a string value in result from the passed-in string */
  988 
  989 static inline awk_value_t *
  990 r_make_string(const gawk_api_t *api,    /* needed for emalloc */
  991           awk_ext_id_t ext_id,  /* ditto */
  992           const char *string,
  993           size_t length,
  994           awk_bool_t duplicate,
  995           awk_value_t *result)
  996 {
  997     return r_make_string_type(api, ext_id, string, length, duplicate, result, AWK_STRING);
  998 }
  999 
 1000 #define make_const_string(str, len, result) r_make_string(api, ext_id, str, len, awk_true, result)
 1001 #define make_malloced_string(str, len, result)  r_make_string(api, ext_id, str, len, awk_false, result)
 1002 
 1003 #define make_const_regex(str, len, result)  r_make_string_type(api, ext_id, str, len, awk_true, result, AWK_REGEX)
 1004 #define make_malloced_regex(str, len, result)   r_make_string_type(api, ext_id, str, len, awk_false, result, AWK_REGEX)
 1005 
 1006 /*
 1007  * Note: The caller may not create a STRNUM, but it can create a string that is
 1008  * flagged as user input that MAY be a STRNUM. Gawk will decide whether it's a
 1009  * STRNUM or a string by checking whether the string is numeric.
 1010  */
 1011 #define make_const_user_input(str, len, result) r_make_string_type(api, ext_id, str, len, 1, result, AWK_STRNUM)
 1012 #define make_malloced_user_input(str, len, result)  r_make_string_type(api, ext_id, str, len, 0, result, AWK_STRNUM)
 1013 
 1014 /* make_null_string --- make a null string value */
 1015 
 1016 static inline awk_value_t *
 1017 make_null_string(awk_value_t *result)
 1018 {
 1019     memset(result, 0, sizeof(*result));
 1020     result->val_type = AWK_UNDEFINED;
 1021 
 1022     return result;
 1023 }
 1024 
 1025 /* make_number --- make a number value in result */
 1026 
 1027 static inline awk_value_t *
 1028 make_number(double num, awk_value_t *result)
 1029 {
 1030     result->val_type = AWK_NUMBER;
 1031     result->num_value = num;
 1032     result->num_type = AWK_NUMBER_TYPE_DOUBLE;
 1033     return result;
 1034 }
 1035 
 1036 /*
 1037  * make_number_mpz --- make an mpz number value in result.
 1038  * The mpz_ptr must be from a call to get_mpz_ptr. Gawk will now
 1039  * take ownership of this memory.
 1040  */
 1041 
 1042 static inline awk_value_t *
 1043 make_number_mpz(void *mpz_ptr, awk_value_t *result)
 1044 {
 1045     result->val_type = AWK_NUMBER;
 1046     result->num_type = AWK_NUMBER_TYPE_MPZ;
 1047     result->num_ptr = mpz_ptr;
 1048     return result;
 1049 }
 1050 
 1051 /*
 1052  * make_number_mpfr --- make an mpfr number value in result.
 1053  * The mpfr_ptr must be from a call to get_mpfr_ptr. Gawk will now
 1054  * take ownership of this memory.
 1055  */
 1056 
 1057 static inline awk_value_t *
 1058 make_number_mpfr(void *mpfr_ptr, awk_value_t *result)
 1059 {
 1060     result->val_type = AWK_NUMBER;
 1061     result->num_type = AWK_NUMBER_TYPE_MPFR;
 1062     result->num_ptr = mpfr_ptr;
 1063     return result;
 1064 }
 1065 
 1066 
 1067 /*
 1068  * Each extension must define a function with this prototype:
 1069  *
 1070  *  int dl_load(gawk_api_t *api_p, awk_ext_id_t id)
 1071  *
 1072  * The return value should be zero on failure and non-zero on success.
 1073  *
 1074  * For the macros to work, the function should save api_p in a global
 1075  * variable named 'api' and save id in a global variable named 'ext_id'.
 1076  * In addition, a global function pointer named 'init_func' should be
 1077  * defined and set to either NULL or an initialization function that
 1078  * returns non-zero on success and zero upon failure.
 1079  */
 1080 
 1081 extern int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id);
 1082 
 1083 #if 0
 1084 /* Boilerplate code: */
 1085 int plugin_is_GPL_compatible;
 1086 
 1087 static gawk_api_t *const api;
 1088 static awk_ext_id_t ext_id;
 1089 static const char *ext_version = NULL; /* or ... = "some string" */
 1090 
 1091 static awk_ext_func_t func_table[] = {
 1092     { "name", do_name, 1 },
 1093     /* ... */
 1094 };
 1095 
 1096 /* EITHER: */
 1097 
 1098 static awk_bool_t (*init_func)(void) = NULL;
 1099 
 1100 /* OR: */
 1101 
 1102 static awk_bool_t
 1103 init_my_extension(void)
 1104 {
 1105     ...
 1106 }
 1107 
 1108 static awk_bool_t (*init_func)(void) = init_my_extension;
 1109 
 1110 dl_load_func(func_table, some_name, "name_space_in_quotes")
 1111 #endif
 1112 
 1113 #define dl_load_func(func_table, extension, name_space) \
 1114 int dl_load(const gawk_api_t *const api_p, awk_ext_id_t id)  \
 1115 { \
 1116     size_t i, j; \
 1117     int errors = 0; \
 1118 \
 1119     api = api_p; \
 1120     ext_id = (void **) id; \
 1121 \
 1122     if (api->major_version != GAWK_API_MAJOR_VERSION \
 1123         || api->minor_version < GAWK_API_MINOR_VERSION) { \
 1124         fprintf(stderr, #extension ": version mismatch with gawk!\n"); \
 1125         fprintf(stderr, "\tmy version (API %d.%d), gawk version (API %d.%d)\n", \
 1126             GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION, \
 1127             api->major_version, api->minor_version); \
 1128         exit(1); \
 1129     } \
 1130 \
 1131     check_mpfr_version(extension); \
 1132 \
 1133     /* load functions */ \
 1134     for (i = 0, j = sizeof(func_table) / sizeof(func_table[0]); i < j; i++) { \
 1135         if (func_table[i].name == NULL) \
 1136             break; \
 1137         if (! add_ext_func(name_space, & func_table[i])) { \
 1138             warning(ext_id, #extension ": could not add %s", \
 1139                     func_table[i].name); \
 1140             errors++; \
 1141         } \
 1142     } \
 1143 \
 1144     if (init_func != NULL) { \
 1145         if (! init_func()) { \
 1146             warning(ext_id, #extension ": initialization function failed"); \
 1147             errors++; \
 1148         } \
 1149     } \
 1150 \
 1151     if (ext_version != NULL) \
 1152         register_ext_version(ext_version); \
 1153 \
 1154     return (errors == 0); \
 1155 }
 1156 
 1157 #if defined __GNU_MP_VERSION && defined MPFR_VERSION_MAJOR
 1158 #define check_mpfr_version(extension) do { \
 1159     if (api->gmp_major_version != __GNU_MP_VERSION \
 1160         || api->gmp_minor_version < __GNU_MP_VERSION_MINOR) { \
 1161         fprintf(stderr, #extension ": GMP version mismatch with gawk!\n"); \
 1162         fprintf(stderr, "\tmy version (%d, %d), gawk version (%d, %d)\n", \
 1163             __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, \
 1164             api->gmp_major_version, api->gmp_minor_version); \
 1165         exit(1); \
 1166     } \
 1167     if (api->mpfr_major_version != MPFR_VERSION_MAJOR \
 1168         || api->mpfr_minor_version < MPFR_VERSION_MINOR) { \
 1169         fprintf(stderr, #extension ": MPFR version mismatch with gawk!\n"); \
 1170         fprintf(stderr, "\tmy version (%d, %d), gawk version (%d, %d)\n", \
 1171             MPFR_VERSION_MAJOR, MPFR_VERSION_MINOR, \
 1172             api->mpfr_major_version, api->mpfr_minor_version); \
 1173         exit(1); \
 1174     } \
 1175 } while (0)
 1176 #else
 1177 #define check_mpfr_version(extension) /* nothing */
 1178 #endif
 1179 
 1180 #endif /* GAWK */
 1181 
 1182 #ifdef __cplusplus
 1183 }
 1184 #endif  /* C++ */
 1185 
 1186 #endif /* _GAWK_API_H */