Skip to content
Authors

File prod_janet.c

File List > prod_janet > src > prod_janet.c

Go to the documentation of this file

#include "prod_janet.h"
#include <string.h>
#include <pdgl_defs.h>
#include <janet.h>
#include <fmem.h>
#include <stdbool.h>

/*************************************************************************************************/
/************************** Extern ***************************************************************/
/*************************************************************************************************/

extern const unsigned char init_script_janet[];

/*************************************************************************************************/
/************************** Defines **************************************************************/
/*************************************************************************************************/

/*************************************************************************************************/
/************************** Typedefs *************************************************************/
/*************************************************************************************************/

/*************************************************************************************************/
/************************** Private Function Declarations ****************************************/
/*************************************************************************************************/
STATIC_INLINE char *prod_janet_execute(const void *config, const char *script);

/* cppcheck-suppress constParameterCallback*/
STATIC_INLINE Janet prod_janet_pdglcout(int32_t argc, Janet *argv);


/*************************************************************************************************/
/************************** Local Variables ******************************************************/
/*************************************************************************************************/


static const JanetReg cfuns[] = {
    { "out", prod_janet_pdglcout, "Print function that pushes data onto the output string." },
    { NULL,  NULL,                NULL                                                      }
};



/*************************************************************************************************/
/************************** Public Function Definitions ******************************************/
/*************************************************************************************************/
/* Docstring in header */
const char * prod_janet_resolve(const void *config)
{
    const char *retval = NULL;

    if (NULL != config)
    {
        const prod_janet_config_t *typed_cfg = (const prod_janet_config_t *)config;
        if ((0 != typed_cfg->out_str_len) && (NULL != typed_cfg->out_str))
        {
            typed_cfg->out_str[0] = '\0';
            if (NULL != typed_cfg->repl_str)
            {
                retval = prod_janet_execute(config, typed_cfg->repl_str);
            }
        }
    }

    return retval;
}

/* Docstring in header */
const char * prod_janet_terminate(const void *config)
{
    const char *retval = NULL;

    if (NULL != config)
    {
        const prod_janet_config_t *typed_cfg = (const prod_janet_config_t *)config;
        if ((0 != typed_cfg->out_str_len) && (NULL != typed_cfg->out_str))
        {
            typed_cfg->out_str[0] = '\0';
            if (NULL != typed_cfg->term_str)
            {
                retval = prod_janet_execute(config, typed_cfg->term_str);
            }
        }
    }

    return retval;
}

/*************************************************************************************************/
/************************** Private Function Definitions *****************************************/
/*************************************************************************************************/

static char * prod_janet_execute(const void *config, const char *script)
{
    {
        const prod_janet_config_t *typed_cfg = (const prod_janet_config_t *)config;
        const char * script_str = (const char *)init_script_janet;
        char *       retval     = NULL;
        JanetTable * env        = NULL;
        JanetTable * sub_env    = NULL;
        JanetBuffer *errBuffer  = NULL;
        Janet        module_cache;
        Janet        result;

        /* Initialize the virtual machine. Do this before any calls to Janet functions. */
        janet_init();

        env     = janet_core_env(NULL);
        sub_env = janet_table(0);

        /* Build new c module with print out function overloaded*/
        janet_cfuns(sub_env, "pdglc", cfuns);
        janet_def(sub_env, "cfg_ptr", janet_wrap_pointer((void *)config),
                  "Pointer to the configuration being worked on.");
        module_cache = janet_resolve_core("module/cache");
        janet_table_put(janet_unwrap_table(module_cache), janet_cstringv("pdglc"),
                        janet_wrap_table(sub_env));

        /* Replace the standard error of the Janet environment with a c string. */
        errBuffer = janet_buffer(DEFS_PDGL_MAX_STRING_SIZE);
        janet_setdyn("err", janet_wrap_buffer(errBuffer));


        /* Run the startup script to overload the print function*/

        /*@@@NOTE: I have no idea if this is a good way to do this. It seems to work and should be
         * invisible to a user. Submit a bug if there's an issue.*/

        if (0 == janet_dostring(env, script_str, "main",
                                &result))
        {
            /* Make sure the result isn't garbage collected*/
            janet_gcroot(result);
            if (0 == janet_dostring(env, script, "main", &result))
            {
                retval = typed_cfg->out_str;
            }
        }
        /* Something went wrong since `retval` is still NULL. Report that error.*/
        if (NULL == retval)
        {
            janet_stacktrace(janet_current_fiber(), result);
            janet_buffer_push_u8(errBuffer, 0);
            /*@@@TODO: Add logging fprintf(stderr, "%s", errBuffer->data); */
        }

        /* Make sure the result is garbage collected*/
        janet_gcunroot(result);

        /* Clean up the Janet VM*/
        janet_deinit();

        return retval;
    }
}

/* cppcheck-suppress constParameterCallback*/
STATIC_INLINE Janet prod_janet_pdglcout(int32_t argc, Janet *argv)
{
    const char *text = NULL;
    const prod_janet_config_t *typed_cfg = NULL;
    size_t cur_out_len = 0;

    /* Ensure exactly two arguments*/
    janet_fixarity(argc, 2);
    /* Parse the first argument into a string*/
    text = janet_getcstring(argv, 0);
    /* Parse the second argument into a prod_janet_config_t pointer*/
    typed_cfg   = (const prod_janet_config_t *)janet_getpointer(argv, 1);
    cur_out_len = strlen(typed_cfg->out_str);

    /* If there is room left in the output buffer for the production. */
    if (0 < cur_out_len - (strlen(typed_cfg->out_str) + strlen(text)))
    {
        char *end = typed_cfg->out_str + cur_out_len;
        sprintf(end, "%s", text);
    }
    else/* Otherwise, panic. */
    {
        janet_panicf("Buffer is out of space!");
    }

    return janet_wrap_nil();
}