/*
    This file was generated by "mtxrun --script "mtx-wtoc.lua" from the metapost cweb
    files but now maintained as C file.
*/

# ifndef MP_H
# define MP_H

# include "auxcompiler.h"

# include <errno.h>
# include <string.h>
# include <float.h>
# include <math.h>
# include <stdlib.h>
# include <stdarg.h>
# include <ctype.h>
# include <sys/stat.h>
# include <time.h>
# include <setjmp.h>

# ifdef _WIN32

    # include <stdio.h>
    # include <fcntl.h>
    # include <io.h>

# else

    # include <unistd.h>

# endif

# include "avl.h"
# include "auxmemory.h"
# include "auxposit.h"
# include "auxbytemaps.h"

/*tex

We used to have three header files: common, mpmp and mplib, but there ws some (growing) dependency on
the one hand and we decided to target just \LUAMETATEX\ on the other. After all, this is a special
version. So, we now have one header file only. The variables from |MP_options| are included inside
the |MP_instance| wholesale. This also permits some further stripping. Actually we can probably get
rid of the intermediate \POSTSCRIPT\ representation or add a little more abstraction.

*/

/*tex
    The \LUATEX\ \METAPOST\ library goes to version 3.0 so we need to stay ahead of that or use a
    rather future number, like 30 or so. This is to be decided.
*/

# define metapost_version "3.16.03"

typedef struct MP_instance *MP;

# if 1

    /* Before we enable this we need to (double) check:

        -- odd (in double)
        -- random seed (either upgrade or cast, or take from lua instead)
        -- all int and (int) in files

    */

    typedef int64_t mp_scaled_t;

    # define mp_scaled_bits      64
    # define mpscaledround       llround
    # define decNumberToScaled   decNumberToInt32
    # define decNumberFromScaled decNumberFromInt32

# else

    typedef int32_t mp_scaled_t;

    # define mp_scaled_bits      32
    # define mpscaledround       lround
    # define decNumberToScaled   decNumberToInt32
    # define decNumberFromScaled decNumberFromInt32

# endif

typedef enum mp_number_type {
    mp_nan_type,
    mp_scaled_type,
    mp_fraction_type,
    mp_angle_type,
    mp_double_type,
    mp_binary_type,
    mp_decimal_type,
    mp_posit_type
} mp_number_type;

# define is_number(A) ((A).type != mp_nan_type)

typedef union mp_number_store {
    void        *num;
    double       dval;
    mp_scaled_t  val;
    posit_t      pval;
} mp_number_store;

typedef struct mp_number_data {
    mp_number_store data;
    mp_number_type  type;
} mp_number_data;

typedef struct mp_number_data mp_number;

typedef enum mp_filetype {
    mp_filetype_terminal, /* the terminal (input) */
    mp_filetype_program,  /* \MP\ language input */
    mp_filetype_text      /* first text file for readfrom and writeto primitives */
} mp_filetype;

typedef enum mp_origins {
    mp_origin_unset      = 0,
    mp_origin_metapost   = 1,
    mp_origin_luatex     = 2,
    mp_origin_luametatex = 3,
} mp_origins;

typedef enum mp_legacies {
    mp_legacy_unset    = 0,
    mp_legacy_output   = 1,
    mp_legacy_font     = 2,
    mp_legacy_text     = 3,
    mp_legacy_language = 4,
} mp_legacies;

typedef struct mp_primitive_data {
    const char    *name;
    unsigned char  command;
    unsigned char  operation;
    unsigned char  origin;
    unsigned char  legacy;
} mp_primitive_data;

typedef char *(*mp_file_finder)     (MP, const char *, const char *, int);
typedef char *(*mp_script_runner)   (MP, const char *m, size_t len, int n);
typedef void  (*mp_internal_runner) (MP, int action, int n, int type, const char *iname);
typedef void  (*mp_log_runner)      (MP, int, const char *s, size_t l);
typedef int   (*mp_overload_runner) (MP, int, const char *, int);
typedef void  (*mp_error_runner)    (MP, const char *, const char *, int);
typedef void  (*mp_warning_runner)  (MP, const char *);
typedef void  (*mp_status_runner)   (MP);
typedef char *(*mp_text_maker)      (MP, const char *, size_t, int);
typedef void *(*mp_file_opener)     (MP, const char *, const char *, int);
typedef char *(*mp_file_reader)     (MP, void *, size_t *);
typedef void  (*mp_file_closer)     (MP, void *);
typedef int   (*mp_file_eoftest)    (MP, void *);
typedef void  (*mp_file_flush)      (MP, void *);
typedef void  (*mp_file_writer)     (MP, void *, const char *);

typedef struct mp_lstring {
    unsigned char *str;  /* the string value */
    size_t         len;  /* its length */
    int            refs; /* number of references */
} mp_lstring;

typedef mp_lstring *mp_string; /* for pointers to string values */

typedef enum mp_interaction_mode {
    mp_unspecified_mode, /* extra value for command-line switch */
    mp_batch_mode,       /* omits all stops and omits terminal output */
    mp_nonstop_mode,     /* omits all stops */
    mp_scroll_mode,      /* omits error stops */
    mp_error_stop_mode,  /* stops at every opportunity to interact */
    mp_silent_mode       /* stops at every opportunity to interact but not always*/
} mp_interaction_mode;

typedef enum mp_history_state {
    mp_spotless,             /* |history| value when nothing has been amiss yet */
    mp_warning_issued,       /* |history| value when |begin_diagnostic| has been called */
    mp_error_message_issued, /* |history| value when |error| has been called */
    mp_fatal_error_stop,     /* |history| value when termination was premature */
    mp_system_error_stop     /* |history| value when termination was due to disaster */
} mp_history_state;

/*tex
    At some point we introduced \quote {posit} mode in extended \METAPOST\ but then the traditional
    library got \quote {interval} mode.
*/

typedef enum mp_math_mode {
    mp_math_scaled_mode,
    mp_math_double_mode,
    mp_math_binary_mode,
    mp_math_decimal_mode,
    mp_math_posit_mode,
    mp_math_interval_mode,
} mp_math_mode;

typedef struct mp_graphic_object *mp_graphic_object_node;
typedef struct mp_dash_object    *mp_dash_object_node;
typedef struct mp_shape_object   *mp_shape_object_node;
typedef struct mp_start_object   *mp_start_object_node;
typedef struct mp_stop_object    *mp_stop_object_node;
typedef struct mp_edge_object    *mp_edge_object_node;
typedef struct mp_knot_object    *mp_knot_object_node;

typedef struct mp_knot_data *mp_knot;

typedef struct mp_knot_data {
    mp_number     x_coord;       /* the |x| coordinate of this knot */
    mp_number     y_coord;       /* the |y| coordinate of this knot */
    union {
        mp_number left_x;        /* the |x| coordinate of previous control point */
        mp_number left_curl;     /* curl information when entering this knot */
        mp_number left_given;    /* given direction when entering this knot */
    };
    union {
        mp_number left_y;        /* the |y| coordinate of previous control point */
        mp_number left_tension;  /* tension information when entering this knot */
    };
    union {
        mp_number right_x;       /* the |x| coordinate of next control point */
        mp_number right_curl;    /* curl information when leaving this knot */
        mp_number right_given;   /* given direction when leaving this knot */
    };
    union {
        mp_number right_y;       /* the |y| coordinate of next control point */
        mp_number right_tension; /* tension information when leaving this knot */
    };
    union { 
        mp_knot next; 
        mp_knot link; /* fr memory pool */ 
    };
    mp_knot       prev;
    unsigned char left_type;
    unsigned char right_type;
    unsigned char originator;
    unsigned char state;
    signed   int  info;
    /* we now have some 3 bytes slack that we can use */
} mp_knot_data;

typedef struct mp_knot_object {
    double                  x_coord;
    double                  y_coord;
    double                  left_x;
    double                  left_y;
    double                  right_x;
    double                  right_y;
    union { 
        mp_knot_object_node next;
        mp_knot_object_node link;
    };
    mp_knot_object_node     prev;
    unsigned char           left_type;
    unsigned char           right_type;
    unsigned char           originator;
    unsigned char           state;
    signed int              info;
} mp_knot_object;

typedef enum mp_knot_originator {
    mp_program_code,  /* not created by a user */
    mp_metapost_user  /* created by a user */
} mp_knot_originator;

typedef enum mp_knot_states {
    mp_regular_knot,
    mp_begin_knot,
    mp_end_knot,
    mp_single_knot,
} mp_knot_states;

# define mp_valid_knot_state(s) (s >= mp_regular_knot && s <= mp_single_knot)

# undef term_in
# undef term_out

typedef struct mp_run_data {
    void                *term_in; /* dummy pointer */
    mp_edge_object_node  edges;
} mp_run_data;

typedef struct mp_color {
    union {
        double red;
        double cyan;
    };
    union {
        double green;
        double magenta;
    };
    union {
        double blue;
        double yellow;
    };
    union {
        double black;
        double gray;
    };
} mp_color;

/*TEX
    This mp_graphic_object gets cast onto the fill and stroke. For some reason we don't distinguish
    between start and stop here. The regular \METAPOST\ nodes get transformed into these. The 
    backend uses doubles while the frontend uses scaled, doubles, posits or decimals. 
*/

typedef struct mp_graphic_object {
    int                        type;
    int                        stacking;
    union { 
        mp_graphic_object_node link;
        mp_graphic_object_node next;
    };
} mp_graphic_object;

typedef struct mp_dash_object {
    double                   offset;
    double                  *array;
    union { 
        mp_dash_object_node  link;
        mp_dash_object_node  next;
    };
} mp_dash_object;

typedef struct mp_shape_object {
    int                        type;
    int                        stacking;
    union { 
        mp_graphic_object_node link;
        mp_graphic_object_node next;
    };
    char                      *pre_script;
    char                      *post_script;
    size_t                     pre_length;
    size_t                     post_length;
    mp_color                   color;
    mp_knot_object_node        path;
    mp_knot_object_node        htap;
    mp_knot_object_node        pen;
    double                     miterlimit;
    mp_dash_object            *dash;
    unsigned char              color_model;
    unsigned char              linejoin;
    unsigned char              linecap;
    unsigned char              padding_0; /* pen_type */
    unsigned char              curvature;
    unsigned char              padding_1;
 // unsigned char              padding_2;
 // unsigned char              padding_3;
    short                      mesh;
    char                      *bytemap;
    int                        bytemapnx;
    int                        bytemapny;
    int                        bytemapnz;
} mp_shape_object;

typedef struct mp_start_object {
    int                      type;
    int                      stacking;
    union {
        mp_edge_object_node  next;
        mp_edge_object_node  link;
    };
    char                    *pre_script;
    char                    *post_script;
    size_t                   pre_length;
    size_t                   post_length;
    mp_knot_object_node      path;
} mp_start_object;

typedef struct mp_stop_object {
    int                      type;
    int                      stacking;
    union {
        mp_edge_object_node  next;
        mp_edge_object_node  link;
    };
    char                    *pre_script;
    char                    *post_script;
    size_t                   pre_length;
    size_t                   post_length;
    mp_knot_object_node      path;
} mp_stop_object;

typedef struct mp_edge_object {
    mp_graphic_object_node  body;
    union {
        mp_edge_object_node next;
        mp_edge_object_node link;
    };
    MP                      parent;
    double                  minx;
    double                  miny;
    double                  maxx;
    double                  maxy;
    double                  width;
    double                  height;
    double                  depth;
    double                  italic;
    int                     charcode;
    int                     padding;
} mp_edge_object;

