PreviousUpNext

15.4.819  src/lib/make-library-glue/make-library-glue.pkg

## make-library-glue.pkg
#
# Build much of the code required
# to make a C library like Gtk or OpenGL
# available at the Mythryl level, driven
# by an xxx-construction.plan file.
#
# The format of xxx-construction.plan files
# is documented in Note[1] at bottom of file.
#
# make-library-glue.pkg really shouldn't be in
# standard.lib because it is not of general interest,
# but at the moment that is the path of least
# resistance.    -- 2013-01-12 CrT

# Compiled by:
#     src/lib/std/standard.lib

stipulate
    package paf =  patchfile;                                                                   # patchfile                     is from   src/lib/make-library-glue/patchfile.pkg
    package pfj =  planfile_junk;                                                               # planfile_junk                 is from   src/lib/make-library-glue/planfile-junk.pkg
    package pfs =  patchfiles;                                                                  # patchfiles                    is from   src/lib/make-library-glue/patchfiles.pkg
    package plf =  planfile;                                                                    # planfile                      is from   src/lib/make-library-glue/planfile.pkg
    package sm  =  string_map;                                                                                  # string_map            is from   src/lib/src/string-map.pkg
    #
    Pfs         =  pfs::Patchfiles;
herein
    api      Make_Library_Glue
    {
        Field = { fieldname: String,
                  filename:  String,
                  lines:   List(String),                                                        # Not exported.
                  line_1:  Int,
                  line_n:  Int,
                  used:    Ref(Bool)
                };

        Fields = sm::Map( Field );

        State;
        #
        Paths = {   construction_plan                                   :  String,              # E.g. "src/opt/gtk/etc/gtk-construction.plan"
                    lib_name                                            :  String,              # E.g. "opengl" -- Must match the   #define CLIB_NAME "opengl"   line in   .../src/opt/xxx/c/in-main/libmythryl-xxx.c
                    #                                                                           # Files which will be patched:
                    xxx_client_api                                      :  String,              # E.g. "src/opt/gtk/src/gtk-client.api"
                    xxx_client_g_pkg                                    :  String,              # E.g. "src/opt/gtk/src/gtk-client-g.pkg"
                    xxx_client_driver_api                               :  String,              # E.g. "src/opt/gtk/src/gtk-client-driver.api"
                    xxx_client_driver_for_library_in_c_subprocess_pkg   :  String,              # E.g. "src/opt/gtk/src/gtk-client-driver-for-library-in-c-subprocess.pkg"
                    xxx_client_driver_for_library_in_main_process_pkg   :  String,              # E.g, "src/opt/gtk/src/gtk-client-driver-for-library-in-main-process.pkg"
                    mythryl_xxx_library_in_c_subprocess_c               :  String,              # E.g. "src/opt/gtk/c/in-sub/mythryl-gtk-library-in-c-subprocess.c"
                    libmythryl_xxx_c                                    :  String,              # E.g. "src/opt/gtk/c/in-main/libmythryl-gtk.c"
                    section_libref_xxx_tex                              :  String               # E.g., "doc/tex/section-libref-gtk.tex";
                };

        Builder_Stuff
          =
          {
            path:                                                                               Paths,
            #
            maybe_get_field:                                                                    (Fields, String) -> Null_Or(String),
                  get_field:                                                                    (Fields, String) ->         String,
                  get_field_location:                                                           (Fields, String) -> String,
            #
            build_table_entry_for_'libmythryl_xxx_c':                                           Pfs -> (String, String) -> Pfs,
            build_trie_entry_for_'mythryl_xxx_library_in_c_subprocess_c':                       Pfs ->  String          -> Pfs,
            #   
            build_fun_declaration_for_'xxx_client_driver_api':                                  Pfs -> { c_fn_name: String,  libcall: String,  result_type: String } -> Pfs,
            build_fun_definition_for_'xxx_client_driver_for_library_in_c_subprocess_pkg':       Pfs -> { c_fn_name: String,  libcall: String,  result_type: String } -> Pfs,
            #   
            build_fun_declaration_for_'xxx_client_api':                                         Pfs -> { fn_name: String,  fn_type: String,  api_doc:  String } -> Pfs,
            build_fun_definition_for_'xxx_client_driver_for_library_in_main_process_pkg':       Pfs -> { fn_name: String,  c_fn_name: String,  fn_type: String, libcall: String, result_type: String } -> Pfs,

            to_xxx_client_driver_api:                                                           Pfs -> String -> Pfs,
            to_xxx_client_driver_for_library_in_c_subprocess_pkg:                               Pfs -> String -> Pfs,
            to_xxx_client_driver_for_library_in_main_process_pkg:                               Pfs -> String -> Pfs,
            to_xxx_client_g_pkg_funs:                                                           Pfs -> String -> Pfs,
            to_xxx_client_g_pkg_types:                                                          Pfs -> String -> Pfs,
            to_xxx_client_api_funs:                                                             Pfs -> String -> Pfs,
            to_xxx_client_api_types:                                                            Pfs -> String -> Pfs,
            to_mythryl_xxx_library_in_c_subprocess_c_funs:                                      Pfs -> String -> Pfs,
            to_mythryl_xxx_library_in_c_subprocess_c_trie:                                      Pfs -> String -> Pfs,
            to_libmythryl_xxx_c_table:                                                          Pfs -> String -> Pfs,
            to_libmythryl_xxx_c_funs:                                                           Pfs -> String -> Pfs,
            to_section_libref_xxx_tex_apitable:                                                 Pfs -> String -> Pfs,
            to_section_libref_xxx_tex_libtable:                                                 Pfs -> String -> Pfs,

            custom_fns_codebuilt_for_'libmythryl_xxx_c':                                        Ref(Int),
            custom_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c':                   Ref(Int),
            callback_fns_handbuilt_for_'xxx_client_g_pkg':                                      Ref(Int),

            note__section_libref_xxx_tex__entry
              :
              Pfs
              ->
              { fields:         Fields,
                fn_name:        String,         # E.g. "make_window"
                fn_type:        String,         # E.g. "Session -> String"
                url:            String,         # E.g. "http://library.gnome.org/devel/gtk/stable/GtkTable.html#gtk-table-set-col-spacing"
                libcall:        String          # E.g. "gtk_table_set_col_spacing( GTK_TABLE(/*table*/w0), /*col*/i1, /*spacing*/i2)"
              }
              ->
              Pfs
          };

        Custom_Body_Stuff  =  { fn_name: String,  libcall: String,  libcall_more: String,  to_mythryl_xxx_library_in_c_subprocess_c_funs: Pfs -> String -> Pfs,  path: Paths };
        Custom_Body_Stuff2 =  { fn_name: String,  libcall: String,  libcall_more: String,  to_libmythryl_xxx_c_funs:                      Pfs -> String -> Pfs,  path: Paths };

        Plugin  = LIBCALL_TO_ARGS_FN    (String -> List(String))
                #
                | BUILD_ARG_LOAD_FOR_'MYTHRYL_XXX_LIBRARY_IN_C_SUBPROCESS' (String, (String, Int, String) -> String)
                | BUILD_ARG_LOAD_FOR_'LIBMYTHRYL_XXX_C'                    (String, (String, Int, String) -> String)
                #
                | HANDLE_NONSTANDARD_RESULT_TYPE_FOR__BUILD_PLAIN_FUN_FOR__'MYTHRYL_XXX_LIBRARY_IN_C_SUBPROCESS_C'  (String,  Pfs -> Custom_Body_Stuff  -> Pfs)
                | HANDLE_NONSTANDARD_RESULT_TYPE_FOR__BUILD_PLAIN_FUN_FOR__'LIBMYTHRYL_XXX_C'                       (String,  Pfs -> Custom_Body_Stuff2 -> Pfs)
                #
                | FIGURE_FUNCTION_RESULT_TYPE (String, String -> String)
                #
                | DO_COMMAND_FOR_'XXX_CLIENT_DRIVER_FOR_LIBRARY_IN_C_SUBPROCESS_PKG' (String, String)
                | DO_COMMAND_TO_STRING_FN (String, String)
                #
                | CLIENT_DRIVER_ARG_TYPE (String, String)
                | CLIENT_DRIVER_RESULT_TYPE (String, String)
                ;

        make_library_glue: Paths -> List(plf::Paragraph_Definition(Builder_Stuff)) -> List(Plugin) -> Void;
    };
end;

stipulate
    package fil =  file__premicrothread;                                                        # file__premicrothread          is from   src/lib/std/src/posix/file--premicrothread.pkg
    package lms =  list_mergesort;                                                              # list_mergesort                is from   src/lib/src/list-mergesort.pkg
    package iow =  io_wait_hostthread;                                                          # io_wait_hostthread            is from   src/lib/std/src/hostthread/io-wait-hostthread.pkg
    package paf =  patchfile;                                                                   # patchfile                     is from   src/lib/make-library-glue/patchfile.pkg
    package pfj =  planfile_junk;                                                               # planfile_junk                 is from   src/lib/make-library-glue/planfile-junk.pkg
    package pfs =  patchfiles;                                                                  # patchfiles                    is from   src/lib/make-library-glue/patchfiles.pkg
    package plf =  planfile;                                                                    # planfile                      is from   src/lib/make-library-glue/planfile.pkg
    package psx =  posixlib;                                                                    # posixlib                      is from   src/lib/std/src/psx/posixlib.pkg
    package sm  =  string_map;                                                                  # string_map                    is from   src/lib/src/string-map.pkg
    #
    Pfs         =  pfs::Patchfiles;
    #
    exit_x =  winix__premicrothread::process::exit_x;
    =~          =  regex::(=~);
    sort        =  lms::sort_list;
    chomp       =  string::chomp;
    tolower     =  string::to_lower;
    uniquesort  =  lms::sort_list_and_drop_duplicates;

    fun isfile     filename
        =
        psx::stat::is_file      (psx::stat  filename)  except _ = FALSE;

    #
    fun die_x message
        =
        {   print message;
            exit_x 1;
        };



    # The following are all duplicates of definitions in
    #     src/app/makelib/main/makelib-g.pkg
    # -- possibly a better place should be found
    # for them:

    # Convert    src/opt/xxx/c/in-sub/mythryl-xxx-library-in-c-subprocess.c
    # to                              mythryl-xxx-library-in-c-subprocess.c
    # and such:
    #
    fun basename filename
        =
        case (regex::find_first_match_to_ith_group 1 .|/([^/]+)$| filename)
            THE x => x;
            NULL  => filename;
        esac;           

    # Convert    src/opt/xxx/c/in-sub/mythryl-xxx-library-in-c-subprocess.c
    # to         src/opt/xxx/c/in-sub
    # and such:
    #
    fun dirname filename
        =
        case (regex::find_first_match_to_ith_group 1 .|^(.*)/[^/]+$| filename)
            THE x => x;
            NULL  => ".";                                                       # This follows linux dirname(1), and also produces sensible results.
        esac;

    # Drop leading and trailing
    # whitespace from a string.
    #
    fun trim string
        =
        {   if (string =~ ./^\s*$/)
                #
                "";

            else
                # Drop trailing whitespace:
                #
                string =    case (regex::find_first_match_to_ith_group 1 ./^(.*\S)\s*$/ string)
                                THE x => x;
                                NULL  => string;
                            esac;

                # Drop leading whitespace:
                #
                string =    case (regex::find_first_match_to_ith_group 1 ./^\s*(\S.*)$/ string)
                                THE x => x;
                                NULL  => string;
                            esac;
                string;
            fi;
        };



    fun print_strings         [] =>   printf "[]\n";
        print_strings      [ s ] =>   printf "[ \"%s\" ]\n" s;
        print_strings (s ! rest)
            =>
            {   printf "[ \"%s\"" s;
                apply (\\ s = printf ", \"%s\"" s) rest;
                printf "]\n";
            };
    end;
