suppressPackageStartupMessages({
library(purrr)
library(cheddar)
})
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Source all the header files to initiate all the lists of header information.
#
# Header files contain a list of 'spec' objects where a spec is a combo of:
# (1) the doxygen documentation from the original C header file
# (2) the function declaration from the original C header file
#
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
header_files <- list.files(here::here("data-raw/headers-r"), pattern = "\\.R", full.names = TRUE)
header_files %>% walk(source)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Calculate the name of all the header information objects
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
header_names <- tools::file_path_sans_ext(basename(header_files))
header_names <- gsub("-+", "_", header_names)
header_names
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Calculate the output file root name
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
root_names <- gsub("_header", "", header_names)
root_names <- gsub("-header", "", root_names)
root_names <- gsub("_", "-", root_names)
root_names[root_names == 'cairo'] <- 'cairo--'
root_names
i <- 1
func_specs <- get(header_names[i])
root_name <- root_names[i]
all_externs <- c()
all_callmethoddefs <- c()
for (i in seq_along(header_names)) {
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Pick a func_specs and its output root name
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# func_specs <- sdl_video_header
# root_name <- "sdl-video"
func_specs <- get(header_names[i])
root_name <- root_names[i]
cat(header_names[i], "->", root_name, "\n")
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# What functions are marked as 'include'?
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
func_specs <- keep(func_specs, ~isTRUE(.x$include))
names(func_specs)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Text to ignore when parsing function prototype to 'proto' object
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ignore <- c('cairo_public')
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Override some 'enum' types to read as integer types for code generation
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
type_override = c(
int = 'cairo_bool_t',
# cairo.h enums
int = 'cairo_status_t',
int = 'cairo_content_t',
int = 'cairo_format_t',
int = 'cairo_operator_t',
int = 'cairo_antialias_t',
int = 'cairo_fill_rule_t',
int = 'cairo_line_cap_t',
int = 'cairo_line_join_t',
int = 'cairo_text_cluster_flag_t',
int = 'cairo_font_slant_t',
int = 'cairo_font_weight_t',
int = 'cairo_subpixel_order_t',
int = 'cairo_hint_style_t',
int = 'cairo_hint_metrics_t',
int = 'cairo_font_type_t',
int = 'cairo_path_data_type',
int = 'cairo_device_type_t',
int = 'cairo_surface_observer_mode_t',
int = 'cairo_surface_type_t',
int = 'cairo_pattern_type_t',
int = 'cairo_extend_t',
int = 'cairo_filter_t',
int = 'cairo_region_overlap_t',
# cairo-font-face.h
# cairo-pdf.h
int = 'cairo_pdf_version_t',
int = 'cairo_pdf_outline_flags_t',
int = 'cairo_pdf_metadata_t',
# cairo-ps.h
int = 'cairo_ps_level_t',
# cairo-svg.h
int = 'cairo_svg_version_t',
int = 'cairo_svg_unit_t'
)
int_types = c('cairo_status_t')
dbl_types = c()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Helper function to create a full R function from a spec.
# A spec is a combo of:
# (1) the doxygen documentation from the original C header file
# (2) the function declaration from the original C header file
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
create_r <- function(spec) {
# print(spec$proto_text)
proto <- function_prototype_to_proto(
spec$proto_text,
ignore = ignore,
type_override = type_override,
null_allowed = spec$null_allowed
)
roxy <- gtkdoc_to_roxylist(spec$gtkdoc)
roxy <- update_roxylist_with_proto(roxy, proto)
roxy$family <- root_name
roxygen <- roxylist_to_roxygen(roxy)
# roxygen <- proto_to_roxygen(proto)
rfunc <- proto_to_r_function_text(
proto,
int_types = int_types,
dbl_types = dbl_types,
pre = spec$pre,
post = spec$post
)
paste(roxygen, rfunc, sep = "\n")
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Loop over all specs to create all R functions text
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
r_funcs <- NULL
r_funcs <- map_chr(func_specs, create_r)
r_output <- paste(r_funcs, collapse = "\n\n\n")
r_output <- paste("# This file was auto-generated from C headers", r_output, sep = "\n\n")
# cat(r_output)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Save R code to file in the package
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
r_filename <- paste0(root_name, ".R")
r_filename <- here::here("R", r_filename)
writeLines(r_output, r_filename)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define the generate pre-amble/headers/includes for all C files
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
c_includes <- '// This file was auto-generated from C headers
#include <R.h>
#include <Rinternals.h>
#include <Rdefines.h>
#include <cairo/cairo.h>
#include <cairo/cairo-pdf.h>
#include <cairo/cairo-svg.h>
#include <cairo/cairo-ps.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "aaa.h"
#include "R-finalizers.h"'
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Helper function to create a full C function from a spec.
# A spec is a combo of:
# (1) the doxygen documentation from the original C header file
# (2) the function declaration from the original C header file
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
create_c <- function(spec) {
# print(spec$proto_text)
proto <- function_prototype_to_proto(spec$proto_text, ignore = ignore, type_override = type_override,
null_allowed = spec$null_allowed)
proto_to_c_function_text(proto, int_types = int_types, finalizer = spec$finalizer)
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create all the C code
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
c_funcs <- NULL
c_funcs <- map_chr(func_specs, create_c)
c_output <- paste(c_funcs, collapse = "\n\n\n")
c_output <- paste(c_includes, c_output, sep = "\n\n\n")
# cat(c_output)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Output c code to the src/ directory in the package
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
c_filename <- paste0(root_name, ".c")
c_filename <- here::here("src", c_filename)
writeLines(c_output, c_filename)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create some 'init.c' related artefacts.
# Not currently automatically inserted, but they should be
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
create_extern <- function(spec) {
proto <- function_prototype_to_proto(spec$proto_text, ignore = ignore, type_override = type_override,
null_allowed = spec$null_allowed)
proto_to_extern(proto)
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create some 'init.c' related artefacts.
# Not currently automatically inserted, but they should be
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
create_callmethodef <- function(spec) {
proto <- function_prototype_to_proto(spec$proto_text, ignore = ignore, type_override = type_override,
null_allowed = spec$null_allowed)
proto_to_call_method_def(proto)
}
externs <- map_chr(func_specs, create_extern)
externs <- c(paste("//", root_name, ""), externs, "")
all_externs <- c(all_externs, externs)
callmethoddefs <- map_chr(func_specs, create_callmethodef)
callmethoddefs <- paste0(" ", callmethoddefs, ",")
callmethoddefs <- c(paste(" //", root_name, ""), callmethoddefs)
all_callmethoddefs <- c(all_callmethoddefs, callmethoddefs, "")
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Insert definitions into init
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
init_callmethoddefs <- all_callmethoddefs
init_externs <- all_externs
init_file <- here::here("src", "init.c")
init <- readLines(init_file)
cmd_start <- grep("// ---- begin auto-generated callmethoddefs ----", init)
cmd_end <- grep("// ---- end auto-generated callmethoddefs ----", init)
ext_start <- grep("// ---- begin auto-generated externs ----", init)
ext_end <- grep("// ---- end auto-generated externs ----", init)
init <- c(init[1:cmd_start], all_callmethoddefs, init[cmd_end:length(init)])
init <- c(init[1:ext_start], all_externs , init[ext_end:length(init)])
writeLines(init, init_file)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Tidy whitespace
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
system(r"{sed -i '' -e's/[[:space:]]*$//' R/*.R}")
system(r"{sed -i '' -e's/[[:space:]]*$//' src/*.c}")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.