typedef void (*mp_backend_writer) (MP, void *);

typedef struct MP_options {
    int                halt_on_error; /* do we quit at the first error? */
    void              *userdata;      /* this allows the calling application to setup local (e.g. L for Lua) */
    char              *banner;        /* the banner that is printed to the screen and log */
    int                utf8_mode;
    int                text_mode;
    int                show_mode;
    mp_file_finder     find_file;
    mp_script_runner   run_script;
    mp_internal_runner run_internal;
    mp_log_runner      run_logger;
    mp_overload_runner run_overload;
    mp_error_runner    run_error;
    mp_warning_runner  run_warning;
    mp_status_runner   run_status;
    mp_text_maker      make_text;
    mp_file_opener     open_file;
    mp_file_closer     close_file;
    mp_file_reader     read_file;
    mp_file_writer     write_file;
    int                find_file_id;
    int                run_script_id;
    int                run_internal_id;
    int                run_logger_id;
    int                run_overload_id;
    int                run_error_id;
    int                run_warning_id;
    int                run_status_id;
    int                make_text_id;
    int                open_file_id;
    int                interaction;
    int                random_seed;
    int                math_mode;
    char              *job_name;
    mp_backend_writer  shipout_backend;
} MP_options;

typedef enum mp_color_model {
    mp_no_model,
    mp_grey_model,
    mp_rgb_model,
    mp_cmyk_model,
    mp_uninitialized_model,
} mp_color_model;

typedef enum mp_knot_type {
    mp_endpoint_knot,  /* |mp_left_type| at path beginning and |mp_right_type| at path end */
    mp_explicit_knot,  /* |mp_left_type| or |mp_right_type| when control points are known */
    mp_given_knot,     /* |mp_left_type| or |mp_right_type| when a direction is given */
    mp_curl_knot,      /* |mp_left_type| or |mp_right_type| when a curl is desired */
    mp_open_knot,      /* |mp_left_type| or |mp_right_type| when \MP\ should choose the direction */
    mp_end_cycle_knot
} mp_knot_type;

# define mp_valid_knot_type(k) (k >= mp_endpoint_knot && k <= mp_end_cycle_knot)

typedef enum mp_graphical_object_code {
    mp_unset_code,
    mp_fill_code,
    mp_stroked_code,
    mp_start_clip_code,   /* |type| of a node that starts clipping */
    mp_start_group_code,  /* |type| of a node that gives a |setgroup| path */
    mp_start_bounds_code, /* |type| of a node that gives a |setbounds| path */
    mp_stop_clip_code,    /* |type| of a node that stops clipping */
    mp_stop_group_code,   /* |type| of a node that stops grouping */
    mp_stop_bounds_code,  /* |type| of a node that stops |setbounds| */
    mp_final_graphic
} mp_graphical_object_code;

typedef enum mp_command_code {
    mp_undefined_command,
    mp_btex_command,                /* begin \TeX\ material (|btex|, |verbatimtex|) */
    mp_etex_command,                /* end \TeX\ material (|etex|) */
    mp_if_test_command,             /* conditional text (|if|) */
    mp_fi_or_else_command,          /* delimiters for conditionals (|elseif|, |else|, |fi|) */
    mp_input_command,               /* input a source file (|input|, |endinput|) */
    mp_iteration_command,           /* iterate (|for|, |forsuffixes|, |forever|, |endfor|) */
    mp_repeat_loop_command,         /* special command substituted for |endfor| */
    mp_exit_test_command,           /* premature exit from a loop (|exitif|) */
    mp_relax_command,               /* do nothing (|\char`\\|) */
    mp_scan_tokens_command,         /* put a string into the input buffer */
    mp_runscript_command,           /* put a script result string into the input buffer */
    mp_maketext_command,            /* make a text (typesetting) */
    mp_expand_after_command,        /* look ahead one token */
    mp_defined_macro_command,       /* a macro defined by the user */
    mp_save_command,                /* save a list of tokens (|save|) */
    mp_interim_command,             /* save an internal quantity (|interim|) */
    mp_let_command,                 /* redefine a symbolic token (|let|) */
    mp_new_internal_command,        /* define a new internal quantity (|newinternal|) */
    mp_bytemap_command,   
    mp_macro_def_command,           /* define a macro (|def|, |vardef|, etc.) */
    mp_ship_out_command,            /* output a character (|shipout|) */
    mp_add_to_command,              /* add to edges (|addto|) */
    mp_bounds_command,              /* add bounding path to edges (|setbounds|, |clip|) */
    mp_protection_command,          /* set protection flag (|outer|, |inner|) */
    mp_property_command,
    mp_show_command,                /* diagnostic output (|show|, |showvariable|, etc.) */
    mp_mode_command,                /* set interaction level (|batchmode|, etc.) */
    mp_only_set_command,            /* initialize random number generator (|randomseed|) */
    mp_message_command,             /* communicate to user (|message|, |errmessage|) */
    mp_every_job_command,           /* designate a starting token (|everyjob|) */
    mp_delimiters_command,          /* define a pair of delimiters (|delimiters|) */
    mp_write_command,               /* write text to a file (|write|) */
    mp_type_name_command,           /* declare a type (|numeric|, |pair|, etc.) */
    mp_left_delimiter_command,      /* the left delimiter of a matching pair */
    mp_begin_group_command,         /* beginning of a group (|begingroup|) */
    mp_nullary_command,             /* an operator without arguments (e.g., |normaldeviate|) */
    mp_unary_command,               /* an operator with one argument (e.g., |sqrt|) */
    mp_str_command,                 /* convert a suffix to a string (|str|) */
    mp_void_command,                /* convert a suffix to a boolean (|void|) */
    mp_cycle_command,               /* close a cyclic path (|cycle|) */
    mp_of_binary_command,           /* binary operation taking |of| (e.g., |point|) */
    mp_capsule_command,             /* a value that has been put into a token list */
    mp_string_command,              /* a string constant (e.g., |"hello"|) */
    mp_internal_command,            /* internal numeric parameter (e.g., |pausing|) */
    mp_tag_command,                 /* a symbolic token without a primitive meaning */
    mp_numeric_command,             /* a numeric constant (e.g., |3.14159|) */
    mp_plus_or_minus_command,       /* either |+| or |-| */
    mp_secondary_def_command,       /* a macro defined by |secondarydef| */
    mp_tertiary_binary_command,     /* an operator at the tertiary level (e.g., |++|) */
    mp_left_brace_command,          /* the operator `|\char||| */
    mp_path_join_command,           /* the operator |..| */
    mp_path_connect_command,        /* the operator |--| */
    mp_ampersand_command,           /* the operator `\.\&' */
    mp_tertiary_def_command,        /* a macro defined by |tertiarydef| */
    mp_primary_binary_command,      /* an operator at the expression level (e.g., |<|) */
    mp_equals_command,              /* the operator |=| */
    mp_and_command,                 /* the operator |and| */
    mp_primary_def_command,         /* a macro defined by |primarydef| */
    mp_slash_command,               /* the operator |/| */
    mp_secondary_binary_command,    /* an operator at the binary level (e.g., |shifted|) */
    mp_parameter_commmand,          /* type of parameter (|primary|, |expr|, |suffix|, etc.) */
    mp_controls_command,            /* specify control points explicitly (|controls|) */
    mp_tension_command,             /* specify tension between knots (|tension|) */
    mp_at_least_command,            /* bounded tension value (|atleast|) */
    mp_curl_command,                /* specify curl at an end knot (|curl|) */
    mp_macro_special_command,       /* special macro operators (|quote|, |\#\AT!|, etc.) */
    mp_right_delimiter_command,     /* the right delimiter of a matching pair */
    mp_left_bracket_command,        /* the operator |[| */
    mp_right_bracket_command,       /* the operator |]| */
    mp_right_brace_command,         /* the operator `|\char|}| */
    mp_with_option_command,         /* option for filling (|withpen|, |withweight|, etc.) */
    mp_thing_to_add_command,        /* variant of |addto| (|contour|, |doublepath|, |also|) */
    mp_of_command,                  /* the operator |of| */
    mp_to_command,                  /* the operator |to| */
    mp_step_command,                /* the operator |step| */
    mp_until_command,               /* the operator |until| */
    mp_within_command,              /* the operator |within| */
    mp_assignment_command,          /* the operator |:=| */
    mp_colon_command,               /* the operator |:| */
    mp_comma_command,               /* the operator |,|, must be |colon+1| */
    mp_semicolon_command,           /* the operator |;|, must be |comma+1| */
    mp_end_group_command,           /* end a group (|endgroup|), must be |semicolon+1| */
    mp_stop_command,                /* end a job (|end|, |dump|), must be |end_group+1| */
 // mp_outer_tag_command,           /* protection code added to command code */
    mp_undefined_cs_command,        /* protection code added to command code */
} mp_command_code;

typedef enum mp_variable_type {
    mp_undefined_type,        /* no type has been declared */
    mp_vacuous_type,          /* no expression was present */
    mp_boolean_type,          /* |boolean| with a known value */
    mp_unknown_boolean_type,
    mp_string_type,           /* |string| with a known value */
    mp_unknown_string_type,
    mp_pen_type,              /* |pen| with a known value */
    mp_unknown_pen_type,
    mp_nep_type,              /* |pen| with a known value */
    mp_unknown_nep_type,
    mp_path_type,             /* |path| with a known value */
    mp_unknown_path_type,
    mp_picture_type,          /* |picture| with a known value */
    mp_unknown_picture_type,
    mp_transform_type,        /* |transform| variable or capsule */
    mp_color_type,            /* |color| variable or capsule */
    mp_cmykcolor_type,        /* |cmykcolor| variable or capsule */
    mp_pair_type,             /* |pair| variable or capsule */
    mp_numeric_type,          /* variable that has been declared |numeric| but not used */
    mp_known_type,            /* |numeric| with a known value */
    mp_dependent_type,        /* a linear combination with |fraction| coefficients */
    mp_proto_dependent_type,  /* a linear combination with |scaled| coefficients */
    mp_independent_type,      /* |numeric| with unknown value */
    mp_token_list_type,       /* variable name or suffix argument or text argument */
    mp_structured_type,       /* variable with subscripts and attributes */
    mp_unsuffixed_macro_type, /* variable defined with |vardef| but no |\AT!\#| */
    mp_suffixed_macro_type,   /* variable defined with |vardef| and |\AT!\#| */
    mp_symbol_node_type,
    mp_token_node_type,
    mp_value_node_type,
    mp_attribute_node_type,
    mp_subscript_node_type,
    mp_pair_node_type,
    mp_transform_node_type,
    mp_color_node_type,
    mp_cmykcolor_node_type,
    /*tex
        It is important that the next 7 items remain in this order, for export as
        well as switch/case offsets.
    */
    mp_fill_node_type,
    mp_stroked_node_type,
    mp_start_clip_node_type,
    mp_start_group_node_type,
    mp_start_bounds_node_type,
    mp_stop_clip_node_type,
    mp_stop_group_node_type,
    mp_stop_bounds_node_type,
    mp_dash_node_type,
    mp_dep_node_type,
    mp_if_node_type,
    mp_edge_header_node_type,
} mp_variable_type;