herein

    # This package is invoked in:
    #
    #     src/opt/gtk/sh/make-gtk-glue
    #     src/opt/opengl/sh/make-opengl-glue

    package  make_library_glue:
             Make_Library_Glue
    {
        # Field is a contiguous sequence of lines
        # all with the same linetype field:
        #
        #    foo:  this
        #    foo:  that
        #
        # Most fields will be single-line, but this format
        # supports conveniently including blocks of code,
        # such as complete function definitions.
        #
        # We treat a field as a single string containing
        # embedded newlines, stripped of the linetype field
        # and the colon.  
        #
        Field = { fieldname: String,
                  filename:  String,
                  lines:   List(String),                                                        # Not exported.
                  line_1:  Int,
                  line_n:  Int,
                  used:    Ref(Bool)
                };

        Fields = sm::Map( Field );

        State = { line_number:  Ref(Int),                                                       # Exported as an opaque type.

                  fd:           fil::Input_Stream,

                  fields:       Ref( sm::Map( Field ))
                };



        Paths =   { construction_plan                                   :  String,
                    lib_name                                            :  String,              #  E.g. "xxx".  Must match the   #define CLIB_NAME "xxx"   line in   src/opt/xxx/c/in-main/libmythryl-xxx.c
                    #
                    xxx_client_api                                      :  String,
                    xxx_client_g_pkg                                    :  String,
                    xxx_client_driver_api                               :  String,
                    xxx_client_driver_for_library_in_c_subprocess_pkg   :  String,
                    xxx_client_driver_for_library_in_main_process_pkg   :  String,
                    mythryl_xxx_library_in_c_subprocess_c               :  String,
                    libmythryl_xxx_c                                    :  String,
                    section_libref_xxx_tex                              :  String
                  };

        Builder_Stuff
          =
          {
            path:                                                                                Paths,
            #
            maybe_get_field:                                                                    (Fields, String) -> Null_Or(String),
                  get_field:                                                                    (Fields, String) ->         String,
                  get_field_location:                                                           (Fields, String) -> String,
            #
            build_table_entry_for_'libmythryl_xxx_c':                                           Pfs -> (String, String) -> Pfs,
            build_trie_entry_for_'mythryl_xxx_library_in_c_subprocess_c':                       Pfs ->  String          -> Pfs,
            #   
            build_fun_declaration_for_'xxx_client_driver_api':                                  Pfs -> { c_fn_name: String,  libcall: String,  result_type: String } -> Pfs,
            build_fun_definition_for_'xxx_client_driver_for_library_in_c_subprocess_pkg':       Pfs -> { c_fn_name: String,  libcall: String,  result_type: String } -> Pfs,
            #
            build_fun_declaration_for_'xxx_client_api':                                         Pfs -> { fn_name: String,  fn_type: String,  api_doc: String } -> Pfs,
            build_fun_definition_for_'xxx_client_driver_for_library_in_main_process_pkg':       Pfs -> { fn_name: String,  c_fn_name: String,  fn_type: String, libcall: String, result_type: String } -> Pfs,

            to_xxx_client_driver_api:                                                           Pfs -> String -> Pfs,
            to_xxx_client_driver_for_library_in_c_subprocess_pkg:                               Pfs -> String -> Pfs,
            to_xxx_client_driver_for_library_in_main_process_pkg:                               Pfs -> String -> Pfs,
            to_xxx_client_g_pkg_funs:                                                           Pfs -> String -> Pfs,
            to_xxx_client_g_pkg_types:                                                          Pfs -> String -> Pfs,
            to_xxx_client_api_funs:                                                             Pfs -> String -> Pfs,
            to_xxx_client_api_types:                                                            Pfs -> String -> Pfs,
            to_mythryl_xxx_library_in_c_subprocess_c_funs:                                      Pfs -> String -> Pfs,
            to_mythryl_xxx_library_in_c_subprocess_c_trie:                                      Pfs -> String -> Pfs,
            to_libmythryl_xxx_c_table:                                                          Pfs -> String -> Pfs,
            to_libmythryl_xxx_c_funs:                                                           Pfs -> String -> Pfs,
            to_section_libref_xxx_tex_apitable:                                                 Pfs -> String -> Pfs,
            to_section_libref_xxx_tex_libtable:                                                 Pfs -> String -> Pfs,

            custom_fns_codebuilt_for_'libmythryl_xxx_c':                                        Ref(Int),
            custom_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c':                   Ref(Int),
            callback_fns_handbuilt_for_'xxx_client_g_pkg':                                      Ref(Int),

            note__section_libref_xxx_tex__entry
              :
              Pfs
              ->
              { fields:         Fields,
                fn_name:        String,         # E.g. "make_window"
                fn_type:        String,         # E.g. "Session -> String"
                url:            String,         # E.g. "http://library.gnome.org/devel/gtk/stable/GtkTable.html#gtk-table-set-col-spacing"
                libcall:        String          # E.g. "gtk_table_set_col_spacing( GTK_TABLE(/*table*/w0), /*col*/i1, /*spacing*/i2)"
              }
              ->
              Pfs
          };

        Custom_Body_Stuff  =  { fn_name: String,  libcall: String,  libcall_more: String,  to_mythryl_xxx_library_in_c_subprocess_c_funs: Pfs -> String -> Pfs,  path: Paths };
        Custom_Body_Stuff2 =  { fn_name: String,  libcall: String,  libcall_more: String,  to_libmythryl_xxx_c_funs:                      Pfs -> String -> Pfs,  path: Paths };

        Plugin  = LIBCALL_TO_ARGS_FN    (String -> List(String))
                #
                | BUILD_ARG_LOAD_FOR_'MYTHRYL_XXX_LIBRARY_IN_C_SUBPROCESS' (String, (String, Int, String) -> String)
                | BUILD_ARG_LOAD_FOR_'LIBMYTHRYL_XXX_C'                    (String, (String, Int, String) -> String)
                #
                | HANDLE_NONSTANDARD_RESULT_TYPE_FOR__BUILD_PLAIN_FUN_FOR__'MYTHRYL_XXX_LIBRARY_IN_C_SUBPROCESS_C'  (String,  Pfs -> Custom_Body_Stuff  -> Pfs)
                | HANDLE_NONSTANDARD_RESULT_TYPE_FOR__BUILD_PLAIN_FUN_FOR__'LIBMYTHRYL_XXX_C'                       (String,  Pfs -> Custom_Body_Stuff2 -> Pfs)
                #
                | FIGURE_FUNCTION_RESULT_TYPE (String, String -> String)
                #
                | DO_COMMAND_FOR_'XXX_CLIENT_DRIVER_FOR_LIBRARY_IN_C_SUBPROCESS_PKG' (String, String)
                | DO_COMMAND_TO_STRING_FN (String, String)
                #
                | CLIENT_DRIVER_ARG_TYPE (String, String)
                | CLIENT_DRIVER_RESULT_TYPE (String, String)
                ;
        #
        fun make_library_glue   (path: Paths)   (paragraph_definitions: List(plf::Paragraph_Definition(Builder_Stuff)))   (plugins: List(Plugin))
            =
            {
                note_plugins  plugins;

                plan =  plf::read_planfile  paragraph_defs  path.construction_plan;

                pfs  = plf::map_patchfiles_per_plan  builder_stuff  pfs  plan;

                pfs =  write_section_libref_xxx_tex_table  pfs  (.fn_name, .libcall, to_section_libref_xxx_tex_apitable);
                pfs =  write_section_libref_xxx_tex_table  pfs  (.libcall, .fn_name, to_section_libref_xxx_tex_libtable);


                printf "\n";

                printf "%4d   plain     functions codebuilt for %s\n"           *plain_fns_codebuilt_for_'libmythryl_xxx_c'                             (basename  path.libmythryl_xxx_c);
                printf "%4d   custom    functions codebuilt for %s\n"           *custom_fns_codebuilt_for_'libmythryl_xxx_c'                            (basename  path.libmythryl_xxx_c);

                printf "%4d   plain     functions codebuilt for %s\n"           *plain_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c'        (basename  path.mythryl_xxx_library_in_c_subprocess_c);
                printf "%4d   custom    functions codebuilt for %s\n"           *custom_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c'       (basename  path.mythryl_xxx_library_in_c_subprocess_c);

                printf "%4d   plain     functions codebuilt for %s\n"           *plain_fns_codebuilt_for_'xxx_client_g_pkg'                             (basename  path.xxx_client_g_pkg);
                printf "%4d   plain     functions handbuilt for %s\n"           *plain_fns_handbuilt_for_'xxx_client_g_pkg'                             (basename  path.xxx_client_g_pkg);

                printf "%4d   callback  functions codebuilt for %s\n"           *callback_fns_handbuilt_for_'xxx_client_g_pkg'                          (basename  path.xxx_client_g_pkg);
                printf "%4d   callback  functions handbuilt for %s\n"           *callback_fns_handbuilt_for_'xxx_client_g_pkg'                          (basename  path.xxx_client_g_pkg);


                narration =  pfs::write_patchfiles   pfs;                                       # Narration lines generated via   sprintf "Successfully patched %4d lines in %s\n"  *patch_lines_written  filename;     in   src/lib/make-library-glue/patchfile.pkg

                printf "\n";
                apply  {. printf "%s\n" #msg; }   narration;
                printf "\n";
            }
            where

                # First, establish patch ids for our patchpoints:
                #
                patch_id_'functions'_in_'xxx_client_driver_api'                         = { patchname => "functions",           filename => path.xxx_client_driver_api                                  };
                #
                patch_id_'body'_in_'xxx_client_driver_for_library_in_main_process_pkg'  = { patchname => "body",                filename => path.xxx_client_driver_for_library_in_main_process_pkg      };
                #
                patch_id_'body'_in_'xxx_client_driver_for_library_in_c_subprocess_pkg'  = { patchname => "body",                filename => path.xxx_client_driver_for_library_in_c_subprocess_pkg      };
                #
                patch_id_'functions'_in_'xxx_client_api'                                = { patchname => "functions",           filename => path.xxx_client_api                                         };
                patch_id_'types'_in_'xxx_client_api'                                    = { patchname => "types",               filename => path.xxx_client_api                                         };
                #
                patch_id_'functions'_in_'xxx_client_g_pkg'                              = { patchname => "functions",           filename => path.xxx_client_g_pkg                                       };
                patch_id_'types'_in_'xxx_client_g_pkg'                                  = { patchname => "types",               filename => path.xxx_client_g_pkg                                       };
                #
                patch_id_'functions'_in_'mythryl_xxx_library_in_c_subprocess_c'         = { patchname => "functions",           filename => path.mythryl_xxx_library_in_c_subprocess_c                  };
                patch_id_'table'_in_'mythryl_xxx_library_in_c_subprocess_c'             = { patchname => "table",               filename => path.mythryl_xxx_library_in_c_subprocess_c                  };
                #
                patch_id_'functions'_in_'libmythryl_xxx_c'                              = { patchname => "functions",           filename => path.libmythryl_xxx_c                                       };
                patch_id_'table'_in_'libmythryl_xxx_c'                                  = { patchname => "table",               filename => path.libmythryl_xxx_c                                       };
                #
                patch_id_'api_calls'_in_'section_libref_xxx_tex'                        = { patchname => "api_calls",           filename => path.section_libref_xxx_tex                                 };
                patch_id_'binding_calls'_in_'section_libref_xxx_tex'                    = { patchname => "binding_calls",       filename => path.section_libref_xxx_tex                                 };



                # Next, load into memory all the files which we will be patching:
                #
                pfs =   (pfs::load_patchfiles
                          [ 
                            path.xxx_client_driver_api,
                            path.xxx_client_driver_for_library_in_c_subprocess_pkg,
                            path.xxx_client_driver_for_library_in_main_process_pkg,
                            path.xxx_client_g_pkg,
                            path.xxx_client_api,
                            path.mythryl_xxx_library_in_c_subprocess_c,
                            path.libmythryl_xxx_c,
                            path.section_libref_xxx_tex
                          ]
                        );


                # Clear out the current contents of all patches,
                # to make way for the new versions we are about
                # to create:
                #
                pfs =  pfs::empty_all_patches  pfs;



                # Initialize all of our state:

                plain_fns_codebuilt_for_'libmythryl_xxx_c'  =  REF 0;
                custom_fns_codebuilt_for_'libmythryl_xxx_c' =  REF 0;

                plain_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c'   =  REF 0;
                custom_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c'  =  REF 0;

                plain_fns_handbuilt_for_'xxx_client_g_pkg'     =  REF 0;
                plain_fns_codebuilt_for_'xxx_client_g_pkg'     =  REF 0;

# XXX SUCKO FIXME was one of thes supposed to be 'codebuilt'?
                callback_fns_handbuilt_for_'xxx_client_g_pkg'  =  REF 0;
                callback_fns_handbuilt_for_'xxx_client_g_pkg'  =  REF 0;


                nonstandard_result_type_handlers_for__build_plain_fun_for__'mythryl_xxx_library_in_c_subprocess_c' =  REF (sm::empty: sm::Map( Pfs -> Custom_Body_Stuff   -> Pfs ));
                nonstandard_result_type_handlers_for__build_plain_fun_for__'libmythryl_xxx_c'                      =  REF (sm::empty: sm::Map( Pfs -> Custom_Body_Stuff2  -> Pfs ));
                #
                arg_load_fns_for_'mythryl_xxx_library_in_c_subprocess_c'        =  REF (sm::empty: sm::Map( (String,Int,String) -> String ));
                arg_load_fns_for_'libmythryl_xxx_c'                             =  REF (sm::empty: sm::Map( (String,Int,String) -> String ));
                #
                figure_function_result_type_fns    =  REF (sm::empty: sm::Map( String -> String ));
                #
                do_command_for                     =  REF (sm::empty: sm::Map( String ));
                do_command_to_string_fn            =  REF (sm::empty: sm::Map( String ));
                #
                client_driver_arg_type             =  REF (sm::empty: sm::Map( String ));
                client_driver_result_type          =  REF (sm::empty: sm::Map( String ));


                #
                fun libcall_to_args_fn  libcall
                    =
                    # 'libcall' is from a line in (say)         src/opt/gtk/etc/gtk-construction.plan
                    # looking something like                    libcall: gtk_table_set_row_spacing( GTK_TABLE(/*table*/w0), /*row*/i1, /*spacing*/i2)
                    #
                    # 'libcall' contains embedded arguments like 'w0', 'i1', 'f2', 'b3', 's4'.
                    # They are what we are interested in here;
                    # our job is to return a sorted, duplicate-free list of them.
                    #
                    # The implementation here is generic;  glue for a particular library
                    # may override it to support additional argument types (like 'w').
                    # See for example libcall_to_args_fn() in   src/opt/gtk/sh/make-gtk-glue
                    #
                    # The argument letter gives us the argument type:
                    #
                    #    i == int
                    #    f == double  (Mythryl "Float")
                    #    b == bool
                    #    s == string
                    #
                    # The argument digit gives us the argument order:
                    #
                    #    0 == first arg
                    #    1 == second arg
                    #    ...
                    #
                    # Get list of above args, sorting by trailing digit
                    # and dropping duplicates:
                    #
                    {   raw_list    =  regex::find_all_matches_to_regex  ./\b[bfis][0-9]\b/  libcall;
                        #
                        cooked_list =  uniquesort  compare_fn  raw_list;

                        cooked_list;
                    }
                    where       
                        fun compare_fn (xn, yn)                                 # Compare "s0" and "b1" as "0" and "1":
                            =
                            {   xn' = string::extract (xn, 1, NULL);
                                yn' = string::extract (yn, 1, NULL);

                                string::compare (xn', yn');
                            };
                    end;        


                ref_libcall_to_args_fn =  REF libcall_to_args_fn;
                #
                fun libcall_to_args  libcall
                    =
                    *ref_libcall_to_args_fn  libcall;




                # Convenience functions to append
                # lines (strings) to our patchpoints:
                #
                fun to_xxx_client_driver_api                                    pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'functions'_in_'xxx_client_driver_api'                           };
                fun to_xxx_client_driver_for_library_in_c_subprocess_pkg        pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'body'_in_'xxx_client_driver_for_library_in_c_subprocess_pkg'    };
                fun to_xxx_client_driver_for_library_in_main_process_pkg        pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'body'_in_'xxx_client_driver_for_library_in_main_process_pkg'    };
                fun to_xxx_client_g_pkg_funs                                    pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'functions'_in_'xxx_client_g_pkg'                                };
                fun to_xxx_client_g_pkg_types                                   pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'types'_in_'xxx_client_g_pkg'                                    };
                fun to_xxx_client_api_funs                                      pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'functions'_in_'xxx_client_api'                                  };
                fun to_xxx_client_api_types                                     pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'types'_in_'xxx_client_api'                                      };
                fun to_mythryl_xxx_library_in_c_subprocess_c_funs               pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'functions'_in_'mythryl_xxx_library_in_c_subprocess_c'           };
                fun to_mythryl_xxx_library_in_c_subprocess_c_trie               pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'table'_in_'mythryl_xxx_library_in_c_subprocess_c'               };
                fun to_libmythryl_xxx_c_table                                   pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'table'_in_'libmythryl_xxx_c'                                    };
                fun to_libmythryl_xxx_c_funs                                    pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'functions'_in_'libmythryl_xxx_c'                                };
                fun to_section_libref_xxx_tex_apitable                          pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'api_calls'_in_'section_libref_xxx_tex'                          };
                fun to_section_libref_xxx_tex_libtable                          pfs string =   pfs::append_to_patch  pfs  { lines => [ string ],  patch_id => patch_id_'binding_calls'_in_'section_libref_xxx_tex'                      };



                # Save and index resources supplied by client:
                #
                fun note_plugins  plugins
                    =
                    apply  note_plugin  plugins
                    where
                        fun note_plugin (LIBCALL_TO_ARGS_FN  libcall_to_args_fn)
                                =>
                                ref_libcall_to_args_fn :=  libcall_to_args_fn;

                            note_plugin (BUILD_ARG_LOAD_FOR_'MYTHRYL_XXX_LIBRARY_IN_C_SUBPROCESS' (arg_type, arg_load_builder))
                                =>
                                arg_load_fns_for_'mythryl_xxx_library_in_c_subprocess_c' :=  sm::set  (*arg_load_fns_for_'mythryl_xxx_library_in_c_subprocess_c',  arg_type,  arg_load_builder);

                            note_plugin (BUILD_ARG_LOAD_FOR_'LIBMYTHRYL_XXX_C' (arg_type, arg_load_builder))
                                =>
                                arg_load_fns_for_'libmythryl_xxx_c' :=  sm::set  (*arg_load_fns_for_'libmythryl_xxx_c',  arg_type,  arg_load_builder);

                            note_plugin (HANDLE_NONSTANDARD_RESULT_TYPE_FOR__BUILD_PLAIN_FUN_FOR__'MYTHRYL_XXX_LIBRARY_IN_C_SUBPROCESS_C'  (result_type, function))
                                =>
                                nonstandard_result_type_handlers_for__build_plain_fun_for__'mythryl_xxx_library_in_c_subprocess_c' :=  sm::set  (*nonstandard_result_type_handlers_for__build_plain_fun_for__'mythryl_xxx_library_in_c_subprocess_c',  result_type,  function);

                            note_plugin (HANDLE_NONSTANDARD_RESULT_TYPE_FOR__BUILD_PLAIN_FUN_FOR__'LIBMYTHRYL_XXX_C'  (result_type, function))
                                =>
                                nonstandard_result_type_handlers_for__build_plain_fun_for__'libmythryl_xxx_c' :=  sm::set  (*nonstandard_result_type_handlers_for__build_plain_fun_for__'libmythryl_xxx_c',  result_type,  function);

                            note_plugin (FIGURE_FUNCTION_RESULT_TYPE (type, function))
                                =>
                                figure_function_result_type_fns     :=  sm::set  (*figure_function_result_type_fns, type, function);

                            note_plugin (DO_COMMAND_FOR_'XXX_CLIENT_DRIVER_FOR_LIBRARY_IN_C_SUBPROCESS_PKG' (type, function))
                                =>
                                do_command_for     :=  sm::set  (*do_command_for, type, function);

                            note_plugin (DO_COMMAND_TO_STRING_FN (type, function))
                                =>
                                do_command_to_string_fn     :=  sm::set  (*do_command_to_string_fn, type, function);

                            note_plugin (CLIENT_DRIVER_ARG_TYPE (type, type2))
                                =>
                                client_driver_arg_type     :=  sm::set  (*client_driver_arg_type, type, type2);

                            note_plugin (CLIENT_DRIVER_RESULT_TYPE (type, type2))
                                =>
                                client_driver_result_type     :=  sm::set  (*client_driver_result_type, type, type2);
                        end;
                    end;





                #
                fun field_location (field: Field)
                    =
                    field.line_1 == field.line_n  ??  sprintf "line %d" field.line_1
                                                  ::  sprintf "lines %d-%d" field.line_1 field.line_n;

                #
                fun maybe_get_field (fields: Fields, field_name)
                    =
                    case (sm::get (fields, field_name))
                        #
                        THE field => { field.used := TRUE;  THE (string::cat field.lines); };
                        NULL      => NULL;
                    esac;

                #
                fun get_field (fields: Fields, field_name)
                    =
                    case (sm::get (fields, field_name))
                        #
                        THE field => { field.used := TRUE; 
                                       string::cat field.lines;
                                     };

                        NULL      => die_x (sprintf "Required field %s missing\n"  field_name);
                    esac;

                #
                fun get_field_location (fields: Fields, field_name)
                    =
                    case (sm::get (fields, field_name))
                        #
                        THE field => { field.used := TRUE;  field_location field; };
                        #
                        NULL      => die_x (sprintf "Required field %s missing\n"  field_name);
                    esac;



                #
                fun clear_state (state: State)
                    =
                    {   foreach (sm::keyvals_list *state.fields) {.
                            #
                            #pair -> (field_name, field);

                            if (not *field.used)
                                #
                                die_x(sprintf "Field %s at %s unsupported.\n"
                                             field_name
                                             (field_location field)
                                    );
                            fi;
                        }; 

                        state.fields :=  (sm::empty: sm::Map( Field ));
                    };





                # Count number of arguments.
                # We need this for check_argc():
                #
                fun count_args  libcall
                    =
                    list::length (libcall_to_args  libcall);

                #
                fun get_nth_arg_type (n, libcall)
                    =
                    {   arg_list =  libcall_to_args  libcall;

                        if (n <   0
                        or  n >=  list::length  arg_list
                        )
                            raise exception DIE (sprintf "get_nth_arg_type: No %d-th arg in '%s'!" n libcall);
                        fi;

                        arg = list::nth (arg_list, n);          # Fetch "w0" or "i0" or such.

                        string::extract (arg, 0, THE 1);        # Convert "w0" to "w" or "i0" to "i" etc.
                    };

                #
                fun arg_types_are_all_unique  libcall
                    =
                    {   # Get the list of parameters,
                        # something like [ "w0", "i1", "i2" ]:
                        #
                        args  =  libcall_to_args  libcall;

                        # Turn parameter list into type list,
                        # something like [ 'w', 'i', 'i' ]:
                        #
                        types =  map   {. string::get_byte_as_char (#string,0); }   args;

                        # Eliminate duplicate types from above:
                        #
                        types =   uniquesort  char::compare  types;

                        # If 'args' is same length as 'types' then
                        # all types are unique:
                        #
                        list::length args  ==  list::length types;
                    };

                #
                fun xxx_client_driver_api_type (libcall, result_type)
                    =
                    {   input_type =  REF "(Session";
                        #
                        arg_count  =  count_args  libcall;

                        for (a = 0;  a < arg_count;  ++a) {
                            #
                            t = get_nth_arg_type( a, libcall );

                            case t
                                "b" =>     input_type :=  *input_type  +  ", Bool";
                                "i" =>     input_type :=  *input_type  +  ", Int";
                                "f" =>     input_type :=  *input_type  +  ", Float";
                                "s" =>     input_type :=  *input_type  +  ", String";
                                #
                                x            => case (sm::get (*client_driver_arg_type, x))
                                                    #
                                                    THE type2 =>  input_type :=  *input_type  +  ", " + type2;                          # Handle "w" etc
                                                    NULL      =>  raise exception DIE (sprintf "Unsupported arg type '%s'" t);
                                                esac;
                            esac;
                        };

                        input_type :=  *input_type  +  ")";


                        output_type
                            =
                            case result_type
                                #
                                "Bool"       =>  "Bool";
                                "Float"      =>  "Float";
                                "Int"        =>  "Int";
                                "Void"       =>  "Void";
                                #
                                x            => case (sm::get (*client_driver_result_type, x))  
                                                    #
                                                    THE type2 =>    type2;      # "Widget", "new Widget"
                                                    #   
                                                    NULL      =>    {   printf "Supported result types:\n";
                                                                        print_strings (sm::keys_list *client_driver_result_type);
                                                                        raise exception DIE ("xxx_client_driver_api_type: Unsupported result type: " + result_type);
                                                                    };
                                                esac;
                            esac;

                        (*input_type, output_type);
                    };
                #        
                stipulate
                    #
                    line_count = REF 2;

                herein
                    #
                    fun build_fun_declaration_for_'xxx_client_driver_api'  (pfs: Pfs)   { c_fn_name, libcall, result_type }
                        =
                        {
                            # Add a blank line every three declarations:
                            #
                            line_count :=  *line_count + 1;
                            #   
                            pfs =   if ((*line_count % 3) == 0)
                                        #
                                        to_xxx_client_driver_api  pfs  "\n";
                                    else
                                        pfs;
                                    fi;

                            pfs = to_xxx_client_driver_api  pfs  (sprintf  "    %-40s"  (c_fn_name + ":"));


                            (xxx_client_driver_api_type  (libcall,  result_type))
                                ->
                                (input_type,  output_type);


                            pfs = to_xxx_client_driver_api  pfs  (sprintf "%-40s -> %s;\n"  input_type  output_type);

                            pfs;
                        };
                end;






                #
                fun write_do_command  (pfs: Pfs)  (do_command, fn_name, libcall, result_prefix, result_expression)
                    =
                    {
                        pfs =   if (result_expression != "")
                                     to_xxx_client_driver_for_library_in_c_subprocess_pkg pfs ("        {   result = " + do_command + " (session");
                                else to_xxx_client_driver_for_library_in_c_subprocess_pkg pfs ("        " + do_command + " (session");
                                fi;

                        pfs =   if (result_prefix != "")    to_xxx_client_driver_for_library_in_c_subprocess_pkg  pfs (.', "' + result_prefix + .'"');
                                else                        pfs;
                                fi;

                        pfs =   to_xxx_client_driver_for_library_in_c_subprocess_pkg  pfs  (.', "' + fn_name + .'"');

                        prefix = .' + " " +';

                        arg_count = count_args libcall;


                        pfs =   for (a = 0, pfs = pfs;  a < arg_count;  ++a;  pfs) {
                                    #
                                    t = get_nth_arg_type( a, libcall );

                                    pfs =    case t
                                                "b" =>  to_xxx_client_driver_for_library_in_c_subprocess_pkg   pfs  (sprintf  "%s bool_to_string %s%d"                  prefix t a);
                                                "f" =>  to_xxx_client_driver_for_library_in_c_subprocess_pkg   pfs  (sprintf  "%s eight_byte_float::to_string %s%d"     prefix t a);
                                                "i" =>  to_xxx_client_driver_for_library_in_c_subprocess_pkg   pfs  (sprintf  "%s int::to_string %s%d"                  prefix t a);
                                                "s" =>  to_xxx_client_driver_for_library_in_c_subprocess_pkg   pfs  (sprintf  "%s string_to_string %s%d"                prefix t a);
                                                #
                                                 x  =>  case (sm::get (*do_command_to_string_fn, x))
                                                            #
                                                            THE to_string => to_xxx_client_driver_for_library_in_c_subprocess_pkg   pfs  (sprintf  "%s %s %s%d" prefix  to_string  t  a);
                                                            #
                                                            NULL          => raise exception DIE ("Unsupported arg type '" + x + "'");
                                                        esac;
                                            esac;
                                };

                        pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg  pfs   ");\n";


                        pfs =   if (result_expression != "")
                                    #
                                    pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg pfs "\n";
                                    pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg pfs ("            " + result_expression + "\n");
                                    pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg pfs "        };\n\n\n";
                                    pfs;
                                else
                                    pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg pfs "\n\n";
                                    pfs;
                                fi;

                        pfs;
                    };

                # Build a function for   .../src/opt/xxx/src/xxx-client-driver-for-library-in-c-subprocess.pkg
                # looking like
                #
                #    fun make_status_bar_context_id (session, w0, s1)   # Int
                #        =
                #        do_int_command (session, "make_status_bar_context_id", "make_status_bar_context_id" + " " + widget_to_string w0 + " " + string_to_string s1);
                #
                fun build_fun_definition_for_'xxx_client_driver_for_library_in_c_subprocess_pkg'  (pfs: Pfs)  { c_fn_name, libcall, result_type }
                    =
                    {   pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg  pfs  ("    fun " + c_fn_name + " (session");
                        #
                        arg_count = count_args( libcall );

                        pfs =   for (a = 0, pfs = pfs;  a < arg_count;  ++a;  pfs) {
                                    #
                                    arg_type = get_nth_arg_type( a, libcall );

                                    pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg  pfs  (sprintf ", %s%d" arg_type a);

                                    pfs;
                                };

                        pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg  pfs  (")\t# " + result_type + "\n");
                        pfs = to_xxx_client_driver_for_library_in_c_subprocess_pkg  pfs  ("        =\n");

                        pfs =   if   (result_type == "Int")          write_do_command pfs ("do_int_command",    c_fn_name, libcall, c_fn_name, "");
                                elif (result_type == "Bool")         write_do_command pfs ("do_string_command", c_fn_name, libcall, c_fn_name, "the (int::from_string result) != 0;");
                                elif (result_type == "Float")        write_do_command pfs ("do_string_command", c_fn_name, libcall, c_fn_name, "the (eight_byte_float::from_string result);");
                                elif (result_type == "Void")         write_do_command pfs ("do_void_command",   c_fn_name, libcall, "", "");
                                else
                                    case (sm::get (*do_command_for, result_type))
                                        #
                                        THE do_command  =>           write_do_command pfs (do_command,          c_fn_name, libcall, c_fn_name, "");
                                        #
                                        NULL            =>           raise exception DIE ("Unsupported result type: " + result_type);
                                    esac;
                                fi;
                        pfs;
                    };

                #
                fun n_blanks n
                    =
                    n_blanks' (n, "")
                    where
                        fun n_blanks' (0, string) => string;
                            n_blanks' (i, string) => n_blanks' (i - 1, " " + string);
                        end;
                    end;

                # Build a function for   .../src/opt/xxx/src/xxx-client-driver-for-library-in-main-process.pkg
                # looking like
                #
                # NEED TO WORK OUT APPROPRIATE VARIATION FOR THIS
                #
                #    fun make_status_bar_context_id (session, w0, s1)   # Int
                #        =
                #        do_int_command (session, "make_status_bar_context_id", "make_status_bar_context_id" + " " + widget_to_string w0 + " " + string_to_string s1);
                #
                fun build_fun_definition_for_'xxx_client_driver_for_library_in_main_process_pkg'  (pfs: Pfs)  { fn_name, c_fn_name, fn_type, libcall, result_type }
                    =
                    {
                        # Construct xxx-client-driver-for-library-in-main-process.pkg level type for this function.
                        # The xxx-client-g.pkg level type may involve records or tuples,
                        # but at this level we always have tuples:
                        #
                        (xxx_client_driver_api_type (libcall, result_type))
                            ->
                            (input_type, output_type);

                        pfs =   to_xxx_client_driver_for_library_in_main_process_pkg  pfs  "\n";
                        pfs =   to_xxx_client_driver_for_library_in_main_process_pkg  pfs
                                    (sprintf "    #      %-80s   # %s type\n"
                                             ( (n_blanks (string::length_in_bytes fn_name))
                                             + (fn_type =~ ./^\(/ ?? "" :: " ")                    # If type starts with a paren exdent it one space.
                                             +  fn_type
                                             )
                                             (basename path.xxx_client_api)
                                    );

                        pfs =   to_xxx_client_driver_for_library_in_main_process_pkg  pfs
                                    (sprintf "    my %s:   %s%s -> %s\n"
                                              c_fn_name
                                             (input_type =~ ./^\(/ ?? "" :: " ")                   # If type starts with a paren exdent it one space.
                                              input_type
                                              output_type
                                    );

                        pfs =   to_xxx_client_driver_for_library_in_main_process_pkg  pfs   "        =\n";

                        pfs =   to_xxx_client_driver_for_library_in_main_process_pkg  pfs
                                    #
                                    (sprintf "        ci::find_c_function { lib_name => \"%s\", fun_name => \"%s\" };\n"
                                        path.lib_name   
                                        c_fn_name
                                    );

                        pfs =   to_xxx_client_driver_for_library_in_main_process_pkg  pfs   "\n";

                        pfs;
                    };


                # Convert .|xxx_foo| to .|xxx\_foo|
                # to protect it from TeX's ire:
                #
                fun slash_underlines  string
                    =
                    regex::replace_all ./_/ .|\_| string;


                # Write a trie line into file  src/opt/xxx/c/in-sub/mythryl-xxx-library-in-c-subprocess.c
                #
                fun build_trie_entry_for_'mythryl_xxx_library_in_c_subprocess_c'  (pfs: Pfs)  name
                    =
                    {
                        to_mythryl_xxx_library_in_c_subprocess_c_trie  pfs
                            #
                            (sprintf
                                "    set_trie( trie, %-46s%-46s);\n"
                                (.'"'  + name + .'",')
                                ("do__" + name));
                    };  

                # Write a line like
                #
                #     CFUNC("init","init",      do__gtk_init,           "Void -> Void")
                #
                # into file   src/opt/xxx/c/in-main/libmythryl-xxx.c
                #
                fun build_table_entry_for_'libmythryl_xxx_c'  (pfs: Pfs)  (fn_name, fn_type)
                    =
                    {   to_libmythryl_xxx_c_table   pfs
                            #
                            (sprintf "CFUNC(%-44s%-44s%-54s%s%s)\n"
                                ("\""   + fn_name + "\",")
                                ("\""   + fn_name + "\",")
                                ("do__" + fn_name + ",")
                                (fn_type =~ ./^\(/ ?? "" :: " ")                           # If type starts with a paren exdent it one space.
                                ("\""         + fn_type + "\"")
                            );
                    };

                Doc_Entry
                    =
                    { fn_name:  String,
                      libcall:  String,
                      url:      String,
                      fn_type:  String
                    };

                doc_entries =  REF ([]: List( Doc_Entry ));

                # Note a tex documentation table
                # line for file  section-libref-xxx.tex.
                #
                fun note__section_libref_xxx_tex__entry
                    #   
                    (pfs: Pfs)          # We don't actually use this at present, but this regularizes the code, and a future version might use it.
                    #   
                    { fields: Fields,
                      fn_name,          # E.g. "make_window"
                      libcall,          # E.g. "gtk_table_set_col_spacing( GTK_TABLE(/*table*/w0), /*col*/i1, /*spacing*/i2)"
                      url,              # E.g. "http://library.gnome.org/devel/gtk/stable/GtkTable.html#gtk-table-set-col-spacing"
                      fn_type           # E.g. "Session -> Widget"
                    }
                    =
                    {
                        # Get name of the C Gtk function/var
                        # wrapped by this Mythryl function:
                        #
                        libcall
                            =
                            case (maybe_get_field(fields,"doc-fn"))
                                #
                                THE field => field;     # doc-fn is a manual override used when libcall is unusable for documentation.

                                NULL =>
                                    {   # libcall is something like   gtk_widget_set_size_request( GTK_WIDGET(/*widget*/w0), /*wide*/i1, /*high*/i2)
                                        # but all we want here is the
                                        # initial function name:
                                        #
                                        libcall =   case (regex::find_first_match_to_regex ./[A-Za-z0-9_']+/ libcall)
                                                        THE x => x;
                                                        NULL  => "";
                                                    esac;

                                        # If libcall does not begin with [Gg], it
                                        # is probably not useful in this context:
                                        #
                                        libcall =  (libcall =~ ./^[Gg]/)  ??  libcall
                                                                          ::  "";

                                        libcall;
                                    };  
                            esac;


                        fn_name =  slash_underlines  fn_name;
                        libcall =  slash_underlines  libcall;
                        url     =  slash_underlines  url;               # Probably not needed.
                        fn_type =  slash_underlines  fn_type;

                        doc_entries :=   { fn_name, libcall, url, fn_type }  !  *doc_entries;

                        pfs;
                    };

                # Write tex documentation table into file  section-libref-xxx.tex:
                #
                fun write_section_libref_xxx_tex_table
                    #
                    (pfs: Pfs)
                    #
                    ( field1:           Doc_Entry -> String,
                      field2:           Doc_Entry -> String,
                      to_section:       Pfs -> String -> Pfs
                    )
                    =
                    {
                        # Define the sort order for the table:
                        #
                        fun compare_fn
                            ( a: Doc_Entry,
                              b: Doc_Entry
                            )
                            =
                            {   a1 = field1 a;    a2 = field2 a;
                                b1 = field1 b;    b2 = field2 b;

                                # If primary keys are equal,
                                # sort on the secondary keys:
                                #
                                if (a1 != b1)   a1 > b1;
                                else            a2 > b2;
                                fi;
                            };

                        entries =  sort  compare_fn  *doc_entries;
                        
                        pfs =   fold_forward 
                                    (\\ (entry, pfs)
                                        =
                                        {   entry -> { fn_name, libcall, url, fn_type };
                                            #
                                            entry1 = field1 entry;
                                            entry2 = field2 entry;

                                            pfs =   if (entry1 != "")
                                                        to_section  pfs
                                                            (sprintf "%s & %s & %s & %s \\\\ \\hline\n"
                                                                entry1
                                                                entry2
                                                                (url == "" ?? ""
                                                                           :: (.|\ahref{\url{| + url + "}}{doc}"))
                                                                fn_type
                                                            );
                                                    else
                                                        pfs;
                                                    fi;
                                            pfs;
                                        }
                                    )
                                    pfs                         # Initial value of result.
                                    entries                     # Iterate over this list.
                                    ;
                        pfs;
                    };

                #
                fun build_fun_header_for__'mythryl_xxx_library_in_c_subprocess_c'  (pfs: Pfs)  (fn_name, args)
                    =
                    {   pfs = to_mythryl_xxx_library_in_c_subprocess_c_funs  pfs   "\n";
                        pfs = to_mythryl_xxx_library_in_c_subprocess_c_funs  pfs   "static void\n";
                        pfs = to_mythryl_xxx_library_in_c_subprocess_c_funs  pfs  ("do__" + fn_name + "( int argc, unsigned char** argv )\n");
                        pfs = to_mythryl_xxx_library_in_c_subprocess_c_funs  pfs   "{\n";
                        pfs = to_mythryl_xxx_library_in_c_subprocess_c_funs  pfs  (sprintf "    check_argc( \"do__%s\", %d, argc );\n" fn_name args);
                        pfs = to_mythryl_xxx_library_in_c_subprocess_c_funs  pfs   "\n";
                        pfs;
                    };


                # Build C code
                # to fetch all the arguments
                # out of argc/argv:
                #
                fun build_fun_arg_loads_for_'mythryl_xxx_library_in_c_subprocess_c'  (pfs: Pfs)  (fn_name, args, libcall)
                    =
                    {   
                        pfs =   for (a = 0, pfs = pfs;   a < args;  ++a;  pfs) {

                                    # Remember type of this arg,
                                    # which will be one of:
                                    #   w (widget),
                                    #   i (int),
                                    #   b (bool)
                                    #   s (string)
                                    #   f (double):
                                    #
                                    arg_type = get_nth_arg_type( a, libcall );

                                    pfs =   if   (arg_type == "b")    to_mythryl_xxx_library_in_c_subprocess_c_funs pfs (sprintf  "    int               b%d =                        bool_arg( argc, argv, %d );\n"  a a);
                                            elif (arg_type == "f")    to_mythryl_xxx_library_in_c_subprocess_c_funs pfs (sprintf  "    double            f%d =                      double_arg( argc, argv, %d );\n"  a a);
                                            elif (arg_type == "i")    to_mythryl_xxx_library_in_c_subprocess_c_funs pfs (sprintf  "    int               i%d =                         int_arg( argc, argv, %d );\n"  a a);
                                            elif (arg_type == "s")    to_mythryl_xxx_library_in_c_subprocess_c_funs pfs (sprintf  "    char*             s%d =                      string_arg( argc, argv, %d );\n"  a a);

                                            else
                                                case (sm::get  (*arg_load_fns_for_'mythryl_xxx_library_in_c_subprocess_c', arg_type))   # Custom library-specific arg type handling for "w" etc.
                                                    #
                                                    THE build_arg_load_fn =>  to_mythryl_xxx_library_in_c_subprocess_c_funs  pfs  (build_arg_load_fn (arg_type, a, libcall));
                                                    #
                                                    NULL                  =>  raise exception DIE ("Bug: unsupported arg type '" + arg_type + "' #" + int::to_string a + " from libcall '" + libcall + "\n");
                                                esac;
                                            fi;

                                    pfs;
                                };
                        pfs;
                    };

                # Synthesize a function for   mythryl-xxx-library-in-c-subprocess.c  like
                # 
                #    static void
                #    do__set_adjustment_value( int argc, unsigned char** argv )
                #    {
                #        check_argc( "do__make_label", 2, argc );
                #    
                #        {   GtkAdjustment* w0 =  (GtkAdjustment*) widget_arg( argc, argv, 0 );
                #            double         f1 =                   double_arg( argc, argv, 1 );
                #
                #            gtk_adjustment_set_value( GTK_ADJUSTMENT(w0), /*value*/f1);
                #        }
                #    }
                #    
                fun build_plain_fun_for_'mythryl_xxx_library_in_c_subprocess_c'
                    #
                    (pfs: Pfs)
                    #
                    ( x:       Builder_Stuff,
                      fields:  Fields,  
                      fn_name,                  # E.g., "make_window2"
                      fn_type,                  # E.g., "Session -> Widget".
                      libcall,                  # E.g., "gtk_window_new( GTK_WINDOW_TOPLEVEL )".
                      result                    # E.g., "Float"
                    )
                    =
                    {   to =  to_mythryl_xxx_library_in_c_subprocess_c_funs;
                        #
                        arg_count =  count_args  libcall;

                        pfs = build_fun_header_for__'mythryl_xxx_library_in_c_subprocess_c'     pfs   (fn_name, arg_count);
                        pfs = build_fun_arg_loads_for_'mythryl_xxx_library_in_c_subprocess_c'  pfs   (fn_name, arg_count, libcall);

                        libcall_more
                            =
                            case (maybe_get_field (fields, "libcal+"))  THE field => field;
                                                                        NULL      => "";
                            esac;

                        pfs =   case result
                                    #
                                    "Void"
                                        =>
                                        {   # Now we just print
                                            # the supplied gtk call
                                            # and wrap up:
                                            #
                                            pfs = to pfs   "\n";
                                            pfs = to pfs  ("    " + libcall + ";\n");                           pfs = if (libcall_more != "")  to pfs libcall_more;  else pfs; fi;
                                            pfs = to pfs   "}\n";
                                            pfs = to pfs  ("/* Above fn built by src/lib/make-library-glue/make-library-glue.pkg:  build_plain_fun_for_'mythryl_xxx_library_in_c_subprocess_c'  per  " + path.construction_plan + ". */\n");
                                            pfs;
                                        };

                                    "Bool"
                                        =>
                                        {   pfs = to pfs  "\n";
                                            pfs = to pfs ("    int result = " + libcall + ";\n");               pfs = if (libcall_more != "")  to pfs libcall_more;  else pfs; fi;
                                            pfs = to pfs  "\n";
                                            pfs = to pfs ("     printf(              \"" + fn_name + "%d\\n\", result);      fflush( stdout );\n");
                                            pfs = to pfs ("    fprintf(log_fd, \"SENT: " + fn_name + "%d\\n\", result);      fflush( log_fd );\n");
                                            pfs = to pfs  "}\n";
                                            pfs = to pfs ("/* Above fn built by src/lib/make-library-glue/make-library-glue.pkg:  build_plain_fun_for_'mythryl_xxx_library_in_c_subprocess_c'  per  " + path.construction_plan + ". */\n");
                                            pfs;
                                        };

                                    "Float"
                                        =>
                                        {   pfs = to pfs  "\n";
                                            pfs = to pfs ("    double result = " + libcall + ";\n");            pfs = if (libcall_more != "")  to pfs libcall_more;  else pfs; fi;
                                            pfs = to pfs  "\n";
                                            pfs = to pfs ("     printf(              \"" + fn_name + "%f\\n\", result);      fflush( stdout );\n");
                                            pfs = to pfs ("    fprintf(log_fd, \"SENT: " + fn_name + "%f\\n\", result);      fflush( log_fd );\n");
                                            pfs = to pfs  "}\n";
                                            pfs = to pfs ("/* Above fn built by src/lib/make-library-glue/make-library-glue.pkg:  build_plain_fun_for_'mythryl_xxx_library_in_c_subprocess_c'  per  " + path.construction_plan + ". */\n");
                                            pfs;        
                                        };

                                    "Int"
                                        =>
                                        {   pfs = to pfs  "\n";
                                            pfs = to pfs ("    int result = " + libcall + ";\n");               pfs = if (libcall_more != "")  to pfs libcall_more;  else pfs; fi;
                                            pfs = to pfs  "\n";
                                            pfs = to pfs ("     printf(              \"" + fn_name + "%d\\n\", result);      fflush( stdout );\n");
                                            pfs = to pfs ("    fprintf(log_fd, \"SENT: " + fn_name + "%d\\n\", result);      fflush( log_fd );\n");
                                            pfs = to pfs  "}\n";
                                            pfs = to pfs ("/* Above fn built by src/lib/make-library-glue/make-library-glue.pkg:  build_plain_fun_for_'mythryl_xxx_library_in_c_subprocess_c'  per  " + path.construction_plan + ". */\n");
                                            pfs;
                                        };


                                    _   =>  case (sm::get  (*nonstandard_result_type_handlers_for__build_plain_fun_for__'mythryl_xxx_library_in_c_subprocess_c', result))                                                       # Custom library-specific arg type handling for "Widget", "new Widget" etc.
                                                #
                                                THE build_fn =>  build_fn pfs { fn_name, libcall, libcall_more, to_mythryl_xxx_library_in_c_subprocess_c_funs, path };
                                                NULL         =>  raise exception DIE (sprintf "Unsupported result type '%s'" result);
                                            esac;
                                esac;

                        plain_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c'
                            :=
                            *plain_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c'
                            + 1;

                        pfs;
                    };

                #
                fun build_fun_header_for__'libmythryl_xxx_c'  (pfs: Pfs)  (fn_name, fn_type, args, libcall, result_type)
                    =
                    {
                        (xxx_client_driver_api_type  (libcall,  result_type))
                            ->
                            (input_type, output_type);
                            

                        # C comments don't nest, so we must change
                        # any C comments in input_type or output_type:
                        #
                        input_type  = regex::replace_all   .|/\*|   "(*"    input_type;
                        input_type  = regex::replace_all   .|\*/|   "*)"    input_type;
                        #
                        output_type = regex::replace_all   .|/\*|   "(*"   output_type;
                        output_type = regex::replace_all   .|\*/|   "*)"   output_type;


                        pfs = to_libmythryl_xxx_c_funs pfs ("/* do__" + fn_name + "\n");
                        pfs = to_libmythryl_xxx_c_funs pfs  " *\n";
                        pfs = to_libmythryl_xxx_c_funs pfs (" * " + (basename path.xxx_client_api) + "        type:   " + (   fn_type =~ ./^\(/ ?? "" :: " ") + fn_type + "\n");
                        pfs = to_libmythryl_xxx_c_funs pfs (" * " + (basename path.xxx_client_driver_api) + " type:   " + (input_type =~ ./^\(/ ?? "" :: " ") + input_type + " -> " + output_type + "\n");
                        pfs = to_libmythryl_xxx_c_funs pfs  " */\n";
                        pfs = to_libmythryl_xxx_c_funs pfs ("static Val   do__" + fn_name + "   (Task* task, Val arg)\n");
                        pfs = to_libmythryl_xxx_c_funs pfs  "{\n";
                        pfs = to_libmythryl_xxx_c_funs pfs  "\n";

                        pfs;
                    };

                #
                fun build_fun_trailer_for__'libmythryl_xxx_c' pfs
                    =
                    {
                        pfs = to_libmythryl_xxx_c_funs pfs  "}\n";
                        pfs = to_libmythryl_xxx_c_funs pfs ("/* Above fn built by src/lib/make-library-glue/make-library-glue.pkg:  write_libmythryl_xxx_c_plain_fun  per  " + path.construction_plan + ". */\n");
                        pfs = to_libmythryl_xxx_c_funs pfs  "\n";
                        pfs = to_libmythryl_xxx_c_funs pfs  "\n";

                        pfs;
                    };


                # Build C code
                # to fetch all the arguments
                # out of argc/argv:
                #
                fun build_fun_arg_loads_for__'libmythryl_xxx_c'  (pfs: Pfs)  (fn_name, fn_type, args, libcall)
                    =
                    {
                        case args
                            0 => pfs;

                #            Having just one argument used to be a special case
                #            because then we passed the argument directly rather
                #            than packed within a tuple.  But the first argument
                #            to a gtk-client-driver-for-library-in-main-process.pkg function is always a Session,
                #            and it is more efficient to pass on the tuple from
                #            that layer to the mythryl-gtk-library-in-main-process.c layer rather than
                #            unpacking and repacking just to get rid of the Session
                #            argument, consequently if we have any arguments of
                #            interest (i.e., non-Session arguments) at this point
                #            we will always have a tuple, eliminating the special
                #                case.  I've left this code here, commented out, just
                #            in case this situation changes and it is needed again:
                #
                #
                #            1 => {  arg_type = get_nth_arg_type( 0, libcall );
                #
                #                   if   (arg_type == "b")    to_libmythryl_xxx_c_funs "    int    b0 = TAGGED_INT_TO_C_INT(arg) == HEAP_TRUE;\n";
                #                   elif (arg_type == "f")    to_libmythryl_xxx_c_funs "    double f0 = *(PTR_CAST(double*, arg));\n";
                #                   elif (arg_type == "i")    to_libmythryl_xxx_c_funs "    int    i0 = TAGGED_INT_TO_C_INT(arg);\n";
                #                   elif (arg_type == "s")    to_libmythryl_xxx_c_funs "    char*  s0 = HEAP_STRING_AS_C_STRING(arg);\n";
                #                   elif (arg_type == "w")
                #
                #                       # Usually we fetch a widget as just
                #                       #
                #                       #    GtkWidget* widget    =  widget[ TAGGED_INT_TO_C_INT(arg) ];
                #                       #
                #                       # or such, but in a few cases we must cast to
                #                       # another type:
                #                       #  o If we see   GTK_ADJUSTMENT(w0)    we must do   GtkAdjustment*  w0 =  (GtkAdjustment*)  widget[ TAGGED_INT_TO_C_INT(arg) ];
                #                       #  o If we see   GTK_SCALE(w0)         we must do   GtkScale*       w0 =  (GtkScale*)       widget[ TAGGED_INT_TO_C_INT(arg) ];
                #                       #  o If we wee   GTK_RADIO_BUTTON(w0)  we must do   GtkRadioButton* w0 =  (GtkRadioButton*) widget[ TAGGED_INT_TO_C_INT(arg) ];
                #
                #                       widget_type = REF "GtkWidget";
                #
                #                       if   (libcall =~   ./GTK_ADJUSTMENT\(\s*w0\s*\)/)   widget_type := "GtkAdjustment";
                #                       elif (libcall =~        ./GTK_SCALE\(\s*w0\s*\)/)   widget_type := "GtkScale";
                #                       elif (libcall =~ ./GTK_RADIO_BUTTON\(\s*w0\s*\)/)   widget_type := "GtkRadioButton";
                #                       fi;
                #
                #                       to_libmythryl_xxx_c_funs (sprintf  "    %-14s    w0 =    %-16s  widget[ TAGGED_INT_TO_C_INT(arg) ];\n"
                #                                                  (*widget_type + "*")
                #                                                  ("(" + *widget_type + "*)")
                #                                        );
                #
                #                   else
                #                       raise exception DIE ("Bug: unsupported arg type '" + arg_type + "' #0 from libcall '" + libcall + "\n");
                #                   fi;
                #               };

                            _ => {  if (args < 0)  die_x "build_fun_arg_loads_for__'libmythryl_xxx_c': Negative 'args' value not supported.";  fi;
                                    #
                                    pfs =   for (a = 0, pfs = pfs;   a < args;  ++a;  pfs) {
                                                #
                                                # Remember type of this arg,
                                                # which will be one of:
                                                #   w (widget),
                                                #   i (int),
                                                #   b (bool)
                                                #   s (string)
                                                #   f (double):
                                                #
                                                arg_type = get_nth_arg_type( a, libcall );

                                                pfs =   if   (arg_type == "b")    to_libmythryl_xxx_c_funs pfs (sprintf  "    int               b%d =                            GET_TUPLE_SLOT_AS_VAL( arg, %d) == HEAP_TRUE;\n"   a (a+1)); # +1 because 1st arg is always Session.
                                                        elif (arg_type == "f")    to_libmythryl_xxx_c_funs pfs (sprintf  "    double            f%d =        *(PTR_CAST(double*, GET_TUPLE_SLOT_AS_VAL( arg, %d)));\n"              a (a+1));
                                                        elif (arg_type == "i")    to_libmythryl_xxx_c_funs pfs (sprintf  "    int               i%d =                            GET_TUPLE_SLOT_AS_INT( arg, %d);\n"                a (a+1));
                                                        elif (arg_type == "s")    to_libmythryl_xxx_c_funs pfs (sprintf  "    char*             s%d =   HEAP_STRING_AS_C_STRING (GET_TUPLE_SLOT_AS_VAL( arg, %d));\n"               a (a+1));
                                                        else
                                                            case (sm::get  (*arg_load_fns_for_'libmythryl_xxx_c', arg_type))            # Custom library-specific arg type handling for "w" etc.
                                                                #
                                                                THE build_arg_load_fn =>  to_libmythryl_xxx_c_funs pfs (build_arg_load_fn (arg_type, a, libcall));
                                                                #
                                                                NULL                  =>  raise exception DIE ("Bug: unsupported arg type '" + arg_type + "' #" + int::to_string a + " from libcall '" + libcall + "\n");
                                                            esac;
                                                        fi;

                                                pfs;
                                            };
                                    pfs;
                                };
                        esac;
                    };
                #
                fun build_fun_body_for__'libmythryl_xxx_c'
                    #
                    (pfs: Pfs)
                    #
                    ( x:        Builder_Stuff,
                      fields:   Fields, 
                      fn_name,                  # E.g., "make_window2"
                      fn_type,                  # E.g., "Session -> Widget".
                      libcall,                  # E.g., "gtk_window_new( GTK_WINDOW_TOPLEVEL )".
                      result_type               # E.g., "Float"
                    )
                    =
                    {
                        to =  to_libmythryl_xxx_c_funs;

                        libcall_more
                            =
                            case (maybe_get_field (fields, "libcal+"))  THE field => field;
                                                                                NULL      => "";
                            esac;

                        pfs =   case result_type
                                    #
                                    "Void"
                                        =>
                                        {   # Now we just print
                                            # the supplied gtk call
                                            # and wrap up:
                                            #
                                            pfs = to pfs  "\n";
                                            pfs = to pfs ("    " + libcall + ";\n");                            pfs = if (libcall_more != "")  to pfs libcall_more;  else pfs; fi;
                                            pfs = to pfs  "\n";
                                            pfs = to pfs  "    return HEAP_VOID;\n";
                                            #
                                            pfs;
                                        };

                                    "Bool"
                                        =>
                                        {   pfs = to pfs   "\n";
                                            pfs = to pfs  ("    int result = " + libcall + ";\n");              pfs = if (libcall_more != "")  to pfs libcall_more;  else pfs; fi;
                                            pfs = to pfs   "\n";
                                            pfs = to pfs   "    return  result ? HEAP_TRUE : HEAP_FALSE;\n";
                                            #
                                            pfs;
                                        };

                                    "Float"
                                        =>
                                        {   pfs = to pfs   "\n";
                                            pfs = to pfs  ("    double d = " + libcall + ";\n");                pfs = if (libcall_more != "")  to pfs libcall_more;  else pfs; fi;
                                            pfs = to pfs   "\n";
                                            pfs = to pfs   "    return  make_float64(task, d );\n";
                                            #
                                            pfs;
                                        };

                                    "Int"
                                        =>
                                        {   pfs = to pfs   "\n";
                                            pfs = to pfs  ("    int result = " + libcall + ";\n");              pfs = if (libcall_more != "")  to pfs libcall_more;  else pfs; fi;
                                            pfs = to pfs   "\n";
                                            pfs = to pfs   "    return TAGGED_INT_FROM_C_INT(result);\n";
                                            #
                                            pfs;
                                        };


                                    _   =>  case (sm::get  (*nonstandard_result_type_handlers_for__build_plain_fun_for__'libmythryl_xxx_c', result_type))                                                       # Custom library-specific arg type handling for "Widget", "new Widget" etc.
                                                #
                                                THE build_fn =>  build_fn  pfs  { fn_name, libcall, libcall_more, to_libmythryl_xxx_c_funs, path };
                                                #
                                                NULL         =>  raise exception DIE (sprintf "Unsupported result type '%s'" result_type);
                                            esac;

                                esac;
                        pfs;
                    };

                # Synthesize a function for   libmythryl-xxx.c  like
                # 
                #   /* do__gtk_init : Void -> Void
                #    *
                #    *
                #    */
                #   
                #   static Val do__gtk_init (Task* task, Val arg)
                #   {
                #       int y         = INT1_LIB7toC(              GET_TUPLE_SLOT_AS_INT(arg, 0) );
                #       char *symname = HEAP_STRING_AS_C_STRING(   GET_TUPLE_SLOT_AS_VAL(arg, 1) );
                #       int lazy      =                            GET_TUPLE_SLOT_AS_VAL(arg, 2) == HEAP_TRUE;
                #
                #       int result = move( y, x );
                #   
                #       if (result == ERR)     return RAISE_ERROR__MAY_HEAPCLEAN(task, "move", NULL);
                #   
                #       return HEAP_VOID;
                #   }
                #    
                #    
                #    
                # Cheatsheet:
                #    
                #   Accepting a lone float arg:
                #      double d = *(PTR_CAST(double*, arg));                                            # Example in src/c/lib/math/cos64.c
                #
                #   Accepting a lone int arg:
                #      int socket = TAGGED_INT_TO_C_INT(arg);                                           # Example in src/c/lib/socket/accept.c
                #
                #   Accepting a lone string arg:                                                        # Example in src/c/lib/posix-file-system/readlink.c
                #      char* path = HEAP_STRING_AS_C_STRING(arg);
                #
                #   Accepting a lone Null_Or( Tuple ) arg:                                              # Example in src/c/lib/socket/get-protocol-by-name.c
                #       
                #   Accepting a Bool from a tuple:                                                      # Example in src/c/lib/dynamic-loading/dlopen.c
                #     int lazy = GET_TUPLE_SLOT_AS_VAL (arg, 1) == HEAP_TRUE;
                #
                #   Accepting an Int from a tuple:                                                      # Example in src/c/lib/posix-file-system/fchown.c
                #     int fd =  GET_TUPLE_SLOT_AS_INT (arg, 0);
                #
                #   Accepting a String from a tuple:                                                    # Example in src/c/lib/dynamic-loading/dlsym.c
                #     char *symname = HEAP_STRING_AS_C_STRING (GET_TUPLE_SLOT_AS_VAL (arg, 1));
                #       
                #   Accepting a Float from a tuple:                                                     # THIS IS MY OWN GUESS!
                #     double d =  *(PTR_CAST(double*, GET_TUPLE_SLOT_AS_VAL(arg,%d)));
                #
                #   Accepting a Null_Or(String) from a tuple:                                           # Example in src/c/lib/dynamic-loading/dlopen.c
                #       
                #       
                #   Returning
                #
                #     Void:    return HEAP_VOID;                                                        # Defined in src/c/h/runtime-values.h
                #     TRUE:    return HEAP_TRUE;                                                        # Defined in src/c/h/runtime-values.h
                #     FALSE:   return HEAP_FALSE;                                                       # Defined in src/c/h/runtime-values.h
                #     Int:     return TAGGED_INT_FROM_C_INT(size);                                      # Defined in src/c/h/runtime-values.h
                #     NULL:    return OPTION_NULL;                                                      # Defined in src/c/h/make-strings-and-vectors-etc.h    Example in src/c/machine-dependent/interprocess-signals.c
                #     THE foo: return OPTION_THE(task, foo);                                            # Defined in src/c/h/make-strings-and-vectors-etc.h
                #                                                                                       # Example in src/c/machine-dependent/interprocess-signals.c
                #
                #   Returning a float:
                #              return  make_float64(task, cos(d) );                                     # Defined in src/c/h/make-strings-and-vectors-etc.h
                #
                #   Returning a string:
                #       Val result = allocate_nonempty_ascii_string__may_heapclean(task, size, NULL);
                #       strncpy (HEAP_STRING_AS_C_STRING(result), buf, size);
                #       return result;
                #    
                #   Returning a tuple:                                                                  # Example from src/c/lib/date/gmtime.c
                #
                #       set_slot_in_nascent_heapchunk(task, 0, MAKE_TAGWORD(PAIRS_AND_RECORDS_BTAG, 9));
                #       set_slot_in_nascent_heapchunk(task, 1, TAGGED_INT_FROM_C_INT(tm->tm_sec));
                #       ...
                #       set_slot_in_nascent_heapchunk(task, 9, TAGGED_INT_FROM_C_INT(tm->tm_isdst));
                #
                #       return commit_nascent_heapchunk(task, 9);
                #    
                #    
                #     Return functions which check ERR
                #     and optionally raise an exception:             src/c/lib/raise-error.h
                #
                #       CHK_RETURN_VAL(task, status, val)       Check status for an error (< 0); if okay,
                #                                       then return val.  Otherwise raise
                #                                       SYSTEM_ERROR with the appropriate system
                #                                       error message.
                #
                #       CHK_RETURN(task, status)        Check status for an error (< 0); if okay,
                #                                       then return it as the result (after
                #                                       converting to an Lib7 int).
                #
                #       CHK_RETURN_UNIT(task, status)   Check status for an error (< 0); if okay,
                #                                       then return Void.
                #
                #     GET_TUPLE_SLOT_AS_VAL &Co        are from:  src/c/h/runtime-values.h
                #     allocate_nonempty_ascii_string__may_heapclean    is from:  src/c/h/make-strings-and-vectors-etc.h
                #     CHK_RETURN_VAL &Co are from:  src/c/lib/raise-error.h
                #
                fun build_plain_fun_for_'libmythryl_xxx_c'
                    #
                    (pfs: Pfs)
                    #
                    ( x:        Builder_Stuff,
                      fields:   Fields, 
                      fn_name,                  # E.g., "make_window2"
                      fn_type,                  # E.g., "Session -> Widget".
                      libcall,                  # E.g., "gtk_window_new( GTK_WINDOW_TOPLEVEL )".
                      result_type               # E.g., "Float"
                    )
                    =
                    {   arg_count =  count_args( libcall );
                        #
                        pfs =    build_fun_header_for__'libmythryl_xxx_c' pfs  (            fn_name, fn_type, arg_count, libcall, result_type);
                        pfs = build_fun_arg_loads_for__'libmythryl_xxx_c' pfs  (            fn_name, fn_type, arg_count, libcall);
                        pfs =      build_fun_body_for__'libmythryl_xxx_c' pfs  (x, fields,  fn_name, fn_type, libcall, result_type);
                        pfs =   build_fun_trailer_for__'libmythryl_xxx_c' pfs;

                        plain_fns_codebuilt_for_'libmythryl_xxx_c'
                            :=
                            *plain_fns_codebuilt_for_'libmythryl_xxx_c'
                            + 1;

                        pfs;
                    };

                # Given a libcall like      "gtk_foo( /*bar_to_int bar*/i0, /*zot*/i1 )"
                # and a parameter name like  "i0" or "i1"
                # return nickname like       "bar_to_int bar" or "zot"
                # if available, else         "i0" or "i1":
                #
                fun arg_name (arg, libcall)
                    =
                    {   regex = .|/\*([A-Za-z0-9_' ]+)\*/| + arg;       # Something like:   /*([A-Za-z0-9_' ]+)*/f0
                        #
                        case (regex::find_first_match_to_ith_group 1 regex libcall)
                            THE x => x;
                            NULL  => arg;
                        esac;
                    };

                # Given a libcall like      "gtk_foo( /*bar_to_int bar*/i0, /*zot*/i1 )"
                # and a parameter name like  "i0" or "i1"
                # return nickname like       "bar" or "zot"
                # if available, else         "i0" or "i1":
                #
                fun param_name (arg, libcall)
                    =
                    {   regex = .|/\*([A-Za-z0-9_' ]+)\*/| + arg;               # Something like:   /*([A-Za-z0-9_' ]+)*/f0
                        #
                        case (regex::find_first_match_to_ith_group 1 regex libcall)
                            #
                            THE name => # If 'name' contains blanks, we want
                                        # only the part after the last blank:
                                        # 
                                        case (regex::find_first_match_to_ith_group 1 .|^[:A-Za-z0-9_' ]+ ([A-Za-z0-9_']+)$| name)
                                            THE x => x;
                                            NULL  => name;
                                        esac;
                            NULL => arg;
                        esac;
                    };

                # Synthesize a function for   gtk-client-g.pkg  like
                # 
                #        #
                #        fun make_vertical_scale_with_range (session: Session, min, max, step)
                #            =
                #           drv::make_vertical_scale_with_range (session.subsession, min, max, step);
                #
                fun build_plain_fun_for_'xxx_client_g_pkg'  (pfs:  Pfs)   (x: Builder_Stuff,  fields: Fields, fn_name, libcall)
                    =
                    case (maybe_get_field (fields, "cg-funs"))
                        #
                        THE field
                            =>
                            {   pfs = to_xxx_client_g_pkg_funs  pfs  "        #\n";
                                pfs = to_xxx_client_g_pkg_funs  pfs  field;
                                pfs = to_xxx_client_g_pkg_funs  pfs  "            \n";
                                pfs = to_xxx_client_g_pkg_funs  pfs  "            # Above function handbuilt via src/lib/make-library-glue/make-library-glue.pkg: build_plain_fun_for_'xxx_client_g_pkg'.\n";
                                pfs = to_xxx_client_g_pkg_funs  pfs  "\n";

                                plain_fns_handbuilt_for_'xxx_client_g_pkg'
                                    :=
                                    *plain_fns_handbuilt_for_'xxx_client_g_pkg' + 1;

                                pfs;
                            };

                        NULL =>
                            {
                                arg_count = count_args( libcall );
                                #
                                fun make_args  pfs  get_name            # get_name will be arg_name or param_name.
                                    =
                                    {
                                        pfs =   for (a = 0, pfs = pfs;  a < arg_count;  ++a;  pfs) {

                                                    # Remember type of this arg,
                                                    # which will be one of:
                                                    #   w (widget),
                                                    #   i (int),
                                                    #   b (bool)
                                                    #   s (string)
                                                    #   f (double):
                                                    #
                                                    arg_type = get_nth_arg_type( a, libcall );

                                                    arg = sprintf "%s%d" arg_type a;

                                                    pfs = to_xxx_client_g_pkg_funs  pfs  (sprintf ", %s" (get_name (arg, libcall)));

                                                    pfs;
                                                }; 

                                        pfs;
                                    };

                                # Select between  foo  (session.subsession, bar, zot);
                                #                 foo { session.subsession, bar, zot };
                                #
                                my (lparen, rparen)
                                    =
                                    # It is a poor idea to have xxx-client-g.pkg functions
                                    # with multiple arguments of the same type use
                                    # argument tuples, because it is too easy to
                                    # mis-order such arguments, and the compiler
                                    # type checking won't flag it -- in such cases
                                    # it is better to use argument records:
                                    #
                                    arg_types_are_all_unique  libcall
                                        ??  ( "(" ,  ")" )
                                        ::  ( "{ ", " }" );

                                pfs = to_xxx_client_g_pkg_funs pfs "\n";
                                pfs = to_xxx_client_g_pkg_funs pfs "        #\n";
                                pfs = to_xxx_client_g_pkg_funs pfs "        fun ";
                                pfs = to_xxx_client_g_pkg_funs pfs fn_name;


                                pfs = to_xxx_client_g_pkg_funs pfs (sprintf " %ssession: Session"  lparen);

                                pfs = make_args pfs  param_name;

                                pfs = to_xxx_client_g_pkg_funs pfs (sprintf "%s\n" rparen);


                                # Select between  drv::foo   session.subsession;
                                #                 drv::foo  (session.subsession, bar, zot);
                                #
                                my (lparen, rparen)
                                    =
                                    arg_count == 0
                                        ??  (" ", "" )
                                        ::  ("(", ")");

                                fn_name =   regex::replace_all ./'/ "2" fn_name;                # Primes don't work in C!

                                pfs = to_xxx_client_g_pkg_funs pfs          "            =\n";
                                pfs = to_xxx_client_g_pkg_funs pfs (sprintf "            drv::%s %ssession.subsession" fn_name lparen);

                                pfs = make_args pfs  arg_name;

                                pfs = to_xxx_client_g_pkg_funs pfs (sprintf "%s;\n" rparen);

                                pfs = to_xxx_client_g_pkg_funs pfs  "            \n";
                                pfs = to_xxx_client_g_pkg_funs pfs ("            # Above function autobuilt by src/lib/make-library-glue/make-library-glue.pkg:  build_plain_fun_for_'xxx_client_g_pkg'  per  " + path.construction_plan + ".\n");
                                pfs = to_xxx_client_g_pkg_funs pfs  "\n";


                                plain_fns_codebuilt_for_'xxx_client_g_pkg'
                                    :=
                                    *plain_fns_codebuilt_for_'xxx_client_g_pkg'
                                    + 1;

                                pfs;
                            };
                    esac;

                # Synthesize a xxx-client.api line like
                #
                #      make_window:    Session -> Widget;
                #
                stipulate

                    line_count = REF 2;

                herein

                    #
                    fun build_fun_declaration_for_'xxx_client_api'  (pfs: Pfs)  { fn_name, fn_type, api_doc }
                        =
                        {
                            # Add a blank line every three declarations:
                            #
                            line_count := *line_count + 1;

                            pfs =   if ((*line_count % 3) == 0)
                                        #
                                        to_xxx_client_api_funs  pfs  "\n";
                                    else
                                        pfs;    
                                    fi;

                            # The 'if' here is just to exdent by one char
                            # types starting with a paren, so that we get
                            #
                            #     foo:    Session -> Void;
                            #     bar:   (Session, Widget) -> Void;
                            #
                            # rather than the slightly rattier looking  
                            #
                            #     foo:    Session -> Void;
                            #     bar:    (Session, Widget) -> Void;
                            #
                            pfs =   if (fn_type =~ ./^\(/)      to_xxx_client_api_funs pfs (sprintf "    %-40s%s;\n"  (fn_name + ":")  fn_type);
                                    else                        to_xxx_client_api_funs pfs (sprintf "    %-41s%s;\n"  (fn_name + ":")  fn_type);
                                    fi;

                            pfs =   if (api_doc != "")          to_xxx_client_api_funs pfs api_doc;
                                    else                        pfs;
                                    fi;

                            pfs;
                        };
                end;


                #
                fun figure_function_result_type  (x: Builder_Stuff,  fields: Fields,  fn_name,  fn_type)
                    =
                    # result_type can be "Int", "String", "Bool", "Float" or "Void".
                    #
                    # It can also be "Widget" or "new Widget", the difference being
                    # that in the former case the mythryl-xxx-library-in-c-subprocess.c logic can merely
                    # fetch it out of its array  widget[],  whereas in the latter a
                    # new entry is being created in  widget[].
                    #
                    # We can usually deduce the difference:  If fn_name starts with
                    # "make_" then we have the "new Widget" case, otherwise we have
                    # the "Widget" case:
                    #
                    case (maybe_get_field (fields, "result"))
                        #
                        THE string => string;
                        #
                        NULL =>
                            # Pick off terminal  " -> Void"
                            # or whatever from fn_type
                            # and switch on it:
                            #
                            case (regex::find_first_match_to_ith_group 1 ./->\s*([A-Za-z_']+)\s*$/ fn_type)
                                #
                                THE "Bool"   => "Bool";
                                THE "Float"  => "Float";
                                THE "Int"    => "Int";
                                THE "String" => "String";
                                THE "Void"   => "Void";

                                THE result_type =>  case (sm::get (*figure_function_result_type_fns, result_type))                              # Cf figure_function_result_type in   src/opt/gtk/sh/make-gtk-glue
                                                        #
                                                        THE function =>  function  fn_name;                                                     # E.g., "Widget" -> ("Widget" or "new Widget")
                                                        #
                                                        NULL =>         {   printf "SupporTed result types:\n";
                                                                        print_strings (sm::keys_list  *figure_function_result_type_fns);

                                                                        die_x(sprintf "Unsupported result fn-type %s in type %s at %s..\n"
                                                                                       result_type
                                                                                       fn_type
                                                                                      (get_field_location (fields, "fn-type"))
                                                                             );
                                                                    };
                                                    esac;
                                NULL => die_x(sprintf "UNsupported result fn-type %s at %s..\n"
                                                     fn_type
                                                     (get_field_location (fields, "fn-type"))
                                            );
                            esac;
                    esac;

                #
                fun build_plain_function  { patchfiles,  paragraph: plf::Paragraph,  x: Builder_Stuff }
                    =
                    {   
                        pfs     =  patchfiles;
                        fields  =  paragraph.fields;

                        fn_name =  get_field (fields, "fn-name");                                       # E.g., "make_window".
                        fn_type =  get_field (fields, "fn-type");                                       # E.g., "Session -> Widget".
                        libcall =  get_field (fields, "libcall");                                       # E.g., "gtk_window_new( GTK_WINDOW_TOPLEVEL )".

                        url     =   case (maybe_get_field(fields,"url"))      THE field =>  field;  NULL =>  "";   esac;
                        api_doc =   case (maybe_get_field(fields,"api-doc"))  THE field =>  field;  NULL =>  "";   esac;

                        c_fn_name =  regex::replace_all  ./'/  "2"  fn_name;                            # C fn names cannot contain apostrophes.

                        result_type =  figure_function_result_type  (x, fields, fn_name, fn_type);

                        pfs = build_trie_entry_for_'mythryl_xxx_library_in_c_subprocess_c' pfs (           c_fn_name );
                        pfs = build_plain_fun_for_'mythryl_xxx_library_in_c_subprocess_c'  pfs (x, fields, c_fn_name, fn_type, libcall, result_type);

                        pfs = build_plain_fun_for_'libmythryl_xxx_c'                       pfs (x, fields, c_fn_name, fn_type, libcall, result_type);
                        pfs = build_table_entry_for_'libmythryl_xxx_c'                     pfs            (c_fn_name, fn_type);


                        pfs = note__section_libref_xxx_tex__entry  pfs  { fields, fn_name, libcall, url, fn_type };

                        pfs = build_fun_declaration_for_'xxx_client_driver_api'                                 pfs {    c_fn_name, libcall, result_type };
                        pfs = build_fun_definition_for_'xxx_client_driver_for_library_in_c_subprocess_pkg'      pfs {    c_fn_name, libcall, result_type };

                        pfs = build_fun_declaration_for_'xxx_client_api'                                        pfs { fn_name, fn_type, api_doc };
                        pfs = build_fun_definition_for_'xxx_client_driver_for_library_in_main_process_pkg'      pfs { fn_name, c_fn_name, fn_type, libcall, result_type };

                        pfs = build_plain_fun_for_'xxx_client_g_pkg'                                            pfs (x, fields, fn_name, libcall);

                        pfs;
                    };


                #
                fun build_function_doc { patchfiles,  paragraph: plf::Paragraph,  x: Builder_Stuff }
                    =
                    {   
                        pfs      =  patchfiles;
                        fields   =  paragraph.fields;

                        url    = case (maybe_get_field(fields,"url"))
                                     #  
                                     THE field => field;
                                     NULL      => "";
                                 esac;

                        fn_name  =  get_field(fields, "fn-name");       # "make_window" or such.
                        fn_type  =  get_field(fields, "fn-type");       # "Session -> Widget" or such.

                        pfs =  note__section_libref_xxx_tex__entry  pfs  { fields, fn_name, libcall => "", url, fn_type };

                        pfs;
                    };


                #
                fun build_mythryl_type  { patchfiles,  paragraph: plf::Paragraph,  x: Builder_Stuff }
                    =
                    {   
                        pfs      =  patchfiles;
                        fields   =  paragraph.fields;

                        type     =  get_field(fields, "cg-typs");
                        #
                        pfs      =  to_xxx_client_api_types     pfs     type;
                        pfs      =  to_xxx_client_g_pkg_types   pfs     type;

                        pfs;
                    };
                #
                fun build_mythryl_code  { patchfiles,  paragraph: plf::Paragraph,  x: Builder_Stuff }
                    =
                    {   
                        pfs      =  patchfiles;
                        fields   =  paragraph.fields;

                        code     =  get_field(fields, "cg-funs");
                        #
                        pfs = to_xxx_client_g_pkg_funs  pfs  code;

                        pfs;
                    };











                fn_doc__definition
                    =
                    { name   => "fn_doc",
                      do     =>  build_function_doc,
                      fields => [ { fieldname => "fn-name",  traits => [] },
                                  { fieldname => "fn-type",  traits => [] },
                                  { fieldname => "doc-fn",   traits => [ plf::OPTIONAL ] },
                                  { fieldname => "url",      traits => [ plf::OPTIONAL ] }
                                ]
                    };

                plain_fn__definition
                    =
                    { name   => "plain_fn",
                      do     =>  build_plain_function,
                      fields => [ { fieldname => "fn-name",  traits => [] },
                                  { fieldname => "fn-type",  traits => [] },
                                  { fieldname => "libcall",  traits => [] },
                                  { fieldname => "libcal+",  traits => [ plf::OPTIONAL, plf::DO_NOT_TRIM_WHITESPACE, plf::ALLOW_MULTIPLE_LINES ] },
                                  { fieldname => "lowtype",  traits => [ plf::OPTIONAL ] },
                                  { fieldname => "result",   traits => [ plf::OPTIONAL ] },
                                  { fieldname => "api-doc",  traits => [ plf::OPTIONAL ] },
                                  { fieldname => "doc-fn",   traits => [ plf::OPTIONAL ] },
                                  { fieldname => "url",      traits => [ plf::OPTIONAL ] },
                                  { fieldname => "cg-funs",  traits => [ plf::OPTIONAL, plf::DO_NOT_TRIM_WHITESPACE, plf::ALLOW_MULTIPLE_LINES ] }
                                ]
                    };

                mythryl_code__definition
                    =
                    { name   => "mythryl_code",
                      do     =>  build_mythryl_code,
                      fields => [ { fieldname => "cg-funs",  traits => [ plf::DO_NOT_TRIM_WHITESPACE, plf::ALLOW_MULTIPLE_LINES ] }
                                ]
                    };

                mythryl_type__definition
                    =
                    { name   => "mythryl_type",
                      do     =>  build_mythryl_type,
                      fields => [ { fieldname => "cg-typs",  traits => [ plf::DO_NOT_TRIM_WHITESPACE, plf::ALLOW_MULTIPLE_LINES ] }
                                ]
                    };




                builder_stuff =   { path,
                                    #
                                    maybe_get_field,
                                          get_field,
                                          get_field_location,
                                    #
                                    build_table_entry_for_'libmythryl_xxx_c',
                                    build_trie_entry_for_'mythryl_xxx_library_in_c_subprocess_c',
                                    #   
                                    build_fun_declaration_for_'xxx_client_api',
                                    build_fun_declaration_for_'xxx_client_driver_api',
                                    build_fun_definition_for_'xxx_client_driver_for_library_in_c_subprocess_pkg',
                                    build_fun_definition_for_'xxx_client_driver_for_library_in_main_process_pkg',

                                    to_xxx_client_driver_api,
                                    to_xxx_client_driver_for_library_in_c_subprocess_pkg,
                                    to_xxx_client_driver_for_library_in_main_process_pkg,
                                    to_xxx_client_g_pkg_funs,
                                    to_xxx_client_g_pkg_types,
                                    to_xxx_client_api_funs,
                                    to_xxx_client_api_types,
                                    to_mythryl_xxx_library_in_c_subprocess_c_funs,
                                    to_mythryl_xxx_library_in_c_subprocess_c_trie,
                                    to_libmythryl_xxx_c_table,
                                    to_libmythryl_xxx_c_funs,
                                    to_section_libref_xxx_tex_apitable,
                                    to_section_libref_xxx_tex_libtable,

                                    custom_fns_codebuilt_for_'libmythryl_xxx_c',
                                    custom_fns_codebuilt_for_'mythryl_xxx_library_in_c_subprocess_c',
                                    callback_fns_handbuilt_for_'xxx_client_g_pkg',

                                    note__section_libref_xxx_tex__entry
                                  };


                paragraph_defs
                    =
                    plf::digest_paragraph_definitions   sm::empty   "make-library-glue.pkg"
                        #
                        ( paragraph_definitions
                          @
                          [
                            fn_doc__definition,
                            plain_fn__definition,
                            mythryl_code__definition,
                            mythryl_type__definition
                          ]
                        );
            end;
    };
end;

###################################################################################
# Note[1]:  Format of             xxx-construction.plan               files
#
# These notes are outdated;  should look at
#     src/lib/make-library-glue/planfile.api
# and
#     *__definition
# above.  Should write more docs, too. :-)
#
#
# An xxx-construction.plan file is broken
# into logical paragraphs separated by blank lines.
#
# In general each paragraph describes one end-user-callable
# function in (say) the Gtk API.
#
# Each paragraph consists of one or more lines;
# each line begins with a colon-delimited type
# field determining its semantics.
#
# Supported line types are:
#
#     do:  Must appear in every paragraph.
#               Determines which make-library-glue function processes the paragraph:
#                   plain_fn       build_plain_function      # The usual case.
#                   callback_fn    build_callback_function   # Special-purpose variant.
#                   fn_doc         build_function_doc        # Document fn without code generation, e.g. for Mythryl-only fns.
#                   mythryl_code   build_mythryl_code        # Special hack to deposit verbatim Mythryl code.
#                   mythryl_type   build_mythryl_type        # Special hack to deposit verbatim Mythryl declarations.
#
#     The 'do' line determines which other
#     lines may appear in the paragraph, per the
#     following table. ("X" == mandatory, "O" == optional):
#
#                  callback_fn   fn_doc   plain_fn   mythryl_code  mythryl_type
#                  -----------   ------   --------   ------------  -----------
#
#         fn-name:      X           X         X
#         fn-type:      X           X         X
#         lowtype:      X                     X
#         libcall:                            X
#         libcal+:                            O
#         result:                             O
#         api-doc:                            O
#         doc-fn:       O           O         O
#         url:          O           O         O
#         cg-funs:      O                     O            X
#         cg-typs:                                                    X
#
#
#     fn-name:  Name of the end-user-callable Mythryl function,   e.g. halt_and_catch_fire
#     fn-type:  Mythryl type for the function,                    e.g. Int -> Void
#     url:      URL documenting the underlying C Gtk function,    e.g. http://library.gnome.org/devel/gtk/stable/gtk-General.html#gtk-init
#     cg-funs:  Literal Mythryl code to be inserted near bottom of xxx-client-g.pkg
#     cg-typs:  Literal Mythryl code to be inserted near top    of xxx-client-g.pkg and also in xxx-client.api
#     lowtype:  Gtk cast macro for widget: Usually G_OBJECT, occasionally GTK_MENU_ITEM or such.
#
#     doc-fn:   Usually name of fn for documentation purposes is obtained from 'libcall' line,
#               but this line may be used to specify it explicitly.
#
#     api-doc:  Comment line(s) to be appended to fn declaration in xxx-client.api.
#
#     libcall:  C-level library call to make                          e.g. gtk_layout_put( GTK_LAYOUT(w0), GTK_WIDGET(w1), i2, i3)
#
#               libcall contains embedded arguments like w0, i1, f2, b3, s4.
#               
#               The argument letter gives us the argument type:
#               
#                  w == widget
#                  i == int
#                  f == double  (Mythryl "Float")
#                  b == bool
#                  s == string
#               
#               The argument digit gives us the argument order:
#               
#                  0 == first arg
#                  1 == second arg
#                  ...
#
#     libcal+:  More code to be inserted immediately after the 'libcall' code
#               in libmythryl-xxx.c and mythryl-xxx-library-in-c-subprocess.c.
#
#     result:   C-level result type for call.  In practice we always default
#               this and make-library-glue deduces it from the Mythryl type.
#               #
#               Can be one of "Int", "String", "Bool", "Float" or "Void".
#               #
#               Can also be "Widget" or "new Widget", the difference being
#               that in the former case the mythryl-gtk-server.c logic can merely
#               fetch it out of its array  widget[],  whereas in the latter a
#               new entry is being created in  widget[].
#               #
#               We can usually deduce the difference:  If fn_name starts with
#               "make_" then we have the "new Widget" case, otherwise we have
#               the "Widget" case:



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext