void gs_lib_ctx_fin(gs_memory_t *mem)
{
    gs_lib_ctx_t *ctx;
    gs_memory_t *ctx_mem;
    int refs, i;
    gs_fs_list_t *fs;
    gs_callout_list_t *entry;

    if (!mem || !mem->gs_lib_ctx)
        return;

    ctx = mem->gs_lib_ctx;
    ctx_mem = ctx->memory;

    sjpxd_destroy(mem);
    gscms_destroy(ctx_mem);
    gs_free_object(ctx_mem, ctx->profiledir,
        "gs_lib_ctx_fin");

    gs_free_object(ctx_mem, ctx->default_device_list,
                "gs_lib_ctx_fin");

    gs_free_object(ctx_mem, ctx->name_table_root, "gs_lib_ctx_fin");
    gs_free_object(ctx_mem, ctx->io_device_table_root, "gs_lib_ctx_fin");
    gs_free_object(ctx_mem, ctx->font_dir_root, "gs_lib_ctx_fin");

#ifndef GS_THREADSAFE
    mem_err_print = NULL;
#endif

    gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
    refs = --ctx->core->refs;
    gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
    if (refs == 0) {
        gx_monitor_free((gx_monitor_t *)(ctx->core->monitor));
#ifdef WITH_CAL
        cal_fin(ctx->core->cal_ctx, ctx->core->memory);
#endif
        gs_purge_scratch_files(ctx->core->memory);
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_reading);
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_writing);
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_control);

        fs = ctx->core->fs;
        while (fs) {
            gs_fs_list_t *next = fs->next;
            gs_free_object(fs->memory, fs, "gs_lib_ctx_fin");
            fs = next;
        }

        entry = ctx->core->callouts;
        while (entry) {
            gs_callout_list_t *next = entry->next;
            gs_free_object(mem->non_gc_memory, entry, "gs_callout_list_t");
            entry = next;
        }

        for (i = 0; i < ctx->core->argc; i++)
            gs_free_object(ctx->core->memory, ctx->core->argv[i], "gs_lib_ctx_arg");
        gs_free_object(ctx->core->memory, ctx->core->argv, "gs_lib_ctx_args");

        gs_free_object(ctx->core->memory, ctx->core, "gs_lib_ctx_fin");
    }
    remove_ctx_pointers(ctx_mem);

    gs_free_object(ctx_mem, ctx, "gs_lib_ctx_init");
}
void gs_lib_ctx_fin(gs_memory_t *mem)
{
    gs_lib_ctx_t *ctx;
    gs_memory_t *ctx_mem;
    int refs, i;
    gs_fs_list_t *fs;
    gs_callout_list_t *entry;

    if (!mem || !mem->gs_lib_ctx)
        return;

    ctx = mem->gs_lib_ctx;
    ctx_mem = ctx->memory;

    sjpxd_destroy(mem);
    gscms_destroy(ctx_mem);
    gs_free_object(ctx_mem, ctx->profiledir,
        "gs_lib_ctx_fin");

    gs_free_object(ctx_mem, ctx->default_device_list,
                "gs_lib_ctx_fin");

    gs_free_object(ctx_mem, ctx->name_table_root, "gs_lib_ctx_fin");
    gs_free_object(ctx_mem, ctx->io_device_table_root, "gs_lib_ctx_fin");
    gs_free_object(ctx_mem, ctx->font_dir_root, "gs_lib_ctx_fin");

#ifndef GS_THREADSAFE
    mem_err_print = NULL;
#endif

    gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
    refs = --ctx->core->refs;
    gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
    if (refs == 0) {
        gx_monitor_free((gx_monitor_t *)(ctx->core->monitor));
#ifdef WITH_CAL
        cal_fin(ctx->core->cal_ctx, ctx->core->memory);
#endif
        gs_purge_scratch_files(ctx->core->memory);
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_reading);
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_writing);
        gs_purge_control_paths(ctx->core->memory, gs_permit_file_control);

        fs = ctx->core->fs;
        while (fs) {
            gs_fs_list_t *next = fs->next;
            gs_free_object(fs->memory, fs, "gs_lib_ctx_fin");
            fs = next;
        }

        entry = ctx->core->callouts;
        while (entry) {
            gs_callout_list_t *next = entry->next;
            gs_free_object(mem->non_gc_memory, entry, "gs_callout_list_t");
            entry = next;
        }

        for (i = 0; i < ctx->core->argc; i++)
            gs_free_object(ctx->core->memory, ctx->core->argv[i], "gs_lib_ctx_arg");
        gs_free_object(ctx->core->memory, ctx->core->argv, "gs_lib_ctx_args");

        gs_free_object(ctx->core->memory, ctx->core, "gs_lib_ctx_fin");
    }
    remove_ctx_pointers(ctx_mem);

    gs_free_object(ctx_mem, ctx, "gs_lib_ctx_init");
}