typedef enum mp_name_type_type {
    mp_root_operation,                /* |name_type| at the top level of a variable */
    mp_saved_root_operation,          /* same, when the variable has been saved */
    mp_structured_root_operation,     /* |name_type| where a |mp_structured| branch occurs */
    mp_subscript_operation,           /* |name_type| in a subscript node */
    mp_attribute_operation,           /* |name_type| in an attribute node */
    mp_x_part_operation,              /* |name_type| in the |xpart| of a node */
    mp_y_part_operation,              /* |name_type| in the |ypart| of a node */
    mp_z_part_operation,             
    mp_w_part_operation,             
    mp_xx_part_operation,             /* |name_type| in the |xxpart| of a node */
    mp_xy_part_operation,             /* |name_type| in the |xypart| of a node */
    mp_yx_part_operation,             /* |name_type| in the |yxpart| of a node */
    mp_yy_part_operation,             /* |name_type| in the |yypart| of a node */
    mp_red_part_operation,            /* |name_type| in the |redpart| of a node */
    mp_green_part_operation,          /* |name_type| in the |greenpart| of a node */
    mp_blue_part_operation,           /* |name_type| in the |bluepart| of a node */
    mp_cyan_part_operation,           /* |name_type| in the |redpart| of a node */
    mp_magenta_part_operation,        /* |name_type| in the |greenpart| of a node */
    mp_yellow_part_operation,         /* |name_type| in the |bluepart| of a node */
    mp_black_part_operation,          /* |name_type| in the |greenpart| of a node */
    mp_grey_part_operation,           /* |name_type| in the |greypart| of a node */
    mp_capsule_operation,             /* |name_type| in stashed-away subexpressions */
    mp_token_operation,               /* |name_type| in a numeric token or string token */
    mp_boolean_type_operation,        /* the order needs to match the types (as we use deltas) ! */
    mp_string_type_operation,
    mp_pen_type_operation,
    mp_nep_type_operation,
    mp_path_type_operation,
    mp_picture_type_operation,
    mp_transform_type_operation,
    mp_color_type_operation,
    mp_cmykcolor_type_operation,
    mp_pair_type_operation,
    mp_numeric_type_operation,
    /* Symbolic nodes also have |name_type|, which is a different enumeration */
    mp_normal_operation,
    mp_internal_operation,            /* for values of internals */
    mp_macro_operation,               /* for macro names */
    mp_expr_operation,                /* for macro parameters if type |expr| */
    mp_suffix_operation,              /* for macro parameters if type |suffix| */
    mp_text_operation,                /* for macro parameters if type |text| */
    /* snippet: operation codes */
    mp_true_operation,                /* operation code for |true| */
    mp_false_operation,               /* operation code for |false| */
    mp_null_picture_operation,        /* operation code for |nullpicture| */
    mp_null_pen_operation,            /* operation code for |nullpen| */
    mp_read_string_operation,         /* operation code for |readstring| */
    mp_pen_circle_operation,          /* operation code for |pencircle| */
    mp_normal_deviate_operation,      /* operation code for |normaldeviate| */
    mp_read_from_operation,           /* operation code for |readfrom| */
    mp_close_from_operation,          /* operation code for |closefrom| */
    mp_odd_operation,                 /* operation code for |odd| */
    mp_known_operation,               /* operation code for |known| */
    mp_unknown_operation,             /* operation code for |unknown| */
    mp_not_operation,                 /* operation code for |not| */
    mp_decimal_operation,             /* operation code for |decimal| */
    mp_reverse_operation,             /* operation code for |reverse| */
    mp_uncycle_operation,             /* operation code for |uncycle| */
    mp_singularity_operation,         /* operation code for |singularity| */
    mp_make_path_operation,           /* operation code for |makepath| */
    mp_make_pen_operation,            /* operation code for |makepen| */
    mp_make_nep_operation,            /* operation code for |makenep| */
    mp_convexed_operation,            /* operation code for |convexed| */
    mp_uncontrolled_operation,        /* operation code for |uncontrolled| */
    mp_oct_operation,                 /* operation code for |oct| */
    mp_hex_operation,                 /* operation code for |hex| */
    mp_ASCII_operation,               /* operation code for |ASCII| */
    mp_char_operation,                /* operation code for |char| */
    mp_segments_operation,            /* operation code for |segments| */
    mp_length_operation,              /* operation code for |length| */
    mp_no_length_operation,           /* operation code for |nolength| */
    mp_first_point_operation,
    mp_first_pre_control_operation,
    mp_first_post_control_operation,
    mp_first_direction_operation,
    mp_first_unit_direction_operation,
    mp_last_point_operation,
    mp_last_pre_control_operation,
    mp_last_post_control_operation,
    mp_last_direction_operation,
    mp_last_unit_direction_operation,
    mp_prune_singularities_operation,            
    mp_turning_operation,             /* operation code for |turningnumber| */
    mp_color_model_operation,         /* operation code for |colormodel| */
    mp_path_part_operation,           /* operation code for |pathpart| */
    mp_pen_part_operation,            /* operation code for |penpart| */
    mp_dash_part_operation,           /* operation code for |dashpart| */
    mp_prescript_part_operation,      /* operation code for |prescriptpart| */
    mp_postscript_part_operation,     /* operation code for |postscriptpart| */
    mp_stacking_part_operation,       /* operation code for |stackingpart| */
    mp_sqrt_operation,                /* operation code for |sqrt| */
    mp_norm_operation,                /* operation code for |knownnorm| */
    mp_m_exp_operation,               /* operation code for |mexp| */
    mp_m_log_operation,               /* operation code for |mlog| */
    mp_sin_d_operation,               /* operation code for |sind| */
    mp_cos_d_operation,               /* operation code for |cosd| */
    mp_floor_operation,               /* operation code for |floor| */
    mp_normalize_operation,           /* operation code for |normalize| */
    mp_uniform_deviate_operation,     /* operation code for |uniformdeviate| */
    mp_ll_corner_operation,           /* operation code for |llcorner| */
    mp_lr_corner_operation,           /* operation code for |lrcorner| */
    mp_ul_corner_operation,           /* operation code for |ulcorner| */
    mp_ur_corner_operation,           /* operation code for |urcorner| */
    mp_corners_operation,             /* operation code for |corners| */
    mp_center_of_operation,           /* operation code for |centerof| */
    mp_center_of_mass_operation,      /* operation code for |centerofmass| */
    mp_x_range_operation,             /* operation code for |xrange| */
    mp_y_range_operation,             /* operation code for |yrange| */
    mp_delta_point_operation,         /* operation code for |deltapoint| */
    mp_delta_precontrol_operation,    /* operation code for |deltaprecontrol| */
    mp_delta_postcontrol_operation,   /* operation code for |deltapostcontrol| */
    mp_delta_direction_operation,     /* operation code for |deltadirection| */
    mp_delta_unit_direction_operation,/* operation code for |deltaunitdirection| */
    mp_delta_arclength_operation,     /* operation code for |deltaarclength| */
    mp_delta_iterator_index_operation,/* operation code for |deltaiteratorindex| */
    mp_arc_length_operation,          /* operation code for |arclength| */
    mp_angle_operation,               /* operation code for |angle| */
    mp_cycle_operation,               /* operation code for |cycle| */
    mp_recycle_operation,             /* operation code for |cycle| */
    mp_no_cycle_operation,            /* operation code for |nocycle| */
    mp_x_relative_operation,          /* operation code for |xrelative| */
    mp_y_relative_operation,          /* operation code for |yrelative| */
    mp_xy_relative_operation,         /* operation code for |xyrelative| */
    mp_x_absolute_operation,          /* operation code for |xabsolute| */
    mp_y_absolute_operation,          /* operation code for |yabsolute| */
    mp_xy_absolute_operation,         /* operation code for |xyabsolute| */
    mp_filled_operation,              /* operation code for |filled| */
    mp_stroked_operation,             /* operation code for |stroked| */
    mp_clipped_operation,             /* operation code for |clipped| */
    mp_grouped_operation,             /* operation code for |bounded| */
    mp_bounded_operation,             /* operation code for |grouped| */
    mp_plus_operation,                /* operation code for \.+ */
    mp_minus_operation,               /* operation code for \.- */
    mp_times_operation,               /* operation code for \.* */
    mp_over_operation,                /* operation code for \./ */
    mp_power_operation,               /* operation code for \.^ */
    mp_pythag_add_operation,          /* operation code for |++| */
    mp_pythag_sub_operation,          /* operation code for |+-+| */
    mp_dotprod_operation,             /* operation code for |knowndotprod| */
    mp_crossprod_operation,           /* operation code for |knowncrossprod| */
    mp_div_operation,                 /* operation code for |knowndiv| */
    mp_mod_operation,                 /* operation code for |knownmod| */
    mp_or_operation,                  /* operation code for |or| */
    mp_and_operation,                 /* operation code for |and| */
    mp_less_than_operation,           /* operation code for \.< */
    mp_less_or_equal_operation,       /* operation code for |<=| */
    mp_greater_than_operation,        /* operation code for \.> */
    mp_greater_or_equal_operation,    /* operation code for |>=| */
    mp_equal_operation,               /* operation code for \.= */
    mp_unequal_operation,             /* operation code for |<>| */
    mp_concat_operation,              /* operation code for \.\& */
    mp_just_append_operation,         /* operation code for \.\&\& */
    mp_tolerant_concat_operation,     /* operation code for \.\&\&\& */
    mp_tolerant_append_operation,     /* operation code for \.\&\&\&\& */
    mp_rotated_operation,             /* operation code for |rotated| */
    mp_slanted_operation,             /* operation code for |slanted| */
    mp_scaled_operation,              /* operation code for |scaled| */
    mp_shifted_operation,             /* operation code for |shifted| */
    mp_transformed_operation,         /* operation code for |transformed| */
    mp_x_scaled_operation,            /* operation code for |xscaled| */
    mp_y_scaled_operation,            /* operation code for |yscaled| */
    mp_z_scaled_operation,            /* operation code for |zscaled| */
    mp_xy_scaled_operation,           /* operation code for |xyscaled| */
    mp_x_shifted_operation,           /* operation code for |xshifted| */
    mp_y_shifted_operation,           /* operation code for |yshifted| */
    mp_bytemap_scaled_operation,
    mp_uncycled_operation,            /* operation code for |uncycled| */
    mp_intertimes_operation,          /* operation code for |intersectiontimes| */
    mp_intertimes_list_operation,     /* operation code for |intersectiontimeslist| */
    mp_double_dot_operation,          /* operation code for improper |..| */
    /* the |of| operations: */
    mp_substring_operation,           /* operation code for |substring| */
    mp_subpath_operation,             /* operation code for |subpath| */
    mp_segment_operation,             /* operation code for |subpath| */
    mp_direction_time_operation,      /* operation code for |directiontime| */
    mp_point_operation,               /* operation code for |point| */
    mp_precontrol_operation,          /* operation code for |precontrol| */
    mp_postcontrol_operation,         /* operation code for |postcontrol| */
    mp_direction_operation,           /* operation code for |direction| */
    mp_unit_direction_operation,      /* operation code for |unitdirection| */
    mp_last_xy_operation,       
    mp_last_x_operation,       
    mp_last_y_operation,       
    mp_previous_xy_operation,       
    mp_previous_x_operation,       
    mp_previous_y_operation,       
    mp_path_point_operation,          /* operation code for |pathpoint| */
    mp_path_precontrol_operation,     /* operation code for |pathprecontrol| */
    mp_path_postcontrol_operation,    /* operation code for |pathpostcontrol| */
    mp_path_direction_operation,      /* operation code for |pathdirection| */
    mp_path_unit_direction_operation, /* operation code for |pathunitdirection| */
    mp_path_state_operation,          /* operation code for |pathstate| */
    mp_path_index_operation,          /* operation code for |pathindex| */
    mp_path_lastindex_operation,      /* operation code for |pathlastindex| */
    mp_path_length_operation,         /* operation code for |pathlength| */
    mp_path_first_operation,          /* operation code for |pathfirst| */
    mp_path_last_operation,           /* operation code for |pathlast| */
    mp_path_xpart_operation,          /* operation code for |pathxpart| */
    mp_path_ypart_operation,          /* operation code for |pathypart| */
    mp_pen_offset_operation,          /* operation code for |penoffset| */
    mp_arc_time_operation,            /* operation code for |arctime| */
    mp_arc_point_operation,           /* operation code for |arcpoint| */
    mp_arc_point_list_operation,      /* operation code for |arcpointlist| */
    mp_subarc_length_operation,       /* operation code for |subarclength| */
    mp_version_operation,             /* operation code for |mpversion| */
    mp_iterator_index_operation,
    mp_envelope_operation,            /* operation code for |envelope| */
    mp_boundingpath_operation,        /* operation code for |boundingpath| */
    mp_bytemap_value_operation,
    mp_bytemap_found_operation,
    mp_bytemap_path_operation,
    mp_bytemap_bounds_operation,
} mp_name_type_type;

