%%
%% NOTE: switches-by-context-fn.R is to be edited (if necessary) in inst/misc
%%
\documentclass[10pt,a4paper]{article}
\usepackage{verbatim}
\usepackage[top=1.0cm,bottom=1.5cm,left=1.0cm,right=1.0cm]{geometry}
\usepackage{longtable} %,booktabs}
\usepackage[utf8]{inputenc}
\usepackage[pdftex,bookmarks,colorlinks,linkcolor=blue]{hyperref}
\usepackage{listings}
\usepackage{array}
\usepackage{framed}
\usepackage{Sweave}
\usepackage{placeins} % for FloatBarrier
\usepackage[tablewithin=section]{caption}
%% formatting
% use a san-serif font for online display
\renewcommand\familydefault{cmss}
\usepackage{parskip}
\newcommand{\Lsmc}[1]{\small #1}
\title{Switch Summary by Context}
%\VignetteIndexEntry{Switch Summary by Context}
%\SweaveUTF8
%
\begin{document}
%\maketitle
%\tableofcontents
\SweaveSyntax{SweaveSyntaxLatex}
%
% First we need to download the switches summary file from
% https://reduce-algebra.sourceforge.io. This was originally switches.php, but following
% the PHP critical security issue covered by CVE-2026-109618 and CVE-2026-109619 has been
% renamed by SourceForge to switches.php.html and is a static file (all .php have been
% renamed to .php.html). In fact it has been static since Jan 2025 as Francis Wright
% discovered. He plans to change how the web site to a static one built by code but will
% leave the names as .php.html in the meantime.
%
% In order to do this we need to define the function php2txt() which downloads the first
% file in the list c(switches.php.html, switches.html, switches.php) that it finds to
% hopefully avoid having to publish a new version of redcas if the name changes. It saves
% the timestamp in the file to avoid recreating the vignette if the time stamp has not
% changed. It then converts HTML markup to LaTeX markup and writes the modified file to
% the file named in the "out" argument or switches.data.time-stamp if out is missing.
%
% We also define txt2tex() which produces the tables for each context.
%
\begin{Scode}{echo=false}
## Function: getSwitches: download whichever switches file is present
## Args:
## urls: vector of the possible (base)names of the switches file
## Value: list of two elements:
## 1. name of downloaded file or "none" if download failed
## 2. vector of the contents of the downloaded file
getSwitches <- function (urls) {
## we'll return the first one that does not fail
for (i in 1:length(urls)) {
switches <- tryCatch(readLines(ucon <- url(urls[i]), warn=FALSE),
warning=function(w) FALSE,
error=function(e) FALSE)
close(ucon)
if (is.logical(switches)) {
if (i == length(urls)) {
message("Switches document could not be downloaded.")
swname <- "none"
switches <- ""
}
next
} else {
message("Downloading ", urls[i])
swname <- basename(urls[i])
break
}
}
return(list(swname, switches))
}
## Function: php2txt: download and create a text file with HTML markup converted to LaTeX
## Args:
## out: character, optional. file name for converted switch.html. Default is
## switch.data.mod-date
## Value: only side-effects:
## 1. create switches.data.last-mod-date containing html converted to LaTeX
## 2. create switches.last.update.RDS containing dates of downloaded pages,
## most recent first.
php2txt <- function(out) {
## download, or read from local copy if already downloaded today
phpfiles <- c("switches.html", "switches.php.html", "switches.php")
## download but avoid downloading multiple times on the same day
if (file.exists(phpfiles[1]) && as.Date(file.mtime(phpfiles[1])) == Sys.Date() ) {
message("note: reading local switches.html")
sw.1 <- list("switches.html", readLines("switches.html"))
} else {
sw.1 <- getSwitches(paste0("https://reduce-algebra.sourceforge.io/", phpfiles))
if (sw.1[[1]] == "none") stop("Cannot create switches-by-context.tex. Stopping.")
writeLines(sw.1[[2]], phpfiles[1])
}
## input has invalid utf8 chars x201C (“), x201D (”), x2019 (’) and x2013 (–) on
## various records. Neither Sweave nor texi2dvi like this. So preamble includes
## [utf8]{inputenc} and the SweaveUTF8 command
sw.1[[2]] <- gsub('[“”]', '"', sw.1[[2]])
sw.1[[2]] <- gsub('’', "'", sw.1[[2]])
sw.1[[2]] <- gsub("–", "-", sw.1[[2]])
## check whether the page has been updated since last fetch
if (file.exists("switches.last.update.RDS")) {
switches.last.update <- readRDS("switches.last.update.RDS")
} else {
switches.last.update <- as.Date("1970-01-01")
}
if (length(plm.idx <- grep("Page last modified on", sw.1[[2]])) == 0) {
stop("Could not find \"Page last modified on\".")
} else {
page.mod.date <- as.Date(gsub("(^ *|st|nd|rd|th|\\.)", "", sw.1[[2]][plm.idx+1]),
"%A %e %B %Y")
if (page.mod.date <= switches.last.update[1]) {
message(
paste0("note: nothing to do https://reduce-algebra.sourceforge.io/", sw.1[[1]],
"\n not updated since last download."))
q("no")
} else {
pmd.sfx <- as.character(page.mod.date)
if (missing(out)) out <- paste0("switches.data.", pmd.sfx)
}
}
## find the start/end of the two tables (tbody) and extract them
sw.idx <- which(grepl("?tbody",sw.1[[2]],ignore.case=TRUE))
sw.doc <- sw.1[[2]][(sw.idx[1]+1):(sw.idx[2]-1)]
sw.undoc <- sw.1[[2]][(sw.idx[3]+1):(sw.idx[4]-1)]
## convert html markup to LaTeX markup. This is partly very specialized (handling of xi)
h2l <- c(
## needs to be before ?em> translation
"&radic[^.]+.", "$\\\\sqrt{x^2}$ to $|x|$.",
"→", "$\\\\rightarrow$",
"?code>", "$",
"", "{\\\\it ",
"", "}",
"_", "\\\\_",
## must be after _ -> \_ but before
"ξ([^<]+)", "$\\\\xi_\\1$",
"([^<]+)", "$^\\1$",
"([^<]+)", "$_\\1$",
"?span[^>]*>", "",
"–", "",
"([^$])ξ", "\\1$\\\\xi$",
"<", "",
">", "",
""", "\042",
" ", " "
)
sw.from <- h2l[seq(1, length(h2l), 2)]
sw.to <- h2l[seq(2, length(h2l), 2)]
for (i in 1:length(sw.from)) sw.doc <- gsub(sw.from[i], sw.to[i], sw.doc)
## create data frame for sw.doc. This assumes that each table row consists of 6 lines of
## text: tr, 4x th/td and /tr
sw.doc.len <- length(sw.doc)
sw.doc.df <- data.frame(
switch=gsub("( +| | | )", "", sw.doc[seq(2, sw.doc.len, 6)]),
state=gsub("( +| | )", "", sw.doc[seq(3, sw.doc.len, 6)]),
context=gsub("( +| | )", "", sw.doc[seq(4, sw.doc.len, 6)]),
description=paste0(gsub("( +| | )", "", sw.doc[seq(5, sw.doc.len, 6)]),
" \\\\")
)
write.table(sw.doc.df, out, quote=FALSE, sep="\t", row.names=FALSE)
message(paste("note: wrote converted ", phpfiles[1], " to ", out))
## save this modification date (stack)
switches.last.update <- c(page.mod.date, switches.last.update)
saveRDS(switches.last.update, "switches.last.update.RDS")
return(pmd.sfx)
}
## Function: txt2tex: return formatted LaTeX for a context type
## Args:
## date.idx: integer, required. index of desired update date. Default: 1, most recent
## date.suffix: logical, required. Use modification date as file suffix. Default: TRUE
## type: char, general or package. Default: general
## longtable: logical, required. Use longtable or table/tabular. Default: FALSE
## fsize: logical, wrap each column in \Lsmc{}. \Lsmc is defined in the Rnw file
## Value: only side-effects: create switches.last-mod-date.tex|pdf
txt2tex <- function(date.idx=1, date.suffix=TRUE, type="general", longtable=FALSE, fsize=FALSE) {
pmd.date <- readRDS("switches.last.update.RDS")[date.idx]
pmd.sfx <- paste0(".", pmd.date)
idata <- paste0("switches.data", if (date.suffix) pmd.sfx else "")
## Read the data
switches <- read.table(idata, header = TRUE, sep = "\t", quote="",
colClasses = c('character','character','character','character'))
if (fsize) {
for (var in c('switch','state','description')) {
switches[,var] <- paste0("\\Lsmc{", switches[,var], "}")
}
}
isGeneral <- grepl("([A-Z][a-z]+|\\*)", switches$context)
if (tolower(type) == "general") {swtype <- switches[which(isGeneral),] }
else {swtype <- switches[which(!isGeneral),] }
sw.by.c <- swtype[order(swtype$context), c('context','switch','state','description')]
## in order to have * (global) as first table, this must be done no earlier than here
if (any(c.global <- grepl("^\\*$", sw.by.c$context))) {
sw.by.c$context[which(c.global)] <- "Global"
}
## debugging
## return(sw.by.c)
## end debugging
## by context
contexts <- unique(sw.by.c$context)
## for default size >10pt some contexts need longtable so define separate begin/end
## for longtable and table. Order of caption differs too. By using
## caption[]{continued} in the endhead, duplicated entries in LoT are avoided when a
## table spans pages.
tab.head <- "\\bfseries{Switch} & \\bfseries{Default} & \\bfseries{Effect} \\\\"
hline <- "\\hline"
topline <- hline #"\\toprule"
botline <- hline #"\\bottomrule"
txt.c <- vector("character")
for (context in contexts) {
this.context <- sw.by.c[sw.by.c$context == context,c('switch','state','description')]
## to get hyphenation working in the switch column
## if (any(nchar(this.context$switch) > 15)) {
## this.context$switch <- paste0("\\hspace{0pt}", this.context$switch)
## }
this.context$switch <- ifelse(nchar(this.context$switch) > 18,
sub("\\_", "\\_\\\\\\\\", this.context$switch),
this.context$switch)
txt.c <- c(txt.c,
if (longtable) {
c("\n\\begin{longtable}[c]{p{4cm}lp{10cm}}",
paste0("\\caption{", context, "}\\\\"), ## needs newline in longtable
tab.head, topline, "\\endfirsthead",
"\\caption[]{(continued)}\\\\",
tab.head, topline, "\\endhead"
)
} else {
c("\n\\begin{table}[hp]",
"\\begin{center}",
paste0("\\caption{", context, "}"),
"\\begin{tabular}{p{4cm}lp{10cm}}",
tab.head, topline
)
},
apply(this.context, 1, paste, collapse = " & "),
botline,
if (longtable) {
"\\end{longtable}\n"
} else {
c("\\end{tabular}", "\\end{center}", "\\end{table}\n")
}
)
}
return(txt.c)
}
pmd.date <- php2txt()
\end{Scode}
\section*{Switch Summary by Context \Sexpr{pmd.date}}
\label{sec:introduction}
This document list switches available within REDUCE via the commands {\it ON} and {\it
OFF}. The switches are presented by context. Section~\ref{sec:general} covers switches
which are not specific to a package while Section~\ref{sec:package} shows package-specific
ones. For an alphabetical listing see the online
\href{https://reduce-algebra.sourceforge.io/switches.html}{REDUCE Switch Summary} from which this
document is derived.
See appendix~\ref{sec:rebuild} for instructions on how to rebuild this document.
\listoftables
\newpage
\section{Switch summary by context: general switches}
\label{sec:general}
\begin{Scode}{label=update, echo=FALSE, results=tex}
writeLines(swgen <- txt2tex(date.idx=1, date.suffix=TRUE, type="general", longtable=FALSE))
\end{Scode}
\FloatBarrier
\section{Switch summary by context: package-specific switches}
\label{sec:package}
\begin{Scode}{label=update, echo=FALSE, results=tex}
writeLines(swpkg <- txt2tex(date.idx=1, date.suffix=TRUE, type="package", longtable=FALSE))
\end{Scode}
\FloatBarrier
\appendix
\section{Rebuilding this document}
\label{sec:rebuild}
This document was created using the source for this vignette, {\it
switches-by-context.Rnw}, which includes all the code necessary for downloading the
\href{https://reduce-algebra.sourceforge.io/switches.html}{Switch Summary} page and
building this vignette. Since the switch summary may change, a new version of this
document may be created by saving the Rnw file to a directory of your choice and executing
it using {\textit R CMD Sweave -{}-pdf}. The first time this is run it saves the last
update date from the Switch Summary to {\it switches.last.update.RDS} and on subsequent
runs only updates if the date in the current Switch Summary is later. To unconditionally
update, delete or rename {\it switches.last.update.RDS} prior to executing {\textit
Sweave}.
Note that updating the actual vignette in the package requires a new version of the
package.
\end{document}