17.4.6.5 Customized Output Wrappers

An output wrapper is the mirror image of an input parser. It allows an extension to take over the output to a file opened with the ‘>’ or ‘>>’ I/O redirection operators (see Redirecting Output of print and printf).

The output wrapper is very similar to the input parser structure:

typedef struct awk_output_wrapper {
    const char *name;   /* name of the wrapper */
    awk_bool_t (*can_take_file)(const awk_output_buf_t *outbuf);
    awk_bool_t (*take_control_of)(awk_output_buf_t *outbuf);
    awk_const struct awk_output_wrapper *awk_const next;  /* for gawk */
} awk_output_wrapper_t;

The members are as follows:

const char *name;

This is the name of the output wrapper.

awk_bool_t (*can_take_file)(const awk_output_buf_t *outbuf);

This points to a function that examines the information in the awk_output_buf_t structure pointed to by outbuf. It should return true if the output wrapper wants to take over the file, and false otherwise. It should not change any state (variable values, etc.) within gawk.

awk_bool_t (*take_control_of)(awk_output_buf_t *outbuf);

The function pointed to by this field is called when gawk decides to let the output wrapper take control of the file. It should fill in appropriate members of the awk_output_buf_t structure, as described next, and return true if successful, false otherwise.

awk_const struct output_wrapper *awk_const next;

This is for use by gawk; therefore it is marked awk_const so that the extension cannot modify it.

The awk_output_buf_t structure looks like this:

typedef struct awk_output_buf {
    const char *name;   /* name of output file */
    const char *mode;   /* mode argument to fopen */
    FILE *fp;           /* stdio file pointer */
    awk_bool_t redirected;  /* true if a wrapper is active */
    void *opaque;       /* for use by output wrapper */
    size_t (*gawk_fwrite)(const void *buf, size_t size, size_t count,
                FILE *fp, void *opaque);
    int (*gawk_fflush)(FILE *fp, void *opaque);
    int (*gawk_ferror)(FILE *fp, void *opaque);
    int (*gawk_fclose)(FILE *fp, void *opaque);
} awk_output_buf_t;

Here too, your extension will define XXX_can_take_file() and XXX_take_control_of() functions that examine and update data members in the awk_output_buf_t. The data members are as follows:

const char *name;

The name of the output file.

const char *mode;

The mode string (as would be used in the second argument to fopen()) with which the file was opened.

FILE *fp;

The FILE pointer from <stdio.h>. gawk opens the file before attempting to find an output wrapper.

awk_bool_t redirected;

This field must be set to true by the XXX_take_control_of() function.

void *opaque;

This pointer is opaque to gawk. The extension should use it to store a pointer to any private data associated with the file.

size_t (*gawk_fwrite)(const void *buf, size_t size, size_t count,
                      FILE *fp, void *opaque);
int (*gawk_fflush)(FILE *fp, void *opaque);
int (*gawk_ferror)(FILE *fp, void *opaque);
int (*gawk_fclose)(FILE *fp, void *opaque);

These pointers should be set to point to functions that perform the equivalent function as the <stdio.h> functions do, if appropriate. gawk uses these function pointers for all output. gawk initializes the pointers to point to internal “pass-through” functions that just call the regular <stdio.h> functions, so an extension only needs to redefine those functions that are appropriate for what it does.

The XXX_can_take_file() function should make a decision based upon the name and mode fields, and any additional state (such as awk variable values) that is appropriate. gawk attempts to open the named file for writing. The fp member will be NULL only if it fails.

When gawk calls XXX_take_control_of(), that function should fill in the other fields as appropriate, except for fp, which it should just use normally if it’s not NULL.

You register your output wrapper with the following function:

void register_output_wrapper(awk_output_wrapper_t *output_wrapper);

Register the output wrapper pointed to by output_wrapper with gawk.