# define mp_first_operation  mp_root_operation
# define mp_last_operation   mp_bytemap_bounds_operation
# define mp_min_of_operation mp_substring_operation

typedef enum mp_class_codes {
    mp_digit_class             =  0, /* the class number of |0123456789| */
    mp_period_class            =  1, /* the class number of |.| */
    mp_space_class             =  2, /* the class number of spaces and nonstandard characters */
    mp_percent_class           =  3, /* the class number of `\.\%' */
    mp_string_class            =  4, /* the class number of |"| */
    mp_comma_class             =  5, /* the , */
    mp_semicolon_class         =  6, /* the ; */
    mp_left_parenthesis_class  =  7, /* the class number of |(| */
    mp_right_parenthesis_class =  8, /* the class number of |)| */
    mp_letter_class            =  9, /* letters and the underline character */
    mp_suffix_class            = 15,
    mp_left_bracket_class      = 17, /* |[| */
    mp_right_bracket_class     = 18, /* |]| */
    mp_brace_class             = 19,
    mp_invalid_class           = 20, /* bad character in the input */
    mp_max_class               = 20, /* the largest class number */
} mp_class_codes;

typedef enum mp_text_codes {
    mp_forever_text,     /* |token_type| code for loop texts */
    mp_loop_text,        /* |token_type| code for loop texts */
    mp_parameter_text,   /* |token_type| code for parameter texts */
    mp_backed_up_text,   /* |token_type| code for texts to be reread */
    mp_inserted_text,    /* |token_type| code for inserted texts */
    mp_macro_text,       /* |token_type| code for macro replacement texts */
    mp_file_bottom_text, /* lowest file code */
} mp_text_codes;

typedef enum mp_scanner_states {
    mp_normal_state,        /* |scanner_status| at \quote {quiet times} */
    mp_skipping_state,      /* |scanner_status| when false conditional text is being skipped */
    mp_flushing_state,      /* |scanner_status| when junk after a statement is being ignored */
    mp_absorbing_state,     /* |scanner_status| when a |text| parameter is being scanned */
    mp_var_defining_state,  /* |scanner_status| when a |vardef| is being scanned */
    mp_op_defining_state,   /* |scanner_status| when a macro |def| is being scanned */
    mp_loop_defining_state, /* |scanner_status| when a |for| loop is being scanned */
    mp_tex_flushing_state,
} mp_scanner_states;

typedef enum mp_verbatim_codes {
    mp_btex_code,
    mp_verbatim_code,
} mp_verbatim_codes;

typedef enum mp_def_codes {
    mp_end_def_code,       /* command modifier for |enddef| */
    mp_def_code,           /* command modifier for |def| */
    mp_var_def_code,       /* command modifier for |vardef| */
    mp_primary_def_code,   /* command modifier for |primarydef| */
    mp_secondary_def_code, /* command modifier for |secondarydef| */
    mp_tertiary_def_code,  /* command modifier for |tertiarydef| */
} mp_def_codes;

typedef enum mp_only_set_codes {
    mp_random_seed_code,
    mp_max_knot_pool_code,
} mp_only_set_codes;

typedef enum mp_bytemap_codes {
    mp_bytemap_set_byte_code,
    mp_bytemap_set_offset_code,
    mp_bytemap_copy_code,
    mp_bytemap_new_code,
    mp_bytemap_set_code,
    mp_bytemap_clip_code,
    mp_bytemap_reduce_code,
    mp_bytemap_set_options_code,
    mp_bytemap_reset_code,
    mp_bytemap_reset_all_code,
} mp_bytemap_codes;

typedef enum mp_for_codes {
    mp_end_for_code,           /* command modifier for |endfor| */
    mp_start_forever_code,     /* command modifier for |forever| */
    mp_start_for_code,         /* command modifier for |for| */
    mp_start_forsuffixes_code, /* command modifier for |forsuffixes| */
} mp_for_codes;

typedef enum mp_macro_fix_codes {
    mp_macro_quote_code,  /* |macro_special| modifier for |quote| */
    mp_macro_prefix_code, /* |macro_special| modifier for |\#\AT!| */
    mp_macro_at_code,     /* |macro_special| modifier for |\AT!| */
    mp_macro_suffix_code, /* |macro_special| modifier for |\AT!\#| */
} mp_macro_fix_codes;

typedef enum mp_controls_codes {
    mp_both_controls_code, 
    mp_first_control_code,
    mp_second_control_code,
} mp_controls_codes;

typedef enum mp_if_codes {
    mp_no_if_code,
    mp_if_code,      /* code for |if| being evaluated */
    mp_fi_code,      /* code for |fi| */
    mp_else_code,    /* code for |else| */
    mp_else_if_code, /* code for |elseif| */
} mp_if_codes;

typedef enum mp_show_codes {
    mp_show_token_code,        /* show the meaning of a single token */
    mp_show_stats_code,        /* show current memory and string usage */
    mp_show_code,              /* show a list of expressions */
    mp_show_var_code,          /* show a variable and its descendents */
    mp_show_dependencies_code, /* show dependent variables in terms of independents */
} mp_show_codes;

typedef enum mp_with_codes {
    mp_with_pen_code,
    mp_with_dashed_code,
    mp_with_pre_script_code,
    mp_with_post_script_code,
    mp_with_nested_pre_script_code,
    mp_with_nested_post_script_code,
    mp_with_stacking_code,
    mp_with_no_model_code,
    mp_with_grey_model_code,
    mp_with_uninitialized_model_code,
    mp_with_rgb_model_code,
    mp_with_cmyk_model_code,
    mp_with_linecap_code,
    mp_with_linejoin_code,
    mp_with_miterlimit_code,
    mp_with_curvature_code,
    mp_with_mesh_code,
    mp_with_bytemap_code,
    mp_with_nothing_code,    /* quits scanning of a with, avoids lookahead */
} mp_with_codes;

typedef enum mp_add_codes {
    mp_add_double_path_code, /* command modifier for |doublepath| */
    mp_add_contour_code,     /* command modifier for |contour| */
    mp_add_also_code,        /* command modifier for |also| */
} mp_add_codes ;

typedef enum mp_message_codes {
    mp_normal_message_code,
    mp_error_message_code,
    mp_error_help_code,
} mp_message_codes;

typedef enum mp_protection_codes {
    mp_inner_protection_code,
    mp_outer_protection_code,
} mp_protection_codes;

typedef enum mp_input_codes {
    mp_input_code,
    mp_end_input_code,
} mp_input_codes;

typedef enum mp_stop_codes {
    mp_end_code,
    mp_dump_code,
} mp_stop_codes;

/* types in the outer block */

/* types in the outer block */

typedef void        (*convert_func)                      (mp_number *A);
typedef void        (*m_log_func)                        (MP mp, mp_number *r, const mp_number *A);
typedef void        (*m_exp_func)                        (MP mp, mp_number *r, const mp_number *A);
typedef void        (*m_unif_rand_func)                  (MP mp, mp_number *ret, const mp_number *x_orig);
typedef void        (*m_norm_rand_func)                  (MP mp, mp_number *ret);
typedef void        (*pyth_add_func)                     (MP mp, mp_number *r, const mp_number *A, const mp_number *B);
typedef void        (*pyth_add3_func)                    (MP mp, mp_number *r, const mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*pyth_sub_func)                     (MP mp, mp_number *r, mp_number *A, const mp_number *B);
typedef void        (*power_of_func)                     (MP mp, mp_number *r, const mp_number *A, const mp_number *B);
typedef void        (*n_arg_func)                        (MP mp, mp_number *r, const mp_number *A, const mp_number *B);
typedef void        (*velocity_func)                     (MP mp, mp_number *r, const mp_number *A, const mp_number *B, const mp_number *C, const mp_number *D, const mp_number *E);
typedef int         (*ab_vs_cd_func)                     (const mp_number *A, const mp_number *B, const mp_number *C, const mp_number *D);
typedef void        (*crossing_point_func)               (MP mp, mp_number *r, const mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*number_from_int_func)              (mp_number *A, mp_scaled_t B);
typedef void        (*number_from_boolean_func)          (mp_number *A, mp_scaled_t B);
typedef void        (*number_from_scaled_func)           (mp_number *A, mp_scaled_t B);
typedef void        (*number_from_double_func)           (mp_number *A, double B);
typedef void        (*number_from_addition_func)         (mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*number_half_from_addition_func)    (mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*number_from_subtraction_func)      (mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*number_half_from_subtraction_func) (mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*number_from_div_func)              (mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*number_from_mul_func)              (mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*number_from_int_div_func)          (mp_number *A, const mp_number *B, mp_scaled_t C);
typedef void        (*number_from_int_mul_func)          (mp_number *A, const mp_number *B, mp_scaled_t C);
typedef void        (*number_from_of_the_way_func)       (MP mp, mp_number *A, const mp_number *t, const mp_number *B, const mp_number *C);
typedef void        (*number_negate_func)                (mp_number *A);
typedef void        (*number_add_func)                   (mp_number *A, const mp_number *B);
typedef void        (*number_subtract_func)              (mp_number *A, const mp_number *B);
typedef void        (*number_modulo_func)                (mp_number *A, const mp_number *B);
typedef void        (*number_half_func)                  (mp_number *A);
typedef void        (*number_double_func)                (mp_number *A);
typedef void        (*number_abs_func)                   (mp_number *A);
typedef void        (*number_clone_func)                 (mp_number *A, const mp_number *B);
typedef void        (*number_negated_clone_func)         (mp_number *A, const mp_number *B);
typedef void        (*number_abs_clone_func)             (mp_number *A, const mp_number *B);
typedef void        (*number_swap_func)                  (mp_number *A, mp_number *B);
typedef void        (*number_add_scaled_func)            (mp_number *A, mp_scaled_t B);
typedef void        (*number_multiply_int_func)          (mp_number *A, mp_scaled_t B);
typedef void        (*number_divide_int_func)            (mp_number *A, mp_scaled_t B);
typedef mp_scaled_t (*number_to_int_func)                (const mp_number *A);
typedef mp_scaled_t (*number_to_boolean_func)            (const mp_number *A);
typedef mp_scaled_t (*number_to_scaled_func)             (const mp_number *A);
typedef mp_scaled_t (*number_round_func)                 (const mp_number *A);
typedef void        (*number_floor_func)                 (mp_number *A);
typedef double      (*number_to_double_func)             (const mp_number *A);
typedef int         (*number_odd_func)                   (const mp_number *A);
typedef int         (*number_equal_func)                 (const mp_number *A, const mp_number *B);
typedef int         (*number_less_func)                  (const mp_number *A, const mp_number *B);
typedef int         (*number_greater_func)               (const mp_number *A, const mp_number *B);
typedef int         (*number_non_equal_abs_func)         (const mp_number *A, const mp_number *B);
typedef void        (*make_scaled_func)                  (MP mp, mp_number *ret, const mp_number *A, const mp_number *B);
typedef void        (*make_fraction_func)                (MP mp, mp_number *ret, const mp_number *A, const mp_number *B);
typedef void        (*take_fraction_func)                (MP mp, mp_number *ret, const mp_number *A, const mp_number *B);
typedef void        (*take_scaled_func)                  (MP mp, mp_number *ret, const mp_number *A, const mp_number *B);
typedef void        (*sin_cos_func)                      (MP mp, const mp_number *A, mp_number *S, mp_number *C);
typedef void        (*slow_add_func)                     (MP mp, mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*slow_sub_func)                     (MP mp, mp_number *A, const mp_number *B, const mp_number *C);
typedef void        (*sqrt_func)                         (MP mp, mp_number *ret, const mp_number *A);
typedef void        (*init_randoms_func)                 (MP mp, int seed);
typedef void        (*allocate_number_func)              (MP mp, mp_number *A, mp_number_type t);
typedef void        (*allocate_number_clone_func)        (MP mp, mp_number *A, mp_number_type t, const mp_number *B);
typedef void        (*allocate_number_abs_func)          (MP mp, mp_number *A, mp_number_type t, const mp_number *B);
typedef void        (*allocate_number_div_func)          (MP mp, mp_number *A, mp_number_type t, const mp_number *B, const mp_number *C);
typedef void        (*allocate_number_mul_func)          (MP mp, mp_number *A, mp_number_type t, const mp_number *B, const mp_number *C);
typedef void        (*allocate_number_add_func)          (MP mp, mp_number *A, mp_number_type t, const mp_number *B, const mp_number *C);
typedef void        (*allocate_number_sub_func)          (MP mp, mp_number *A, mp_number_type t, const mp_number *B, const mp_number *C);
typedef void        (*allocate_number_double_func)       (MP mp, mp_number *A, double B);
typedef void        (*free_number_func)                  (MP mp, mp_number *n);
typedef void        (*fraction_to_round_scaled_func)     (mp_number *n);
typedef void        (*print_func)                        (MP mp, const mp_number *A);
typedef char       *(*tostring_func)                     (MP mp, const mp_number *A);
typedef void        (*scan_func)                         (MP mp, mp_scaled_t A);
typedef void        (*mp_free_func)                      (MP mp);
typedef void        (*set_precision_func)                (MP mp);

/*tex
    We use a prefix |md_| so that we don't get complaints about recursive macro definitions. This
    is cleaner than redefining the macros.
*/

typedef struct math_data {
    mp_number                         md_precision_default;
    mp_number                         md_precision_max;
    mp_number                         md_precision_min;
    mp_number                         md_epsilon_t;
    mp_number                         md_inf_t;
    mp_number                         md_negative_inf_t;
    mp_number                         md_one_third_inf_t;
    mp_number                         md_zero_t;
    mp_number                         md_unity_t;
    mp_number                         md_two_t;
    mp_number                         md_three_t;
    mp_number                         md_half_unit_t;
    mp_number                         md_three_quarter_unit_t;
    mp_number                         md_fraction_one_t;
    mp_number                         md_fraction_half_t;
    mp_number                         md_fraction_three_t;
    mp_number                         md_fraction_four_t;
    mp_number                         md_one_eighty_deg_t;
    mp_number                         md_negative_one_eighty_deg_t;
    mp_number                         md_three_sixty_deg_t;
    mp_number                         md_one_k;
    mp_number                         md_sqrt_8_e_k;
    mp_number                         md_twelve_ln_2_k;
    mp_number                         md_coef_bound_k;
    mp_number                         md_coef_bound_minus_1;
    mp_number                         md_twelvebits_3;
    mp_number                         md_arc_tol_k;
    mp_number                         md_twentysixbits_sqrt2_t;
    mp_number                         md_twentyeightbits_d_t;
    mp_number                         md_twentysevenbits_sqrt2_d_t;
    mp_number                         md_fraction_threshold_t;
    mp_number                         md_half_fraction_threshold_t;
    mp_number                         md_scaled_threshold_t;
    mp_number                         md_half_scaled_threshold_t;
    mp_number                         md_near_zero_angle_t;
    mp_number                         md_p_over_v_threshold_t;
    mp_number                         md_equation_threshold_t;
    mp_number                         md_warning_limit_t;
    allocate_number_func              md_allocate;
    allocate_number_clone_func        md_allocate_clone;
    allocate_number_abs_func          md_allocate_abs;
    allocate_number_div_func          md_allocate_div;
    allocate_number_mul_func          md_allocate_mul;
    allocate_number_add_func          md_allocate_add;
    allocate_number_sub_func          md_allocate_sub;
    allocate_number_double_func       md_allocate_double;
    free_number_func                  md_free;
    number_from_int_func              md_from_int;
    number_from_boolean_func          md_from_boolean;
    number_from_scaled_func           md_from_scaled;
    number_from_double_func           md_from_double;
    number_from_addition_func         md_from_addition;
    number_half_from_addition_func    md_half_from_addition;
    number_from_subtraction_func      md_from_subtraction;
    number_half_from_subtraction_func md_half_from_subtraction;
    number_from_div_func              md_from_div;
    number_from_mul_func              md_from_mul;
    number_from_int_div_func          md_from_int_div;
    number_from_int_mul_func          md_from_int_mul;
    number_from_of_the_way_func       md_from_of_the_way;
    number_negate_func                md_negate;
    number_add_func                   md_add;
    number_subtract_func              md_subtract;
    number_half_func                  md_half;
    number_modulo_func                md_modulo;
    number_double_func                md_do_double;
    number_abs_func                   md_abs;
    number_clone_func                 md_clone;
    number_negated_clone_func         md_negated_clone;
    number_abs_clone_func             md_abs_clone;
    number_swap_func                  md_swap;
    number_add_scaled_func            md_add_scaled;
    number_multiply_int_func          md_multiply_int;
    number_divide_int_func            md_divide_int;
    number_to_int_func                md_to_int;
    number_to_boolean_func            md_to_boolean;
    number_to_scaled_func             md_to_scaled;
    number_to_double_func             md_to_double;
    number_odd_func                   md_odd;
    number_equal_func                 md_equal;
    number_less_func                  md_less;
    number_greater_func               md_greater;
    number_non_equal_abs_func         md_non_equal_abs;
    number_round_func                 md_round_unscaled;
    number_floor_func                 md_floor_scaled;
    make_scaled_func                  md_make_scaled;
    make_fraction_func                md_make_fraction;
    take_fraction_func                md_take_fraction;
    take_scaled_func                  md_take_scaled;
    velocity_func                     md_velocity;
    ab_vs_cd_func                     md_ab_vs_cd;
    crossing_point_func               md_crossing_point;
    n_arg_func                        md_n_arg;
    m_log_func                        md_m_log;
    m_exp_func                        md_m_exp;
    m_unif_rand_func                  md_m_unif_rand;
    m_norm_rand_func                  md_m_norm_rand;
    pyth_add_func                     md_pyth_add;
    pyth_add3_func                    md_pyth_add3;
    pyth_sub_func                     md_pyth_sub;
    power_of_func                     md_power_of;
    fraction_to_round_scaled_func     md_fraction_to_round_scaled;
    convert_func                      md_fraction_to_scaled;
    convert_func                      md_scaled_to_fraction;
    convert_func                      md_scaled_to_angle;
    convert_func                      md_angle_to_scaled;
    init_randoms_func                 md_init_randoms;
    sin_cos_func                      md_sin_cos;
    sqrt_func                         md_sqrt;
    slow_add_func                     md_slow_add;
    slow_sub_func                     md_slow_sub;
    print_func                        md_print;
    tostring_func                     md_tostring;
    scan_func                         md_scan_numeric;
    scan_func                         md_scan_fractional;
    mp_free_func                      md_free_math;
    set_precision_func                md_set_precision;
} math_data;

typedef unsigned short quarterword; /* 1/4 of a 64 bit word */
typedef int            halfword;    /* 1/2 of a 64 bit word */

/*tex 

    It is more convenient toi have these in one place. The records are defined later. Some 
    nodes are for housekeeping, others concern graphics. We also encounter export related 
    objects. 

    Some nodes are mized in linked lists to then we cast them in away that the common fields 
    overlap. 

*/

typedef struct mp_value_node_data     *mp_value_node;
typedef struct mp_node_data           *mp_node;
typedef struct mp_symbol_data         *mp_symbol;       
typedef struct mp_subst_data          *mp_subst_node;            /* will become mp_subst */

typedef struct mp_save_data           *mp_save;
typedef struct mp_loop_data           *mp_loop_node;             /* will become mp_loop */
typedef struct mp_if_data             *mp_if_node;               /* will become mp_if */

typedef struct mp_node_data           *mp_symbolic_node;
typedef struct mp_node_data           *mp_token_node;

typedef struct mp_pair_node_data      *mp_pair_node;
typedef struct mp_transform_node_data *mp_transform_node;
typedef struct mp_color_node_data     *mp_color_node;
typedef struct mp_shape_node_data     *mp_shape_node;
typedef struct mp_start_node_data     *mp_start_node;
typedef struct mp_stop_node_data      *mp_stop_node;
typedef struct mp_dash_node_data      *mp_dash_node;

typedef struct mp_independent_data {
    union { 
        int serial;      /* only for |indep_value|, used together with |scale| */
        int equivalent; 
    };
    int scale;           /* only for |indep_scale|, used together with |serial| */
} mp_independent_data;

typedef struct mp_value_data {
    mp_independent_data indep;
    mp_number           n;
    mp_string           str;
    mp_symbol           sym;
    mp_node             node;
    mp_knot             p;
} mp_value_data;

typedef struct mp_value {
    mp_variable_type type;
    mp_value_data    data;
} mp_value;

/*tex

\MP\ also has a bunch of internal parameters that a user might want to fuss with. Every such
parameter has an identifying code number, defined here.

*/

typedef enum mp_given_internal {
    mp_number_system_internal = 1,   /* the number system as set up by |numbersystem| */
    mp_number_precision_internal,    /* the number system precision as set up by |numberprecision| */
    mp_job_name_internal,            /* the jobname as set up from the options stucture */
    mp_tracing_titles_internal,      /* show titles online when they appear */
    mp_tracing_equations_internal,   /* show each variable when it becomes known */
    mp_tracing_capsules_internal,    /* show capsules too */
    mp_tracing_dependencies_internal,/* show dependencies (de)allocation */
    mp_tracing_choices_internal,     /* show the control points chosen for paths */
    mp_tracing_specs_internal,       /* show path subdivision prior to filling with polygonal a pen */
    mp_tracing_commands_internal,    /* show commands and operations before they are performed */
    mp_tracing_restores_internal,    /* show when a variable or internal is restored */
    mp_tracing_macros_internal,      /* show macros before they are expanded */
    mp_tracing_output_internal,      /* dummy */
    mp_tracing_stats_internal,       /* show memory usage at end of job */ /* now a dummy */
    mp_tracing_online_internal,      /* show long diagnostics on terminal and in the log file */
    mp_year_internal,                /* the current year (e.g., 1984) */
    mp_month_internal,               /* the current month (e.g., 3 $\equiv$ March) */
    mp_day_internal,                 /* the current day of the month */
    mp_time_internal,                /* the number of minutes past midnight when this job started */
    mp_hour_internal,                /* the number of hours past midnight when this job started */
    mp_minute_internal,              /* the number of minutes in that hour when this job started */
    mp_char_code_internal,           /* the number of the next character to be output */
    mp_char_wd_internal,             /* the width of the next character to be output */
    mp_char_ht_internal,             /* the height of the next character to be output */
    mp_char_dp_internal,             /* the depth of the next character to be output */
    mp_char_ic_internal,             /* the italic correction of the next character to be output */
    mp_pausing_internal,             /* dummy */
    mp_showstopping_internal,        /* positive to stop after each |show| command */
    mp_texscriptmode_internal,       /* controls spacing in texmode */
    mp_overloadmode_internal,
    mp_linejoin_internal,            /* as in \ps: 0 for mitered, 1 for round, 2 for beveled */
    mp_linecap_internal,             /* as in \ps: 0 for butt, 1 for round, 2 for square */
    mp_stacking_internal,
    mp_miterlimit_internal,          /* controls miter length as in \ps */
    mp_warning_check_internal,       /* controls error message when variable value is large */
    mp_default_zero_angle_internal,   
    mp_true_corners_internal,        /* positive to make |llcorner| etc. ignore |setbounds| */
    mp_default_color_model_internal, /* the default color model for unspecified items */
    mp_restore_clip_color_internal,
    mp_less_digits_internal,
    mp_intersection_precision_internal,
    mp_join_tolerance_internal,
    mp_single_quote_mode_internal,
    mp_prune_options_internal,
} mp_given_internal;

# define max_given_internal mp_prune_options_internal

typedef struct mp_internal {
    mp_value  v;
    char     *intname;
    int       run;
    int       padding;
} mp_internal;

typedef enum mp_prune_options {
    collapse_regular_regular_prune = 0x01,
    collapse_begin_regular_prune   = 0x02,
    collapse_regular_end_prune     = 0x04,
    collapse_begin_end_prune       = 0x08,
    wipe_single_prune              = 0x10,
    connect_segments_prune         = 0x20,
} mp_prune_options;

typedef struct mp_symbol_data {
    int        type;
    int        property; /* we had padding room anyway */
    mp_value   v;
    mp_string  text;
    void      *parent; /* can be MP */
} mp_symbol_data;

typedef enum mp_macro_info {
    mp_general_macro,    /* preface to a macro defined with a parameter list */
    mp_primary_macro,    /* preface to a macro with a |primary| parameter */
    mp_secondary_macro,  /* preface to a macro with a |secondary| parameter */
    mp_tertiary_macro,   /* preface to a macro with a |tertiary| parameter */
    mp_expr_macro,       /* preface to a macro with an undelimited |expr| parameter */
    mp_of_macro,         /* preface to a macro with undelimited `|expr| |x| |of|~|y|' parameters */
    mp_suffix_macro,     /* preface to a macro with an undelimited |suffix| parameter */
    mp_text_macro,       /* preface to a macro with an undelimited |text| parameter */
    mp_expr_parameter,   /* used by |expr| primitive */
    mp_suffix_parameter, /* used by |suffix| primitive */
    mp_text_parameter    /* used by |text| primitive */
} mp_macro_info;

typedef struct mp_save_data {
    int                  type;
    int                  padding;
    mp_internal          value;
    struct mp_save_data *link;
} mp_save_data;

typedef enum mp_bb_code {
    mp_x_code, /* index for |minx| and |maxx| */
    mp_y_code  /* index for |miny| and |maxy| */
} mp_bb_code;

typedef struct mp_in_state_record {
    int       start_field;
    int       loc_field;
    int       limit_field;
    int       index_field;
    mp_node   nstart_field;
    mp_node   nloc_field;
    mp_string name_field;
} mp_in_state_record;

typedef struct mp_subst_data {
    mp_name_type_type info_mod;
    int               value_mod;
    int               value_data;
    int               padding;
    mp_symbol         info;
    mp_subst_node     link;
} mp_subst_data;

typedef struct mp_loop_data {
    mp_symbol            var ;        /* the var of the loop */
    mp_node              info;        /* iterative text of this loop */
    mp_node              type;        /* the special type of this loop, or a pointer into mem */
    mp_node              list;        /* the remaining list elements */
    mp_node              list_start;  /* head of the list of elements */
    mp_number            old_value;   /* previous value of current arithmetic value */
    mp_number            value;       /* current arithmetic value */
    mp_number            step_size;   /* arithmetic step size */
    mp_number            final_value; /* end arithmetic value */
    struct mp_loop_data *link;        /* the enclosing loop, if any */
    mp_knot              point;
    mp_number            index;
} mp_loop_data;

typedef struct mp_if_data {
    mp_variable_type   type;
    mp_name_type_type  name_type;
    struct mp_if_data *link;
 // int                hasnumber;
    int                if_line_field;
} mp_if_data;

/*tex

The user's terminal acts essentially like other files of text, except that it is used both for input
and for output. When the terminal is considered an input file, the file variable is called |term_in|,
and when it is considered an output file the file variable is |term_out|.

Sometimes it is necessary to synchronize the input/output mixture that happens on the user's terminal,
and three system-dependent procedures are used for this purpose. The first of these, |update_terminal|,
is called when we want to make sure that everything we have output to the terminal so far has actually
left the computer's internal buffers and been sent. The second, |clear_terminal|, is called when we
wish to cancel any input that the user may have typed ahead (since we are about to issue an unexpected
error message). The third, |wake_up_terminal|, is supposed to revive the terminal if the user has
disabled it by some instruction to the operating system. The following macros show how these operations
can be specified:The global variable |loc| should be set so that the character to be read next by \MP\
is in |buffer [loc]|. This character should not be blank, and we should have |loc < last|.

*/

// # define update_terminal()  mp_print_nl_only(mp); /* empty the terminal output buffer */
// # define clear_terminal()                         /* clear the terminal input buffer */
// # define wake_up_terminal() mp_print_nl_only(mp); /* cancel the user's cancellation of output */

typedef enum mp_selectors {
    mp_new_string_selector,   /* printing is deflected to the string pool */
    mp_no_print_selector,     /* |selector| setting that makes data disappear */
    mp_term_only_selector,    /* printing is destined for the terminal only */
    mp_log_only_selector,     /* printing is destined for the transcript file only */
    mp_term_and_log_selector, /* normal |selector| setting */
    mp_first_file_selector,   /* first write file selector */
} mp_selectors;

typedef enum mp_logging_targets {
    mp_void_logging_target,
    mp_term_logging_target,
    mp_file_logging_target,
    mp_both_logging_target,
    mp_error_logging_target,
} mp_logging_targets;

# define mp_fputs(b,f)            (mp->write_file)(mp, f, b)
# define mp_log_string(target,s)  (mp->run_logger)(mp, target, s, strlen(s))
# define mp_log_mpstr(target,s,l) (mp->run_logger)(mp, target, s, l)
# define mp_log_cr(target)        (mp->run_logger)(mp, target, "\n", 1)
# define mp_log_chr(target,s)     { unsigned char ss[2] = { s, 0 }; (mp->run_logger)(mp, target, (const char *) ss, 1); }
# define mp_log_error(s)          (mp->run_logger)(mp, mp_error_logging_target, s, strlen(s))

typedef struct mp_node_data {
    union {
        mp_command_code  command;
        mp_variable_type type;
    };
    mp_name_type_type    name_type;
    struct mp_node_data *link;
 // int                  hasnumber;
 // int                  padding;
    /* specific */
    mp_value_data        data;
} mp_node_data;

typedef enum mp_linecap_codes {
    mp_butt_linecap_code,
    mp_rounded_linecap_code,
    mp_squared_linecap_code,
    /* see below */
    mp_weird_linecap_code,
} mp_linecap_codes;

typedef enum mp_linejoin_codes {
    mp_mitered_linejoin_code,
    mp_rounded_linejoin_code,
    mp_beveled_linejoin_code,
    /* we see this value being used */
    mp_weird_linejoin_code,
} mp_linejoin_codes;

typedef enum mp_curvature_codes {
    mp_default_curvature_code,
    mp_always_curvature_code,
    mp_never_curvature_code,
    mp_repeat_curvature_code,
    /* we see this value being used */
    mp_weird_curvature_code,
} mp_curvature_codes;

# define internal_data(A)         mp->internal[(A)].v.data
# define internal_value(A)        mp->internal[(A)].v.data.n
# define internal_string(A)       mp->internal[A].v.data.str
# define set_internal_string(A,B) mp->internal[(A)].v.data.str=(B)
# define internal_name(A)         mp->internal[(A)].intname
# define set_internal_name(A,B)   mp->internal[(A)].intname=(B)
# define internal_type(A)         mp->internal[A].v.type
# define set_internal_type(A,B)   mp->internal[(A)].v.type=(B)
# define internal_run(A)          mp->internal[(A)].run
# define set_internal_run(A,B)    mp->internal[(A)].run=(B)

typedef struct mp_value_node_data {
    mp_variable_type     type;
    mp_name_type_type    name_type;
    struct mp_node_data *link;
 // int                  hasnumber;
 // int                  padding;
    /* specific */
    mp_value_data        data;
    mp_number            subscript;
    mp_symbol            hashloc;
    mp_node              parent;
    mp_node              attr_head;
    mp_node              subscr_head;
} mp_value_node_data;

typedef struct mp_pair_node_data {
    mp_variable_type     type;
    mp_name_type_type    name_type;
    struct mp_node_data *link;
 // int                  hasnumber;
 // int                  padding;
    /* specific */
    mp_node              x_part;
    mp_node              y_part;
} mp_pair_node_data;

typedef struct mp_transform_node_data {
    mp_variable_type     type;
    mp_name_type_type    name_type;
    struct mp_node_data *link;
 // int                  hasnumber;
 // int                  padding;
    /* specific */
    mp_node              tx_part;
    mp_node              ty_part;
    mp_node              xx_part;
    mp_node              yx_part;
    mp_node              xy_part;
    mp_node              yy_part;
} mp_transform_node_data;

typedef struct mp_color_node_data {
    mp_variable_type     type;
    mp_name_type_type    name_type;
    struct mp_node_data *link;
 // int                  hasnumber;
 // int                  padding;
    /* specific */
    union {
        mp_node red_part;
        mp_node cyan_part;
        mp_node x_part;
    };
    union {
        mp_node green_part;
        mp_node magenta_part;
        mp_node y_part;
    };
    union {
        mp_node blue_part;
        mp_node yellow_part;
        mp_node z_part;
    };
    union {
        mp_node grey_part;
        mp_node black_part;
        mp_node w_part;
    };
} mp_color_node_data;

typedef struct mp_shape_node_data {
    mp_variable_type           type;
    mp_name_type_type          name_type;
    struct mp_shape_node_data *link;
 // int                        hasnumber;
 // int                        stacking;
    /*common */
    int                        stacking;
    mp_string                  pre_script;
    mp_string                  post_script;
    union {                    
        mp_number              red;
        mp_number              cyan;
    };                         
    union {                    
        mp_number              green;
        mp_number              magenta;
    };                         
    union {                    
        mp_number              blue;
        mp_number              yellow;
    };                         
    union {                    
        mp_number              black;
        mp_number              grey;
    };
    /* specific to paths */
    mp_knot                    path;
    mp_knot                    pen;
    mp_node                    dash;
    mp_number                  dashscale;
    mp_number                  miterlimit;
    unsigned char              color_model;
    unsigned char              linejoin;
    unsigned char              linecap;
    unsigned char              pen_type;
    unsigned char              curvature;
    unsigned char              padding_1;
    short                      bytemap;
    short                      mesh;
} mp_shape_node_data;

typedef struct mp_start_node_data {
    mp_variable_type     type;
    mp_name_type_type    name_type;
    struct mp_node_data *link;
 // int                  hasnumber;
 // int                  stacking;
    /* specific */
    int                  stacking;
    mp_string            pre_script;
    mp_string            post_script;
    mp_knot              path;
} mp_start_node_data;

typedef struct mp_stop_node_data {
    mp_variable_type     type;
    mp_name_type_type    name_type;
    struct mp_node_data *link;
 // int                  hasnumber;
 // int                  stacking;
    /* specific */
    int                  stacking;
} mp_stop_node_data;

typedef struct mp_dash_node_data {
    mp_variable_type          type;
    mp_name_type_type         name_type;
    struct mp_dash_node_data *link;
 // int                       hasnumber;
 // int                       padding;
    /* specific */
    mp_number                 start_x; /* the starting $x$~coordinate in a dash node */
    mp_number                 stop_x;  /* the ending $x$~coordinate in a dash node */
    mp_number                 dash_y;  /* $y$ value for the dash list in an edge header */
    mp_node                   dash_info;
} mp_dash_node_data;

typedef struct mp_edge_header_node_data {
    mp_variable_type     type;
    mp_name_type_type    name_type;
    struct mp_node_data *link;
 // int                  hasnumber;
 // int                  padding;
    /* specific */
    mp_number            start_x;
    mp_number            stop_x;
    mp_number            dash_y;
    mp_node              dash_info;
    mp_number            minx;
    mp_number            miny;
    mp_number            maxx;
    mp_number            maxy;
    mp_node              bblast;
    int                  bbtype; /* tells how bounding box data depends on |truecorners| */
    int                  ref_count; 
    mp_node              list;
    mp_node              obj_tail;  
} mp_edge_header_node_data;

typedef struct mp_edge_header_node_data *mp_edge_header_node;

typedef enum mp_bound_codes {
    mp_no_bounds_code,    /* |bbtype| value when bounding box data is valid for all |truecorners| values */
    mp_bounds_set_code,   /* |bbtype| value when bounding box data is for |truecorners|${}\le 0$ */
    mp_bounds_unset_code, /* |bbtype| value when bounding box data is for |truecorners|${}>0$ */
} mp_bound_codes;

typedef enum mp_expression_scan_types {
    mp_expression_scan_code,
    mp_primary_scan_code,
    mp_secondary_scan_code,
    mp_tertiary_scan_code,
} mp_expression_scan_types;

typedef enum mp_internal_action_types {
    mp_initialize_internal_code,
    mp_save_internal_code, 
    mp_restore_internal_code, 
 // mp_tracing_internal_code, 
} mp_internal_action_types; 

typedef struct mp_memory_pool_data {
    void *list;  /* head of available list */
    int   used;  /* currently used */
    int   max;   /* maximum used */
    int   pool;  /* size of pool */
    union { 
        int   kept;  /* kept in reserve */
        int   step;  /* step up when full */
    };
    union { 
        size_t size;  /* size or record */
        size_t count; /* allocated bytes */
    };
    int   state; 
} mp_memory_pool_data;

typedef enum mp_memory_pool_states { 
    mp_pool_uknown,
    mp_pool_counted,
    mp_pool_pooled,
    mp_pool_persistent,
} mp_memory_pool_states;

typedef enum mp_memory_pool_types { 
    mp_token_pool,
    mp_symbol_pool, /* not a pool, just statistics */
    mp_pair_pool,
    mp_color_pool,
    mp_transform_pool,
    mp_dash_pool,
    mp_knot_pool,
    mp_shape_pool,
    mp_start_pool,
    mp_stop_pool,
    mp_edge_header_pool,
    mp_value_pool,
    mp_symbolic_pool,
    mp_save_pool,
    mp_if_pool,
    mp_loop_pool,
    mp_subst_pool,
    mp_edge_object_pool,
    mp_dash_object_pool,
    mp_knot_object_pool,
    mp_shape_object_pool,
    mp_start_object_pool,
    mp_stop_object_pool,
    mp_identifiers_pool,
    mp_internals_pool,
    mp_bytemaps_pool,
    mp_bytemap_data_pool,
    mp_max_pool,
} mp_memory_pool_types;

/* Random generation. We might actually move this to \LUA\ at some point. */

# define mp_random_KK            100                              /* the long lag  */
# define mp_random_LL            37                               /* the short lag */
# define mp_random_MM            (1L << 30)                       /* the modulus */
# define mp_random_mod_diff(x,y) (((x) - (y)) & (mp_random_MM-1)) /* subtraction mod MM */
# define mp_random_TT            70                               /* guaranteed separation between streams */
# define mp_random_QUALITY       1009                             /* recommended quality level for high-res use */

typedef struct mp_random_info {
    long  x[mp_random_KK];
    long  buf[mp_random_QUALITY];
    long  dummy;
    long  started;
    long *ptr;
} mp_random_info;

/*tex Constants and variables per instance: */

typedef struct MP_instance {
    /*  */
    void               *userdata;               /* this allows the calling application to setup local (e.g. L for Lua) */
    char               *banner;                 /* the banner that is printed to the screen and log */
    int                 utf8_mode;
    int                 text_mode;
    int                 show_mode;
    int                 halt_on_error;          /* do we quit at the first error? */
    /*  */
    mp_file_finder      find_file;
    mp_script_runner    run_script;
    mp_internal_runner  run_internal;
    mp_log_runner       run_logger;
    mp_overload_runner  run_overload;
    mp_error_runner     run_error;
    mp_warning_runner   run_warning;
    mp_status_runner    run_status;
    mp_text_maker       make_text;
    mp_file_opener      open_file;
    mp_file_closer      close_file;
    mp_file_reader      read_file;
    mp_file_writer      write_file;
    int                 find_file_id;
    int                 run_script_id;
    int                 run_internal_id;
    int                 run_logger_id;
    int                 run_overload_id;
    int                 run_error_id;
    int                 run_warning_id;
    int                 run_status_id;
    int                 make_text_id;
    int                 open_file_id;
    /*  */
    int                 less_digits; 
    int                 interaction;
    int                 random_seed;
    int                 math_mode;
    /*  */
    char               *job_name;
    /*  */
    mp_backend_writer   shipout_backend;
    /*  */
    math_data          *math;
    /*  */
    int                 max_in_open;            /* maximum number of input files and error insertions that can be going on simultaneously */
    /*  */
    char               *name_of_file;           /* the name of a system file */
    /*  */
    size_t              buf_size;               /* maximum number of characters simultaneously present in current lines of open files */
    unsigned char      *buffer;                 /* lines of characters being read */
    size_t              first;                  /* the first unused position in |buffer| */
    size_t              last;                   /* end of the line just input to |buffer| */
    size_t              max_buf_stack;          /* largest index used in |buffer| */
    /*  */
    void               *term_in;                /* the terminal as an input file */
    /*  */
    avl_tree            strings;                /* string avl tree */
    unsigned char      *cur_string;             /*  current string buffer */
    size_t              cur_length;             /* current index in that buffer */
    size_t              cur_string_size;        /*  malloced size of |cur_string| */
    /*  */
    int                 pool_in_use;            /* total number of string bytes actually in use */
    int                 max_pool_used;          /* maximum |pool_in_use| so far */
    int                 strings_in_use;         /* total number of strings actually in use */
    int                 max_strings_used;       /* maximum |strs_in_use| so far */
    /*  */
    unsigned int        selector;               /* where to print a message */
    unsigned int        term_offset;            /* the number of characters on the current terminal line */
    unsigned int        file_offset;            /* the number of characters on the current file line */
    /*  */
    int                 history;                /* has the source input been clean so far? */
    int                 error_count;            /* the number of scrolled errors since the last statement ended */
    mp_string           error_help;             /* a string set up by |errhelp| */
    int                 long_help_seen;         /* has the long |\\errmessage| help been used? */
    /*  */
    jmp_buf            *jump_buffer;
    /*  */
    int                 run_state;              /* are we processing input ? */
    int                 finished;               /* set true by |close_files_and_terminate| */
    /*  */
    int                 arithmic_error;
    /*  */
    mp_number           randoms[55];            /* the last 55 random values generated */
    int                 j_random;               /* the number of unused |randoms| */
    /*  */
    mp_memory_pool_data memory_pool[mp_max_pool];
    /*  */
    mp_dash_node        null_dash;
    mp_value_node       dep_head;
    mp_node             inf_val;
    mp_node             zero_val;
    mp_node             temp_val;
    mp_node             end_attr;
    mp_node             bad_vardef;
    mp_node             temp_head;
    mp_node             hold_head;
    mp_node             spec_head;
    /*  */
    mp_internal        *internal;               /* the values of internal quantities */
    /*  */
    bytemap_data       *bytemaps;
    /*  */
    unsigned int        old_selector;
    /*  */
    int                 char_class[256];
    /*  */
    avl_tree            symbols;                /* avl tree of symbolic tokens */
    avl_tree            frozen_symbols;         /* avl tree of frozen symbolic tokens */
    avl_iterator        symbol_iterator;
    mp_symbol           frozen_bad_vardef;
    mp_symbol           frozen_colon;
    mp_symbol           frozen_end_def;
    mp_symbol           frozen_end_for;
    mp_symbol           frozen_end_group;
    mp_symbol           frozen_etex;
    mp_symbol           frozen_fi;
    mp_symbol           frozen_inaccessible;
    mp_symbol           frozen_left_bracket;
    mp_symbol           frozen_repeat_loop;
    mp_symbol           frozen_right_delimiter;
    mp_symbol           frozen_semicolon;
    mp_symbol           frozen_slash;
    mp_symbol           frozen_undefined;
    mp_symbol           frozen_dump;
    /*  */
    mp_symbol           id_lookup_test;
    /*  */
    mp_save_data       *save_ptr;               /* the most recently saved item */
    /*  */
    mp_knot             path_tail;              /* the node that links to the beginning of a path */
    /*  */
    int                 path_size;              /* maximum number of knots between breakpoints of a path */
    int                 bbox_nesting;           /* be nice */
    mp_number          *delta_x;
    mp_number          *delta_y;
    mp_number          *delta;                  /* knot differences */
    mp_number          *psi;                    /* turning angles */
    /*  */
    mp_number          *theta;                  /* values of $\theta_k$ */
    mp_number          *uu;                     /* values of $u_k$ */
    mp_number          *vv;                     /* values of $v_k$ */
    mp_number          *ww;                     /* values of $w_k$ */
    /*  */
    mp_number           st;
    mp_number           ct;
    mp_number           sf;
    mp_number           cf;                     /* sines and cosines */
    /*  */
    mp_number           bbmin[2];
    mp_number           bbmax[2];
    /*  */
    mp_number           half_cos[8];            /* ${1\over2}\cos(45k)$ */
    mp_number           d_cos[8];               /* a magic constant times $\cos(45k)$ */
    /*  */
    mp_number           cur_x;                  /* all-purpose return value registers */
    mp_number           cur_y;
    /*  */
    mp_number           last_x;                 /* turle states */
    mp_number           last_y;   
    mp_number           previous_x;
    mp_number           previous_y;   
    /*  */
    int                 spec_offset;            /* number of pen edges between |h| and the initial offset */
    int                 spec_padding;           /* be nice */
    /*  */
    mp_knot             spec_p1;
    mp_knot             spec_p2;                /* pointers to distinguished knots */
    /*  */
    unsigned int        tol_step;               /* either 0 or 3, usually */
    /*  */
    mp_number          *bisect_stack;
    int                 bisect_ptr;
    /*  */
    mp_number           cur_t;
    mp_number           cur_tt;                 /* controls and results of |cubic_intersection| */
    int                 time_to_go;             /* this many backtracks before giving up */
    mp_number           max_t;                  /* maximum of $2^{l+1}$ so far achieved */
    /*  */
    mp_number           delx;
    mp_number           dely;                   /* the components of $\Delta=2^l(w_0-z_0)$ */
    int                 tol;                    /* bound on the uncertainty in the overlap test */
    int                 uv;
    int                 xy;                     /* pointers to the current packets of interest */
    int                 three_l;                /* |tol_step| times the bisection level */
    mp_number           appr_t;
    mp_number           appr_tt;                /* best approximations known to the answers */
    /*  */
    int                 serial_no;              /* the most recent serial number */
    /*  */
    int                 fix_needed;             /* does at least one |independent| variable need scaling? */
    int                 watch_coefs;            /* should we scale coefficients that exceed |coef_bound|? */
    mp_value_node       dep_final;              /* location of the constant term and final link */
    /*  */
    mp_node             cur_mod_;               /* current command, symbol, and its operands */
    /*  */
    mp_in_state_record *input_stack;
    int                 input_ptr;              /* first unused location of |input_stack| */
    int                 max_input_stack;        /* largest value of |input_ptr| when pushing */
    mp_in_state_record  cur_input;              /* the \quote {top} input state */
    int                 stack_size;             /* maximum number of simultaneous input sources */
    /*  */
    int                 in_open;                /* the number of lines in the buffer, less one */
    int                 in_open_max;            /* highest value of |in_open| ever seen */
    unsigned int        open_parens;            /* the number of open text files */
    void              **input_files;
    int                *input_lines;            /* the line number for each file */
    /*  */
    mp_node            *parameter_stack;        /* token list pointers for parameters */
    int                 parameter_ptr;          /* first unused entry in |parameter_stack| */
    int                 max_parameter_stack;    /* largest value of |parameter_ptr| */
    int                 parameter_size;         /* maximum number of simultaneous macro parameters */
    /*  */
    int                 file_ptr;               /* shallowest level shown by |show_context| */
    /*  */
    int                 scanner_status;         /* are we scanning at high speed? */
    mp_symbol           warning_info;           /* if so, what else do we need to know, in case an error occurs? */
    int                 warning_line;
    mp_node             warning_info_node;
    /*  */
    int                 force_eof;              /* should the next |input| be aborted early? */
    /*  */
    mp_symbol           bg_loc;
    mp_symbol           eg_loc;                 /* hash addresses of |begingroup| and |endgroup| */
    /*  */
    int                 expand_depth_count;     /* current expansion depth */
    int                 expand_depth;           /* current expansion depth */
    /*  */
    mp_if_node          cond_ptr;               /* top of the condition stack */
    int                 if_limit;               /* upper bound on |fi_or_else| codes */
    int                 cur_if;                 /* type of conditional being worked on */
    int                 if_line;                /* line where that conditional began */
    /*  */
    mp_loop_data       *loop_ptr;               /* top of the loop-control-node stack */
    /*  */
    char               *cur_name;               /* name of file just scanned */
    /*  */
    int                 quoted_filename;        /* whether the filename is wrapped in " markers */
    /*  */
    int                 max_read_files;         /* maximum number of simultaneously open |readfrom| files */
    int                 n_of_read_files;        /* number of valid entries in the above arrays */
    void              **read_filehandles;       /* |readfrom| files */
    char              **read_filenames;         /* corresponding file name or 0 if file not open */
    /*  */
    int                 max_write_files;        /* maximum number of simultaneously open |write| */
    int                 n_of_write_files;       /* number of valid entries in the above arrays */
    void              **write_filehandles;      /* |write| files */
    char              **write_filenames;        /* corresponding file name or 0 if file not open */
    /*  */
    mp_value            cur_exp;                /* the value of the expression just found */
    /*  */
    mp_number           max_c   [mp_proto_dependent_type + 1]; /* max coefficient magnitude */
    mp_value_node       max_ptr [mp_proto_dependent_type + 1]; /* where |p| occurs with |max_c| */
    mp_value_node       max_link[mp_proto_dependent_type + 1]; /* other occurrences of |p| */
    /*  */
    int                 var_flag;               /* command that wants a variable */
    /*  */
    mp_string           eof_line;
    mp_string           eof_file;
    /*  */
    mp_number           txx;                    /* current transform coefficients */
    mp_number           txy;
    mp_number           tyx;
    mp_number           tyy;
    mp_number           tx;
    mp_number           ty;
    /*  */
    mp_run_data         run_data;
    /*  */
    int                 last_add_type;          /* command modifier that identifies the last |addto| command */
    /*  */
    mp_symbol           every_job_sym;
    /*  */
    int                 ten_pow[10];            /* $10^0..10^9$ */
    int                 scaled_out;             /* amount of |scaled| that was taken out in |divide_scaled| */
    /*  */
    mp_random_info      random_data;
    /*  */
} MP_instance;

/* mp header stuff */

extern void              mp_print_e_str                (MP mp, const char *s);
//     void              mp_print_e_chr                (MP mp, unsigned char k);
extern void              mp_show_context               (MP mp);
extern void              mp_error                      (MP mp, const char *msg, const char *hlp);
extern void              mp_warn                       (MP mp, const char *msg);
extern void              mp_fatal_error                (MP mp, const char *s);
extern void              mp_confusion                  (MP mp, const char *s);

extern void              mp_show_path                  (MP mp, mp_knot p);

extern int               mp_initialize_symbol_traverse (MP mp);
extern void              mp_kill_symbol_traverse       (MP mp);
extern void             *mp_fetch_symbol_traverse      (MP mp);
extern void             *mp_fetch_symbol               (MP mp, char *s);

extern int               mp_close_path_cycle           (MP mp, mp_knot p, mp_knot q);
extern int               mp_close_path                 (MP mp, mp_knot q, mp_knot first);

extern mp_knot           mp_create_knot                (MP mp);

extern mp_knot           mp_append_knot                (MP mp, mp_knot p, double x, double y);
extern mp_knot           mp_append_knot_xy             (MP mp, mp_knot p, double x, double y, int type);

extern int               mp_set_knot_curl              (MP mp, mp_knot q, double value);
extern int               mp_set_knot_left_curl         (MP mp, mp_knot q, double value);
extern int               mp_set_knot_right_curl        (MP mp, mp_knot q, double value);
extern int               mp_set_knot_simple_curl       (MP mp, mp_knot q);
extern int               mp_set_knot_simple_left_curl  (MP mp, mp_knot q);
extern int               mp_set_knot_simple_right_curl (MP mp, mp_knot q);
extern int               mp_set_knotpair_curls         (MP mp, mp_knot p, mp_knot q, double t1, double t2) ;
extern int               mp_set_knotpair_tensions      (MP mp, mp_knot p, mp_knot q, double t1, double t2) ;
extern int               mp_set_knot_left_tension      (MP mp, mp_knot p, double t1);
extern int               mp_set_knot_right_tension     (MP mp, mp_knot p, double t1);
extern int               mp_set_knot_left_control      (MP mp, mp_knot p, double t1, double t2);
extern int               mp_set_knot_right_control     (MP mp, mp_knot p, double t1, double t2);
extern int               mp_set_knotpair_controls      (MP mp, mp_knot p, mp_knot q, double x1, double y1, double x2, double y2);
extern int               mp_set_knot_direction         (MP mp, mp_knot q, double x, double y) ;
extern int               mp_set_knotpair_directions    (MP mp, mp_knot p, mp_knot q, double x1, double y1, double x2, double y2);

extern int               mp_solve_path                 (MP mp, mp_knot first);
extern void              mp_free_path                  (MP mp, mp_knot p);

extern double            mp_number_as_double           (MP mp, mp_number n);

extern void              mp_set_internal               (MP mp, char *n, char *v, int isstring);

extern int               mp_skip_token_value           (MP mp, int token);

extern void              mp_scan_next_value            (MP mp, int keep, int *token, int *mode, int *kind);
extern void              mp_scan_expr_value            (MP mp, int keep, int *kind);
extern void              mp_scan_token_value           (MP mp, int keep, int *token, int *mode, int *kind);
extern void              mp_scan_symbol_value          (MP mp, int keep, char **s, int expand);
extern void              mp_scan_property_value        (MP mp, int keep, int *kind, char **s, int *property, int *detail);
extern void              mp_scan_numeric_value         (MP mp, int primary, double *d);
extern void              mp_scan_boolean_value         (MP mp, int primary, int *b);
extern int               mp_scan_string_value          (MP mp, int primary, char **s, size_t *l);
extern void              mp_scan_pair_value            (MP mp, int primary, double *x, double *y);
extern void              mp_scan_color_value           (MP mp, int primary, double *r, double *g, double *b);
extern void              mp_scan_cmykcolor_value       (MP mp, int primary, double *c, double *m, double *y, double *k);
extern void              mp_scan_transform_value       (MP mp, int primary, double *x, double *y, double *xx, double *xy, double *yx, double *yy);
extern void              mp_scan_path_value            (MP mp, int primary, mp_knot *k);

extern void              mp_push_numeric_value         (MP mp, double n);
extern void              mp_push_integer_value         (MP mp, int i);
extern void              mp_push_boolean_value         (MP mp, int b);
extern void              mp_push_string_value          (MP mp, const char *s, int l);
extern void              mp_push_pair_value            (MP mp, double x, double y);
extern void              mp_push_color_value           (MP mp, double r, double g, double b);
extern void              mp_push_cmykcolor_value       (MP mp, double c, double m, double y, double k);
extern void              mp_push_transform_value       (MP mp, double x, double y, double xx, double xy, double yx, double yy);
extern void              mp_push_path_value            (MP mp, mp_knot k);
extern void              mp_push_tokens_value          (MP mp, const char *str, size_t length);

extern void              mp_new_randoms                (MP mp);

/* library interfaces */

extern MP                mp_initialize                 (MP_options *opt);
extern int               mp_run                        (MP mp);
extern int               mp_execute                    (MP mp, const char *s, size_t l);
extern int               mp_finish                     (MP mp);
extern char             *mp_metapost_version           (void);
extern mp_run_data      *mp_rundata                    (MP mp);
extern MP_options       *mp_options                    (void);
extern void             *mp_userdata                   (MP mp);
extern int               mp_status                     (MP mp);
extern int               mp_finished                   (MP mp);

extern void              mplib_shipout_backend         (MP mp, void *h);

extern bytemap_data     *mp_bytemap_get_by_index       (MP mp, int index);
extern int               mp_bytemap_new_by_index       (MP mp, int index, int nx, int ny, int nz, unsigned char *data);

extern void              mp_graphic_toss_object        (MP mp, mp_graphic_object_node p);
extern void              mp_graphic_toss_objects       (MP mp, mp_edge_object_node p);

/* memory management header stuff */

extern void             *mp_memory_allocate            (size_t size);
extern void             *mp_memory_clear_allocate      (size_t size);
extern void             *mp_memory_reallocate          (void *p, size_t size);
extern void             *mp_memory_clear_reallocate    (void *p, size_t oldsize, size_t newsize);
extern void              mp_memory_free                (void *p);

extern int               mp_error_code                 (MP mp, int n);

extern int               mp_n_of_primitives            (void);
extern mp_primitive_data mp_get_primitive_data         (int i);

# endif
