diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
index a8baa1e76adff364388f43b6886798a4c25d58b7..78338d6c6cc4335ed97664ba2bcbe401287e6105 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
@@ -1,31 +1,27 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
+ * Copyright (C) 2001-3 Paul Murrell
+ * Copyright (c) 1998-2013, The R Core Team
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates
  *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * All rights reserved.
  */
 package com.oracle.truffle.r.library.grid;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
@@ -48,4 +44,43 @@ public class GridFunctions {
             return RFFIFactory.getRFFI().getGridRFFI().killGrid();
         }
     }
+
+    public abstract static class ValidUnits extends RExternalBuiltinNode.Arg1 {
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg(0).mustBe(stringValue(), RError.Message.GENERIC, "'units' must be character").asStringVector().mustBe(notEmpty(), RError.Message.GENERIC, "'units' must be of length > 0");
+        }
+
+        @Specialization
+        protected RIntVector validUnits(RAbstractStringVector units) {
+            int[] data = new int[units.getLength()];
+            for (int i = 0; i < data.length; i++) {
+                int code = convertUnit(units.getDataAt(i));
+                if (code < 0) {
+                    throw RError.error(this, RError.Message.GENERIC, "Invalid unit");
+                }
+                data[i] = code;
+            }
+            return RDataFactory.createIntVector(data, RDataFactory.COMPLETE_VECTOR);
+        }
+
+        private enum UnitTab {
+            npc(0);
+
+            private final int code;
+
+            UnitTab(int code) {
+                this.code = code;
+            }
+        }
+
+        private static int convertUnit(String unit) {
+            for (UnitTab unitTab : UnitTab.values()) {
+                if (unit.equals(unitTab.name())) {
+                    return unitTab.code;
+                }
+            }
+            return -1;
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.native/gnur/patchXzMakefile b/com.oracle.truffle.r.native/gnur/patchXzMakefile
deleted file mode 100644
index ade46f7204cff323fc8e03b1401c4d3101260480..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/gnur/patchXzMakefile
+++ /dev/null
@@ -1,3 +0,0 @@
-/\$rm -f/s/\$rm/@rm/
-w
-q
diff --git a/com.oracle.truffle.r.native/library/grid/Makefile b/com.oracle.truffle.r.native/library/grid/Makefile
index f128fcf8a4ea847d045bd6a86eda6d24ffe6ae27..58f1789a96f7caa5c52cb451e834c8d46302b4de 100644
--- a/com.oracle.truffle.r.native/library/grid/Makefile
+++ b/com.oracle.truffle.r.native/library/grid/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -21,4 +21,14 @@
 # questions.
 #
 
+OBJ = lib
+
+GNUR_C_FILES := $(notdir $(wildcard $(GNUR_HOME)/src/library/grid/src/*.c))
+
+GNUR_C_OBJECTS := $(addprefix $(OBJ)/, $(GNUR_C_FILES:.c=.o))
+#$(info GNUR_C_OBJECTS=$(GNUR_C_OBJECTS))
+
 include ../lib.mk
+
+$(OBJ)/%.o: $(GNUR_SRC)/%.c
+	$(CC) $(CFLAGS) $(INCLUDES)  $(SUPPRESS_WARNINGS) -c $< -o $@
diff --git a/com.oracle.truffle.r.native/library/grid/src/gpar.c b/com.oracle.truffle.r.native/library/grid/src/gpar.c
deleted file mode 100644
index e98b81e902dfa826d88ab39e060287cd64a38f40..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/gpar.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include "grid.h"
-#include <string.h>
-
-
-extern int gridRegisterIndex;
-
-/* Some access methods for gpars */
-SEXP gpFontSizeSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_FONTSIZE);
-}
-
-double gpFontSize(SEXP gp, int i) {
-    SEXP fontsize = gpFontSizeSXP(gp);
-    return REAL(fontsize)[i % LENGTH(fontsize)];
-}
-
-SEXP gpLineHeightSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_LINEHEIGHT);
-}
-
-double gpLineHeight(SEXP gp, int i) {
-    SEXP lineheight = gpLineHeightSXP(gp);
-    return REAL(lineheight)[i % LENGTH(lineheight)];
-}
-
-/* grid has no concept of 'colour 0' (bg in base) */
-int gpCol(SEXP gp, int i) {
-    SEXP col = VECTOR_ELT(gp, GP_COL);
-    int result;
-    if (isNull(col))
-	result = R_TRANWHITE;
-    else
-	result = RGBpar3(col, i % LENGTH(col), R_TRANWHITE);
-    return result;
-}
-
-SEXP gpFillSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_FILL);
-}
-
-int gpFill(SEXP gp, int i) {
-    SEXP fill = gpFillSXP(gp);
-    int result;
-    if (isNull(fill))
-	result = R_TRANWHITE;
-    else
-	result = RGBpar3(fill, i % LENGTH(fill), R_TRANWHITE);
-    return result;
-}
-
-SEXP gpGammaSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_GAMMA);
-}
-
-double gpGamma(SEXP gp, int i) {
-    SEXP gamma = gpGammaSXP(gp);
-    return REAL(gamma)[i % LENGTH(gamma)];
-}
-
-SEXP gpLineTypeSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_LTY);
-}
-
-int gpLineType(SEXP gp, int i) {
-    SEXP linetype = gpLineTypeSXP(gp);
-    return GE_LTYpar(linetype, i % LENGTH(linetype));
-}
-
-SEXP gpLineWidthSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_LWD);
-}
-
-double gpLineWidth(SEXP gp, int i) {
-    SEXP linewidth = gpLineWidthSXP(gp);
-    return REAL(linewidth)[i % LENGTH(linewidth)];
-}
-
-SEXP gpCexSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_CEX);
-}
-
-double gpCex(SEXP gp, int i) {
-    SEXP cex = gpCexSXP(gp);
-    return REAL(cex)[i % LENGTH(cex)];
-}
-
-SEXP gpFontSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_FONT);
-}
-
-int gpFont(SEXP gp, int i) {
-    SEXP font = gpFontSXP(gp);
-    return INTEGER(font)[i % LENGTH(font)];
-}
-
-SEXP gpFontFamilySXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_FONTFAMILY);
-}
-
-const char* gpFontFamily(SEXP gp, int i) {
-    SEXP fontfamily = gpFontFamilySXP(gp);
-    return CHAR(STRING_ELT(fontfamily, i % LENGTH(fontfamily)));
-}
-
-SEXP gpAlphaSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_ALPHA);
-}
-
-double gpAlpha(SEXP gp, int i) {
-    SEXP alpha = gpAlphaSXP(gp);
-    return REAL(alpha)[i % LENGTH(alpha)];
-}
-
-SEXP gpLineEndSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_LINEEND);
-}
-
-R_GE_lineend gpLineEnd(SEXP gp, int i) {
-    SEXP lineend = gpLineEndSXP(gp);
-    return GE_LENDpar(lineend, i % LENGTH(lineend));
-}
-
-SEXP gpLineJoinSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_LINEJOIN);
-}
-
-R_GE_linejoin gpLineJoin(SEXP gp, int i) {
-    SEXP linejoin = gpLineJoinSXP(gp);
-    return GE_LJOINpar(linejoin, i % LENGTH(linejoin));
-}
-
-SEXP gpLineMitreSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_LINEMITRE);
-}
-
-double gpLineMitre(SEXP gp, int i) {
-    SEXP linemitre = gpLineMitreSXP(gp);
-    return REAL(linemitre)[i % LENGTH(linemitre)];
-}
-
-SEXP gpLexSXP(SEXP gp) {
-    return VECTOR_ELT(gp, GP_LEX);
-}
-
-double gpLex(SEXP gp, int i) {
-    SEXP lex = gpLexSXP(gp);
-    return REAL(lex)[i % LENGTH(lex)];
-}
-
-/*
- * Never access fontface because fontface values are stored in font
- * Historical reasons ...
- */
-
-/*
- * Combine gpar alpha with alpha level stored in colour 
- *
- * finalAlpha = gpAlpha*(R_ALPHA(col)/255)
- *
- * Based on my reading of how group alpha and individual
- * object alphas are combined in the SVG 1.0 docs
- *
- * Also has nice properties:
- *  (i)   range of finalAlpha is 0 to 1.
- *  (ii)  if either of gpAlpha or R_ALPHA(col) are 0 then finalAlpha = 0
- *        (i.e., can never make fully transparent colour less transparent).
- *  (iii) in order to get finalAlpha = 1, both gpAlpha and R_ALPHA(col)
- *        must be 1 (i.e., only way to get fully opaque is if both
- *        alpha levels are fully opaque).
- */
-static unsigned int combineAlpha(double alpha, int col) 
-{
-    unsigned int newAlpha = (unsigned int)((alpha*(R_ALPHA(col)/255.0))*255);
-    return R_RGBA(R_RED(col), R_GREEN(col), R_BLUE(col), newAlpha);
-}
-
-/* 
- * Generate an R_GE_gcontext from a gpar
- */
-void gcontextFromgpar(SEXP gp, int i, const pGEcontext gc, pGEDevDesc dd) 
-{
-    /* 
-     * Combine gpAlpha with col and fill
-     */
-    gc->col = combineAlpha(gpAlpha(gp, i), gpCol(gp, i));
-    gc->fill = combineAlpha(gpAlpha(gp, i), gpFill(gp, i));
-    gc->gamma = gpGamma(gp, i);
-    /*
-     * Combine gpLex with lwd
-     * Also scale by GSS_SCALE (a "zoom" factor)
-     */
-    gc->lwd = gpLineWidth(gp, i) * gpLex(gp, i) * 
-	REAL(gridStateElement(dd, GSS_SCALE))[0];
-    gc->lty = gpLineType(gp, i);
-    gc->lend = gpLineEnd(gp, i);
-    gc->ljoin = gpLineJoin(gp, i);
-    gc->lmitre = gpLineMitre(gp, i);
-    gc->cex = gpCex(gp, i);
-    /*
-     * Scale by GSS_SCALE (a "zoom" factor)
-     */
-    gc->ps = gpFontSize(gp, i) * REAL(gridStateElement(dd, GSS_SCALE))[0];
-    gc->lineheight = gpLineHeight(gp, i);
-    gc->fontface = gpFont(gp, i);
-    strcpy(gc->fontfamily, gpFontFamily(gp, i));
-}
-
-SEXP L_setGPar(SEXP gpars) 
-{
-    /* Set the value of the current gpars on the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    setGridStateElement(dd, GSS_GPAR, gpars);
-    return R_NilValue;
-}
-
-SEXP L_getGPar(void) 
-{
-    /* Get the value of the current gpars on the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_GPAR);
-}
-
-SEXP L_getGPsaved() 
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_GPSAVED);
-}
-
-SEXP L_setGPsaved(SEXP gpars) 
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    setGridStateElement(dd, GSS_GPSAVED, gpars);
-    return R_NilValue;
-}
-
-void initGPar(pGEDevDesc dd)
-{
-    pDevDesc dev = dd->dev;
-    SEXP gpar, gparnames, class;
-    SEXP gpfill, gpcol, gpgamma, gplty, gplwd, gpcex, gpfs, gplh, gpfont;
-    SEXP gpfontfamily, gpalpha, gplineend, gplinejoin, gplinemitre, gplex;
-    SEXP gsd = (SEXP) dd->gesd[gridRegisterIndex]->systemSpecific;
-    PROTECT(gpar = allocVector(VECSXP, 15));
-    PROTECT(gparnames = allocVector(STRSXP, 15));
-    SET_STRING_ELT(gparnames, GP_FILL, mkChar("fill"));
-    SET_STRING_ELT(gparnames, GP_COL, mkChar("col"));
-    SET_STRING_ELT(gparnames, GP_GAMMA, mkChar("gamma"));
-    SET_STRING_ELT(gparnames, GP_LTY, mkChar("lty"));
-    SET_STRING_ELT(gparnames, GP_LWD, mkChar("lwd"));
-    SET_STRING_ELT(gparnames, GP_CEX, mkChar("cex"));
-    SET_STRING_ELT(gparnames, GP_FONTSIZE, mkChar("fontsize"));
-    SET_STRING_ELT(gparnames, GP_LINEHEIGHT, mkChar("lineheight"));
-    SET_STRING_ELT(gparnames, GP_FONT, mkChar("font"));
-    SET_STRING_ELT(gparnames, GP_FONTFAMILY, mkChar("fontfamily"));
-    SET_STRING_ELT(gparnames, GP_ALPHA, mkChar("alpha"));
-    SET_STRING_ELT(gparnames, GP_LINEEND, mkChar("lineend"));
-    SET_STRING_ELT(gparnames, GP_LINEJOIN, mkChar("linejoin"));
-    SET_STRING_ELT(gparnames, GP_LINEMITRE, mkChar("linemitre"));
-    SET_STRING_ELT(gparnames, GP_LEX, mkChar("lex"));
-    setAttrib(gpar, R_NamesSymbol, gparnames);
-    PROTECT(gpfill = allocVector(STRSXP, 1));
-    SET_STRING_ELT(gpfill, 0, mkChar(col2name(dev->startfill)));
-    SET_VECTOR_ELT(gpar, GP_FILL, gpfill);
-    PROTECT(gpcol = allocVector(STRSXP, 1));
-    SET_STRING_ELT(gpcol, 0, mkChar(col2name(dev->startcol)));
-    SET_VECTOR_ELT(gpar, GP_COL, gpcol);
-    PROTECT(gpgamma = allocVector(REALSXP, 1));
-    REAL(gpgamma)[0] = dev->startgamma;
-    SET_VECTOR_ELT(gpar, GP_GAMMA, gpgamma);
-    PROTECT(gplty = GE_LTYget(dev->startlty));
-    SET_VECTOR_ELT(gpar, GP_LTY, gplty);
-    PROTECT(gplwd = allocVector(REALSXP, 1));
-    REAL(gplwd)[0] = 1;
-    SET_VECTOR_ELT(gpar, GP_LWD, gplwd);
-    PROTECT(gpcex = allocVector(REALSXP, 1));
-    REAL(gpcex)[0] = 1;
-    SET_VECTOR_ELT(gpar, GP_CEX, gpcex);
-    PROTECT(gpfs = allocVector(REALSXP, 1));
-    REAL(gpfs)[0] = dev->startps;
-    SET_VECTOR_ELT(gpar, GP_FONTSIZE, gpfs);
-    PROTECT(gplh = allocVector(REALSXP, 1));
-    REAL(gplh)[0] = 1.2;
-    SET_VECTOR_ELT(gpar, GP_LINEHEIGHT, gplh);
-    PROTECT(gpfont = allocVector(INTSXP, 1));
-    INTEGER(gpfont)[0] = dev->startfont;
-    SET_VECTOR_ELT(gpar, GP_FONT, gpfont);
-    PROTECT(gpfontfamily = allocVector(STRSXP, 1));
-    /* 
-     * A font family of "" means that the default font
-     * set up by the device will be used.
-     */
-    SET_STRING_ELT(gpfontfamily, 0, mkChar(""));
-    SET_VECTOR_ELT(gpar, GP_FONTFAMILY, gpfontfamily);
-    PROTECT(gpalpha = allocVector(REALSXP, 1));
-    REAL(gpalpha)[0] = 1;
-    SET_VECTOR_ELT(gpar, GP_ALPHA, gpalpha);
-    PROTECT(gplineend = allocVector(STRSXP, 1));
-    SET_STRING_ELT(gplineend, 0, mkChar("round"));
-    SET_VECTOR_ELT(gpar, GP_LINEEND, gplineend);
-    PROTECT(gplinejoin = allocVector(STRSXP, 1));
-    SET_STRING_ELT(gplinejoin, 0, mkChar("round"));
-    SET_VECTOR_ELT(gpar, GP_LINEJOIN, gplinejoin);
-    PROTECT(gplinemitre = allocVector(REALSXP, 1));
-    REAL(gplinemitre)[0] = 10;
-    SET_VECTOR_ELT(gpar, GP_LINEMITRE, gplinemitre);
-    PROTECT(gplex = allocVector(REALSXP, 1));
-    REAL(gplex)[0] = 1;
-    SET_VECTOR_ELT(gpar, GP_LEX, gplex);
-    PROTECT(class = allocVector(STRSXP, 1));
-    SET_STRING_ELT(class, 0, mkChar("gpar"));
-    classgets(gpar, class);
-    SET_VECTOR_ELT(gsd, GSS_GPAR, gpar);
-    UNPROTECT(18);
-}
diff --git a/com.oracle.truffle.r.native/library/grid/src/grid.c b/com.oracle.truffle.r.native/library/grid/src/grid.c
deleted file mode 100644
index c04bd2e4fc3aacf0dc6d7e032397de1ff1734e1c..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/grid.c
+++ /dev/null
@@ -1,3694 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003-2013 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-
-#define GRID_MAIN
-#include "grid.h"
-#include <math.h>
-#include <float.h>
-#include <string.h>
-
-/* NOTE:
- * The extensive use of L or L_ prefixes dates back to when this 
- * package used to be called "lattice"
- */
-
-extern int gridRegisterIndex;
-
-void getDeviceSize(pGEDevDesc dd, double *devWidthCM, double *devHeightCM) 
-{
-    double left, right, bottom, top;
-    dd->dev->size(&left, &right, &bottom, &top, dd->dev);
-    *devWidthCM = fabs(right - left) * dd->dev->ipr[0] * 2.54;
-    *devHeightCM = fabs(top - bottom) * dd->dev->ipr[1] * 2.54;
-}
-
-static Rboolean deviceChanged(double devWidthCM, double devHeightCM, 
-			      SEXP currentvp)
-{
-    Rboolean result = FALSE;
-    SEXP pvpDevWidthCM, pvpDevHeightCM;
-    PROTECT(pvpDevWidthCM = VECTOR_ELT(currentvp, PVP_DEVWIDTHCM));
-    PROTECT(pvpDevHeightCM = VECTOR_ELT(currentvp, PVP_DEVHEIGHTCM));
-    if (fabs(REAL(pvpDevWidthCM)[0] - devWidthCM) > 1e-6) {
-	result = TRUE;
-	REAL(pvpDevWidthCM)[0] = devWidthCM;
-	SET_VECTOR_ELT(currentvp, PVP_DEVWIDTHCM, pvpDevWidthCM);
-    }
-    if (fabs(REAL(pvpDevHeightCM)[0] - devHeightCM) > 1e-6) {
-	result = TRUE;
-	REAL(pvpDevHeightCM)[0] = devHeightCM;
-	SET_VECTOR_ELT(currentvp, PVP_DEVHEIGHTCM, pvpDevHeightCM);
-    }
-    UNPROTECT(2);
-    return result;
-}
-
-/* Register grid with R's graphics engine
- */
-SEXP L_initGrid(SEXP GridEvalEnv) 
-{
-    R_gridEvalEnv = GridEvalEnv;
-    GEregisterSystem(gridCallback, &gridRegisterIndex);
-    return R_NilValue;
-}
-
-SEXP L_killGrid() 
-{
-    GEunregisterSystem(gridRegisterIndex);
-    return R_NilValue;
-}
-
-/* Get the current device (the graphics engine creates one if nec.)
- */
-pGEDevDesc getDevice() 
-{
-    return GEcurrentDevice();
-}
-
-/* If this is the first time that a grid operation has occurred for 
- * this device, do some initialisation.
- */
-void dirtyGridDevice(pGEDevDesc dd) {
-    if (!LOGICAL(gridStateElement(dd, GSS_GRIDDEVICE))[0]) {
-	SEXP gsd, griddev;
-	/* Record the fact that this device has now received grid output
-	 */
-	gsd = (SEXP) dd->gesd[gridRegisterIndex]->systemSpecific;
-	PROTECT(griddev = allocVector(LGLSXP, 1));
-	LOGICAL(griddev)[0] = TRUE;
-	SET_VECTOR_ELT(gsd, GSS_GRIDDEVICE, griddev);
-	UNPROTECT(1);
-	/*
-	 * Start the first page on the device
-	 * (But only if no other graphics system has not already done so)
-	 */
-	if (!GEdeviceDirty(dd)) {
-	    R_GE_gcontext gc;
-	    SEXP currentgp = gridStateElement(dd, GSS_GPAR);
-	    gcontextFromgpar(currentgp, 0, &gc, dd);
-	    GENewPage(&gc, dd);
-	    GEdirtyDevice(dd);
-	}
-	/*
-	 * Only initialise viewport once new page has started
-	 * (required for postscript output [at least])
-	 */
-	initVP(dd);
-	initDL(dd);
-    }
-}
-
-SEXP L_gridDirty()
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    dirtyGridDevice(dd);
-    return R_NilValue;
-}
-
-void getViewportContext(SEXP vp, LViewportContext *vpc)
-{
-    fillViewportContextFromViewport(vp, vpc);
-}
-
-SEXP L_currentViewport() 
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_VP);
-}
-
-SEXP doSetViewport(SEXP vp, 
-		   /* 
-		    * Are we setting the top-level viewport?
-		    */
-		   Rboolean topLevelVP,
-		   /* 
-		    * Are we pushing a new viewport?
-		    * (or just revisiting an already-pushed viewport?)
-		    */
-		   Rboolean pushing,
-		   pGEDevDesc dd)
-{
-    int i, j;
-    double devWidthCM, devHeightCM;
-    double xx1, yy1, xx2, yy2;
-    SEXP currentClip, widthCM, heightCM;
-    /* Get the current device size 
-     */
-    getDeviceSize((dd), &devWidthCM, &devHeightCM);
-    if (!topLevelVP && pushing) {
-	SEXP parent = gridStateElement(dd, GSS_VP);
-	/* Set the viewport's parent
-	 * Need to do this in here so that redrawing via R BASE display
-	 * list works 
-	 */
-	SET_VECTOR_ELT(vp, PVP_PARENT, parent);
-	/*
-	 * Make this viewport a child of its parent
-	 * This involves assigning a value in the parent's
-	 * children slot (which is an environment), using
-	 * the viewport's name as the symbol name.
-	 * NOTE that we are deliberately using defineVar to
-	 * assign the vp SEXP itself, NOT a copy.
-	 */
-	defineVar(install(CHAR(STRING_ELT(VECTOR_ELT(vp, VP_NAME), 0))),
-		  vp, 
-		  VECTOR_ELT(parent, PVP_CHILDREN));
-    }
-    /* Calculate the transformation for the viewport.
-     * This will hopefully only involve updating the transformation
-     * from the previous viewport.
-     * However, if the device has changed size, we will need to
-     * recalculate the transformation from the top-level viewport
-     * all the way down.
-     * NEVER incremental for top-level viewport
-     */
-    calcViewportTransform(vp, viewportParent(vp), 
-			  !topLevelVP &&
-			  !deviceChanged(devWidthCM, devHeightCM, 
-					 viewportParent(vp)), dd);
-    /* 
-     * We must "turn off" clipping
-     * We set the clip region to be the entire device
-     * (actually, as for the top-level viewport, we set it
-     *  to be slightly larger than the device to avoid 
-     *  "edge effects")
-     */
-    if (viewportClip(vp) == NA_LOGICAL) {
-	xx1 = toDeviceX(-0.5*devWidthCM/2.54, GE_INCHES, dd);
-	yy1 = toDeviceY(-0.5*devHeightCM/2.54, GE_INCHES, dd);
-	xx2 = toDeviceX(1.5*devWidthCM/2.54, GE_INCHES, dd);
-	yy2 = toDeviceY(1.5*devHeightCM/2.54, GE_INCHES, dd);
-	GESetClip(xx1, yy1, xx2, yy2, dd);
-    }
-    /* If we are supposed to clip to this viewport ...
-     * NOTE that we will only clip if there is no rotation
-     */
-    else if (viewportClip(vp)) {
-	double rotationAngle = REAL(viewportRotation(vp))[0];
-	if (rotationAngle != 0 &&
-            rotationAngle != 90 &&
-            rotationAngle != 270 &&
-            rotationAngle != 360) {
-	    warning(_("cannot clip to rotated viewport"));
-            /* Still need to set clip region for this viewport.
-               So "inherit" parent clip region.
-               In other words, 'clip=TRUE' + 'rot=15' = 'clip=FALSE'
-            */
-            SEXP parentClip;
-            PROTECT(parentClip = viewportClipRect(viewportParent(vp)));
-            xx1 = REAL(parentClip)[0];
-            yy1 = REAL(parentClip)[1];
-            xx2 = REAL(parentClip)[2];
-            yy2 = REAL(parentClip)[3];
-            UNPROTECT(1);
-        } else {
-	    /* Calculate a clipping region and set it
-	     */
-	    SEXP x1, y1, x2, y2;
-	    LViewportContext vpc;
-	    double vpWidthCM = REAL(viewportWidthCM(vp))[0];
-	    double vpHeightCM = REAL(viewportHeightCM(vp))[0];
-	    R_GE_gcontext gc;
-	    LTransform transform;
-	    for (i=0; i<3; i++)
-		for (j=0; j<3; j++)
-		    transform[i][j] = 
-			REAL(viewportTransform(vp))[i + 3*j];
-	    if (!topLevelVP) {
-		PROTECT(x1 = unit(0, L_NPC));
-		PROTECT(y1 = unit(0, L_NPC));
-		PROTECT(x2 = unit(1, L_NPC));
-		PROTECT(y2 = unit(1, L_NPC));
-	    } else {
-		/* Special case for top-level viewport.
-		 * Set clipping region outside device boundaries.
-		 * This means that we have set the clipping region to
-		 * something, but avoids problems if the nominal device
-		 * limits are actually within its physical limits
-		 * (e.g., PostScript)
-		 */
-	        PROTECT(x1 = unit(-.5, L_NPC));
-		PROTECT(y1 = unit(-.5, L_NPC));
-		PROTECT(x2 = unit(1.5, L_NPC));
-		PROTECT(y2 = unit(1.5, L_NPC));
-	    }
-	    getViewportContext(vp, &vpc);
-	    gcontextFromViewport(vp, &gc, dd);
-	    transformLocn(x1, y1, 0, vpc, &gc, 
-			  vpWidthCM, vpHeightCM,
-			  dd,
-			  transform,
-			  &xx1, &yy1);
-	    transformLocn(x2, y2, 0, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd,
-			  transform,
-			  &xx2, &yy2);
-	    UNPROTECT(4);  /* unprotect x1, y1, x2, y2 */
-	    /* The graphics engine only takes device coordinates
-	     */
-	    xx1 = toDeviceX(xx1, GE_INCHES, dd);
-	    yy1 = toDeviceY(yy1, GE_INCHES, dd);
-	    xx2 = toDeviceX(xx2, GE_INCHES, dd);
-	    yy2 = toDeviceY(yy2, GE_INCHES, dd);
-	    GESetClip(xx1, yy1, xx2, yy2, dd);
-	}
-    } else {
-	/* If we haven't set the clipping region for this viewport
-	 * we need to save the clipping region from its parent
-	 * so that when we pop this viewport we can restore that.
-	 */
-	/* NOTE that we are relying on grid.R setting clip=TRUE
-	 * for the top-level viewport, else *BOOM*!
-	 */
-	SEXP parentClip;
-	PROTECT(parentClip = viewportClipRect(viewportParent(vp)));
-	xx1 = REAL(parentClip)[0];
-	yy1 = REAL(parentClip)[1];
-	xx2 = REAL(parentClip)[2];
-	yy2 = REAL(parentClip)[3];
-	UNPROTECT(1);
-    }
-    PROTECT(currentClip = allocVector(REALSXP, 4));
-    REAL(currentClip)[0] = xx1;
-    REAL(currentClip)[1] = yy1;
-    REAL(currentClip)[2] = xx2;
-    REAL(currentClip)[3] = yy2;
-    SET_VECTOR_ELT(vp, PVP_CLIPRECT, currentClip);
-    /*
-     * Save the current device size
-     */
-    PROTECT(widthCM = allocVector(REALSXP, 1));
-    REAL(widthCM)[0] = devWidthCM;
-    SET_VECTOR_ELT(vp, PVP_DEVWIDTHCM, widthCM);
-    PROTECT(heightCM = allocVector(REALSXP, 1));
-    REAL(heightCM)[0] = devHeightCM;
-    SET_VECTOR_ELT(vp, PVP_DEVHEIGHTCM, heightCM);
-    UNPROTECT(3);
-    return vp;
-}
-
-SEXP L_setviewport(SEXP invp, SEXP hasParent)
-{
-    SEXP vp;
-    SEXP pushedvp, fcall;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    /*
-     * Duplicate the viewport passed in because we are going
-     * to modify it to hell and gone.
-     */
-    PROTECT(vp = duplicate(invp));
-    /* 
-     * Call R function pushedvp() 
-     */
-    PROTECT(fcall = lang2(install("pushedvp"),
-			  vp));
-    PROTECT(pushedvp = eval(fcall, R_gridEvalEnv)); 
-    pushedvp = doSetViewport(pushedvp, !LOGICAL(hasParent)[0], TRUE, dd);
-    /* Set the value of the current viewport for the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */
-    setGridStateElement(dd, GSS_VP, pushedvp);
-    UNPROTECT(3);
-    return R_NilValue;
-}
-
-/* 
- * Find a viewport in the current viewport tree by name
- *
- * Have to do this in C code so that we get THE SEXP in
- * the tree, NOT a copy of it.
- */
-
-/*
- * Some helper functions to call R code because I have no idea
- * how to do this in C code
- */
-static Rboolean noChildren(SEXP children) 
-{
-    SEXP result, fcall;
-    PROTECT(fcall = lang2(install("no.children"),
-			  children));
-    PROTECT(result = eval(fcall, R_gridEvalEnv)); 
-    UNPROTECT(2);
-    return LOGICAL(result)[0];
-}
-
-static Rboolean childExists(SEXP name, SEXP children) 
-{
-    SEXP result, fcall;
-    PROTECT(fcall = lang3(install("child.exists"),
-			  name, children));
-    PROTECT(result = eval(fcall, R_gridEvalEnv)); 
-    UNPROTECT(2);
-    return LOGICAL(result)[0];
-}
-
-static SEXP childList(SEXP children) 
-{
-    SEXP result, fcall;
-    PROTECT(fcall = lang2(install("child.list"),
-			  children));
-    PROTECT(result = eval(fcall, R_gridEvalEnv)); 
-    UNPROTECT(2);
-    return result;    
-}
-
-/*
-find.in.children <- function(name, children) {
-  cpvps <- ls(env=children)
-  ncpvp <- length(cpvps)
-  count <- 0
-  found <- FALSE
-  while (count < ncpvp && !found) {
-    result <- find.viewport(name, get(cpvps[count+1], env=children))
-    found <- result$found
-    count <- count + 1
-  }
-  if (!found)
-    result <- list(found=FALSE, pvp=NULL)
-  return(result)
-}
-*/
-static SEXP findViewport(SEXP name, SEXP strict, SEXP vp, int depth);
-static SEXP findInChildren(SEXP name, SEXP strict, SEXP children, int depth) 
-{
-    SEXP childnames = childList(children);
-    int n = LENGTH(childnames);
-    int count = 0;
-    Rboolean found = FALSE;
-    SEXP result = R_NilValue;
-    PROTECT(childnames);
-    PROTECT(result);
-    while (count < n && !found) {
-	result = findViewport(name, strict,
-			      findVar(install(CHAR(STRING_ELT(childnames, count))),
-				      children),
-			      depth);
-	found = INTEGER(VECTOR_ELT(result, 0))[0] > 0;
-	count = count + 1;
-    }
-    if (!found) {
-	SEXP temp, zeroDepth;
-	PROTECT(temp = allocVector(VECSXP, 2));
-	PROTECT(zeroDepth = allocVector(INTSXP, 1));
-	INTEGER(zeroDepth)[0] = 0;
-	SET_VECTOR_ELT(temp, 0, zeroDepth);
-	SET_VECTOR_ELT(temp, 1, R_NilValue);
-	UNPROTECT(2);
-	result = temp;
-    }
-    UNPROTECT(2);
-    return result;
-}
-			   
-/*
-find.viewport <- function(name, pvp) {
-  found <- FALSE
-  if (length(ls(env=pvp$children)) == 0)
-    return(list(found=FALSE, pvp=NULL))
-  else 
-    if (exists(name, env=pvp$children, inherits=FALSE)) 
-      return(list(found=TRUE,
-                  pvp=get(name, env=pvp$children, inherits=FALSE)))
-    else 
-      find.in.children(name, pvp$children)
-}
-*/
-static SEXP findViewport(SEXP name, SEXP strict, SEXP vp, int depth) 
-{
-    SEXP result, zeroDepth, curDepth;
-    PROTECT(result = allocVector(VECSXP, 2));
-    PROTECT(zeroDepth = allocVector(INTSXP, 1));
-    INTEGER(zeroDepth)[0] = 0;
-    PROTECT(curDepth = allocVector(INTSXP, 1));
-    INTEGER(curDepth)[0] = depth;
-    /* 
-     * If there are no children, we fail
-     */
-    if (noChildren(viewportChildren(vp))) {
-	SET_VECTOR_ELT(result, 0, zeroDepth);
-	SET_VECTOR_ELT(result, 1, R_NilValue);
-    } else if (childExists(name, viewportChildren(vp))) {
-	SET_VECTOR_ELT(result, 0, curDepth);
-	SET_VECTOR_ELT(result, 1, 
-		       /*
-			* Does this do inherits=FALSE?
-			*/
-		       findVar(install(CHAR(STRING_ELT(name, 0))), 
-			       viewportChildren(vp)));
-    } else {
-	/*
-	 * If this is a strict match, fail
-	 * Otherwise recurse into children
-	 */
-	if (LOGICAL(strict)[0]) {
-	    SET_VECTOR_ELT(result, 0, zeroDepth);
-	    SET_VECTOR_ELT(result, 1, R_NilValue);
-	} else {
-	    result = findInChildren(name, strict, viewportChildren(vp),
-				    depth + 1);
-	}
-    }
-    UNPROTECT(3);
-    return result;
-}
-
-SEXP L_downviewport(SEXP name, SEXP strict) 
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    /* Get the value of the current viewport for the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */    
-    SEXP gvp = gridStateElement(dd, GSS_VP);
-    /* 
-     * Try to find the named viewport
-     */
-    SEXP found, vp;
-    int depth = 1;
-    PROTECT(found = findViewport(name, strict, gvp, depth));
-    if (INTEGER(VECTOR_ELT(found, 0))[0]) {
-	vp = doSetViewport(VECTOR_ELT(found, 1), FALSE, FALSE, dd);
-	/* Set the value of the current viewport for the current device
-	 * Need to do this in here so that redrawing via R BASE display
-	 * list works 
-	 */
-	setGridStateElement(dd, GSS_VP, vp);
-        UNPROTECT(1);    
-    } else {
-        /* Important to have an error here, rather than back in
-         * R code AFTER this point.  Otherwise, an unsuccessful
-         * downViewport() will be recorded on the engine DL!
-         */
-        char msg[1024];
-        snprintf(msg, 1024, "Viewport '%s' was not found", 
-		 CHAR(STRING_ELT(name, 0)));
-        UNPROTECT(1);    
-        error(_(msg));
-    }
-    return VECTOR_ELT(found, 0);    
-}
-
-/* 
- * Find a viewport PATH in the current viewport tree by name
- *
- * Similar to L_downviewport
- */
-
-static Rboolean pathMatch(SEXP path, SEXP pathsofar, SEXP strict) 
-{
-    SEXP result, fcall;
-    PROTECT(fcall = lang4(install("pathMatch"),
-			  path, pathsofar, strict));
-    PROTECT(result = eval(fcall, R_gridEvalEnv)); 
-    UNPROTECT(2);
-    return LOGICAL(result)[0];    
-}
-
-static SEXP growPath(SEXP pathsofar, SEXP name) 
-{
-    SEXP result, fcall;
-    if (isNull(pathsofar))
-	result = name;
-    else {
-	PROTECT(fcall = lang3(install("growPath"),
-			      pathsofar, name));
-	PROTECT(result = eval(fcall, R_gridEvalEnv)); 
-	UNPROTECT(2);
-    }
-    return result;    
-}
-
-static SEXP findvppath(SEXP path, SEXP name, SEXP strict, 
-		       SEXP pathsofar, SEXP vp, int depth);
-static SEXP findvppathInChildren(SEXP path, SEXP name, 
-				 SEXP strict, SEXP pathsofar,
-				 SEXP children, int depth) 
-{
-    SEXP childnames = childList(children);
-    int n = LENGTH(childnames);
-    int count = 0;
-    Rboolean found = FALSE;
-    SEXP result = R_NilValue;
-    PROTECT(childnames);
-    PROTECT(result);
-    while (count < n && !found) {
-	SEXP vp, newpathsofar;
-	PROTECT(vp = findVar(install(CHAR(STRING_ELT(childnames, count))),
-			     children));
-	PROTECT(newpathsofar = growPath(pathsofar,
-					VECTOR_ELT(vp, VP_NAME)));
-	result = findvppath(path, name, strict, newpathsofar, vp, depth);
-	found = INTEGER(VECTOR_ELT(result, 0))[0] > 0;
-	count = count + 1;
-	UNPROTECT(2);
-    }
-    if (!found) {
-	SEXP temp, zeroDepth;
-	PROTECT(temp = allocVector(VECSXP, 2));
-	PROTECT(zeroDepth = allocVector(INTSXP, 1));
-	INTEGER(zeroDepth)[0] = 0;
-	SET_VECTOR_ELT(temp, 0, zeroDepth);
-	SET_VECTOR_ELT(temp, 1, R_NilValue);
-	UNPROTECT(2);
-	result = temp;
-    }
-    UNPROTECT(2);
-    return result;
-}
-			   
-static SEXP findvppath(SEXP path, SEXP name, SEXP strict, 
-		       SEXP pathsofar, SEXP vp, int depth) 
-{
-    SEXP result, zeroDepth, curDepth;
-    PROTECT(result = allocVector(VECSXP, 2));
-    PROTECT(zeroDepth = allocVector(INTSXP, 1));
-    INTEGER(zeroDepth)[0] = 0;
-    PROTECT(curDepth = allocVector(INTSXP, 1));
-    INTEGER(curDepth)[0] = depth;
-    /* 
-     * If there are no children, we fail
-     */
-    if (noChildren(viewportChildren(vp))) {
-	SET_VECTOR_ELT(result, 0, zeroDepth);
-	SET_VECTOR_ELT(result, 1, R_NilValue);
-	
-    } 
-    /* 
-     * Check for the viewport name AND whether the rest
-     * of the path matches (possibly strictly)
-     */
-    else if (childExists(name, viewportChildren(vp)) &&
-	     pathMatch(path, pathsofar, strict)) {
-	SET_VECTOR_ELT(result, 0, curDepth);
-	SET_VECTOR_ELT(result, 1, 
-		       /*
-			* Does this do inherits=FALSE?
-			*/
-		       findVar(install(CHAR(STRING_ELT(name, 0))), 
-			       viewportChildren(vp)));
-    } else {
-	result = findvppathInChildren(path, name, strict, pathsofar,
-				      viewportChildren(vp), depth + 1);
-    }
-    UNPROTECT(3);
-    return result;
-}
-
-SEXP L_downvppath(SEXP path, SEXP name, SEXP strict) 
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    /* Get the value of the current viewport for the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */    
-    SEXP gvp = gridStateElement(dd, GSS_VP);
-    /* 
-     * Try to find the named viewport
-     */
-    SEXP found, vp;
-    int depth = 1;
-    PROTECT(found = findvppath(path, name, strict, R_NilValue, gvp, depth));
-    if (INTEGER(VECTOR_ELT(found, 0))[0]) {
-	vp = doSetViewport(VECTOR_ELT(found, 1), FALSE, FALSE, dd);
-	/* Set the value of the current viewport for the current device
-	 * Need to do this in here so that redrawing via R BASE display
-	 * list works 
-	 */
-	setGridStateElement(dd, GSS_VP, vp);
-        UNPROTECT(1);    
-    } else {
-        /* Important to have an error here, rather than back in
-         * R code AFTER this point.  Otherwise, an unsuccessful
-         * downViewport() will be recorded on the engine DL!
-         */
-        char msg[1024];
-        snprintf(msg, 1024, "Viewport '%s' was not found", 
-		 CHAR(STRING_ELT(name, 0)));
-        UNPROTECT(1);    
-        error(_(msg));
-    }
-    return VECTOR_ELT(found, 0);    
-}
-
-/* This is similar to L_setviewport, except that it will NOT 
- * recalculate the viewport transform if the device has not changed size
- */
-SEXP L_unsetviewport(SEXP n)
-{
-    int i;
-    double xx1, yy1, xx2, yy2;
-    double devWidthCM, devHeightCM;
-    SEXP parentClip;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    /* Get the value of the current viewport for the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */    
-    SEXP gvp = gridStateElement(dd, GSS_VP);
-    /* NOTE that the R code has already checked that .grid.viewport$parent
-     * is non-NULL
-     * 
-     * BUT this may not be called from R code !!
-     * (e.g., when the graphics engine display list is replayed;
-     *  problems can occur when grid output is mixed with base output;
-     *  for example, plot.new() is called between a viewport push and pop)
-     */
-    SEXP newvp = VECTOR_ELT(gvp, PVP_PARENT);
-    if (isNull(newvp))
-	error(_("cannot pop the top-level viewport ('grid' and 'graphics' output mixed?)"));
-    for (i = 1; i < INTEGER(n)[0]; i++) {
-	gvp = newvp;
-	newvp = VECTOR_ELT(gvp, PVP_PARENT);
-	if (isNull(newvp))
-	    error(_("cannot pop the top-level viewport ('grid' and 'graphics' output mixed?)"));
-    }
-    /* 
-     * Remove the child (gvp) from the parent's (newvp) "list" of
-     * children
-     */
-    /* 
-     * This has to be done via a call to R-level ...
-     *   remove(gvp$name, envir=newvp$children, inherits=FALSE)
-     * ... because RemoveVariable in envir.c is not exported (why not?)
-     *
-     * I tried to model this on the example in the section 
-     * "System and foreign language interfaces ... Evaluating R expressions"
-     * in the "Writing R Extensions" manual, but the compiler didn't
-     * like CAR(t) as an lvalue.
-     */
-    {
-	SEXP fcall, false, t;
-	PROTECT(gvp); PROTECT(newvp);
-	PROTECT(false = allocVector(LGLSXP, 1));
-	LOGICAL(false)[0] = FALSE;
-	PROTECT(fcall = lang4(install("remove"), 
-			      VECTOR_ELT(gvp, VP_NAME),
-			      VECTOR_ELT(newvp, PVP_CHILDREN),
-			      false));
-	t = fcall;
-	t = CDR(CDR(t));
-	SET_TAG(t, install("envir")); 
-	t = CDR(t);
-	SET_TAG(t, install("inherits")); 
-	eval(fcall, R_gridEvalEnv); 
-	UNPROTECT(4);
-    }
-    /* Get the current device size 
-     */
-    getDeviceSize(dd, &devWidthCM, &devHeightCM);
-    if (deviceChanged(devWidthCM, devHeightCM, newvp))
-	calcViewportTransform(newvp, viewportParent(newvp), 1, dd);
-    /* 
-     * Enforce the current viewport settings
-     */
-    setGridStateElement(dd, GSS_GPAR, viewportgpar(newvp));
-    /* Set the clipping region to the parent's cur.clip
-     */
-    parentClip = viewportClipRect(newvp);
-    xx1 = REAL(parentClip)[0];
-    yy1 = REAL(parentClip)[1];
-    xx2 = REAL(parentClip)[2];
-    yy2 = REAL(parentClip)[3];
-    GESetClip(xx1, yy1, xx2, yy2, dd);
-    /* Set the value of the current viewport for the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */
-    setGridStateElement(dd, GSS_VP, newvp);
-    /* 
-     * Remove the parent from the child
-     * This is not strictly necessary, but it is conceptually
-     * more complete and makes it more likely that we will
-     * detect incorrect code elsewhere (because it is likely to
-     * trigger a segfault if other code is incorrect)
-     *
-     * NOTE: Do NOT do this any earlier or you will
-     * remove the PROTECTive benefit of newvp pointing
-     * to part of the (global) grid state
-     */
-    SET_VECTOR_ELT(gvp, PVP_PARENT, R_NilValue);
-    return R_NilValue;
-}
-
-/* This is similar to L_unsetviewport, except that it will NOT 
- * modify parent-child relations 
- */
-SEXP L_upviewport(SEXP n)
-{
-    int i;
-    double xx1, yy1, xx2, yy2;
-    double devWidthCM, devHeightCM;
-    SEXP parentClip;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    /* Get the value of the current viewport for the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */    
-    SEXP gvp = gridStateElement(dd, GSS_VP);
-    SEXP newvp = VECTOR_ELT(gvp, PVP_PARENT);
-    if (isNull(newvp))
-	error(_("cannot pop the top-level viewport ('grid' and 'graphics' output mixed?)"));
-    for (i = 1; i < INTEGER(n)[0]; i++) {
-	gvp = newvp;
-	newvp = VECTOR_ELT(gvp, PVP_PARENT);
-	if (isNull(newvp))
-	    error(_("cannot pop the top-level viewport ('grid' and 'graphics' output mixed?)"));
-    }
-    /* Get the current device size 
-     */
-    getDeviceSize(dd, &devWidthCM, &devHeightCM);
-    if (deviceChanged(devWidthCM, devHeightCM, newvp))
-	calcViewportTransform(newvp, viewportParent(newvp), 1, dd);
-    /* 
-     * Enforce the current viewport settings
-     */
-    setGridStateElement(dd, GSS_GPAR, viewportgpar(newvp));
-    /* Set the clipping region to the parent's cur.clip
-     */
-    parentClip = viewportClipRect(newvp);
-    xx1 = REAL(parentClip)[0];
-    yy1 = REAL(parentClip)[1];
-    xx2 = REAL(parentClip)[2];
-    yy2 = REAL(parentClip)[3];
-    GESetClip(xx1, yy1, xx2, yy2, dd);
-#if 0
-	    /* This is a VERY short term fix to avoid mucking
-	     * with the core graphics during feature freeze
-	     * It should be removed post R 1.4 release
-	     */
-	    dd->dev->clipLeft = fmin2(xx1, xx2);
-	    dd->dev->clipRight = fmax2(xx1, xx2);
-	    dd->dev->clipTop = fmax2(yy1, yy2);
-	    dd->dev->clipBottom = fmin2(yy1, yy2); 
-#endif
-    /* Set the value of the current viewport for the current device
-     * Need to do this in here so that redrawing via R BASE display
-     * list works 
-     */
-    setGridStateElement(dd, GSS_VP, newvp);
-    return R_NilValue;
-}
-
-SEXP L_getDisplayList() 
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_DL);
-}
-
-SEXP L_setDisplayList(SEXP dl) 
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    setGridStateElement(dd, GSS_DL, dl);
-    return R_NilValue;
-}
-
-/*
- * Get the element at index on the DL
- */
-SEXP L_getDLelt(SEXP index)
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    SEXP dl, result;
-    PROTECT(dl = gridStateElement(dd, GSS_DL));
-    result = VECTOR_ELT(dl, INTEGER(index)[0]);
-    UNPROTECT(1);
-    return result;
-}
-
-/* Add an element to the display list at the current location
- * Location is maintained in R code
- */
-SEXP L_setDLelt(SEXP value)
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    SEXP dl;
-    PROTECT(dl = gridStateElement(dd, GSS_DL));
-    SET_VECTOR_ELT(dl, INTEGER(gridStateElement(dd, GSS_DLINDEX))[0], value);
-    UNPROTECT(1);
-    return R_NilValue;
-}
-
-SEXP L_getDLindex()
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_DLINDEX);
-}
-
-SEXP L_setDLindex(SEXP index)
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    setGridStateElement(dd, GSS_DLINDEX, index);
-    return R_NilValue;
-}
-
-SEXP L_getDLon()
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_DLON);
-}
-
-SEXP L_setDLon(SEXP value)
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    SEXP prev;
-    prev = gridStateElement(dd, GSS_DLON);
-    setGridStateElement(dd, GSS_DLON, value);
-    return prev;
-}
-
-SEXP L_getEngineDLon()
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_ENGINEDLON);
-}
-
-SEXP L_setEngineDLon(SEXP value)
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    setGridStateElement(dd, GSS_ENGINEDLON, value);
-    return R_NilValue;
-}
-
-SEXP L_getCurrentGrob() 
-{
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_CURRGROB);
-}
-
-SEXP L_setCurrentGrob(SEXP value)
-{
-    pGEDevDesc dd = getDevice();
-    setGridStateElement(dd, GSS_CURRGROB, value);
-    return R_NilValue;
-}
-
-SEXP L_getEngineRecording() 
-{
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_ENGINERECORDING);
-}
-
-SEXP L_setEngineRecording(SEXP value)
-{
-    pGEDevDesc dd = getDevice();
-    setGridStateElement(dd, GSS_ENGINERECORDING, value);
-    return R_NilValue;
-}
-
-SEXP L_currentGPar()
-{
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    return gridStateElement(dd, GSS_GPAR);
-}
-
-SEXP L_newpagerecording()
-{
-    pGEDevDesc dd = getDevice();
-    if (dd->ask) {
-	NewFrameConfirm(dd->dev);
-	/*
-	 * User may have killed device during pause for prompt
-	 */
-	if (NoDevices())
-	    error(_("attempt to plot on null device"));
-	else
-	    /* 
-	     * Should throw an error if dd != GECurrentDevice ?
-	     */
-	    dd = GEcurrentDevice();
-    }
-    GEinitDisplayList(dd);
-    return R_NilValue;
-}
-
-SEXP L_newpage()
-{
-    pGEDevDesc dd = getDevice();
-    R_GE_gcontext gc;
-    /* 
-     * Has the device been drawn on yet?
-     */
-    Rboolean deviceDirty = GEdeviceDirty(dd);
-    /*
-     * Has the device been drawn on BY GRID yet?
-     */
-    Rboolean deviceGridDirty = LOGICAL(gridStateElement(dd, 
-							GSS_GRIDDEVICE))[0];
-    /*
-     * Initialise grid on device
-     * If no drawing on device yet, does a new page
-     */
-    if (!deviceGridDirty) {
-        dirtyGridDevice(dd);
-    } 
-    /*
-     * If device has previously been drawn on (by grid or other system)
-     * do a new page
-     */
-    if (deviceGridDirty || deviceDirty) {
-	SEXP currentgp = gridStateElement(dd, GSS_GPAR);
-	gcontextFromgpar(currentgp, 0, &gc, dd);
-	GENewPage(&gc, dd);
-    }
-    return R_NilValue;
-}
-
-SEXP L_initGPar()
-{
-    pGEDevDesc dd = getDevice();
-    initGPar(dd);
-    return R_NilValue;
-}
-
-SEXP L_initViewportStack()
-{
-    pGEDevDesc dd = getDevice();
-    initVP(dd);
-    return R_NilValue;
-}
-
-SEXP L_initDisplayList()
-{
-    pGEDevDesc dd = getDevice();
-    initDL(dd);
-    return R_NilValue;
-}
-
-void getViewportTransform(SEXP currentvp, 
-			  pGEDevDesc dd, 
-			  double *vpWidthCM, double *vpHeightCM,
-			  LTransform transform, double *rotationAngle) 
-{
-    int i, j;
-    double devWidthCM, devHeightCM;
-    getDeviceSize((dd), &devWidthCM, &devHeightCM) ;
-    if (deviceChanged(devWidthCM, devHeightCM, currentvp)) {
-	/* IF the device has changed, recalculate the viewport transform
-	 */
-	calcViewportTransform(currentvp, viewportParent(currentvp), 1, dd); 
-    }
-    for (i=0; i<3; i++)
-	for (j=0; j<3; j++)
-	    transform[i][j] = 
-		REAL(viewportTransform(currentvp))[i + 3*j];
-    *rotationAngle = REAL(viewportRotation(currentvp))[0];
-    *vpWidthCM = REAL(viewportWidthCM(currentvp))[0];
-    *vpHeightCM = REAL(viewportHeightCM(currentvp))[0];
-}
-
-
-/***************************
- * CONVERSION FUNCTIONS
- ***************************
- */
-
-/*
- * WITHIN THE CURRENT VIEWPORT ... 
- *
- * Given a unit object and whether it is a location/dimension,
- * convert to location/dimension in unit B
- *
- * NOTE: When this is used to convert a mouse click on a device to
- * a location/dimension, the conversion of the mouse click to 
- * a unit within the current viewport has to be done elsewhere.
- * e.g., in interactive.R, this is done by applying the inverse
- * of the current viewport transformation to get a location in
- * inches within the current viewport.
- * 
- * This should ideally create a unit object to ensure that the
- * values it returns are treated as values in the correct 
- * coordinate system.  For now, this is MUCH easier to do in
- * R code, so it is the responsibility of the R code calling this
- * to create the unit object correctly/honestly.
- *
- * NOTE also that the unitto supplied should be a "valid" integer 
- * (the best way to get that is to use the valid.units()
- *  function in unit.R)
- *
- * what = 0 means x, 1 means y, 2 means width, 3 means height
- */
-SEXP L_convert(SEXP x, SEXP whatfrom,
-	       SEXP whatto, SEXP unitto) {
-    int i, nx;
-    SEXP answer;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    int TOunit, FROMaxis, TOaxis;
-    Rboolean relConvert;
-    /* 
-     * Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    /* 
-     * We do not need the current transformation, but
-     * we need the side effects of calculating it in
-     * case the device has been resized (or only just created)
-     */
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    nx = unitLength(x);
-    PROTECT(answer = allocVector(REALSXP, nx));
-    for (i=0; i<nx; i++) {
-        gcontextFromgpar(currentgp, i, &gc, dd);
-        TOunit = INTEGER(unitto)[i % LENGTH(unitto)];
-        FROMaxis = INTEGER(whatfrom)[0];
-        TOaxis = INTEGER(whatto)[0];
-        /* 
-         * Special case: FROM unit is just a plain, relative unit AND
-         *               TO unit is relative AND
-         *               NOT converting from 'x' to 'y' (or vice versa) ...
-         * 
-         *               ... AND relevant widthCM or heightCM is zero
-         *
-         * In these cases do NOT transform thru INCHES 
-         * (to avoid divide-by-zero, but still do something useful)
-         */
-        relConvert = (!isUnitArithmetic(x) && !isUnitList(x) &&
-                      (unitUnit(x, i) == L_NATIVE || unitUnit(x, i) == L_NPC) &&
-                      (TOunit == L_NATIVE || TOunit == L_NPC) &&
-                      ((FROMaxis == TOaxis) ||
-                       (FROMaxis == 0 && TOaxis == 2) ||
-                       (FROMaxis == 2 && TOaxis == 0) ||
-                       (FROMaxis == 1 && TOaxis == 3) ||
-                       (FROMaxis == 3 && TOaxis == 1)));
-        /* 
-         * First, convert the unit object passed in to a value in INCHES
-         * (within the current viewport)
-         */
-        switch (FROMaxis) {
-        case 0:
-            if (relConvert && vpWidthCM < 1e-6) {
-                REAL(answer)[i] = 
-                    transformXYtoNPC(unitValue(x, i), unitUnit(x, i),
-                                     vpc.xscalemin, vpc.xscalemax);
-            } else {
-                relConvert = FALSE;
-                REAL(answer)[i] = 
-                    transformXtoINCHES(x, i, vpc, &gc,
-                                       vpWidthCM, vpHeightCM, 
-                                       dd);
-            }
-            break;
-        case 1:
-            if (relConvert && vpHeightCM < 1e-6) {
-                REAL(answer)[i] = 
-                    transformXYtoNPC(unitValue(x, i), unitUnit(x, i),
-                                     vpc.yscalemin, vpc.yscalemax);
-            } else {
-                relConvert = FALSE;
-                REAL(answer)[i] = 
-                    transformYtoINCHES(x, i, vpc, &gc,
-                                       vpWidthCM, vpHeightCM, 
-                                       dd);
-            }
-            break;
-        case 2:
-            if (relConvert && vpWidthCM < 1e-6) {
-                REAL(answer)[i] = 
-                    transformWHtoNPC(unitValue(x, i), unitUnit(x, i),
-                                     vpc.xscalemin, vpc.xscalemax);
-            } else {
-                relConvert = FALSE;
-                REAL(answer)[i] = 
-                    transformWidthtoINCHES(x, i, vpc, &gc,
-                                           vpWidthCM, vpHeightCM, 
-                                           dd);
-            }
-            break;
-        case 3:
-            if (relConvert && vpHeightCM < 1e-6) {
-                REAL(answer)[i] = 
-                    transformWHtoNPC(unitValue(x, i), unitUnit(x, i),
-                                     vpc.yscalemin, vpc.yscalemax);
-            } else {
-                relConvert = FALSE;
-                REAL(answer)[i] = 
-                    transformHeighttoINCHES(x, i, vpc, &gc,
-                                            vpWidthCM, vpHeightCM, 
-                                            dd);
-            }
-            break;
-        }
-        /* 
-         * Now, convert the values in INCHES to a value in the specified
-         * coordinate system 
-         * (within the current viewport)
-         *
-         * BUT do NOT do this step for the special "relConvert" case
-         */
-        switch (TOaxis) {
-        case 0:
-            if (relConvert) {
-                REAL(answer)[i] = transformXYfromNPC(REAL(answer)[i], TOunit,
-                                                     vpc.xscalemin,
-                                                     vpc.xscalemax);
-            } else {
-                REAL(answer)[i] = 
-                    transformXYFromINCHES(REAL(answer)[i], TOunit,
-                                          vpc.xscalemin,
-                                          vpc.xscalemax,
-                                          &gc,
-                                          vpWidthCM, vpHeightCM, 
-                                          dd);
-            }
-            break;
-        case 1:
-            if (relConvert) {
-                REAL(answer)[i] = transformXYfromNPC(REAL(answer)[i], TOunit,
-                                                     vpc.yscalemin,
-                                                     vpc.yscalemax);
-            } else {
-                REAL(answer)[i] = 
-                    transformXYFromINCHES(REAL(answer)[i], TOunit,
-                                          vpc.yscalemin,
-                                          vpc.yscalemax,
-                                          &gc,
-                                          vpHeightCM, vpWidthCM, 
-                                          dd);
-            }
-            break;
-        case 2:
-            if (relConvert) {
-                REAL(answer)[i] = transformWHfromNPC(REAL(answer)[i], TOunit,
-                                                     vpc.xscalemin,
-                                                     vpc.xscalemax);
-            } else {
-                REAL(answer)[i] = 
-                    transformWidthHeightFromINCHES(REAL(answer)[i], TOunit,
-                                                   vpc.xscalemin,
-                                                   vpc.xscalemax,
-                                                   &gc,
-                                                   vpWidthCM, vpHeightCM, 
-                                                   dd);
-            }
-            break;
-        case 3:
-            if (relConvert) {
-                REAL(answer)[i] = transformWHfromNPC(REAL(answer)[i], TOunit,
-                                                     vpc.yscalemin,
-                                                     vpc.yscalemax);
-            } else {
-                REAL(answer)[i] = 
-                    transformWidthHeightFromINCHES(REAL(answer)[i], TOunit,
-                                                   vpc.yscalemin,
-                                                   vpc.yscalemax,
-                                                   &gc,
-                                                   vpHeightCM, vpWidthCM, 
-                                                   dd);
-                break;
-            }
-        }
-    }
-    UNPROTECT(1);
-    return answer;
-}
-
-/*
- * Given a layout.pos.row and a layout.pos.col, calculate
- * the region allocated by the layout of the current viewport
- *
- * Not a conversion as such, but similarly vulnerable to device resizing
- */
-SEXP L_layoutRegion(SEXP layoutPosRow, SEXP layoutPosCol) {
-    LViewportLocation vpl;
-    SEXP answer;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LTransform transform;
-    SEXP currentvp;
-    /* 
-     * Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    //currentgp = gridStateElement(dd, GSS_GPAR);
-    /* 
-     * We do not need the current transformation, but
-     * we need the side effects of calculating it in
-     * case the device has been resized (or only just created)
-     */
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    /* 
-     * Only proceed if there is a layout currently defined
-     */
-    if (isNull(viewportLayout(currentvp)))
-	error(_("there is no layout defined"));
-    /* 
-     * The result is a numeric containing left, bottom, width, and height
-     */
-    PROTECT(answer = allocVector(REALSXP, 4));
-    /* 
-     * NOTE:  We are assuming here that calcViewportLocationFromLayout
-     * returns the allocated region with a ("left", "bottom") 
-     * justification.  This is CURRENTLY true, but ...
-     */
-    calcViewportLocationFromLayout(layoutPosRow,
-				   layoutPosCol,
-				   currentvp,
-				   &vpl);
-    /* 
-     * I am not returning the units created in C code
-     * because they do not have the units attribute set
-     * so they do not behave nicely back in R code.
-     * Instead, I take the values and my knowledge that they
-     * are NPC units and construct real unit objects back in 
-     * R code.
-     */
-    REAL(answer)[0] = unitValue(vpl.x, 0);
-    REAL(answer)[1] = unitValue(vpl.y, 0);
-    REAL(answer)[2] = unitValue(vpl.width, 0);
-    REAL(answer)[3] = unitValue(vpl.height, 0);
-    UNPROTECT(1);
-    return answer;
-}
-
-/***************************
- * EDGE DETECTION 
- ***************************
- */
-
-/*
- * Calculate the point on the edge of a rectangle at angle theta
- * 0 = East, 180 = West, etc ...
- * Assumes that x- and y-values are in INCHES
- * Assumes that theta is within [0, 360)
- */
-static void rectEdge(double xmin, double ymin, double xmax, double ymax,
-		     double theta,
-		     double *edgex, double *edgey) 
-{
-    double xm = (xmin + xmax)/2;
-    double ym = (ymin + ymax)/2;
-    double dx = (xmax - xmin)/2;
-    double dy = (ymax - ymin)/2;
-    /*
-     * FIXME: Special case 0 width or 0 height
-     */
-    /*
-     * Special case angles 
-     */
-    if (theta == 0) {
-	*edgex = xmax;
-	*edgey = ym;
-    } else if (theta == 270) {
-	*edgex = xm;
-	*edgey = ymin;
-    } else if (theta == 180) {
-	*edgex = xmin;
-	*edgey = ym;
-    } else if (theta == 90) {
-	*edgex = xm;
-	*edgey = ymax;
-    } else {
-	double cutoff = dy/dx;
-	double angle = theta/180*M_PI;
-	double tanTheta = tan(angle);
-	double cosTheta = cos(angle);
-	double sinTheta = sin(angle);
-	if (fabs(tanTheta) < cutoff) { /* Intersect with side */
-	    if (cosTheta > 0) { /* Right side */
-		*edgex = xmax;
-		*edgey = ym + tanTheta*dx;
-	    } else { /* Left side */
-		*edgex = xmin;
-		*edgey = ym - tanTheta*dx;
-	    }
-	} else { /* Intersect with top/bottom */
-	    if (sinTheta > 0) { /* Top */
-		*edgey = ymax;
-		*edgex = xm + dy/tanTheta;
-	    } else { /* Bottom */
-		*edgey = ymin;
-		*edgex = xm - dy/tanTheta;
-	    }
-	}
-    }
-}
-
-/*
- * Calculate the point on the edge of a rectangle at angle theta
- * 0 = East, 180 = West, etc ...
- * Assumes that x- and y-values are in INCHES
- * Assumes that theta is within [0, 360)
- */
-static void circleEdge(double x, double y, double r,
-		       double theta,
-		       double *edgex, double *edgey)
-{
-    double angle = theta/180*M_PI;
-    *edgex = x + r*cos(angle);
-    *edgey = y + r*sin(angle);
-}
-
-/*
- * Calculate the point on the edge of a *convex* polygon at angle theta
- * 0 = East, 180 = West, etc ...
- * Assumes that x- and y-values are in INCHES
- * Assumes that vertices are in clock-wise order
- * Assumes that theta is within [0, 360)
- */
-static void polygonEdge(double *x, double *y, int n,
-			double theta,
-			double *edgex, double *edgey) {
-    int i, v1, v2;
-    double xm, ym;
-    double xmin = DOUBLE_XMAX;
-    double xmax = -DOUBLE_XMAX;
-    double ymin = DOUBLE_XMAX;
-    double ymax = -DOUBLE_XMAX;
-    int found = 0;
-    double angle = theta/180*M_PI;
-    double vangle1, vangle2;
-    /*
-     * Find "centre" of polygon
-     */
-    for (i=0; i<n; i++) {
-	if (x[i] < xmin)
-	    xmin = x[i];
-	if (x[i] > xmax)
-	    xmax = x[i];
-	if (y[i] < ymin)
-	    ymin = y[i];
-	if (y[i] > ymax)
-	    ymax = y[i];
-    }
-    xm = (xmin + xmax)/2;
-    ym = (ymin + ymax)/2;
-    /*
-     * Special case zero-width or zero-height
-     */ 
-    if (fabs(xmin - xmax) < 1e-6) {
-        *edgex = xmin;
-        if (theta == 90) 
-	    *edgey = ymax;
-	else if (theta == 270)
-	    *edgey = ymin;
-	else
-	    *edgey = ym;
-	return;
-    }
-    if (fabs(ymin - ymax) < 1e-6) {
-        *edgey = ymin;
-        if (theta == 0) 
-	    *edgex = xmax;
-	else if (theta == 180)
-	    *edgex = xmin;
-	else
-	    *edgex = xm;
-	return;
-    }	    
-    /*
-     * Find edge that intersects line from centre at angle theta
-     */
-    for (i=0; i<n; i++) {
-	v1 = i;
-	v2 = v1 + 1;
-	if (v2 == n)
-	    v2 = 0;
-	/*
-	 * Result of atan2 is in range -PI, PI so convert to
-	 * 0, 360 to correspond to angle
-	 */
-	vangle1 = atan2(y[v1] - ym, x[v1] - xm);
-	if (vangle1 < 0)
-	    vangle1 = vangle1 + 2*M_PI;
-	vangle2 = atan2(y[v2] - ym, x[v2] - xm);
-	if (vangle2 < 0)
-	    vangle2 = vangle2 + 2*M_PI;
-	/*
-	 * If vangle1 < vangle2 then angles are either side of 0
-	 * so check is more complicated
-	 */
-	if ((vangle1 >= vangle2 && 
-	     vangle1 >= angle && vangle2 < angle) || 
-	    (vangle1 < vangle2 && 
-	     ((vangle1 >= angle && 0 <= angle) ||
-	      (vangle2 < angle && 2*M_PI >= angle)))) {
-	    found = 1;
-	    break;
-	}
-    }
-    /*
-     * Find intersection point of "line from centre to bounding rect"
-     * and edge
-     */
-    if (found) {
-	double x1 = xm;
-	double y1 = ym;
-	double x2, y2;
-	double x3 = x[v1];
-	double y3 = y[v1];
-	double x4 = x[v2];
-	double y4 = y[v2];
-	double numa, denom, ua;
-	rectEdge(xmin, ymin, xmax, ymax, theta,
-		 &x2, &y2);
-	numa = ((x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3));
-	denom = ((y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1));
-	ua = numa/denom;
-	if (!R_FINITE(ua)) {
-	    /*
-	     * Should only happen if lines are parallel, which 
-	     * shouldn't happen!  Unless, perhaps the polygon has
-	     * zero extent vertically or horizontally ... ?
-	     */
-	    error(_("polygon edge not found (zero-width or zero-height?)"));
-	}
-	/*
-	 * numb = ((x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3));
-	 * ub = numb/denom;
-	 */
-	*edgex = x1 + ua*(x2 - x1);
-	*edgey = y1 + ua*(y2 - y1);
-    } else {
-	error(_("polygon edge not found"));    
-    }
-}
-
-/*
- * Given a set of points, calculate the convex hull then
- * find the edge of that hull
- *
- * NOTE:  assumes that 'grDevices' package has been loaded 
- * so that chull() is available (grid depends on grDevices)
- */
-static void hullEdge(double *x, double *y, int n,
-		     double theta,
-		     double *edgex, double *edgey) 
-{
-    const void *vmax;
-    int i, nh;
-    double *hx, *hy;
-    SEXP xin, yin, chullFn, R_fcall, hull;    
-    int adjust = 0;
-    double *xkeep, *ykeep;
-    vmax = vmaxget();
-    /* Remove any NA's because chull() can't cope with them */
-    xkeep = (double *) R_alloc(n, sizeof(double));
-    ykeep = (double *) R_alloc(n, sizeof(double));
-    for (i=0; i<n; i++) {
-        if (!R_FINITE(x[i]) || !R_FINITE(y[i])) {
-            adjust--;
-        } else {
-            xkeep[i + adjust] = x[i];
-            ykeep[i + adjust] = y[i];
-        }
-    }
-    n = n + adjust;
-    PROTECT(xin = allocVector(REALSXP, n));
-    PROTECT(yin = allocVector(REALSXP, n));
-    for (i=0; i<n; i++) {
-        REAL(xin)[i] = xkeep[i];
-        REAL(yin)[i] = ykeep[i];
-    }
-    /*
-     * Determine convex hull
-     */
-    PROTECT(chullFn = findFun(install("chull"), R_gridEvalEnv));
-    PROTECT(R_fcall = lang3(chullFn, xin, yin));
-    PROTECT(hull = eval(R_fcall, R_gridEvalEnv));
-    nh = LENGTH(hull);
-    hx = (double *) R_alloc(nh, sizeof(double));
-    hy = (double *) R_alloc(nh, sizeof(double));
-    for (i=0; i<nh; i++) {
-	hx[i] = x[INTEGER(hull)[i] - 1];
-	hy[i] = y[INTEGER(hull)[i] - 1];
-    }
-    /*
-     * Find edge of that hull
-     */
-    polygonEdge(hx, hy, nh, theta, 
-		edgex, edgey);
-    vmaxset(vmax);
-    UNPROTECT(5);
-}
-
-/***************************
- * DRAWING PRIMITIVES
- ***************************
- */
-
-/*
- * Draw an arrow head, given the vertices of the arrow head.
- * Assume vertices are in DEVICE coordinates.
- */
-static void drawArrow(double *x, double *y, SEXP type, int i,
-		      const pGEcontext gc, pGEDevDesc dd) 
-{
-    int nt = LENGTH(type);
-    switch (INTEGER(type)[i % nt]) {
-    case 1:
-	GEPolyline(3, x, y, gc, dd);
-	break;
-    case 2:
-	GEPolygon(3, x, y, gc, dd);
-	break;
-    }
-}
-
-/*
- * Calculate vertices for drawing an arrow head.
- * Assumes that x and y locations are in INCHES.
- * Returns vertices in DEVICE coordinates.
- */
-static void calcArrow(double x1, double y1,
-		      double x2, double y2,
-		      SEXP angle, SEXP length, int i,
-		      LViewportContext vpc,
-		      double vpWidthCM, double vpHeightCM,
-		      double *vertx, double *verty,
-		      const pGEcontext gc, pGEDevDesc dd) 
-{
-    int na = LENGTH(angle);
-    int nl = LENGTH(length);
-    double xc, yc, rot;
-    double l1, l2, l, a;
-    l1 = transformWidthtoINCHES(length, i % nl, vpc, gc,
-				vpWidthCM, vpHeightCM,
-				dd);
-    l2 = transformHeighttoINCHES(length, i % nl, vpc, gc,
-				 vpWidthCM, vpHeightCM,
-				 dd);
-    l = fmin2(l1, l2);
-    a = DEG2RAD * REAL(angle)[i % na];
-    xc = x2 - x1;
-    yc = y2 - y1;
-    rot= atan2(yc, xc);
-    vertx[0] = toDeviceX(x1 + l * cos(rot+a),
-			 GE_INCHES, dd);
-    verty[0] = toDeviceY(y1 + l * sin(rot+a),
-			 GE_INCHES, dd);
-    vertx[1] = toDeviceX(x1, 
-			 GE_INCHES, dd);
-    verty[1] = toDeviceY(y1,
-			 GE_INCHES, dd);
-    vertx[2] = toDeviceX(x1 + l * cos(rot-a),
-			 GE_INCHES, dd);
-    verty[2] = toDeviceY(y1 + l * sin(rot-a),
-			 GE_INCHES, dd);
-}
-
-/*
- * Assumes x and y are at least length 2
- * Also assumes x and y are in DEVICE coordinates
- */
-static void arrows(double *x, double *y, int n,
-		   SEXP arrow, int i,
-		   /*
-		    * Which ends we are allowed to draw arrow heads on
-		    * (we may be drawing a line segment that has been
-		    *  broken by NAs)
-		    */
-		   Rboolean start, Rboolean end,
-		   LViewportContext vpc,
-		   double vpWidthCM, double vpHeightCM,
-		   const pGEcontext gc, pGEDevDesc dd) 
-{
-    /*
-     * Write a checkArrow() function to make
-     * sure 'a' is a valid arrow description ?
-     * If someone manages to sneak in a
-     * corrupt arrow description ... BOOM!
-     */			
-    SEXP ends = VECTOR_ELT(arrow, GRID_ARROWENDS);
-    int ne = LENGTH(ends);
-    double vertx[3], verty[3];
-    Rboolean first, last;
-    if (n < 2)
-	error(_("require at least two points to draw arrow"));
-    first = TRUE;
-    last = TRUE;
-    switch (INTEGER(ends)[i % ne]) {
-    case 2: 
-	first = FALSE;
-	break;
-    case 1:
-	last = FALSE;
-	break;
-    }
-    if (first && start) {
-	calcArrow(fromDeviceX(x[0], GE_INCHES, dd),
-		  fromDeviceY(y[0], GE_INCHES, dd),
-		  fromDeviceX(x[1], GE_INCHES, dd),
-		  fromDeviceY(y[1], GE_INCHES, dd),
-		  VECTOR_ELT(arrow, GRID_ARROWANGLE), 
-		  VECTOR_ELT(arrow, GRID_ARROWLENGTH),
-		  i, vpc, vpWidthCM, vpHeightCM, vertx, verty, gc, dd);
-	drawArrow(vertx, verty, 
-		  VECTOR_ELT(arrow, GRID_ARROWTYPE), i, 
-		  gc, dd);
-    } 
-    if (last && end) {
-	calcArrow(fromDeviceX(x[n - 1], GE_INCHES, dd),
-		  fromDeviceY(y[n - 1], GE_INCHES, dd),
-		  fromDeviceX(x[n - 2], GE_INCHES, dd),
-		  fromDeviceY(y[n - 2], GE_INCHES, dd),
-		  VECTOR_ELT(arrow, GRID_ARROWANGLE), 
-		  VECTOR_ELT(arrow, GRID_ARROWLENGTH),
-		  i, vpc, vpWidthCM, vpHeightCM, vertx, verty, gc, dd);
-	drawArrow(vertx, verty, 
-		  VECTOR_ELT(arrow, GRID_ARROWTYPE), i, 
-		  gc, dd);
-    }
-}
-
-SEXP L_moveTo(SEXP x, SEXP y)
-{    
-    double xx, yy;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP devloc, prevloc;
-    SEXP currentvp, currentgp;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    PROTECT(prevloc = gridStateElement(dd, GSS_PREVLOC));
-    PROTECT(devloc = gridStateElement(dd, GSS_CURRLOC));
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    gcontextFromgpar(currentgp, 0, &gc, dd);
-    /* Convert the x and y values to CM locations */
-    transformLocn(x, y, 0, vpc, &gc,
-		  vpWidthCM, vpHeightCM,
-		  dd,
-		  transform,
-		  &xx, &yy);
-    /*
-     * Non-finite values are ok here
-     * L_lineTo figures out what to draw 
-     * when values are non-finite
-     */
-    REAL(prevloc)[0] = REAL(devloc)[0];
-    REAL(prevloc)[1] = REAL(devloc)[1];
-    REAL(devloc)[0] = xx;
-    REAL(devloc)[1] = yy;
-    UNPROTECT(2);
-    return R_NilValue;
-}
-
-SEXP L_lineTo(SEXP x, SEXP y, SEXP arrow)
-{
-    double xx0, yy0, xx1, yy1;
-    double xx, yy;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP devloc, prevloc;
-    SEXP currentvp, currentgp;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    PROTECT(prevloc = gridStateElement(dd, GSS_PREVLOC));
-    PROTECT(devloc = gridStateElement(dd, GSS_CURRLOC));
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    gcontextFromgpar(currentgp, 0, &gc, dd);
-    /* Convert the x and y values to CM locations */
-    transformLocn(x, y, 0, vpc, &gc,
-		  vpWidthCM, vpHeightCM,
-		  dd,
-		  transform,
-		  &xx, &yy);
-    REAL(prevloc)[0] = REAL(devloc)[0];
-    REAL(prevloc)[1] = REAL(devloc)[1];
-    REAL(devloc)[0] = xx;
-    REAL(devloc)[1] = yy;
-    /* The graphics engine only takes device coordinates
-     */
-    xx0 = toDeviceX(REAL(prevloc)[0], GE_INCHES, dd);
-    yy0 = toDeviceY(REAL(prevloc)[1], GE_INCHES, dd), 
-    xx1 = toDeviceX(xx, GE_INCHES, dd);
-    yy1 = toDeviceY(yy, GE_INCHES, dd);
-    if (R_FINITE(xx0) && R_FINITE(yy0) &&
-	R_FINITE(xx1) && R_FINITE(yy1)) {
-	GEMode(1, dd);
-	GELine(xx0, yy0, xx1, yy1, &gc, dd);
-	if (!isNull(arrow)) {
-	    double ax[2], ay[2];
-	    ax[0] = xx0;
-	    ax[1] = xx1;
-	    ay[0] = yy0;
-	    ay[1] = yy1;
-	    arrows(ax, ay, 2,
-		   arrow, 0, TRUE, TRUE, 
-		   vpc, vpWidthCM, vpHeightCM, &gc, dd);
-	}
-	GEMode(0, dd);
-    }
-    UNPROTECT(2);
-    return R_NilValue;
-}
-
-/* We are assuming here that the R code has checked that x and y 
- * are unit objects and that vp is a viewport
- */
-SEXP L_lines(SEXP x, SEXP y, SEXP index, SEXP arrow) 
-{
-    int i, j, nx, nl, start=0;
-    double *xx, *yy;
-    double xold, yold;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    const void *vmax;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    GEMode(1, dd);
-    /* 
-     * Number of lines 
-     */
-    nl = LENGTH(index);
-    for (j=0; j<nl; j++) {
-	SEXP indices = VECTOR_ELT(index, j);
-	gcontextFromgpar(currentgp, j, &gc, dd);
-	/* 
-	 * Number of vertices
-	 *
-	 * x and y same length forced in R code 
-	 */
-	nx = LENGTH(indices); 
-	/* Convert the x and y values to CM locations */
-	vmax = vmaxget();
-	xx = (double *) R_alloc(nx, sizeof(double));
-	yy = (double *) R_alloc(nx, sizeof(double));
-	xold = NA_REAL;
-	yold = NA_REAL;
-	for (i=0; i<nx; i++) {
-	    transformLocn(x, y, INTEGER(indices)[i] - 1, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd,
-			  transform,
-			  &(xx[i]), &(yy[i]));
-	    /* The graphics engine only takes device coordinates
-	     */
-	    xx[i] = toDeviceX(xx[i], GE_INCHES, dd);
-	    yy[i] = toDeviceY(yy[i], GE_INCHES, dd);
-	    if ((R_FINITE(xx[i]) && R_FINITE(yy[i])) &&
-		!(R_FINITE(xold) && R_FINITE(yold)))
-	        start = i;
-	    else if ((R_FINITE(xold) && R_FINITE(yold)) &&
-		     !(R_FINITE(xx[i]) && R_FINITE(yy[i]))) {
-	        if (i-start > 1) {
-		    GEPolyline(i-start, xx+start, yy+start, &gc, dd);
-		    if (!isNull(arrow)) {
-		        /*
-			 * Can draw an arrow at the start if the points
-			 * include the first point.
-			 * CANNOT draw an arrow at the end point 
-			 * because we have just broken the line for an NA.
-			 */
-		        arrows(xx+start, yy+start, i-start,
-			       arrow, j, start == 0, FALSE,
-			       vpc, vpWidthCM, vpHeightCM, &gc, dd);
-		    }
-		}
-	    }
-	    else if ((R_FINITE(xold) && R_FINITE(yold)) &&
-		     (i == nx-1)) {
-	        GEPolyline(nx-start, xx+start, yy+start, &gc, dd);
-		if (!isNull(arrow)) {
-		    /*
-		     * Can draw an arrow at the start if the points
-		     * include the first point.
-		     * Can draw an arrow at the end point.
-		     */
- 		    arrows(xx+start, yy+start, nx-start, 
-			   arrow, j, start == 0, TRUE,
-			   vpc, vpWidthCM, vpHeightCM, &gc, dd);
-		}
-	    } 
-	    xold = xx[i];
-	    yold = yy[i];
-	}
-	vmaxset(vmax);
-    }
-    GEMode(0, dd);
-    return R_NilValue;
-}
-
-/* We are assuming here that the R code has checked that x and y 
- * are unit objects 
- */
-SEXP gridXspline(SEXP x, SEXP y, SEXP s, SEXP o, SEXP a, SEXP rep, SEXP index,
-		 double theta, Rboolean draw, Rboolean trace) 
-{
-    int i, j, nx, np, nloc;
-    double *xx, *yy, *ss;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    SEXP tracePts = R_NilValue;
-    SEXP result = R_NilValue;
-    double edgex, edgey;
-    double xmin = DOUBLE_XMAX;
-    double xmax = -DOUBLE_XMAX;
-    double ymin = DOUBLE_XMAX;
-    double ymax = -DOUBLE_XMAX;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    gcontextFromgpar(currentgp, 0, &gc, dd);
-    /* 
-     * Number of xsplines
-     */
-    np = LENGTH(index);
-    PROTECT(tracePts = allocVector(VECSXP, np));
-    nloc = 0;
-    for (i=0; i<np; i++) {
-	const void *vmax;
-	SEXP indices = VECTOR_ELT(index, i);
-	SEXP points;
-	gcontextFromgpar(currentgp, i, &gc, dd);
-	/* 
-	 * Number of vertices
-	 *
-	 * Check in R code that x and y same length
-	 */
-	nx = LENGTH(indices); 
-	/* Convert the x and y values to CM locations */
-	vmax = vmaxget();
-	if (draw)
-	    GEMode(1, dd);
-	xx = (double *) R_alloc(nx, sizeof(double));
-	yy = (double *) R_alloc(nx, sizeof(double));
-	ss = (double *) R_alloc(nx, sizeof(double));
-	for (j=0; j<nx; j++) {
-	    ss[j] = REAL(s)[(INTEGER(indices)[j] - 1) % LENGTH(s)];
-	    /*
-	     * If drawing, convert to INCHES on device
-	     * If just calculating bounds, convert to INCHES within current vp
-	     */
-	    if (draw) {
-		transformLocn(x, y, INTEGER(indices)[j] - 1, vpc, &gc,
-			      vpWidthCM, vpHeightCM,
-			      dd,
-			      transform,
-			      &(xx[j]), &(yy[j]));
-	    } else {
-		xx[j] = transformXtoINCHES(x, INTEGER(indices)[j] - 1,
-					   vpc, &gc,
-					   vpWidthCM, vpHeightCM, 
-					   dd);
-		yy[j] = transformYtoINCHES(y, INTEGER(indices)[j] - 1,
-					   vpc, &gc,
-					   vpWidthCM, vpHeightCM, 
-					   dd);	    
-	    }
-	    /* The graphics engine only takes device coordinates
-	     */
-	    xx[j] = toDeviceX(xx[j], GE_INCHES, dd);
-	    yy[j] = toDeviceY(yy[j], GE_INCHES, dd);
-	    if (!(R_FINITE(xx[j]) && R_FINITE(yy[j]))) {
-		    error(_("non-finite control point in Xspline"));
-	    }
-	}
-	PROTECT(points = GEXspline(nx, xx, yy, ss,
-				   LOGICAL(o)[0], LOGICAL(rep)[0],
-				   draw, &gc, dd));
-        {
-            /*
-             * In some cases, GEXspline seems to produce identical points 
-             * (at least observed at end of spline)
-             * so trim identical points from the ends 
-             * (so arrow heads are drawn at correct angle)
-             */
-            int np = LENGTH(VECTOR_ELT(points, 0));
-            double *px = REAL(VECTOR_ELT(points, 0));
-            double *py = REAL(VECTOR_ELT(points, 1));
-            int start = 0;
-            int end = np - 1;
-            /*
-             * DEBUGGING ...
-             int k;
-             for (k=0; k<np; k++) {
-             GESymbol(px[k], py[k], 16, 3, &gc, dd); 
-             }
-	     * ... DEBUGGING
-	     */
-	    while (np > 1 && 
-		   (px[start] == px[start + 1]) &&
-		   (py[start] == py[start + 1])) {
-		start++;
-		np--;
-	    }
-	    while (np > 1 && 
-		   (px[end] == px[end - 1]) &&
-		   (py[end] == py[end - 1])) {
-		end--;
-		np--;
-	    }
-            if (trace) {
-                int k;
-                int count = end - start + 1;
-                double *keepXptr, *keepYptr;
-                SEXP keepPoints, keepX, keepY;
-                PROTECT(keepPoints = allocVector(VECSXP, 2));
-                PROTECT(keepX = allocVector(REALSXP, count));
-                PROTECT(keepY = allocVector(REALSXP, count));
-                keepXptr = REAL(keepX);
-                keepYptr = REAL(keepY);
-                for (k=start; k<(end + 1); k++) {
-                    keepXptr[k - start] = fromDeviceX(px[k], GE_INCHES, dd);
-                    keepYptr[k - start] = fromDeviceY(py[k], GE_INCHES, dd);
-                }
-                SET_VECTOR_ELT(keepPoints, 0, keepX);
-                SET_VECTOR_ELT(keepPoints, 1, keepY);
-                SET_VECTOR_ELT(tracePts, i, keepPoints);
-                UNPROTECT(3); /* keepPoints & keepX & keepY */
-            }
-            if (draw && !isNull(a) && !isNull(points)) {
-                /*
-                 * Can draw an arrow at the either end.
-                 */
-                arrows(&(px[start]), &(py[start]), np,
-                       a, i, TRUE, TRUE,
-                       vpc, vpWidthCM, vpHeightCM, &gc, dd);
-            }
-            if (!draw && !trace && !isNull(points)) {
-                /*
-                 * Update bounds
-                 */
-                int j, n = LENGTH(VECTOR_ELT(points, 0));
-                double *pxx = (double *) R_alloc(n, sizeof(double));
-                double *pyy = (double *) R_alloc(n, sizeof(double));
-                for (j=0; j<n; j++) {
-                    pxx[j] = fromDeviceX(px[j], GE_INCHES, dd);
-                    pyy[j] = fromDeviceY(py[j], GE_INCHES, dd);
-                    if (R_FINITE(pxx[j]) && R_FINITE(pyy[j])) {
-                        if (pxx[j] < xmin)
-                            xmin = pxx[j];
-                        if (pxx[j] > xmax)
-                            xmax = pxx[j];
-                        if (pyy[j] < ymin)
-                            ymin = pyy[j];
-                        if (pyy[j] > ymax)
-                            ymax = pyy[j];
-                        nloc++;
-                    }
-                }
-                /*
-                 * Calculate edgex and edgey for case where this is 
-                 * the only xspline
-                 */
-                hullEdge(pxx, pyy, n, theta, &edgex, &edgey);
-            }
-        } /* End of trimming-redundant-points code */
-	UNPROTECT(1); /* points */
-	if (draw)
-	    GEMode(0, dd);
-	vmaxset(vmax);
-    }
-    if (!draw && !trace && nloc > 0) {
-	PROTECT(result = allocVector(REALSXP, 4));
-	/*
-	 * If there is more than one xspline, just produce edge
-	 * based on bounding rect of all xsplines
-	 */
-	if (np > 1) {
-	    rectEdge(xmin, ymin, xmax, ymax, theta,
-		     &edgex, &edgey);
-	}
-	/*
-	 * Reverse the scale adjustment (zoom factor)
-	 * when calculating physical value to return to user-level
-	 */
-	REAL(result)[0] = edgex / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[1] = edgey / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[2] = (xmax - xmin) / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[3] = (ymax - ymin) / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-        UNPROTECT(1); /* result */
-    } else if (trace) {
-        result = tracePts;
-    }
-    UNPROTECT(1); /* tracePts */
-    return result;
-}
-
-SEXP L_xspline(SEXP x, SEXP y, SEXP s, SEXP o, SEXP a, SEXP rep, SEXP index) 
-{
-    gridXspline(x, y, s, o, a, rep, index, 0, TRUE, FALSE);
-    return R_NilValue;
-}
-
-SEXP L_xsplineBounds(SEXP x, SEXP y, SEXP s, SEXP o, SEXP a, SEXP rep, 
-		     SEXP index, SEXP theta) 
-{
-    return gridXspline(x, y, s, o, a, rep, index, REAL(theta)[0], 
-                       FALSE, FALSE);
-}
-
-SEXP L_xsplinePoints(SEXP x, SEXP y, SEXP s, SEXP o, SEXP a, SEXP rep, 
-		     SEXP index, SEXP theta) 
-{
-    return gridXspline(x, y, s, o, a, rep, index, REAL(theta)[0], 
-                       FALSE, TRUE);
-}
-
-SEXP L_segments(SEXP x0, SEXP y0, SEXP x1, SEXP y1, SEXP arrow) 
-{
-    int i, nx0, ny0, nx1, ny1, maxn;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    maxn = nx0 = unitLength(x0); 
-    ny0 = unitLength(y0);
-    nx1 = unitLength(x1);
-    ny1 = unitLength(y1);
-    if (ny0 > maxn)
-	maxn = ny0;
-    if (nx1 > maxn)
-	maxn = nx1;
-    if (ny1 > maxn)
-	maxn = ny1;
-    /* Convert the x and y values to INCHES locations */
-    /* FIXME:  Need to check for NaN's and NA's
-     */
-    GEMode(1, dd);
-    for (i=0; i<maxn; i++) {
-	double xx0, yy0, xx1, yy1;
-	gcontextFromgpar(currentgp, i, &gc, dd);
-	transformLocn(x0, y0, i, vpc, &gc, 
-		      vpWidthCM, vpHeightCM,
-		      dd, transform, &xx0, &yy0);
-	transformLocn(x1, y1, i, vpc, &gc,
-		      vpWidthCM, vpHeightCM,
-		      dd, transform, &xx1, &yy1);
-	/* The graphics engine only takes device coordinates
-	 */
-	xx0 = toDeviceX(xx0, GE_INCHES, dd);
-	yy0 = toDeviceY(yy0, GE_INCHES, dd);
-	xx1 = toDeviceX(xx1, GE_INCHES, dd);
-	yy1 = toDeviceY(yy1, GE_INCHES, dd);
-	if (R_FINITE(xx0) && R_FINITE(yy0) &&
-	    R_FINITE(xx1) && R_FINITE(yy1)) {
-	    GELine(xx0, yy0, xx1, yy1, &gc, dd);
-	    if (!isNull(arrow)) {
-		double ax[2], ay[2];
-		ax[0] = xx0;
-		ax[1] = xx1;
-		ay[0] = yy0;
-		ay[1] = yy1;
-		arrows(ax, ay, 2,
-		       arrow, i, TRUE, TRUE,
-		       vpc, vpWidthCM, vpHeightCM, &gc, dd);
-	    }
-	}
-    }
-    GEMode(0, dd);
-    return R_NilValue;
-}
-
-static int getArrowN(SEXP x1, SEXP x2, SEXP xnm1, SEXP xn, 
-		     SEXP y1, SEXP y2, SEXP ynm1, SEXP yn)
-{      
-    int nx2, nxnm1, nxn, ny1, ny2, nynm1, nyn, maxn;
-    maxn = 0;
-    /* 
-     * x1, y1, xnm1, and ynm1 could be NULL if this is adding
-     * arrows to a line.to
-     */
-    if (isNull(y1))
-	ny1 = 0;
-    else
-	ny1 = unitLength(y1);
-    nx2 = unitLength(x2);
-    ny2 = unitLength(y2);
-    if (isNull(xnm1))
-	nxnm1 = 0;
-    else
-	nxnm1 = unitLength(xnm1);
-    if (isNull(ynm1))
-	nynm1 = 0;
-    else
-	nynm1 = unitLength(ynm1);
-    nxn = unitLength(xn);
-    nyn = unitLength(yn);
-    if (ny1 > maxn)
-	maxn = ny1;
-    if (nx2 > maxn)
-	maxn = nx2;
-    if (ny2 > maxn)
-	maxn = ny2;
-    if (nxnm1 > maxn)
-	maxn = nxnm1;
-    if (nynm1 > maxn)
-	maxn = nynm1;
-    if (nxn > maxn)
-	maxn = nxn;
-    if (nyn > maxn)
-	maxn = nyn;
-    return maxn;
-}
-
-SEXP L_arrows(SEXP x1, SEXP x2, SEXP xnm1, SEXP xn, 
-	      SEXP y1, SEXP y2, SEXP ynm1, SEXP yn, 
-	      SEXP angle, SEXP length, SEXP ends, SEXP type) 
-{
-    int i, maxn;
-    int ne;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    Rboolean first, last;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    SEXP devloc = R_NilValue; /* -Wall */
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    maxn = getArrowN(x1, x2, xnm1, xn,
-		     y1, y2, ynm1, yn);
-    ne = LENGTH(ends);
-    /* Convert the x and y values to INCHES locations */
-    /* FIXME:  Need to check for NaN's and NA's
-     */
-    GEMode(1, dd);
-    for (i=0; i<maxn; i++) {
-	double xx1, xx2, xxnm1, xxn, yy1, yy2, yynm1, yyn;
-	double vertx[3];
-	double verty[3];
-	first = TRUE;
-	last = TRUE;
-	switch (INTEGER(ends)[i % ne]) {
-	case 2: 
-	    first = FALSE;
-	    break;
-	case 1:
-	    last = FALSE;
-	    break;
-	}
-	gcontextFromgpar(currentgp, i, &gc, dd);
-	/*
-	 * If we're adding arrows to a line.to
-	 * x1 will be NULL
-	 */
-	if (isNull(x1)) 
-	    PROTECT(devloc = gridStateElement(dd, GSS_CURRLOC));
-	if (first) {
-	    if (isNull(x1)) {
-		xx1 = REAL(devloc)[0];
-		yy1 = REAL(devloc)[1];
-	    } else 
-		transformLocn(x1, y1, i, vpc, &gc,
-			      vpWidthCM, vpHeightCM,
-			      dd, transform, &xx1, &yy1);
-	    transformLocn(x2, y2, i, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd, transform, &xx2, &yy2);
-	    calcArrow(xx1, yy1, xx2, yy2, angle, length, i,
-		      vpc, vpWidthCM, vpHeightCM,
-		      vertx, verty, &gc, dd);
-	    /* 
-	     * Only draw arrow if both ends of first segment 
-	     * are not non-finite
-	     */
-	    if (R_FINITE(toDeviceX(xx2, GE_INCHES, dd)) &&
-		R_FINITE(toDeviceY(yy2, GE_INCHES, dd)) &&
-		R_FINITE(vertx[1]) && R_FINITE(verty[1]))
-		drawArrow(vertx, verty, type, i, &gc, dd);
-	}
-	if (last) {
-	    if (isNull(xnm1)) {
-		xxnm1 = REAL(devloc)[0];
-		yynm1 = REAL(devloc)[1];
-	    } else 
-		transformLocn(xnm1, ynm1, i, vpc, &gc,
-			      vpWidthCM, vpHeightCM,
-			      dd, transform, &xxnm1, &yynm1);
-	    transformLocn(xn, yn, i, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd, transform, &xxn, &yyn);
-	    calcArrow(xxn, yyn, xxnm1, yynm1, angle, length, i,
-		      vpc, vpWidthCM, vpHeightCM,
-		      vertx, verty, &gc, dd);
-	    /* 
-	     * Only draw arrow if both ends of laste segment are
-	     * not non-finite
-	     */
-	    if (R_FINITE(toDeviceX(xxnm1, GE_INCHES, dd)) &&
-		R_FINITE(toDeviceY(yynm1, GE_INCHES, dd)) &&
-		R_FINITE(vertx[1]) && R_FINITE(verty[1]))
-		drawArrow(vertx, verty, type, i, &gc, dd);
-	}
-	if (isNull(x1))
-	    UNPROTECT(1);
-    }
-    GEMode(0, dd);
-    return R_NilValue;
-}
-
-SEXP L_polygon(SEXP x, SEXP y, SEXP index)
-{
-    int i, j, nx, np, start=0;
-    double *xx, *yy;
-    double xold, yold;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    GEMode(1, dd);
-    /* 
-     * Number of polygons 
-     */
-    np = LENGTH(index);
-    for (i=0; i<np; i++) {
-	const void *vmax;
-	SEXP indices = VECTOR_ELT(index, i);
-	gcontextFromgpar(currentgp, i, &gc, dd);
-	/* 
-	 * Number of vertices
-	 *
-	 * Check in R code that x and y same length
-	 */
-	nx = LENGTH(indices); 
-	/* Convert the x and y values to CM locations */
-	vmax = vmaxget();
-	xx = (double *) R_alloc(nx + 1, sizeof(double));
-	yy = (double *) R_alloc(nx + 1, sizeof(double));
-	xold = NA_REAL;
-	yold = NA_REAL;
-	for (j=0; j<nx; j++) {
-	    transformLocn(x, y, INTEGER(indices)[j] - 1, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd,
-			  transform,
-			  &(xx[j]), &(yy[j]));
-	    /* The graphics engine only takes device coordinates
-	     */
-	    xx[j] = toDeviceX(xx[j], GE_INCHES, dd);
-	    yy[j] = toDeviceY(yy[j], GE_INCHES, dd);
-	    if ((R_FINITE(xx[j]) && R_FINITE(yy[j])) &&
-		!(R_FINITE(xold) && R_FINITE(yold)))
-		start = j; /* first point of current segment */
-	    else if ((R_FINITE(xold) && R_FINITE(yold)) &&
-		     !(R_FINITE(xx[j]) && R_FINITE(yy[j]))) {
-		if (j-start > 1) {
-		    GEPolygon(j-start, xx+start, yy+start, &gc, dd);
-		}
-	    }
-	    else if ((R_FINITE(xold) && R_FINITE(yold)) && (j == nx-1)) { 
-		/* last */
-		GEPolygon(nx-start, xx+start, yy+start, &gc, dd);
-	    }
-	    xold = xx[j];
-	    yold = yy[j];
-	}
-	vmaxset(vmax);
-    }
-    GEMode(0, dd);
-    return R_NilValue;
-}
-
-static SEXP gridCircle(SEXP x, SEXP y, SEXP r, 
-		       double theta, Rboolean draw)
-{
-    int i, nx, ny, nr, ncirc;
-    double xx, yy, rr1, rr2, rr = 0.0 /* -Wall */;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    SEXP result = R_NilValue;
-    double xmin = DOUBLE_XMAX;
-    double xmax = -DOUBLE_XMAX;
-    double ymin = DOUBLE_XMAX;
-    double ymax = -DOUBLE_XMAX;
-    double edgex, edgey;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    nx = unitLength(x); 
-    ny = unitLength(y);
-    nr = unitLength(r);
-    if (ny > nx) 
-	nx = ny;
-    if (nr > nx)
-	nx = nr;
-    if (draw) {
-	GEMode(1, dd);
-    }
-    ncirc = 0;
-    for (i=0; i<nx; i++) {
-	gcontextFromgpar(currentgp, i, &gc, dd);
-	/*
-	 * If drawing, convert to INCHES on device
-	 * If just calculating bounds, convert to INCHES within current vp
-	 */
-	if (draw) {
-	    transformLocn(x, y, i, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd,
-			  transform,
-			  &xx, &yy);
-	} else {
-	    xx = transformXtoINCHES(x, i, vpc, &gc,
-				    vpWidthCM, vpHeightCM, 
-				    dd);
-	    yy = transformYtoINCHES(y, i, vpc, &gc,
-				    vpWidthCM, vpHeightCM, 
-				    dd);	    
-	}
-	/* These two will give the same answer unless r is in "native",
-	 * "npc", or some other relative units;  in those cases, just
-	 * take the smaller of the two values.
-	 */
-	rr1 = transformWidthtoINCHES(r, i % nr, vpc, &gc,
-				     vpWidthCM, vpHeightCM,
-				     dd);
-	rr2 = transformHeighttoINCHES(r, i % nr, vpc, &gc,
-				      vpWidthCM, vpHeightCM,
-				      dd);
-	/*
-	 * A negative radius is silently converted to absolute value
-	 */
-	rr = fmin2(fabs(rr1), fabs(rr2));
-	if (R_FINITE(xx) && R_FINITE(yy) && R_FINITE(rr)) {
-	    if (draw) {
-                /* The graphics engine only takes device coordinates
-		 */
-                xx = toDeviceX(xx, GE_INCHES, dd);
-		yy = toDeviceY(yy, GE_INCHES, dd);
-		rr = toDeviceWidth(rr, GE_INCHES, dd);
-		GECircle(xx, yy, rr, &gc, dd);
-	    } else {
-		if (xx + rr < xmin)
-		    xmin = xx + rr;
-		if (xx + rr > xmax)
-		    xmax = xx + rr;
-		if (xx - rr < xmin)
-		    xmin = xx - rr;
-		if (xx - rr > xmax)
-		    xmax = xx - rr;
-		if (yy + rr < ymin)
-		    ymin = yy + rr;
-		if (yy + rr > ymax)
-		    ymax = yy + rr;
-		if (yy - rr < ymin)
-		    ymin = yy - rr;
-		if (yy - rr > ymax)
-		    ymax = yy - rr;
-		ncirc++;		
-	    }
-	}
-    }
-    if (draw) {
-	GEMode(0, dd);
-    } else if (ncirc > 0) {
-	result = allocVector(REALSXP, 4);
-	if (ncirc == 1) {
-	    /*
-	     * Produce edge of actual circle
-	     */
-	    circleEdge(xx, yy, rr, theta, &edgex, &edgey);
-	} else {
-	    /*
-	     * Produce edge of rect bounding all circles
-	     */
-	    rectEdge(xmin, ymin, xmax, ymax, theta,
-		     &edgex, &edgey);
-	}
-	/*
-	 * Reverse the scale adjustment (zoom factor)
-	 * when calculating physical value to return to user-level
-	 */
-	REAL(result)[0] = edgex / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[1] = edgey /
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[2] = (xmax - xmin) /
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[3] = (ymax - ymin) / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-    } 
-    return result;
-}
-
-SEXP L_circle(SEXP x, SEXP y, SEXP r)
-{
-    gridCircle(x, y, r, 0, TRUE);
-    return R_NilValue;
-}
-
-SEXP L_circleBounds(SEXP x, SEXP y, SEXP r, SEXP theta)
-{
-    return gridCircle(x, y, r, REAL(theta)[0], FALSE);
-}
-
-/* We are assuming here that the R code has checked that 
- * x, y, w, and h are all unit objects and that vp is a viewport
- */
-static SEXP gridRect(SEXP x, SEXP y, SEXP w, SEXP h, 
-		     SEXP hjust, SEXP vjust, double theta, Rboolean draw) 
-{
-    double xx, yy, ww, hh;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    int i, ny, nw, nh, maxn, nrect;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    SEXP result = R_NilValue;
-    double edgex, edgey;
-    double xmin = DOUBLE_XMAX;
-    double xmax = -DOUBLE_XMAX;
-    double ymin = DOUBLE_XMAX;
-    double ymax = -DOUBLE_XMAX;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    maxn = unitLength(x); 
-    ny = unitLength(y); 
-    nw = unitLength(w); 
-    nh = unitLength(h); 
-    if (ny > maxn)
-	maxn = ny;
-    if (nw > maxn)
-	maxn = nw;
-    if (nh > maxn)
-	maxn = nh;
-    if (draw) {
-	GEMode(1, dd);
-    }
-    nrect = 0;
-    for (i=0; i<maxn; i++) {
-	gcontextFromgpar(currentgp, i, &gc, dd);
-	/*
-	 * If drawing, convert to INCHES on device
-	 * If just calculating bounds, convert to INCHES within current vp
-	 */
-	if (draw) {	
-	    transformLocn(x, y, i, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd,
-			  transform,
-			  &xx, &yy);
-	} else {
-	    xx = transformXtoINCHES(x, i, vpc, &gc,
-				    vpWidthCM, vpHeightCM, 
-				    dd);
-	    yy = transformYtoINCHES(y, i, vpc, &gc,
-				    vpWidthCM, vpHeightCM, 
-				    dd);	    
-	}
-	ww = transformWidthtoINCHES(w, i, vpc, &gc,
-				    vpWidthCM, vpHeightCM,
-				    dd);
-	hh = transformHeighttoINCHES(h, i, vpc, &gc,
-				     vpWidthCM, vpHeightCM,
-				     dd);
-	/* If the total rotation angle is zero then we can draw a 
-	 * rectangle as the devices understand rectangles
-	 * Otherwise we have to draw a polygon equivalent.
-	 */
-	if (draw) {
-	    if (rotationAngle == 0) {
-		xx = justifyX(xx, ww, REAL(hjust)[i % LENGTH(hjust)]);
-		yy = justifyY(yy, hh, REAL(vjust)[i % LENGTH(vjust)]);
-		/* The graphics engine only takes device coordinates
-		 */
-		xx = toDeviceX(xx, GE_INCHES, dd);
-		yy = toDeviceY(yy, GE_INCHES, dd);
-		ww = toDeviceWidth(ww, GE_INCHES, dd);
-		hh = toDeviceHeight(hh, GE_INCHES, dd);
-		if (R_FINITE(xx) && R_FINITE(yy) && 
-		    R_FINITE(ww) && R_FINITE(hh))
-		    GERect(xx, yy, xx + ww, yy + hh, &gc, dd);
-	    } else {
-		/* We have to do a little bit of work to figure out where the 
-		 * corners of the rectangle are.
-		 */
-		double xxx[5], yyy[5], xadj, yadj;
-		double dw, dh;
-		SEXP zeroInches, xadjInches, yadjInches, wwInches, hhInches;
-		int tmpcol;
-                PROTECT(zeroInches = unit(0, L_INCHES));
-		/* Find bottom-left location */
-		justification(ww, hh, 
-			      REAL(hjust)[i % LENGTH(hjust)], 
-			      REAL(vjust)[i % LENGTH(vjust)], 
-			      &xadj, &yadj);
-		PROTECT(xadjInches = unit(xadj, L_INCHES));
-		PROTECT(yadjInches = unit(yadj, L_INCHES));
-		transformDimn(xadjInches, yadjInches, 0, vpc, &gc,
-			      vpWidthCM, vpHeightCM,
-			      dd, rotationAngle,
-			      &dw, &dh);
-		xxx[0] = xx + dw;
-		yyy[0] = yy + dh;
-		/* Find top-left location */
-		PROTECT(hhInches = unit(hh, L_INCHES));
-		transformDimn(zeroInches, hhInches, 0, vpc, &gc,
-			      vpWidthCM, vpHeightCM,
-			      dd, rotationAngle,
-			      &dw, &dh);
-		xxx[1] = xxx[0] + dw;
-		yyy[1] = yyy[0] + dh;
-		/* Find top-right location */
-		PROTECT(wwInches = unit(ww, L_INCHES));
-		transformDimn(wwInches, hhInches, 0, vpc, &gc,
-			      vpWidthCM, vpHeightCM,
-			      dd, rotationAngle,
-			      &dw, &dh);
-		xxx[2] = xxx[0] + dw;
-		yyy[2] = yyy[0] + dh;
-		/* Find bottom-right location */
-		transformDimn(wwInches, zeroInches, 0, vpc, &gc,
-			      vpWidthCM, vpHeightCM,
-			      dd, rotationAngle,
-			      &dw, &dh);
-		xxx[3] = xxx[0] + dw;
-		yyy[3] = yyy[0] + dh;
-		if (R_FINITE(xxx[0]) && R_FINITE(yyy[0]) &&
-		    R_FINITE(xxx[1]) && R_FINITE(yyy[1]) &&
-		    R_FINITE(xxx[2]) && R_FINITE(yyy[2]) &&
-		    R_FINITE(xxx[3]) && R_FINITE(yyy[3])) {
-		    /* The graphics engine only takes device coordinates
-		     */
-		    xxx[0] = toDeviceX(xxx[0], GE_INCHES, dd);
-		    yyy[0] = toDeviceY(yyy[0], GE_INCHES, dd);
-		    xxx[1] = toDeviceX(xxx[1], GE_INCHES, dd);
-		    yyy[1] = toDeviceY(yyy[1], GE_INCHES, dd);
-		    xxx[2] = toDeviceX(xxx[2], GE_INCHES, dd);
-		    yyy[2] = toDeviceY(yyy[2], GE_INCHES, dd);
-		    xxx[3] = toDeviceX(xxx[3], GE_INCHES, dd);
-		    yyy[3] = toDeviceY(yyy[3], GE_INCHES, dd);
-		    /* Close the polygon */
-		    xxx[4] = xxx[0];
-		    yyy[4] = yyy[0];
-		    /* Do separate fill and border to avoid border being 
-		     * drawn on clipping boundary when there is a fill
-		     */
-		    tmpcol = gc.col;
-		    gc.col = R_TRANWHITE;
-		    GEPolygon(5, xxx, yyy, &gc, dd);
-		    gc.col = tmpcol;
-		    gc.fill = R_TRANWHITE;
-		    GEPolygon(5, xxx, yyy, &gc, dd);
-		}
-                UNPROTECT(5);
-	    }
-	} else { /* Just calculating boundary */
-	    xx = justifyX(xx, ww, REAL(hjust)[i % LENGTH(hjust)]);
-	    yy = justifyY(yy, hh, REAL(vjust)[i % LENGTH(vjust)]);
-	    if (R_FINITE(xx) && R_FINITE(yy) && 
-		R_FINITE(ww) && R_FINITE(hh)) {
-		if (xx < xmin)
-		    xmin = xx;
-		if (xx > xmax)
-		    xmax = xx;
-		if (xx + ww < xmin)
-		    xmin = xx + ww;
-		if (xx + ww > xmax)
-		    xmax = xx + ww;
-		if (yy < ymin)
-		    ymin = yy;
-		if (yy > ymax)
-		    ymax = yy;
-		if (yy + hh < ymin)
-		    ymin = yy + hh;
-		if (yy + hh > ymax)
-		    ymax = yy + hh;
-		/*
-		 * Calculate edgex and edgey for case where this is 
-		 * the only rect
-		 */
-		rectEdge(xx, yy, xx + ww, yy + hh, theta,
-			 &edgex, &edgey);
-		nrect++;
-	    }
-	}
-    }
-    if (draw) {
-	GEMode(0, dd);
-    }
-    if (nrect > 0) {
-	result = allocVector(REALSXP, 4);
-	/*
-	 * If there is more than one rect, just produce edge
-	 * based on bounding rect of all rects
-	 */
-	if (nrect > 1) {
-	    rectEdge(xmin, ymin, xmax, ymax, theta,
-		     &edgex, &edgey);
-	}
-	/*
-	 * Reverse the scale adjustment (zoom factor)
-	 * when calculating physical value to return to user-level
-	 */
-	REAL(result)[0] = edgex / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[1] = edgey /
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[2] = (xmax - xmin) /
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[3] = (ymax - ymin) / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-    } 
-    return result;
-}
-
-SEXP L_rect(SEXP x, SEXP y, SEXP w, SEXP h, SEXP hjust, SEXP vjust) 
-{
-    gridRect(x, y, w, h, hjust, vjust, 0, TRUE);
-    return R_NilValue;    
-}
-
-SEXP L_rectBounds(SEXP x, SEXP y, SEXP w, SEXP h, SEXP hjust, SEXP vjust,
-		  SEXP theta) 
-{
-    return gridRect(x, y, w, h, hjust, vjust, REAL(theta)[0], FALSE);
-}
-
-/* FIXME: need to add L_pathBounds ? */
-
-SEXP L_path(SEXP x, SEXP y, SEXP index, SEXP rule)
-{
-    int i, j, k, npoly, *nper, ntot;
-    double *xx, *yy;
-    const void *vmax;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    GEMode(1, dd);
-    vmax = vmaxget();
-    /* 
-     * Number of polygons 
-     */
-    npoly = LENGTH(index);
-    /* 
-     * Total number of points and 
-     * Number of points per polygon
-     */ 
-    ntot = 0;
-    nper = (int *) R_alloc(npoly, sizeof(int));
-    for (i=0; i < npoly; i++) {
-        nper[i] = LENGTH(VECTOR_ELT(index, i));
-        ntot = ntot + nper[i];
-    }
-    xx = (double *) R_alloc(ntot, sizeof(double));
-    yy = (double *) R_alloc(ntot, sizeof(double));
-    k = 0;
-    for (i=0; i < npoly; i++) {
-        SEXP indices = VECTOR_ELT(index, i);
-        for (j=0; j < nper[i]; j++) {            
-	    transformLocn(x, y, INTEGER(indices)[j] - 1, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd,
-			  transform,
-			  &(xx[k]), &(yy[k]));
-	    /* The graphics engine only takes device coordinates
-	     */
-	    xx[k] = toDeviceX(xx[k], GE_INCHES, dd);
-	    yy[k] = toDeviceY(yy[k], GE_INCHES, dd);
-            /* NO NA values allowed in 'x' or 'y'
-             */
-            if (!R_FINITE(xx[k]) || !R_FINITE(yy[k]))
-                error(_("non-finite x or y in graphics path"));
-            k++;
-        }
-    }
-    gcontextFromgpar(currentgp, 0, &gc, dd);
-    GEPath(xx, yy, npoly, nper, INTEGER(rule)[0], &gc, dd);
-    vmaxset(vmax);
-    GEMode(0, dd);
-    return R_NilValue;
-}
-
-/* FIXME: need to add L_rasterBounds */
-
-/* FIXME:  Add more checks on correct inputs,
-   e.g., Raster should be a matrix of R colors */
-SEXP L_raster(SEXP raster, SEXP x, SEXP y, SEXP w, SEXP h, 
-              SEXP hjust, SEXP vjust, SEXP interpolate)
-{
-    const void *vmax;
-    int i, n, ny, nw, nh, maxn;
-    double xx, yy, ww, hh;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    SEXP dim;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    unsigned int *image;
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    /* Convert the raster matrix to R internal colours */
-    n = LENGTH(raster);
-    if (n <= 0) {
-        error(_("Empty raster"));  
-    }
-    vmax = vmaxget();
-    /* raster is rather inefficient so allow a native representation as
-       an integer array which requires no conversion */
-    if (inherits(raster, "nativeRaster") && isInteger(raster)) {
-	image = (unsigned int*) INTEGER(raster);
-    } else {
-        image = (unsigned int*) R_alloc(n, sizeof(unsigned int));
-        for (i=0; i<n; i++) {
-            image[i] = RGBpar3(raster, i, R_TRANWHITE);
-        }
-    }
-    dim = getAttrib(raster, R_DimSymbol);
-    maxn = unitLength(x); 
-    ny = unitLength(y); 
-    nw = unitLength(w); 
-    nh = unitLength(h); 
-    if (ny > maxn)
-	maxn = ny;
-    if (nw > maxn)
-	maxn = nw;
-    if (nh > maxn)
-	maxn = nh;
-    GEMode(1, dd);
-    for (i=0; i<maxn; i++) {
-        gcontextFromgpar(currentgp, i, &gc, dd);
-        transformLocn(x, y, i, vpc, &gc,
-                      vpWidthCM, vpHeightCM,
-                      dd,
-                      transform,
-                      &xx, &yy);
-        ww = transformWidthtoINCHES(w, i, vpc, &gc,
-                                    vpWidthCM, vpHeightCM,
-                                    dd);
-        hh = transformHeighttoINCHES(h, i, vpc, &gc,
-                                     vpWidthCM, vpHeightCM,
-                                     dd);
-        if (rotationAngle == 0) {
-            xx = justifyX(xx, ww, REAL(hjust)[i % LENGTH(hjust)]);
-            yy = justifyY(yy, hh, REAL(vjust)[i % LENGTH(vjust)]);
-            /* The graphics engine only takes device coordinates
-             */
-            xx = toDeviceX(xx, GE_INCHES, dd);
-            yy = toDeviceY(yy, GE_INCHES, dd);
-            ww = toDeviceWidth(ww, GE_INCHES, dd);
-            hh = toDeviceHeight(hh, GE_INCHES, dd);
-            if (R_FINITE(xx) && R_FINITE(yy) && 
-                R_FINITE(ww) && R_FINITE(hh))
-                GERaster(image, INTEGER(dim)[1], INTEGER(dim)[0],
-                         xx, yy, ww, hh, rotationAngle, 
-                         LOGICAL(interpolate)[i % LENGTH(interpolate)], 
-                         &gc, dd);
-        } else {
-            /* We have to do a little bit of work to figure out where the 
-             * bottom-left corner of the image is.
-             */
-            double xbl, ybl, xadj, yadj;
-            double dw, dh;
-            SEXP xadjInches, yadjInches;
-            /* Find bottom-left location */
-            justification(ww, hh, 
-                          REAL(hjust)[i % LENGTH(hjust)], 
-                          REAL(vjust)[i % LENGTH(vjust)], 
-                          &xadj, &yadj);
-            PROTECT(xadjInches = unit(xadj, L_INCHES));
-            PROTECT(yadjInches = unit(yadj, L_INCHES));
-            transformDimn(xadjInches, yadjInches, 0, vpc, &gc,
-                          vpWidthCM, vpHeightCM,
-                          dd, rotationAngle,
-                          &dw, &dh);
-            xbl = xx + dw;
-            ybl = yy + dh;
-            xbl = toDeviceX(xbl, GE_INCHES, dd);
-            ybl = toDeviceY(ybl, GE_INCHES, dd);
-            ww = toDeviceWidth(ww, GE_INCHES, dd);
-            hh = toDeviceHeight(hh, GE_INCHES, dd);
-            if (R_FINITE(xbl) && R_FINITE(ybl) &&
-                R_FINITE(ww) && R_FINITE(hh)) {
-                /* The graphics engine only takes device coordinates
-                 */
-                GERaster(image, INTEGER(dim)[1], INTEGER(dim)[0],
-                         xbl, ybl, ww, hh, rotationAngle, 
-                         LOGICAL(interpolate)[i % LENGTH(interpolate)], 
-                         &gc, dd);
-            }
-            UNPROTECT(2);
-        }
-    }
-    GEMode(0, dd);
-    vmaxset(vmax);
-    return R_NilValue;
-}
-
-SEXP L_cap()
-{
-    int i, col, row, nrow, ncol, size;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    int *rint;
-    SEXP raster; 
-    /* The raster is R internal colours, so convert to 
-     * R external colours (strings) 
-     * AND the raster is BY ROW so need to rearrange it
-     * to be BY COLUMN (though the dimensions are correct) */
-    SEXP image, idim;
-    
-    PROTECT(raster = GECap(dd));
-    /* Non-complying devices will return NULL */
-    if (isNull(raster)) {
-        image = raster;
-    } else {
-        size = LENGTH(raster);
-        nrow = INTEGER(getAttrib(raster, R_DimSymbol))[0];
-        ncol = INTEGER(getAttrib(raster, R_DimSymbol))[1];
-        
-        PROTECT(image = allocVector(STRSXP, size));
-        rint = INTEGER(raster);
-        for (i=0; i<size; i++) {
-            col = i % ncol + 1;
-            row = i / ncol + 1;
-            SET_STRING_ELT(image, (col - 1)*nrow + row - 1, 
-                           mkChar(col2name(rint[i])));
-        }
-        
-        PROTECT(idim = allocVector(INTSXP, 2));
-        INTEGER(idim)[0] = nrow;
-        INTEGER(idim)[1] = ncol;
-        setAttrib(image, R_DimSymbol, idim);
-        
-        UNPROTECT(2);
-    }
-    UNPROTECT(1);
-    return image;
-}
-
-/*
- * Code to draw OR size text
- * Combined to avoid code replication
- */
-static SEXP gridText(SEXP label, SEXP x, SEXP y, SEXP hjust, SEXP vjust, 
-		     SEXP rot, SEXP checkOverlap, double theta, Rboolean draw)
-{
-    int i, nx, ny;
-    double *xx, *yy;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP txt, result = R_NilValue;
-    double edgex, edgey;
-    double xmin = DOUBLE_XMAX;
-    double xmax = -DOUBLE_XMAX;
-    double ymin = DOUBLE_XMAX;
-    double ymax = -DOUBLE_XMAX;
-    /* 
-     * Bounding rectangles for checking overlapping
-     * Initialised to shut up compiler
-     */
-    LRect *bounds = NULL;
-    LRect trect;
-    int numBounds = 0;
-    int overlapChecking = LOGICAL(checkOverlap)[0];
-    const void *vmax;
-    SEXP currentvp, currentgp;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    nx = unitLength(x); 
-    ny = unitLength(y);
-    if (ny > nx) 
-	nx = ny;
-    vmax = vmaxget();
-    xx = (double *) R_alloc(nx, sizeof(double));
-    yy = (double *) R_alloc(nx, sizeof(double));
-    for (i=0; i<nx; i++) {
-	gcontextFromgpar(currentgp, i, &gc, dd);
-	/*
-	 * If drawing, convert to INCHES on device
-	 * If just calculating bounds, convert to INCHES within current vp
-	 */
-	if (draw) {	
-	    transformLocn(x, y, i, vpc, &gc,
-			  vpWidthCM, vpHeightCM,
-			  dd,
-			  transform,
-			  &(xx[i]), &(yy[i]));
-	} else {
-	    xx[i] = transformXtoINCHES(x, i, vpc, &gc,
-				       vpWidthCM, vpHeightCM, 
-				       dd);
-	    yy[i] = transformYtoINCHES(y, i, vpc, &gc,
-				       vpWidthCM, vpHeightCM, 
-				       dd);	    
-	}
-    }
-    /* The label can be a string or an expression
-     */
-    PROTECT(txt = label);
-    if (isSymbol(txt) || isLanguage(txt))
-	txt = coerceVector(txt, EXPRSXP);
-    else if (!isExpression(txt))
-	txt = coerceVector(txt, STRSXP);
-    if (overlapChecking || !draw) {
-	bounds = (LRect *) R_alloc(nx, sizeof(LRect));
-    }
-    /* 
-     * Check we have any text to draw
-     */
-    if (LENGTH(txt) > 0) {
-	int ntxt = 0;
-	if (draw) {
-	    /*
-	     * Drawing text
-	     */
-	    GEMode(1, dd);
-	}
-	for (i=0; i<nx; i++) {
-	    int doDrawing = 1;
-	    gcontextFromgpar(currentgp, i, &gc, dd);
-	    /* 
-	     * Generate bounding boxes when checking for overlap
-	     * or sizing text
-	     */
-	    if (overlapChecking || !draw) {
-		int j = 0;
-		textRect(xx[i], yy[i], txt, i, &gc,
-			 REAL(hjust)[i % LENGTH(hjust)], 
-			 REAL(vjust)[i % LENGTH(vjust)], 
-			 /*
-			  * When calculating bounding rect for text
-			  * only consider rotation of text within 
-			  * local context, not relative to device
-			  * (so don't add rotationAngle)
-			  */
-			 numeric(rot, i % LENGTH(rot)), 
-			 dd, &trect);
-		while (doDrawing && (j < numBounds)) 
-		    if (intersect(trect, bounds[j++]))
-			doDrawing = 0;
-		if (doDrawing) {
-		    copyRect(trect, &(bounds[numBounds]));
-		    numBounds++;
-		}
-	    }
-	    if (draw && doDrawing) {
-		/* The graphics engine only takes device coordinates
-		 */
-		xx[i] = toDeviceX(xx[i], GE_INCHES, dd);
-		yy[i] = toDeviceY(yy[i], GE_INCHES, dd);
-		if (R_FINITE(xx[i]) && R_FINITE(yy[i])) {
-		    gcontextFromgpar(currentgp, i, &gc, dd);
-		    if (isExpression(txt))
-			GEMathText(xx[i], yy[i],
-				   VECTOR_ELT(txt, i % LENGTH(txt)),
-				   REAL(hjust)[i % LENGTH(hjust)], 
-				   REAL(vjust)[i % LENGTH(vjust)], 
-				   numeric(rot, i % LENGTH(rot)) + 
-				   rotationAngle, 
-				   &gc, dd);
-		    else
-			GEText(xx[i], yy[i], 
-			       CHAR(STRING_ELT(txt, i % LENGTH(txt))),
-			       (gc.fontface == 5) ? CE_SYMBOL :
-			       getCharCE(STRING_ELT(txt, i % LENGTH(txt))),
-			       REAL(hjust)[i % LENGTH(hjust)], 
-			       REAL(vjust)[i % LENGTH(vjust)], 
-			       numeric(rot, i % LENGTH(rot)) + 
-			       rotationAngle, 
-			       &gc, dd);
-		}
-	    }
-	    if (!draw) {
-		double minx, maxx, miny, maxy;
-		/*
-		 * Sizing text
-		 */
-		if (R_FINITE(xx[i]) && R_FINITE(yy[i])) {
-		    minx = fmin2(trect.x1, 
-				 fmin2(trect.x2, 
-				       fmin2(trect.x3, trect.x4)));
-		    if (minx < xmin)
-			xmin = minx;
-		    maxx = fmax2(trect.x1, 
-				 fmax2(trect.x2, 
-				       fmax2(trect.x3, trect.x4)));
-		    if (maxx > xmax)
-			xmax = maxx;
-		    miny = fmin2(trect.y1, 
-				 fmin2(trect.y2, 
-				       fmin2(trect.y3, trect.y4)));
-		    if (miny < ymin)
-			ymin = miny;
-		    maxy = fmax2(trect.y1, 
-				 fmax2(trect.y2, 
-				       fmax2(trect.y3, trect.y4)));
-		    if (maxy > ymax)
-			ymax = maxy;
-		    /*
-		     * Calculate edgex and edgey for case where this is 
-		     * the only rect
-		     */
-		    {
-			double xxx[4], yyy[4];
-			/*
-			 * Must be in clock-wise order for polygonEdge
-			 */
-			xxx[0] = trect.x4; yyy[0] = trect.y4;
-			xxx[1] = trect.x3; yyy[1] = trect.y3;
-			xxx[2] = trect.x2; yyy[2] = trect.y2;
-			xxx[3] = trect.x1; yyy[3] = trect.y1;
-			polygonEdge(xxx, yyy, 4, theta,
-				    &edgex, &edgey);
-		    }
-		    ntxt++;
-		}
-	    }
-	}
-	if (draw) {
-	    GEMode(0, dd);
-	}
-	if (ntxt > 0) {
-	    result = allocVector(REALSXP, 4);
-	    /*
-	     * If there is more than one text, just produce edge
-	     * based on bounding rect of all text
-	     */
-	    if (ntxt > 1) {
-		/*
-		 * Produce edge of rect bounding all text
-		 */
-		rectEdge(xmin, ymin, xmax, ymax, theta,
-			 &edgex, &edgey);
-	    }
-	    /*
-	     * Reverse the scale adjustment (zoom factor)
-	     * when calculating physical value to return to user-level
-	     */
-	    REAL(result)[0] = edgex / 
-		REAL(gridStateElement(dd, GSS_SCALE))[0];
-	    REAL(result)[1] = edgey / 
-		REAL(gridStateElement(dd, GSS_SCALE))[0];
-	    REAL(result)[2] = (xmax - xmin) / 
-		REAL(gridStateElement(dd, GSS_SCALE))[0];
-	    REAL(result)[3] = (ymax - ymin) / 
-		REAL(gridStateElement(dd, GSS_SCALE))[0];
-	}
-    }
-    vmaxset(vmax);
-    UNPROTECT(1);
-    return result;
-}
-
-SEXP L_text(SEXP label, SEXP x, SEXP y, SEXP hjust, SEXP vjust, 
-	    SEXP rot, SEXP checkOverlap)
-{
-    gridText(label, x, y, hjust, vjust, rot, checkOverlap, 0, TRUE);
-    return R_NilValue;    
-}
-
-/*
- * Return four values representing boundary of text (which may consist
- * of multiple pieces of text, unaligned, and/or rotated) 
- * in INCHES.
- *
- * Result is (xmin, xmax, ymin, ymax)
- *
- * Return NULL if no text to draw;  R code will generate unit from that
- */
-SEXP L_textBounds(SEXP label, SEXP x, SEXP y, 
-		  SEXP hjust, SEXP vjust, SEXP rot, SEXP theta)
-{
-    SEXP checkOverlap = allocVector(LGLSXP, 1);
-    LOGICAL(checkOverlap)[0] = FALSE;
-    return gridText(label, x, y, hjust, vjust, rot, checkOverlap, 
-		    REAL(theta)[0], FALSE);
-}
-
-SEXP L_points(SEXP x, SEXP y, SEXP pch, SEXP size)
-{
-    int i, nx, npch;
-    /*    double *xx, *yy;*/
-    double *xx, *yy;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    double symbolSize;
-    const void *vmax;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    nx = unitLength(x); 
-    npch = LENGTH(pch);
-    /* Convert the x and y values to CM locations */
-    vmax = vmaxget();
-    xx = (double *) R_alloc(nx, sizeof(double));
-    yy = (double *) R_alloc(nx, sizeof(double));
-    for (i=0; i<nx; i++) {
-	gcontextFromgpar(currentgp, i, &gc, dd);
-	transformLocn(x, y, i, vpc, &gc,
-		      vpWidthCM, vpHeightCM,
-		      dd,
-		      transform,
-		      &(xx[i]), &(yy[i]));
-	/* The graphics engine only takes device coordinates
-	 */
-	xx[i] = toDeviceX(xx[i], GE_INCHES, dd);
-	yy[i] = toDeviceY(yy[i], GE_INCHES, dd);
-    }
-    GEMode(1, dd);
-    for (i=0; i<nx; i++)
-	if (R_FINITE(xx[i]) && R_FINITE(yy[i])) {
-	    /* FIXME:  The symbols will not respond to viewport
-	     * rotations !!!
-	     */
-	    int ipch = NA_INTEGER /* -Wall */;
-	    gcontextFromgpar(currentgp, i, &gc, dd);
-	    symbolSize = transformWidthtoINCHES(size, i, vpc, &gc,
-						vpWidthCM, vpHeightCM, dd);
-	    /* The graphics engine only takes device coordinates
-	     */
-	    symbolSize = toDeviceWidth(symbolSize, GE_INCHES, dd);
-	    if (R_FINITE(symbolSize)) {
-                /* 
-                 * FIXME:
-                 * Resolve any differences between this and FixupPch()
-                 * in plot.c ? 
-                 */
-	        if (isString(pch)) {
-		    ipch = GEstring_to_pch(STRING_ELT(pch, i % npch));
-		} else if (isInteger(pch)) {
-		    ipch = INTEGER(pch)[i % npch];
-		} else if (isReal(pch)) {
-		    ipch = R_FINITE(REAL(pch)[i % npch]) ? 
-			(int) REAL(pch)[i % npch] : NA_INTEGER;
-		} else error(_("invalid plotting symbol"));
-		/*
-		 * special case for pch = "."
-		 */
-		if (ipch == 46) symbolSize = gpCex(currentgp, i);
-                /*
-                 * FIXME: 
-                 * For character-based symbols, we need to modify
-                 * gc->cex so that the FONT size corresponds to
-                 * the specified symbolSize.
-                 */
-	        GESymbol(xx[i], yy[i], ipch, symbolSize, &gc, dd);
-	    }
-	}
-    GEMode(0, dd);
-    vmaxset(vmax);
-    return R_NilValue;
-}
-
-SEXP L_clip(SEXP x, SEXP y, SEXP w, SEXP h, SEXP hjust, SEXP vjust) 
-{
-    double xx, yy, ww, hh;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp, currentClip;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    GEMode(1, dd);
-    /*
-     * Only set ONE clip rectangle (i.e., NOT vectorised)
-     */
-    gcontextFromgpar(currentgp, 0, &gc, dd);
-    transformLocn(x, y, 0, vpc, &gc,
-		  vpWidthCM, vpHeightCM,
-		  dd,
-		  transform,
-		  &xx, &yy);
-    ww = transformWidthtoINCHES(w, 0, vpc, &gc,
-				vpWidthCM, vpHeightCM,
-				dd);
-    hh = transformHeighttoINCHES(h, 0, vpc, &gc,
-				 vpWidthCM, vpHeightCM,
-				 dd);
-    /* 
-     * We can ONLY clip if the total rotation angle is zero.
-     */
-    if (rotationAngle == 0) {
-        xx = justifyX(xx, ww, REAL(hjust)[0]);
-	yy = justifyY(yy, hh, REAL(vjust)[0]);
-	/* The graphics engine only takes device coordinates
-	 */
-	xx = toDeviceX(xx, GE_INCHES, dd);
-	yy = toDeviceY(yy, GE_INCHES, dd);
-	ww = toDeviceWidth(ww, GE_INCHES, dd);
-	hh = toDeviceHeight(hh, GE_INCHES, dd);
-	if (R_FINITE(xx) && R_FINITE(yy) && 
-	    R_FINITE(ww) && R_FINITE(hh)) {
-	    GESetClip(xx, yy, xx + ww, yy + hh, dd);
-	    /*
-	     * ALSO set the current clip region for the 
-	     * current viewport so that, if a viewport
-	     * is pushed within the current viewport,
-	     * when that viewport gets popped again,
-	     * the clip region returns to what was set
-	     * by THIS clipGrob (NOT to the current
-	     * viewport's previous setting)
-	     */
-	    PROTECT(currentClip = allocVector(REALSXP, 4));
-	    REAL(currentClip)[0] = xx;
-	    REAL(currentClip)[1] = yy;
-	    REAL(currentClip)[2] = xx + ww;
-	    REAL(currentClip)[3] = yy + hh;
-	    SET_VECTOR_ELT(currentvp, PVP_CLIPRECT, currentClip);
-	    UNPROTECT(1);
-	}
-    } else {
-        warning(_("unable to clip to rotated rectangle"));
-    }
-    GEMode(0, dd);
-    return R_NilValue;    
-}
-
-SEXP L_pretty(SEXP scale) {
-    double min = numeric(scale, 0);
-    double max = numeric(scale, 1);
-    double temp;
-    /* FIXME:  This is just a dummy pointer because we do not have
-     * log scales.  This will cause death and destruction if it is 
-     * not addressed when log scales are added !
-     */
-    double *usr = NULL;
-    double axp[3];
-    /* FIXME:  Default preferred number of ticks hard coded ! */
-    int n = 5;
-    Rboolean swap = min > max;
-    /* 
-     * Feature: 
-     * like R, something like  xscale = c(100,0)  just works 
-     */
-    if(swap) { 
-	temp = min; min = max; max = temp;
-    }
-
-    GEPretty(&min, &max, &n);
-
-    if(swap) {
-	temp = min; min = max; max = temp;
-    }
-
-    axp[0] = min;
-    axp[1] = max;
-    axp[2] = n;
-    /* FIXME:  "log" flag hard-coded to FALSE because we do not
-     * have log scales yet
-     */
-    return Rf_CreateAtVector(axp, usr, n, FALSE);
-}
-
-/* 
- * NOTE: This does not go through the graphics engine, but
- * skips straight to the device to obtain a mouse click.
- * This is because I do not want to put a GELocator in the 
- * graphics engine;  that would be a crappy long term solution.
- * I will wait for a better event-loop/call-back solution before
- * doing something with the graphics engine.
- * This is a stop gap in the meantime.
- * 
- * The answer is in INCHES
- */
-
-SEXP L_locator() {
-    double x = 0;
-    double y = 0;
-    SEXP answer;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    GEMode(2, dd);
-    PROTECT(answer = allocVector(REALSXP, 2));
-    /*
-     * Get a mouse click
-     * Fails if user did not click mouse button 1
-     */
-    if(dd->dev->locator && dd->dev->locator(&x, &y, dd->dev)) {
-	REAL(answer)[0] = fromDeviceX(x, GE_INCHES, dd);
-	REAL(answer)[1] = fromDeviceY(y, GE_INCHES, dd);
-    } else {
-	REAL(answer)[0] = NA_REAL;
-	REAL(answer)[1] = NA_REAL;	
-    }
-    UNPROTECT(1);
-    GEMode(0, dd);
-    return answer;
-}
-
-/*
- * ****************************************
- * Calculating boundaries of primitives
- *
- * ****************************************
- */
-
-/*
- * Return four values representing boundary of set of locations
- * in INCHES.
- *
- * Result is (xmin, xmax, ymin, ymax)
- *
- * Used for lines, segments, polygons
- */
-SEXP L_locnBounds(SEXP x, SEXP y, SEXP theta)
-{
-    int i, nx, ny, nloc;
-    double *xx, *yy;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    SEXP result = R_NilValue;
-    const void *vmax;
-    double xmin = DOUBLE_XMAX;
-    double xmax = -DOUBLE_XMAX;
-    double ymin = DOUBLE_XMAX;
-    double ymax = -DOUBLE_XMAX;
-    double edgex, edgey;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    nx = unitLength(x); 
-    ny = unitLength(y);
-    if (ny > nx) 
-	nx = ny;
-    nloc = 0;
-    vmax = vmaxget();
-    if (nx > 0) {
-	xx = (double *) R_alloc(nx, sizeof(double));
-	yy = (double *) R_alloc(nx, sizeof(double));
-	for (i=0; i<nx; i++) {
-	    gcontextFromgpar(currentgp, i, &gc, dd);
-	    xx[i] = transformXtoINCHES(x, i, vpc, &gc,
-				       vpWidthCM, vpHeightCM, 
-				       dd);
-	    yy[i] = transformYtoINCHES(y, i, vpc, &gc,
-				       vpWidthCM, vpHeightCM, 
-				       dd);
-	    /*
-	     * Determine min/max x/y values
-	     */
-	    if (R_FINITE(xx[i]) && R_FINITE(yy[i])) {
-		if (xx[i] < xmin)
-		    xmin = xx[i];
-		if (xx[i] > xmax)
-		    xmax = xx[i];
-		if (yy[i] < ymin)
-		    ymin = yy[i];
-		if (yy[i] > ymax)
-		    ymax = yy[i];
-		nloc++;
-	    }
-	}
-    }
-    if (nloc > 0) {
-	hullEdge(xx, yy, nx, REAL(theta)[0], &edgex, &edgey);
-	result = allocVector(REALSXP, 4);
-	/*
-	 * Reverse the scale adjustment (zoom factor)
-	 * when calculating physical value to return to user-level
-	 */
-	REAL(result)[0] = edgex / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[1] = edgey / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[2] = (xmax - xmin) / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-	REAL(result)[3] = (ymax - ymin) / 
-	    REAL(gridStateElement(dd, GSS_SCALE))[0];
-    } 
-    vmaxset(vmax);
-    return result;
-}
-
-/*
- * ****************************************
- * Calculating text metrics
- *
- * ****************************************
- */
-SEXP L_stringMetric(SEXP label)
-{
-    int i, n;
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform;
-    SEXP currentvp, currentgp;
-    SEXP txt;
-    SEXP result = R_NilValue;
-    SEXP ascent = R_NilValue;
-    SEXP descent = R_NilValue;
-    SEXP width = R_NilValue;
-    const void *vmax;
-    double asc, dsc, wid;
-    /* Get the current device 
-     */
-    pGEDevDesc dd = getDevice();
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    getViewportContext(currentvp, &vpc);
-    /* The label can be a string or an expression: is protected.
-     */
-    txt = label;
-    if (isSymbol(txt) || isLanguage(txt))
-	txt = coerceVector(txt, EXPRSXP);
-    else if (!isExpression(txt))
-	txt = coerceVector(txt, STRSXP);
-    PROTECT(txt);
-    n = LENGTH(txt);
-    vmax = vmaxget();
-    PROTECT(ascent = allocVector(REALSXP, n));
-    PROTECT(descent = allocVector(REALSXP, n));
-    PROTECT(width = allocVector(REALSXP, n));
-    if (n > 0) {
-	for (i=0; i<n; i++) {
-	    gcontextFromgpar(currentgp, i, &gc, dd);
-            if (isExpression(txt))
-                GEExpressionMetric(VECTOR_ELT(txt, i % LENGTH(txt)), &gc, 
-                                   &asc, &dsc, &wid,
-                                   dd);
-            else 
-                GEStrMetric(CHAR(STRING_ELT(txt, i)), 
-                            getCharCE(STRING_ELT(txt, i)), &gc,
-                            &asc, &dsc, &wid,
-                            dd);
-            /*
-             * Reverse the scale adjustment (zoom factor)
-             * when calculating physical value to return to user-level
-             */
-            REAL(ascent)[i] = fromDeviceHeight(asc, GE_INCHES, dd) / 
-                REAL(gridStateElement(dd, GSS_SCALE))[0];
-            REAL(descent)[i] = fromDeviceHeight(dsc, GE_INCHES, dd) /
-                REAL(gridStateElement(dd, GSS_SCALE))[0];
-            REAL(width)[i] = fromDeviceWidth(wid, GE_INCHES, dd) /
-                REAL(gridStateElement(dd, GSS_SCALE))[0];
-	}
-    }
-    PROTECT(result = allocVector(VECSXP, 3));
-    SET_VECTOR_ELT(result, 0, ascent);
-    SET_VECTOR_ELT(result, 1, descent);
-    SET_VECTOR_ELT(result, 2, width);    
-    vmaxset(vmax);
-    UNPROTECT(5);
-    return result;
-}
-
diff --git a/com.oracle.truffle.r.native/library/grid/src/grid.h b/com.oracle.truffle.r.native/library/grid/src/grid.h
deleted file mode 100644
index 81ac60047890dfcca406fe824aa035efa3181f51..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/grid.h
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003-8 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include <Rconfig.h>
-#include <Rinternals.h>
-#include <Rmath.h>
-
-#include <R_ext/Constants.h>
-#include <R_ext/GraphicsEngine.h>
-
-#include <Rinternals.h>
-#ifdef ENABLE_NLS
-#include <libintl.h>
-#define _(String) dgettext ("grid", String)
-#else
-#define _(String) (String)
-#endif
-
-/* All grid type names are prefixed with an "L" 
- * All grid global variable names are prefixed with an "L_" 
- */
-
-/* This information is stored with R's graphics engine so that 
- * grid can have state information per device and grid output can
- * be maintained on multiple devices.
- */
-
-#define GSS_DEVSIZE 0
-#define GSS_CURRLOC 1
-#define GSS_DL 2
-#define GSS_DLINDEX 3
-#define GSS_DLON 4
-#define GSS_GPAR 5
-#define GSS_GPSAVED 6
-#define GSS_VP 7
-#define GSS_GLOBALINDEX 8
-#define GSS_GRIDDEVICE 9
-#define GSS_PREVLOC 10
-#define GSS_ENGINEDLON 11
-#define GSS_CURRGROB 12
-#define GSS_ENGINERECORDING 13
-/* #define GSS_ASK 14 unused in R >= 2.7.0 */
-#define GSS_SCALE 15
-
-/*
- * Structure of a viewport
- */
-#define VP_X 0
-#define VP_Y 1
-#define VP_WIDTH 2
-#define VP_HEIGHT 3
-#define VP_JUST 4
-#define VP_GP 5
-#define VP_CLIP 6
-#define VP_XSCALE 7
-#define VP_YSCALE 8
-#define VP_ANGLE 9
-#define VP_LAYOUT 10
-#define VP_LPOSROW 11
-#define VP_LPOSCOL 12
-#define VP_VALIDJUST 13
-#define VP_VALIDLPOSROW 14
-#define VP_VALIDLPOSCOL 15
-#define VP_NAME 16
-/* 
- * Additional structure of a pushedvp
- */
-#define PVP_PARENTGPAR 17
-#define PVP_GPAR 18
-#define PVP_TRANS 19
-#define PVP_WIDTHS 20
-#define PVP_HEIGHTS 21
-#define PVP_WIDTHCM 22
-#define PVP_HEIGHTCM 23
-#define PVP_ROTATION 24
-#define PVP_CLIPRECT 25
-#define PVP_PARENT 26
-#define PVP_CHILDREN 27
-#define PVP_DEVWIDTHCM 28
-#define PVP_DEVHEIGHTCM 29
-
-/*
- * Structure of a layout
- */
-#define LAYOUT_NROW 0
-#define LAYOUT_NCOL 1
-#define LAYOUT_WIDTHS 2
-#define LAYOUT_HEIGHTS 3
-#define LAYOUT_RESPECT 4
-#define LAYOUT_VRESPECT 5
-#define LAYOUT_MRESPECT 6
-#define LAYOUT_JUST 7
-#define LAYOUT_VJUST 8
-
-#define GP_FILL 0
-#define GP_COL 1
-#define GP_GAMMA 2
-#define GP_LTY 3
-#define GP_LWD 4
-#define GP_CEX 5
-#define GP_FONTSIZE 6
-#define GP_LINEHEIGHT 7
-#define GP_FONT 8
-#define GP_FONTFAMILY 9
-#define GP_ALPHA 10
-#define GP_LINEEND 11
-#define GP_LINEJOIN 12
-#define GP_LINEMITRE 13
-#define GP_LEX 14
-/* 
- * Keep fontface at the end because it is never used in C code
- */
-#define GP_FONTFACE 15
-
-/*
- * Structure of an arrow description
- */
-#define GRID_ARROWANGLE 0
-#define GRID_ARROWLENGTH 1
-#define GRID_ARROWENDS 2
-#define GRID_ARROWTYPE 3
-
-typedef double LTransform[3][3];
-
-typedef double LLocation[3];
-
-typedef enum {
-    L_adding = 1,
-    L_subtracting = 2,
-    L_summing = 3,
-    L_plain = 4,
-    L_maximising = 5,
-    L_minimising = 6,
-    L_multiplying = 7
-} LNullArithmeticMode;
-
-/* NOTE: The order of the enums here must match the order of the
- * strings in unit.R
- */
-typedef enum {
-    L_NPC = 0,
-    L_CM = 1,
-    L_INCHES = 2,
-    L_LINES = 3,
-    L_NATIVE = 4,
-    L_NULL = 5, /* only used in layout specifications (?) */
-    L_SNPC = 6,
-    L_MM = 7,
-    /* Some units based on TeX's definition thereof
-     */
-    L_POINTS = 8,           /* 72.27 pt = 1 in */
-    L_PICAS = 9,            /* 1 pc     = 12 pt */
-    L_BIGPOINTS = 10,       /* 72 bp    = 1 in */
-    L_DIDA = 11,            /* 1157 dd  = 1238 pt */
-    L_CICERO = 12,          /* 1 cc     = 12 dd */
-    L_SCALEDPOINTS = 13,    /* 65536 sp = 1pt */
-    /* Some units which require an object to query for a value.
-     */
-    L_STRINGWIDTH = 14,
-    L_STRINGHEIGHT = 15,
-    L_STRINGASCENT = 16,
-    L_STRINGDESCENT = 17,
-    /* L_LINES now means multiples of the line height.
-     * This is multiples of the font size.
-     */
-    L_CHAR = 18,
-    L_GROBX = 19,
-    L_GROBY = 20,
-    L_GROBWIDTH = 21,
-    L_GROBHEIGHT = 22,
-    L_GROBASCENT = 23,
-    L_GROBDESCENT = 24,
-    /*
-     * No longer used
-     */
-    L_MYLINES = 103,
-    L_MYCHAR = 104,
-    L_MYSTRINGWIDTH = 105,
-    L_MYSTRINGHEIGHT = 106
-} LUnit;
-
-typedef enum {
-    L_LEFT = 0,
-    L_RIGHT = 1,
-    L_BOTTOM = 2,
-    L_TOP = 3,
-    L_CENTRE = 4,
-    L_CENTER = 5
-} LJustification;
-
-/* An arbitrarily-oriented rectangle.
- * The vertices are assumed to be in order going anticlockwise 
- * around the rectangle.
- */
-typedef struct {
-    double x1;
-    double x2;
-    double x3;
-    double x4;
-    double y1;
-    double y2;
-    double y3;
-    double y4;
-} LRect;
-
-/* A description of the location of a viewport */
-typedef struct {
-    SEXP x;
-    SEXP y;
-    SEXP width;
-    SEXP height;
-    double hjust;
-    double vjust;
-} LViewportLocation;
-
-/* Components of a viewport which provide coordinate information
- * for children of the viewport
- */
-typedef struct {
-    double xscalemin;
-    double xscalemax;
-    double yscalemin;
-    double yscalemax;
-} LViewportContext;
-
-/* Evaluation environment */
-#ifndef GRID_MAIN
-extern SEXP R_gridEvalEnv;
-#else
-SEXP R_gridEvalEnv;
-#endif
-
-
-/* Functions called by R code
- * (from all over the place)
- */
-SEXP L_initGrid(SEXP GridEvalEnv); 
-SEXP L_killGrid(); 
-SEXP L_gridDirty();
-SEXP L_currentViewport(); 
-SEXP L_setviewport(SEXP vp, SEXP hasParent);
-SEXP L_downviewport(SEXP vp, SEXP strict);
-SEXP L_downvppath(SEXP path, SEXP name, SEXP strict);
-SEXP L_unsetviewport(SEXP last);
-SEXP L_upviewport(SEXP last);
-SEXP L_getDisplayList(); 
-SEXP L_setDisplayList(SEXP dl); 
-SEXP L_getDLelt(SEXP index);
-SEXP L_setDLelt(SEXP value);
-SEXP L_getDLindex();
-SEXP L_setDLindex(SEXP index);
-SEXP L_getDLon();
-SEXP L_setDLon(SEXP value);
-SEXP L_getEngineDLon();
-SEXP L_setEngineDLon(SEXP value);
-SEXP L_getCurrentGrob();
-SEXP L_setCurrentGrob(SEXP value);
-SEXP L_getEngineRecording();
-SEXP L_setEngineRecording(SEXP value);
-SEXP L_currentGPar();
-SEXP L_newpagerecording();
-SEXP L_newpage();
-SEXP L_initGPar();
-SEXP L_initViewportStack();
-SEXP L_initDisplayList();
-SEXP L_convertToNative(SEXP x, SEXP what); 
-SEXP L_moveTo(SEXP x, SEXP y);
-SEXP L_lineTo(SEXP x, SEXP y, SEXP arrow);
-SEXP L_lines(SEXP x, SEXP y, SEXP index, SEXP arrow); 
-SEXP L_segments(SEXP x0, SEXP y0, SEXP x1, SEXP y1, SEXP arrow); 
-SEXP L_arrows(SEXP x1, SEXP x2, SEXP xnm1, SEXP xn, 
-	      SEXP y1, SEXP y2, SEXP ynm1, SEXP yn, 
-	      SEXP angle, SEXP length, SEXP ends, SEXP type);
-SEXP L_path(SEXP x, SEXP y, SEXP index, SEXP rule);
-SEXP L_polygon(SEXP x, SEXP y, SEXP index);
-SEXP L_xspline(SEXP x, SEXP y, SEXP s, SEXP o, SEXP a, SEXP rep, SEXP index);
-SEXP L_circle(SEXP x, SEXP y, SEXP r);
-SEXP L_rect(SEXP x, SEXP y, SEXP w, SEXP h, SEXP hjust, SEXP vjust); 
-SEXP L_raster(SEXP raster, SEXP x, SEXP y, SEXP w, SEXP h, 
-              SEXP hjust, SEXP vjust, SEXP interpolate);
-SEXP L_cap();
-SEXP L_text(SEXP label, SEXP x, SEXP y, SEXP hjust, SEXP vjust, 
-	    SEXP rot, SEXP checkOverlap);
-SEXP L_points(SEXP x, SEXP y, SEXP pch, SEXP size);
-SEXP L_clip(SEXP x, SEXP y, SEXP w, SEXP h, SEXP hjust, SEXP vjust); 
-SEXP L_pretty(SEXP scale);
-SEXP L_locator();
-SEXP L_convert(SEXP x, SEXP whatfrom,
-	       SEXP whatto, SEXP unitto);
-SEXP L_layoutRegion(SEXP layoutPosRow, SEXP layoutPosCol);
-
-SEXP L_stringMetric(SEXP label);
-
-/* From matrix.c */
-double locationX(LLocation l);
-
-double locationY(LLocation l);
-
-void copyTransform(LTransform t1, LTransform t2);
-
-void invTransform(LTransform t, LTransform invt);
-
-void identity(LTransform m);
-
-void translation(double tx, double ty, LTransform m);
-
-void scaling(double sx, double sy, LTransform m);
-
-void rotation(double theta, LTransform m);
-
-void multiply(LTransform m1, LTransform m2, LTransform m);
-
-void location(double x, double y, LLocation v);
-
-void trans(LLocation vin, LTransform m, LLocation vout);
-
-/* From unit.c */
-int isUnitArithmetic(SEXP ua);
-
-int isUnitList(SEXP ul);
-
-SEXP unit(double value, int unit);
-
-double unitValue(SEXP unit, int index);
-
-int unitUnit(SEXP unit, int index);
-
-SEXP unitData(SEXP unit, int index);
-
-int unitLength(SEXP u);
-
-extern int L_nullLayoutMode;
-
-double pureNullUnitValue(SEXP unit, int index);
-
-int pureNullUnit(SEXP unit, int index, pGEDevDesc dd);
-
-double transformX(SEXP x, int index, LViewportContext vpc, 
-		  const pGEcontext gc,
-		  double widthCM, double heightCM,
-		  int nullLMode, int nullAMode,
-		  pGEDevDesc dd);
-
-double transformY(SEXP y, int index, LViewportContext vpc,
-		  const pGEcontext gc,
-		  double widthCM, double heightCM,
-		  int nullLMode, int nullAMode,
-		  pGEDevDesc dd);
-
-double transformWidth(SEXP width, int index, LViewportContext vpc,
-		      const pGEcontext gc,
-		      double widthCM, double heightCM,
-		      int nullLMode, int nullAMode,
-		      pGEDevDesc dd);
-
-double transformHeight(SEXP height, int index, LViewportContext vpc,
-		       const pGEcontext gc,
-		       double widthCM, double heightCM,
-		       int nullLMode, int nullAMode,
-		       pGEDevDesc dd);
-
-double transformXtoINCHES(SEXP x, int index, LViewportContext vpc,
-			  const pGEcontext gc,
-			  double widthCM, double heightCM,
-			  pGEDevDesc dd);
-
-double transformYtoINCHES(SEXP y, int index, LViewportContext vpc,
-			  const pGEcontext gc,
-			  double widthCM, double heightCM,
-			  pGEDevDesc dd);
-
-void transformLocn(SEXP x, SEXP y, int index, LViewportContext vpc,
-		   const pGEcontext gc,
-		   double widthCM, double heightCM,
-		   pGEDevDesc dd,
-		   LTransform t,
-		   double *xx, double *yy);
-
-double transformWidthtoINCHES(SEXP w, int index, LViewportContext vpc,
-			      const pGEcontext gc,
-			      double widthCM, double heightCM,
-			      pGEDevDesc dd);
-
-double transformHeighttoINCHES(SEXP h, int index, LViewportContext vpc,
-			       const pGEcontext gc,
-			       double widthCM, double heightCM,
-			       pGEDevDesc dd);
-
-void transformDimn(SEXP w, SEXP h, int index, LViewportContext vpc,
-		   const pGEcontext gc,
-		   double widthCM, double heightCM,
-		   pGEDevDesc dd,
-		   double rotationAngle,
-		   double *ww, double *hh);
-
-double transformXYFromINCHES(double location, int unit, 
-			     double scalemin, double scalemax,
-			     const pGEcontext gc,
-			     double thisCM, double otherCM,
-			     pGEDevDesc dd);
-
-double transformWidthHeightFromINCHES(double value, int unit, 
-				      double scalemin, double scalemax,
-				      const pGEcontext gc,
-				      double thisCM, double otherCM,
-				      pGEDevDesc dd);
-
-double transformXYtoNPC(double x, int from, double min, double max);
-
-double transformWHtoNPC(double x, int from, double min, double max);
-
-double transformXYfromNPC(double x, int to, double min, double max);
-
-double transformWHfromNPC(double x, int to, double min, double max);
-
-/* From just.c */
-double justifyX(double x, double width, double hjust);
-
-double justifyY(double y, double height, double vjust);
-
-double convertJust(int vjust);
-
-void justification(double width, double height, double hjust, double vjust,
-		   double *hadj, double *vadj);
-
-/* From util.c */
-SEXP getListElement(SEXP list, char *str);
-
-void setListElement(SEXP list, char *str, SEXP value);
-
-SEXP getSymbolValue(char *symbolName);
-
-void setSymbolValue(char *symbolName, SEXP value);
-
-double numeric(SEXP x, int index);
-
-void rect(double x1, double x2, double x3, double x4, 
-	  double y1, double y2, double y3, double y4, 
-	  LRect *r);
-
-void copyRect(LRect r1, LRect *r);
-
-int intersect(LRect r1, LRect r2);
-
-void textRect(double x, double y, SEXP text, int i,
-	      const pGEcontext gc,
-	      double xadj, double yadj,
-	      double rot, pGEDevDesc dd, LRect *r);
-
-/* From gpar.c */
-double gpFontSize(SEXP gp, int i);
-
-double gpLineHeight(SEXP gp, int i);
-
-int gpCol(SEXP gp, int i);
-
-SEXP gpFillSXP(SEXP gp);
-
-int gpFill(SEXP gp, int i);
-
-double gpGamma(SEXP gp, int i);
-
-int gpLineType(SEXP gp, int i);
-
-double gpLineWidth(SEXP gp, int i);
-
-double gpCex(SEXP gp, int i);
-
-int gpFont(SEXP gp, int i);
-
-const char* gpFontFamily(SEXP gp, int i);
-
-SEXP gpFontSXP(SEXP gp);
-
-SEXP gpFontFamilySXP(SEXP gp);
-
-SEXP gpFontSizeSXP(SEXP gp);
-
-SEXP gpLineHeightSXP(SEXP gp);
-
-void gcontextFromgpar(SEXP gp, int i, const pGEcontext gc, pGEDevDesc dd);
-
-void initGPar(pGEDevDesc dd);
-
-/* From viewport.c */
-SEXP viewportX(SEXP vp);
-
-SEXP viewportY(SEXP vp);
-
-SEXP viewportWidth(SEXP vp);
-
-SEXP viewportHeight(SEXP vp);
-
-SEXP viewportgpar(SEXP vp);
-
-const char* viewportFontFamily(SEXP vp);
-
-int viewportFont(SEXP vp);
-
-double viewportFontSize(SEXP vp);
-
-double viewportLineHeight(SEXP vp);
-
-Rboolean viewportClip(SEXP vp);
-
-SEXP viewportClipRect(SEXP vp);
-
-double viewportXScaleMin(SEXP vp);
-
-double viewportXScaleMax(SEXP vp);
-
-double viewportYScaleMin(SEXP vp);
-
-double viewportYScaleMax(SEXP vp);
-
-double viewportHJust(SEXP v);
-
-double viewportVJust(SEXP vp);
-
-SEXP viewportLayoutPosRow(SEXP vp);
-
-SEXP viewportLayoutPosCol(SEXP vp);
-
-SEXP viewportLayout(SEXP vp);
-
-SEXP viewportParent(SEXP vp);
-
-SEXP viewportTransform(SEXP vp);
-
-SEXP viewportLayoutWidths(SEXP vp);
-
-SEXP viewportLayoutHeights(SEXP vp);
-
-SEXP viewportWidthCM(SEXP vp);
-
-SEXP viewportHeightCM(SEXP vp);
-
-SEXP viewportRotation(SEXP vp);
-
-SEXP viewportParent(SEXP vp);
-
-SEXP viewportChildren(SEXP vp);
-
-SEXP viewportDevWidthCM(SEXP vp);
-
-SEXP viewportDevHeightCM(SEXP vp);
-
-void fillViewportContextFromViewport(SEXP vp, LViewportContext *vpc);
-
-void copyViewportContext(LViewportContext vpc1, LViewportContext *vpc2);
-
-void gcontextFromViewport(SEXP vp, const pGEcontext gc, pGEDevDesc dd);
-
-void calcViewportTransform(SEXP vp, SEXP parent, Rboolean incremental,
-			   pGEDevDesc dd);
-
-void initVP(pGEDevDesc dd);
-
-/* From layout.c */
-Rboolean checkPosRowPosCol(SEXP viewport, SEXP parent);
-
-void calcViewportLayout(SEXP viewport,
-			double parentWidthCM,
-			double parentHeightCM,
-			LViewportContext parentContext,
-			const pGEcontext parentgc,
-			pGEDevDesc dd);
-
-void calcViewportLocationFromLayout(SEXP layoutPosRow,
-				    SEXP layoutPosCol,
-				    SEXP parent,
-				    LViewportLocation *vpl);
-
-/* From state.c */
-void initDL(pGEDevDesc dd);
-
-SEXP gridStateElement(pGEDevDesc dd, int elementIndex);
-
-void setGridStateElement(pGEDevDesc dd, int elementIndex, SEXP value);
-
-SEXP gridCallback(GEevent task, pGEDevDesc dd, SEXP data);
-
-/* From grid.c */
-SEXP doSetViewport(SEXP vp, 
-		   Rboolean topLevelVP,
-		   Rboolean pushing,
-		   pGEDevDesc dd);
-
-void getDeviceSize(pGEDevDesc dd, double *devWidthCM, double *devHeightCM); 
-
-/* This is, confusingly, a wrapper for GEcurrentDevice */
-pGEDevDesc getDevice();
-
-void getViewportTransform(SEXP currentvp, 
-			  pGEDevDesc dd, 
-			  double *vpWidthCM, double *vpHeightCM,
-			  LTransform transform, double *rotationAngle);
-
-SEXP L_circleBounds(SEXP x, SEXP y, SEXP r, SEXP theta);
-SEXP L_locnBounds(SEXP x, SEXP y, SEXP theta);
-SEXP L_rectBounds(SEXP x, SEXP y, SEXP w, SEXP h, SEXP hjust, SEXP vjust,
-		  SEXP theta);
-SEXP L_textBounds(SEXP label, SEXP x, SEXP y, 
-		  SEXP hjust, SEXP vjust, SEXP rot, SEXP theta);
-SEXP L_xsplineBounds(SEXP x, SEXP y, SEXP s, SEXP o, SEXP a, SEXP rep,
-		     SEXP index, SEXP theta);
-SEXP L_xsplinePoints(SEXP x, SEXP y, SEXP s, SEXP o, SEXP a, SEXP rep,
-		     SEXP index, SEXP theta);
-
-/* From unit.c */
-SEXP validUnits(SEXP units);
-
-/* From gpar.c */
-SEXP L_getGPar(void);
-SEXP L_setGPar(SEXP gpars);
-    
diff --git a/com.oracle.truffle.r.native/library/grid/src/just.c b/com.oracle.truffle.r.native/library/grid/src/just.c
deleted file mode 100644
index c005c35956ce30000a09a7fd7f5f4bfc64cb152e..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/just.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include "grid.h"
-
-/* Modify a location for the correct justification */
-
-/* These tranformations assume that x and width are in the same units */
-/* FIXME:  I don't think we check anywhere that a horizontal justification
- * is not L_BOTTOM or L_TOP (i.e., meaningless).  Ditto for checking
- * vertical justification.
- */
-double justifyX(double x, double width, double hjust) {
-    return x - width*hjust;
-    /*
-     * From when hjust and vjust were enums
-     *
-    double result = 0;
-    switch (hjust) {
-    case L_LEFT: 
-	result = x;
-	break;        
-    case L_RIGHT: 
-	result = x - width;
-	break;
-    case L_CENTRE: 
-    case L_CENTER:
-	result = x - width/2;
-	break;
-    }
-    return result;
-    */
-}
-
-double justifyY(double y, double height, double vjust) {
-    return y - height*vjust;
-    /*
-     * From when hjust and vjust were enums
-     *
-    double result = 0;
-    switch (vjust) {
-    case L_BOTTOM:  
-	result = y;
-	break;
-    case L_TOP:  
-	result = y - height;
-	break;
-    case L_CENTRE:
-    case L_CENTER:
-	result = y - height/2;
-	break;
-    }
-    return result;
-    */
-}
-
-/* Convert enum justification into 0..1 justification */
-double convertJust(int just) {
-    double result = 0;
-    switch (just) {
-    case L_BOTTOM:
-    case L_LEFT:
-	result = 0;
-	break;
-    case L_CENTRE:
-    case L_CENTER:
-	result = .5;
-	break;
-    case L_TOP:
-    case L_RIGHT:
-	result = 1;
-	break;
-    }
-    return result;
-}
-
-/* Return the amount of justification required 
- */
-void justification(double width, double height, double hjust, double vjust,
-		   double *hadj, double *vadj)
-{
-    *hadj = -width*hjust;
-    *vadj = -height*vjust;
-    /*
-     * From when hjust and vjust were enums
-    switch (hjust) {
-    case L_LEFT: 
-	*hadj = 0;
-	break;        
-    case L_RIGHT: 
-	*hadj = -width;
-	break;
-    case L_CENTRE: 
-    case L_CENTER:
-	*hadj = -width/2;
-	break;
-    }
-    switch (vjust) {
-    case L_BOTTOM:  
-	*vadj = 0;
-	break;
-    case L_TOP:  
-	*vadj = -height;
-	break;
-    case L_CENTRE:
-    case L_CENTER:
-	*vadj = -height/2;
-	break;
-    }
-     */
-}
diff --git a/com.oracle.truffle.r.native/library/grid/src/layout.c b/com.oracle.truffle.r.native/library/grid/src/layout.c
deleted file mode 100644
index f338862e7b1e2e5317fc52e1a9fab74cb3bd664b..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/layout.c
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003-2013 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include "grid.h"
-
-/* This stuff always returns an LViewportLocation in "npc" units
- */
-
-int layoutNRow(SEXP l) {
-    return INTEGER(VECTOR_ELT(l, LAYOUT_NROW))[0];
-}
-
-int layoutNCol(SEXP l) {
-    return INTEGER(VECTOR_ELT(l, LAYOUT_NCOL))[0];
-}
-
-SEXP layoutWidths(SEXP l) {
-    return VECTOR_ELT(l, LAYOUT_WIDTHS);
-}
-
-SEXP layoutHeights(SEXP l) {
-    return VECTOR_ELT(l, LAYOUT_HEIGHTS);
-}
-
-int layoutRespect(SEXP l) {
-    return INTEGER(VECTOR_ELT(l, LAYOUT_VRESPECT))[0];
-}
-
-int* layoutRespectMat(SEXP l) {
-    return INTEGER(VECTOR_ELT(l, LAYOUT_MRESPECT));
-}
-
-double layoutHJust(SEXP l) {
-    return REAL(VECTOR_ELT(l, LAYOUT_VJUST))[0];
-}
-
-double layoutVJust(SEXP l) {
-    return REAL(VECTOR_ELT(l, LAYOUT_VJUST))[1];
-}
-
-Rboolean relativeUnit(SEXP unit, int index,
-		   pGEDevDesc dd) {
-    return pureNullUnit(unit, index, dd);
-}
-
-void findRelWidths(SEXP layout, int *relativeWidths,
-		   pGEDevDesc dd) 
-{
-    int i;
-    SEXP widths = layoutWidths(layout);
-    for (i=0; i<layoutNCol(layout); i++) 
-	relativeWidths[i] = relativeUnit(widths, i, dd);
-}
-
-void findRelHeights(SEXP layout, int *relativeHeights,
-		   pGEDevDesc dd) 
-{
-    int i;
-    SEXP heights = layoutHeights(layout);
-    for (i=0; i<layoutNRow(layout); i++) 
-	relativeHeights[i] = relativeUnit(heights, i, dd);
-}
-
-void allocateKnownWidths(SEXP layout, 
-			 int *relativeWidths, 
-			 double parentWidthCM, double parentHeightCM,
-			 LViewportContext parentContext,
-			 const pGEcontext parentgc,
-			 pGEDevDesc dd,
-			 double *npcWidths, double *widthLeftCM) 
-{
-    int i;
-    SEXP widths = layoutWidths(layout);
-    for (i=0; i<layoutNCol(layout); i++) 
-	if (!relativeWidths[i]) {
-	    npcWidths[i] = transformWidth(widths, i, parentContext,
-					  parentgc,
-					  parentWidthCM, parentHeightCM, 
-					  0, 0, dd)*2.54;
-	    *widthLeftCM -= npcWidths[i];
-	}
-}
-
-void allocateKnownHeights(SEXP layout, 
-			  int *relativeHeights,
-			  double parentWidthCM, double parentHeightCM,
-			  LViewportContext parentContext,
-			  const pGEcontext parentgc,
-			  pGEDevDesc dd,
-			  double *npcHeights, double *heightLeftCM) 
-{
-    int i;
-    SEXP heights = layoutHeights(layout);
-    for (i=0; i<layoutNRow(layout); i++) 
-	if (!relativeHeights[i]) {
-	    npcHeights[i] = transformHeight(heights, i, parentContext,
-					    parentgc,
-					    parentWidthCM, parentHeightCM, 
-					    0, 0, dd)*2.54;
-	    *heightLeftCM -= npcHeights[i];
-	}
-}
-
-int colRespected(int col, SEXP layout) {
-    int i;
-    int result = 0;
-    int respect = layoutRespect(layout);
-    int *respectMat = layoutRespectMat(layout);
-    if (respect == 1)
-	result = 1;
-    else
-	for (i=0; i<layoutNRow(layout); i++)
-	    if (respectMat[col*layoutNRow(layout) + i] != 0)
-		result = 1;
-    return result;
-}
-
-int rowRespected(int row, SEXP layout) {
-    int i;
-    int result = 0;
-    int respect = layoutRespect(layout);
-    int *respectMat = layoutRespectMat(layout);
-    if (respect == 1)
-	result = 1;
-    else
-	for (i=0; i<layoutNCol(layout); i++)
-	    if (respectMat[i*layoutNRow(layout) + row] != 0)
-		result = 1;
-    return result;
-}
-
-/* 
- * These sum up ALL relative widths and heights (unit = "null")
- * Some effort is made to find all truly null units
- * (e.g., including a grobwidth unit where the grob's width is null)
- */
-double totalWidth(SEXP layout, int *relativeWidths,
-		  LViewportContext parentContext,
-		  const pGEcontext parentgc,
-		  pGEDevDesc dd)
-{
-    int i;
-    SEXP widths = layoutWidths(layout);
-    double totalWidth = 0;
-    for (i=0; i<layoutNCol(layout); i++) 
-	if (relativeWidths[i])
-	    totalWidth += transformWidth(widths, i, parentContext, 
-					 parentgc,
-					 /* 
-					  * NOTE: 0, 0, here is ok
-					  * because we are only 
-					  * obtaining "null" units
-					  */
-					 0, 0, 1, 0, dd);
-    return totalWidth;
-}
-
-double totalHeight(SEXP layout, int *relativeHeights,
-		   LViewportContext parentContext,
-		   const pGEcontext parentgc,
-		   pGEDevDesc dd)
-{
-    int i;
-    SEXP heights = layoutHeights(layout);
-    double totalHeight = 0;
-    for (i=0; i<layoutNRow(layout); i++) 
-	if (relativeHeights[i])
-	    totalHeight += transformHeight(heights, i, parentContext, 
-					   parentgc,
-					   /* 
-					    * NOTE: 0, 0, here is ok
-					    * because we are only 
-					    * obtaining "null" units
-					    */
-					   0, 0, 1, 0, dd);
-    return totalHeight;
-}
-
-void allocateRespected(SEXP layout, 
-		       int *relativeWidths, int *relativeHeights,
-		       double *reducedWidthCM, double *reducedHeightCM,
-		       LViewportContext parentContext,
-		       const pGEcontext parentgc,
-		       pGEDevDesc dd,
-		       double *npcWidths, double *npcHeights)
-{
-    int i;
-    SEXP widths = layoutWidths(layout);
-    SEXP heights = layoutHeights(layout);
-    int respect = layoutRespect(layout);
-    double sumWidth = totalWidth(layout, relativeWidths, parentContext,
-				 parentgc, dd);
-    double sumHeight = totalHeight(layout, relativeHeights, parentContext,
-				   parentgc, dd);
-    double denom, mult;
-    double tempWidthCM = *reducedWidthCM;
-    double tempHeightCM = *reducedHeightCM;
-    if (respect > 0) {
-	/* Determine whether aspect ratio of available space is
-	 * bigger or smaller than aspect ratio of layout
-	 */
-	// NB: widths could be zero
-	// if ((tempHeightCM / tempWidthCM) > (sumHeight / sumWidth)) {
-	if ( tempHeightCM * sumWidth > sumHeight * tempWidthCM) {
-	    denom = sumWidth;
-	    mult = tempWidthCM;
-	}
-	else {
-	    denom = sumHeight;
-	    mult = tempHeightCM;
-	}
-	/* Allocate respected widths 
-	 */
-	for (i=0; i<layoutNCol(layout); i++)
-	    if (relativeWidths[i])
-		if (colRespected(i, layout)) {
-		    /* 
-		     * Special case of respect, but sumHeight = 0.
-		     * Action is to allocate widths as if unrespected.
-		     * Ok to test == 0 because will only be 0 if 
-		     * all relative heights are actually exactly 0.
-		     */
-		    if (sumHeight == 0) {
-			denom = sumWidth;
-			mult = tempWidthCM;
-		    }
-		    /* Build a unit SEXP with a single value and no data
-		     */
-		    npcWidths[i] = pureNullUnitValue(widths, i) / 
-                        denom*mult;
-		    *reducedWidthCM -= npcWidths[i];
-		}
-	/* Allocate respected heights
-	 */
-	for (i=0; i<layoutNRow(layout); i++)
-	    if (relativeHeights[i])
-		if (rowRespected(i, layout)) {
-		    /* 
-		     * Special case of respect, but sumWidth = 0.
-		     * Action is to allocate widths as if unrespected.
-		     * Ok to test == 0 because will only be 0 if 
-		     * all relative heights are actually exactly 0.
-		     */
-		    if (sumWidth == 0) {
-			denom = sumHeight;
-			mult = tempHeightCM;
-		    }
-		    npcHeights[i] = pureNullUnitValue(heights, i) / 
-                        denom*mult;
-		    *reducedHeightCM -= npcHeights[i];
-		}
-    }
-}
-
-void setRespectedZero(SEXP layout, 
-                      int *relativeWidths, int *relativeHeights,
-                      double *npcWidths, double *npcHeights)
-{
-    int i;
-    for (i=0; i<layoutNCol(layout); i++)
-        if (relativeWidths[i])
-            if (colRespected(i, layout)) 
-                npcWidths[i] = 0;
-    for (i=0; i<layoutNRow(layout); i++)
-        if (relativeHeights[i])
-            if (rowRespected(i, layout)) 
-                npcHeights[i] = 0;
-}
-
-/* These sum up unrespected relative widths and heights (unit = "null")
- */
-double totalUnrespectedWidth(SEXP layout, int *relativeWidths,
-			     LViewportContext parentContext,
-			     const pGEcontext parentgc,
-			     pGEDevDesc dd)
-{
-    int i;
-    SEXP widths = layoutWidths(layout);
-    double totalWidth = 0;
-    for (i=0; i<layoutNCol(layout); i++) 
-	if (relativeWidths[i])
-	    if (!colRespected(i, layout))
-		totalWidth += transformWidth(widths, i, parentContext, 
-					     parentgc,
-					     /* 
-					      * NOTE: 0, 0, here is ok
-					      * because we are only 
-					      * obtaining "null" units
-					      */
-					     0, 0, 1, 0, dd);
-    return totalWidth;
-}
-
-double totalUnrespectedHeight(SEXP layout, int *relativeHeights,
-			      LViewportContext parentContext,
-			      const pGEcontext parentgc,
-			      pGEDevDesc dd)
-{
-    int i;
-    SEXP heights = layoutHeights(layout);
-    double totalHeight = 0;
-    for (i=0; i<layoutNRow(layout); i++) 
-	if (relativeHeights[i])
-	    if (!rowRespected(i, layout))
-		totalHeight += transformHeight(heights, i, parentContext, 
-					       parentgc,
-					       /* 
-						* NOTE: 0, 0, here is ok
-						* because we are only 
-						* obtaining "null" units
-						*/
-					       0, 0, 1, 0, dd);
-    return totalHeight;
-}
-
-
-void setRemainingWidthZero(SEXP layout, 
-                           int *relativeWidths, 
-                           double *npcWidths)
-{
-    int i;
-    for (i=0; i<layoutNCol(layout); i++)
-        if (relativeWidths[i])
-            if (!colRespected(i, layout)) 
-                npcWidths[i] = 0;
-}
-
-void allocateRemainingWidth(SEXP layout, int *relativeWidths,
-			    double remainingWidthCM, 
-			    LViewportContext parentContext, 
-			    const pGEcontext parentgc,
-			    pGEDevDesc dd,
-			    double *npcWidths)
-{
-    int i;
-    SEXP widths = layoutWidths(layout);
-    double sumWidth;
-    sumWidth = totalUnrespectedWidth(layout, relativeWidths,
-				     parentContext, parentgc, dd);
-    if (sumWidth > 0) {
-        for (i=0; i<layoutNCol(layout); i++) 
-            if (relativeWidths[i])
-                if (!colRespected(i, layout))
-                    npcWidths[i] = remainingWidthCM*
-                        transformWidth(widths, i, parentContext, parentgc,
-				   /* 
-				    * NOTE: 0, 0, here is ok
-				    * because we are only 
-				    * obtaining "null" units
-				    */
-                                       0, 0, 1, 0, dd)/
-                        sumWidth;
-    } else {
-        /* 
-         * If ALL relative widths are zero then they all get 
-         * allocated zero width
-         */
-        setRemainingWidthZero(layout, relativeWidths, npcWidths);
-    }
-}
-
-void setRemainingHeightZero(SEXP layout, 
-                            int *relativeHeights, 
-                            double *npcHeights)
-{
-    int i;
-    for (i=0; i<layoutNRow(layout); i++)
-        if (relativeHeights[i])
-            if (!rowRespected(i, layout)) 
-                npcHeights[i] = 0;
-}
-
-void allocateRemainingHeight(SEXP layout, int *relativeHeights,
-			     double remainingHeightCM, 
-			     LViewportContext parentContext,
-			     const pGEcontext parentgc,
-			     pGEDevDesc dd,
-			     double *npcHeights)
-{
-    int i;
-    SEXP heights = layoutHeights(layout);
-    double sumHeight;
-    sumHeight = totalUnrespectedHeight(layout, relativeHeights,
-				       parentContext, parentgc, dd);
-    if (sumHeight > 0) {
-        for (i=0; i<layoutNRow(layout); i++) 
-            if (relativeHeights[i])
-                if (!rowRespected(i, layout))
-                    npcHeights[i] = remainingHeightCM*
-                        transformHeight(heights, i, parentContext, parentgc,
-				    /* 
-				     * NOTE: 0, 0, here is ok
-				     * because we are only 
-				     * obtaining "null" units
-				     */
-                                        0, 0, 1, 0, dd)/
-                        sumHeight;
-    } else {
-        /* 
-         * If ALL relative heights are zero then they all get 
-         * allocated zero height
-         */
-        setRemainingHeightZero(layout, relativeHeights, npcHeights);
-    }
-}
-
-static double sumDims(double dims[], int from, int to)
-{
-    int i;
-    double s = 0;
-    for (i = from; i < to + 1; i++)
-	s = s + dims[i];
-    return s;
-}
-
-static void subRegion(SEXP layout,
-		      int minrow, int maxrow, int mincol, int maxcol,
-		      double widths[], double heights[], 
-                      double parentWidthCM, double parentHeightCM,
-		      double *left, double *bottom, 
-		      double *width, double *height) 
-{
-    double hjust = layoutHJust(layout);
-    double vjust = layoutVJust(layout);
-    double totalWidth = sumDims(widths, 0, layoutNCol(layout) - 1);
-    double totalHeight = sumDims(heights, 0, layoutNRow(layout) - 1);
-    *width = sumDims(widths, mincol, maxcol);
-    *height = sumDims(heights, minrow, maxrow);    
-    /* widths and heights are in CM */
-    *left = parentWidthCM*hjust - totalWidth*hjust + 
-        sumDims(widths, 0, mincol - 1);
-    *bottom =  parentHeightCM*vjust + (1 - vjust)*totalHeight - 
-	sumDims(heights, 0, maxrow);
-    /*
-     * From when hjust and vjust were enums
-     *
-    switch (layoutHJust(layout)) {
-    case L_LEFT:
-	*left = sumDims(widths, 0, mincol - 1);
-	break;
-    case L_RIGHT: 
-	*left = 1 - sumDims(widths, mincol, layoutNCol(layout) - 1);
-	break;
-    case L_CENTRE: 
-    case L_CENTER:
-	*left = (0.5 - totalWidth/2) + sumDims(widths, 0, mincol - 1);
-	break;
-    }
-    switch (layoutVJust(layout)) {
-    case L_BOTTOM:
-	*bottom = totalHeight - sumDims(heights, 0, maxrow);
-	break;
-    case L_TOP:
-	*bottom = 1 - sumDims(heights, 0, maxrow);
-	break;
-    case L_CENTRE: 
-    case L_CENTER:
-	*bottom = (0.5 - totalHeight/2) + totalHeight
-	    - sumDims(heights, 0, maxrow);
-    }
-    */
-}
-
-void calcViewportLayout(SEXP viewport,
-			double parentWidthCM,
-			double parentHeightCM,
-			LViewportContext parentContext,
-			const pGEcontext parentgc,
-			pGEDevDesc dd)
-{
-    int i;
-    SEXP currentWidths, currentHeights;
-    SEXP layout = viewportLayout(viewport);
-    double *npcWidths = (double *) R_alloc(layoutNCol(layout), sizeof(double));
-    double *npcHeights = (double *) R_alloc(layoutNRow(layout), 
-					    sizeof(double));
-    int *relativeWidths = (int *) R_alloc(layoutNCol(layout), sizeof(int));
-    int *relativeHeights = (int *) R_alloc(layoutNRow(layout), sizeof(int));    
-    double reducedWidthCM = parentWidthCM;
-    double reducedHeightCM = parentHeightCM;
-    /* Figure out which rows and cols have relative heights and widths 
-     */
-    findRelWidths(layout, relativeWidths, dd);
-    findRelHeights(layout, relativeHeights, dd);
-    /* For any width or height which has a unit other than "null"
-     * we can immediately figure out its physical size.
-     * We do this and return the widthCM and heightCM 
-     * remaining after these widths and heights have been allocated
-     */
-    allocateKnownWidths(layout, relativeWidths,
-			parentWidthCM, parentHeightCM, 
-			parentContext, parentgc,
-			dd, npcWidths,
-			&reducedWidthCM);
-    allocateKnownHeights(layout, relativeHeights,
-			 parentWidthCM, parentHeightCM, 
-			 parentContext, parentgc,
-			 dd, npcHeights, 
-			 &reducedHeightCM);
-
-    /* Now allocate respected widths and heights and return
-     * widthCM and heightCM remaining 
-     */
-    if (reducedWidthCM > 0 ||
-        reducedHeightCM > 0) {
-        allocateRespected(layout, relativeWidths, relativeHeights, 
-                          &reducedWidthCM, &reducedHeightCM,
-                          parentContext, parentgc, dd,
-                          npcWidths, npcHeights);
-    } else {
-        /* 
-         * IF EITHER we started with ZERO widthCM and heightCM
-         *    OR we've used up all the widthCM and heightCM
-         * THEN all respected widths/heights get ZERO
-         */ 
-        setRespectedZero(layout, relativeWidths, relativeHeights, 
-                         npcWidths, npcHeights);
-    }
-    /* Now allocate relative widths and heights (unit = "null")
-     * in the remaining space
-     */
-    if (reducedWidthCM > 0) {
-        allocateRemainingWidth(layout, relativeWidths,
-                               reducedWidthCM, 
-                               parentContext, parentgc, dd, npcWidths);
-    } else {
-        /* 
-         * IF EITHER we started with ZERO width
-         *    OR we've used up all the width
-         * THEN any relative widths get ZERO
-         */ 
-        setRemainingWidthZero(layout, relativeWidths, npcWidths);
-    }
-    if (reducedHeightCM > 0) {
-        allocateRemainingHeight(layout, relativeHeights,
-                                reducedHeightCM, 
-                                parentContext, parentgc, dd, npcHeights);
-    } else {
-        /* 
-         * IF EITHER we started with ZERO height
-         *    OR we've used up all the height
-         * THEN any relative heights get ZERO
-         */ 
-        setRemainingHeightZero(layout, relativeHeights, npcHeights);
-    }
-    /* Record the widths and heights in the viewport
-     */
-    PROTECT(currentWidths = allocVector(REALSXP, layoutNCol(layout)));
-    PROTECT(currentHeights = allocVector(REALSXP, layoutNRow(layout)));
-    for (i=0; i<layoutNCol(layout); i++) {
-        /* Layout widths are stored in CM
-         */
-	REAL(currentWidths)[i] = npcWidths[i];
-    }
-    for (i=0; i<layoutNRow(layout); i++) {
-        /* Layout heights are stored in CM
-         */
-	REAL(currentHeights)[i] = npcHeights[i];
-    }
-    SET_VECTOR_ELT(viewport, PVP_WIDTHS, currentWidths);
-    SET_VECTOR_ELT(viewport, PVP_HEIGHTS, currentHeights);
-    UNPROTECT(2);
-}
-
-Rboolean checkPosRowPosCol(SEXP vp, SEXP parent) 
-{
-    int ncol = layoutNCol(viewportLayout(parent));
-    int nrow = layoutNRow(viewportLayout(parent));
-    if (!isNull(viewportLayoutPosRow(vp)) &&
-	(INTEGER(viewportLayoutPosRow(vp))[0] < 1 ||
-	 INTEGER(viewportLayoutPosRow(vp))[1] > nrow))
-        error(_("invalid 'layout.pos.row'"));
-    if (!isNull(viewportLayoutPosCol(vp)) &&
-	(INTEGER(viewportLayoutPosCol(vp))[0] < 1 ||
-	 INTEGER(viewportLayoutPosCol(vp))[1] > ncol))
-        error(_("invalid 'layout.pos.col'"));
-    return TRUE;
-}
-
-void calcViewportLocationFromLayout(SEXP layoutPosRow,
-				    SEXP layoutPosCol,
-				    SEXP parent,
-				    LViewportLocation *vpl)
-{
-    int minrow, maxrow, mincol, maxcol;
-    double x, y, width, height;
-    SEXP vpx, vpy, vpwidth, vpheight;
-    SEXP layout = viewportLayout(parent);
-    /* It is possible for ONE of layoutPosRow and layoutPosCol to
-     * be NULL;  this is interpreted as "occupy all rows/cols"
-     * NOTE: The " - 1" is there because R is 1-based and C is zero-based 
-     */
-    if (isNull(layoutPosRow)) {
-	minrow = 0;
-	maxrow = layoutNRow(layout) - 1;
-    } else {
-	minrow = INTEGER(layoutPosRow)[0] - 1;
-	maxrow = INTEGER(layoutPosRow)[1] - 1;
-    }
-    if (isNull(layoutPosCol)) {
-	mincol = 0;
-	maxcol = layoutNCol(layout) - 1;
-    } else {
-	mincol = INTEGER(layoutPosCol)[0] - 1;
-	maxcol = INTEGER(layoutPosCol)[1] - 1;
-    }
-    /* Put the relevant values into vpl */
-    subRegion(viewportLayout(parent), minrow, maxrow, mincol, maxcol,
-	      REAL(viewportLayoutWidths(parent)), 
-	      REAL(viewportLayoutHeights(parent)),
-              REAL(viewportWidthCM(parent))[0],
-              REAL(viewportHeightCM(parent))[0],
-	      &x, &y, &width, &height);
-    /* Layout widths and heights are stored in CM
-     */
-    PROTECT(vpx = unit(x, L_CM));
-    vpl->x = vpx;
-    PROTECT(vpy = unit(y, L_CM));
-    vpl->y = vpy;
-    PROTECT(vpwidth = unit(width, L_CM));
-    vpl->width = vpwidth;
-    PROTECT(vpheight = unit(height, L_CM));
-    vpl->height = vpheight;
-    vpl->hjust = 0;
-    vpl->vjust = 0;
-    /* Question:  Is there any chance that these newly-allocated 
-     * unit SEXPs will get corrupted after this unprotect ??
-     */
-    UNPROTECT(4);
-}
-
diff --git a/com.oracle.truffle.r.native/library/grid/src/matrix.c b/com.oracle.truffle.r.native/library/grid/src/matrix.c
deleted file mode 100644
index edae7088d0d5b5c883a7806515bb3dd1acd46d17..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/matrix.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include "grid.h" 
-
-/* Code for matrices, matrix multiplication, etc for performing
- *  2D affine transformations:  translations, scaling, and rotations.
- */
-
-double locationX(LLocation l) {
-    return l[0];
-}
-
-double locationY(LLocation l) {
-    return l[1];
-}
-
-void copyTransform(LTransform t1, LTransform t2)
-{
-    int i, j;
-    for (i=0; i<3; i++) 
-	for (j=0; j<3; j++)
-	    t2[i][j] = t1[i][j];
-}
-
-void invTransform(LTransform t, LTransform invt)
-{
-    double det = t[0][0]*(t[2][2]*t[1][1] - t[2][1]*t[1][2]) - 
-	t[1][0]*(t[2][2]*t[0][1] - t[2][1]*t[0][2]) +
-	t[2][0]*(t[1][2]*t[0][1] - t[1][1]*t[0][2]);
-    if (det == 0)
-	error(_("singular transformation matrix"));
-    invt[0][0] = 1/det*(t[2][2]*t[1][1] - t[2][1]*t[1][2]);
-    invt[0][1] = -1/det*(t[2][2]*t[0][1] - t[2][1]*t[0][2]);
-    invt[0][2] = 1/det*(t[1][2]*t[0][1] - t[1][1]*t[0][2]);
-    invt[1][0] = -1/det*(t[2][2]*t[1][0] - t[2][0]*t[1][2]);
-    invt[1][1] = 1/det*(t[2][2]*t[0][0] - t[2][0]*t[0][2]);
-    invt[1][2] = -1/det*(t[1][2]*t[0][0] - t[1][0]*t[0][2]);
-    invt[2][0] = 1/det*(t[2][1]*t[1][0] - t[2][0]*t[1][1]);
-    invt[2][1] = -1/det*(t[2][1]*t[0][0] - t[2][0]*t[0][1]);
-    invt[2][2] = 1/det*(t[1][1]*t[0][0] - t[1][0]*t[0][1]);
-}
-
-void identity(LTransform m) 
-{
-    int i, j;
-    for (i=0; i<3; i++) 
-	for (j=0; j<3; j++)
-	    if (i == j)
-		m[i][j] = 1;
-	    else
-		m[i][j] = 0;
-}
-
-void translation(double tx, double ty, LTransform m)
-{
-    identity(m);
-    m[2][0] = tx;
-    m[2][1] = ty;
-}
-
-void scaling(double sx, double sy, LTransform m)
-{
-    identity(m);
-    m[0][0] = sx;
-    m[1][1] = sy;
-}
-
-void rotation(double theta, LTransform m)
-{
-    double thetarad = theta/180*M_PI;
-    double costheta = cos(thetarad);
-    double sintheta = sin(thetarad);
-    identity(m);
-    m[0][0] = costheta;
-    m[0][1] = sintheta;
-    m[1][0] = -sintheta;
-    m[1][1] = costheta;
-}
-
-void multiply(LTransform m1, LTransform m2, LTransform m)
-{
-    m[0][0] = m1[0][0]*m2[0][0] + m1[0][1]*m2[1][0] + m1[0][2]*m2[2][0];
-    m[0][1] = m1[0][0]*m2[0][1] + m1[0][1]*m2[1][1] + m1[0][2]*m2[2][1];
-    m[0][2] = m1[0][0]*m2[0][2] + m1[0][1]*m2[1][2] + m1[0][2]*m2[2][2];
-    m[1][0] = m1[1][0]*m2[0][0] + m1[1][1]*m2[1][0] + m1[1][2]*m2[2][0];
-    m[1][1] = m1[1][0]*m2[0][1] + m1[1][1]*m2[1][1] + m1[1][2]*m2[2][1];
-    m[1][2] = m1[1][0]*m2[0][2] + m1[1][1]*m2[1][2] + m1[1][2]*m2[2][2];
-    m[2][0] = m1[2][0]*m2[0][0] + m1[2][1]*m2[1][0] + m1[2][2]*m2[2][0];
-    m[2][1] = m1[2][0]*m2[0][1] + m1[2][1]*m2[1][1] + m1[2][2]*m2[2][1];
-    m[2][2] = m1[2][0]*m2[0][2] + m1[2][1]*m2[1][2] + m1[2][2]*m2[2][2];
-}
-
-void location(double x, double y, LLocation v)
-{
-    v[0] = x;
-    v[1] = y;
-    v[2] = 1;
-}
-
-void trans(LLocation vin, LTransform m, LLocation vout)
-{
-    vout[0] = vin[0]*m[0][0] + vin[1]*m[1][0] + vin[2]*m[2][0];
-    vout[1] = vin[0]*m[0][1] + vin[1]*m[1][1] + vin[2]*m[2][1];
-    vout[2] = vin[0]*m[0][2] + vin[1]*m[1][2] + vin[2]*m[2][2];
-}
-
-/* Testing code
- * Need to undocument main() below and add #include <math.h> at top of file
- * Correct answers are "2.67 2.00 1.00" for m4=identity
- * and "0.00 2.00 1.00" for m4=rotation
- */
-
-/*
-  main() 
-  {
-  LLocation v1, v2; 
-  LTransform m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11;
-  location(9, 10, v1);
-  translation(-5, -6, m1);
-  scaling(1/7.0, 1/8.0, m2);
-  scaling(7, 8, m3);
-  identity(m4);  
-  rotation(3.141592 / 2, m4); 
-  translation(4, 4, m5);
-  scaling(1/3.0, 1/4.0, m6);
-  multiply(m1, m2, m7);
-  multiply(m7, m3, m8);
-  multiply(m8, m4, m9);
-  multiply(m9, m5, m10);
-  multiply(m10, m6, m11);
-  transform(v1, m11, v2);
-  printf("%1.2f %1.2f %1.2f\n", v2[0], v2[1], v2[2]);	  
-  }
-*/
-
diff --git a/com.oracle.truffle.r.native/library/grid/src/register.c b/com.oracle.truffle.r.native/library/grid/src/register.c
deleted file mode 100644
index 43c2075a343db75eecd3af45069f1aea744e6523..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/register.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3  Paul Murrell
- *                2003-12 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-/* Code to register grid functions with R
- */
-#include <R_ext/Rdynload.h>
-#include "grid.h"
-
-static const R_CallMethodDef callMethods[] = {
-    {"L_initGrid", (DL_FUNC) &L_initGrid, 1},
-    {"L_killGrid", (DL_FUNC) &L_killGrid, 0},
-    {"L_gridDirty", (DL_FUNC) &L_gridDirty, 0},
-    {"L_currentViewport", (DL_FUNC) &L_currentViewport, 0},
-    {"L_setviewport", (DL_FUNC) &L_setviewport, 2}, 
-    {"L_downviewport", (DL_FUNC) &L_downviewport, 2}, 
-    {"L_downvppath", (DL_FUNC) &L_downvppath, 3}, 
-    {"L_unsetviewport", (DL_FUNC) &L_unsetviewport, 1},  
-    {"L_upviewport", (DL_FUNC) &L_upviewport, 1},  
-    {"L_getDisplayList", (DL_FUNC) &L_getDisplayList, 0},
-    {"L_setDisplayList", (DL_FUNC) &L_setDisplayList, 1},
-    {"L_getDLelt", (DL_FUNC) &L_getDLelt, 1},
-    {"L_setDLelt", (DL_FUNC) &L_setDLelt, 1},
-    {"L_getDLindex", (DL_FUNC) &L_getDLindex, 0}, 
-    {"L_setDLindex", (DL_FUNC) &L_setDLindex, 1},
-    {"L_getDLon", (DL_FUNC) &L_getDLon, 0},
-    {"L_setDLon", (DL_FUNC) &L_setDLon, 1},
-    {"L_getEngineDLon", (DL_FUNC) &L_getEngineDLon, 0},
-    {"L_setEngineDLon", (DL_FUNC) &L_setEngineDLon, 1},
-    {"L_getCurrentGrob", (DL_FUNC) &L_getCurrentGrob, 0},
-    {"L_setCurrentGrob", (DL_FUNC) &L_setCurrentGrob, 1},
-    {"L_getEngineRecording", (DL_FUNC) &L_getEngineRecording, 0},
-    {"L_setEngineRecording", (DL_FUNC) &L_setEngineRecording, 1},
-    {"L_currentGPar", (DL_FUNC) &L_currentGPar, 0},
-    {"L_newpagerecording", (DL_FUNC) &L_newpagerecording, 0},
-    {"L_newpage", (DL_FUNC) &L_newpage, 0},
-    {"L_initGPar", (DL_FUNC) &L_initGPar, 0},
-    {"L_initViewportStack", (DL_FUNC) &L_initViewportStack, 0},
-    {"L_initDisplayList", (DL_FUNC) &L_initDisplayList, 0},
-    {"L_moveTo", (DL_FUNC) &L_moveTo, 2},
-    {"L_lineTo", (DL_FUNC) &L_lineTo, 3}, 
-    {"L_lines", (DL_FUNC) &L_lines, 4}, 
-    {"L_segments", (DL_FUNC) &L_segments, 5}, 
-    {"L_arrows", (DL_FUNC) &L_arrows, 12}, 
-    {"L_path", (DL_FUNC) &L_path, 4},
-    {"L_polygon", (DL_FUNC) &L_polygon, 3},
-    {"L_xspline", (DL_FUNC) &L_xspline, 7},
-    {"L_circle", (DL_FUNC) &L_circle, 3},
-    {"L_rect", (DL_FUNC) &L_rect, 6},
-    {"L_raster", (DL_FUNC) &L_raster, 8},
-    {"L_cap", (DL_FUNC) &L_cap, 0},
-    {"L_text", (DL_FUNC) &L_text, 7},
-    {"L_points", (DL_FUNC) &L_points, 4},
-    {"L_clip", (DL_FUNC) &L_clip, 6},
-    {"L_pretty", (DL_FUNC) &L_pretty, 1},
-    {"L_locator", (DL_FUNC) &L_locator, 0},
-    {"L_convert", (DL_FUNC) &L_convert, 4},
-    {"L_layoutRegion", (DL_FUNC) &L_layoutRegion, 2},
-    {"validUnits", (DL_FUNC) &validUnits, 1},
-    {"L_getGPar", (DL_FUNC) &L_getGPar, 0},
-    {"L_setGPar", (DL_FUNC) &L_setGPar, 1},
-    {"L_circleBounds", (DL_FUNC) &L_circleBounds, 4},
-    {"L_locnBounds", (DL_FUNC) &L_locnBounds, 3},
-    {"L_rectBounds", (DL_FUNC) &L_rectBounds, 7},
-    {"L_textBounds", (DL_FUNC) &L_textBounds, 7},
-    {"L_xsplineBounds", (DL_FUNC) &L_xsplineBounds, 8},
-    {"L_xsplinePoints", (DL_FUNC) &L_xsplinePoints, 8},
-    {"L_stringMetric", (DL_FUNC) &L_stringMetric, 1},
-    { NULL, NULL, 0 }
-};
-
-
-void
-#ifdef HAVE_VISIBILITY_ATTRIBUTE
-__attribute__ ((visibility ("default")))
-#endif
-R_init_grid(DllInfo *dll) 
-{
-    /* No .C, .Fortran, or .External routines => NULL
-     */
-    R_registerRoutines(dll, NULL, callMethods, NULL, NULL);
-    R_useDynamicSymbols(dll, FALSE);
-    R_forceSymbols(dll, FALSE);
-}
diff --git a/com.oracle.truffle.r.native/library/grid/src/state.c b/com.oracle.truffle.r.native/library/grid/src/state.c
deleted file mode 100644
index a6e68d670e78ae0bc872a3fda106ff3567787457..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/state.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003-5 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include "grid.h"
-
-int gridRegisterIndex;
-
-/* The gridSystemState (per device) consists of 
- * GSS_DEVSIZE 0 = current size of device
- * GSS_CURRLOC 1 = current location of grid "pen" 
- * GSS_DL 2 = grid display list
- * GSS_DLINDEX 3 = display list index
- * GSS_DLON 4 = is the display list on?
- * GSS_GPAR 5 = gpar settings
- * GSS_GPSAVED 6 = previous gpar settings
- * GSS_VP 7 = viewport
- * GSS_GLOBALINDEX 8 = index of this system state in the global list of states
- * GSS_GRIDDEVICE 9 = does this device contain grid output?
- * GSS_PREVLOC 10 = previous location of grid "pen" 
- * GSS_ENGINEDLON 11 = are we using the graphics engine's display list?
- * GSS_CURRGROB 12 = current grob being drawn (for determining 
- *   the list of grobs to search when evaluating a grobwidth/height
- *   unit via gPath)
- * GSS_ENGINERECORDING 13 = are we already inside a .Call.graphics call?
- *   Used by grid.Call.graphics to avoid unnecessary recording on 
- *   engine display list
- * [GSS_ASK 14 = should we prompt the user before starting a new page?
- *  Replaced by per-device setting as from R 2.7.0.]
- * GSS_SCALE 15 = a scale or "zoom" factor for all output 
- *   (to support "fit to window" resizing on windows device)
- * 
- * NOTE: if you add to this list you MUST change the size of the vector
- * allocated in createGridSystemState() below.
-*/
-
-SEXP createGridSystemState()
-{
-    return allocVector(VECSXP, 16);
-}
-
-void initDL(pGEDevDesc dd)
-{
-    SEXP dl, dlindex;
-    SEXP vp = gridStateElement(dd, GSS_VP);
-    SEXP gsd = (SEXP) dd->gesd[gridRegisterIndex]->systemSpecific;
-    /* The top-level viewport goes at the start of the display list
-     */
-    PROTECT(dl = allocVector(VECSXP, 100));
-    SET_VECTOR_ELT(dl, 0, vp);
-    SET_VECTOR_ELT(gsd, GSS_DL, dl);
-    PROTECT(dlindex = allocVector(INTSXP, 1));
-    INTEGER(dlindex)[0] = 1;
-    SET_VECTOR_ELT(gsd, GSS_DLINDEX, dlindex);
-    UNPROTECT(2);
-}
-
-/*
- * This is used to init some bits of the system state
- * Called when a grahpics engine redraw is about to occur
- * NOTE that it does not init all of the state, in particular,
- * the display list is not initialised here (see initDL), 
- * nor is the ROOT viewport (see initVP),
- * nor is the current gpar (see initGP)
- */
-void initOtherState(pGEDevDesc dd)
-{
-    SEXP currloc, prevloc, recording;
-    SEXP state = (SEXP) dd->gesd[gridRegisterIndex]->systemSpecific;
-    currloc = VECTOR_ELT(state, GSS_CURRLOC);
-    REAL(currloc)[0] = NA_REAL;
-    REAL(currloc)[1] = NA_REAL;    
-    prevloc = VECTOR_ELT(state, GSS_PREVLOC);
-    REAL(prevloc)[0] = NA_REAL;
-    REAL(prevloc)[1] = NA_REAL;    
-    SET_VECTOR_ELT(state, GSS_CURRGROB, R_NilValue);
-    recording = VECTOR_ELT(state, GSS_ENGINERECORDING);
-    LOGICAL(recording)[0] = FALSE;
-    SET_VECTOR_ELT(state, GSS_ENGINERECORDING, recording);
-}
-
-void fillGridSystemState(SEXP state, pGEDevDesc dd) 
-{
-    SEXP devsize, currloc, prevloc;
-
-    PROTECT(state);
-    devsize = allocVector(REALSXP, 2);
-    REAL(devsize)[0] = 0;
-    REAL(devsize)[1] = 0;
-    SET_VECTOR_ELT(state, GSS_DEVSIZE, devsize);
-    /* "current location"
-     * Initial setting relies on the fact that all values sent to devices
-     * are in INCHES;  so (0, 0) is the bottom-left corner of the device.
-     */
-    currloc = allocVector(REALSXP, 2);
-    REAL(currloc)[0] = NA_REAL;
-    REAL(currloc)[1] = NA_REAL;    
-    SET_VECTOR_ELT(state, GSS_CURRLOC, currloc);
-    prevloc = allocVector(REALSXP, 2);
-    REAL(prevloc)[0] = NA_REAL;
-    REAL(prevloc)[1] = NA_REAL;    
-    SET_VECTOR_ELT(state, GSS_PREVLOC, prevloc);
-    SET_VECTOR_ELT(state, GSS_DLON, ScalarLogical(TRUE));
-    SET_VECTOR_ELT(state, GSS_ENGINEDLON, ScalarLogical(TRUE));
-    SET_VECTOR_ELT(state, GSS_CURRGROB, R_NilValue);
-    SET_VECTOR_ELT(state, GSS_ENGINERECORDING, ScalarLogical(FALSE));
-    initGPar(dd);
-    SET_VECTOR_ELT(state, GSS_GPSAVED, R_NilValue);
-    /* Do NOT initialise top-level viewport or grid display list for
-     * this device until there is some grid output 
-     */
-    SET_VECTOR_ELT(state, GSS_GLOBALINDEX, R_NilValue);
-    /* Note that no grid output has occurred on the device yet.
-     */
-    SET_VECTOR_ELT(state, GSS_GRIDDEVICE, ScalarLogical(FALSE));
-#if 0
-    SET_VECTOR_ELT(state, GSS_ASK, ScalarLogical(dd->ask));
-#endif
-    SET_VECTOR_ELT(state, GSS_SCALE, ScalarReal(1.0));
-    UNPROTECT(1);
-}
-
-SEXP gridStateElement(pGEDevDesc dd, int elementIndex)
-{
-    return VECTOR_ELT((SEXP) dd->gesd[gridRegisterIndex]->systemSpecific, 
-		      elementIndex);
-}
-
-void setGridStateElement(pGEDevDesc dd, int elementIndex, SEXP value)
-{
-    SET_VECTOR_ELT((SEXP) dd->gesd[gridRegisterIndex]->systemSpecific, 
-		   elementIndex, value);
-}
-
-static void deglobaliseState(SEXP state)
-{
-    int index = INTEGER(VECTOR_ELT(state, GSS_GLOBALINDEX))[0];
-    SET_VECTOR_ELT(findVar(install(".GRID.STATE"), R_gridEvalEnv), 
-		   index, R_NilValue);
-}
-
-static int findStateSlot()
-{
-    int i;
-    int result = -1;
-    SEXP globalstate = findVar(install(".GRID.STATE"), R_gridEvalEnv);
-    for (i = 0; i < length(globalstate); i++)
-	if (VECTOR_ELT(globalstate, i) == R_NilValue) {
-	    result = i;
-	    break;
-	}
-    if (result < 0)
-	error(_("unable to store 'grid' state.  Too many devices open?"));
-    return result;
-}
-
-static void globaliseState(SEXP state)
-{
-    int index = findStateSlot();
-    SEXP globalstate, indexsxp;
-    PROTECT(globalstate = findVar(install(".GRID.STATE"), R_gridEvalEnv));
-    /* Record the index for deglobalisation
-     */
-    PROTECT(indexsxp = allocVector(INTSXP, 1));
-    INTEGER(indexsxp)[0] = index;
-    SET_VECTOR_ELT(state, GSS_GLOBALINDEX, indexsxp);
-    SET_VECTOR_ELT(globalstate, index, state);
-    UNPROTECT(2);
-}
-
-SEXP gridCallback(GEevent task, pGEDevDesc dd, SEXP data) {
-    SEXP result = R_NilValue;
-    SEXP valid, scale;
-    SEXP gridState;
-    GESystemDesc *sd;
-    SEXP currentgp;
-    SEXP gsd;
-    SEXP devsize;
-    R_GE_gcontext gc;
-    switch (task) {
-    case GE_InitState:
-	/* Create the initial grid state for a device
-	 */
-	PROTECT(gridState = createGridSystemState());
-	/* Store that state with the device for easy retrieval
-	 */
-	sd = dd->gesd[gridRegisterIndex];
-	sd->systemSpecific = (void*) gridState;
-	/* Initialise the grid state for a device
-	 */
-	fillGridSystemState(gridState, dd);
-	/* Also store the state beneath a top-level variable so
-	 * that it does not get garbage-collected
-	 */
-	globaliseState(gridState);
-        /* Indicate success */
-        result = R_BlankString;
-	UNPROTECT(1);
-	break;
-    case GE_FinaliseState:
-	sd = dd->gesd[gridRegisterIndex];
-	/* Simply detach the system state from the global variable
-	 * and it will be garbage-collected
-	 */
-	deglobaliseState((SEXP) sd->systemSpecific);
-	/* Also set the device pointer to NULL
-	 */
-	sd->systemSpecific = NULL;	
-	break;
-    case GE_SaveState:
-	break;
-    case GE_RestoreState:
-	gsd = (SEXP) dd->gesd[gridRegisterIndex]->systemSpecific;
-	PROTECT(devsize = allocVector(REALSXP, 2));
-	getDeviceSize(dd, &(REAL(devsize)[0]), &(REAL(devsize)[1]));
-	SET_VECTOR_ELT(gsd, GSS_DEVSIZE, devsize);
-	UNPROTECT(1);
-	/* Only bother to do any grid drawing setup 
-	 * if there has been grid output
-	 * on this device.
-	 */
-	if (LOGICAL(gridStateElement(dd, GSS_GRIDDEVICE))[0]) {
-	    if (LOGICAL(gridStateElement(dd, GSS_ENGINEDLON))[0]) {
-		/* The graphics engine is about to replay the display list
-		 * So we "clear" the device and reset the grid graphics state
-		 */
-		/* There are two main situations in which this occurs:
-		 * (i) a screen is resized
-		 *     In this case, it is ok-ish to do a GENewPage
-		 *     because that has the desired effect and no 
-		 *     undesirable effects because it only happens on
-		 *     a screen device -- a new page is the same as
-		 *     clearing the screen
-		 * (ii) output on one device is copied to another device
-		 *     In this case, a GENewPage is NOT a good thing, however,
-		 *     here we will start with a new device and it will not
-		 *     have any grid output so this section will not get called
-		 *     SO we will not get any unwanted blank pages.
-		 *
-		 * All this is a bit fragile;  ultimately, what would be ideal
-		 * is a dev->clearPage primitive for all devices in addition
-		 * to the dev->newPage primitive
-		 */ 
-		currentgp = gridStateElement(dd, GSS_GPAR);
-		gcontextFromgpar(currentgp, 0, &gc, dd);
-		GENewPage(&gc, dd);
-		initGPar(dd);
-		initVP(dd);
-		initOtherState(dd);
-	    } else {
-		/*
-		 * If we have turned off the graphics engine's display list
-		 * then we have to redraw the scene ourselves
-		 */
-		SEXP fcall;
-		PROTECT(fcall = lang1(install("draw.all")));
-		eval(fcall, R_gridEvalEnv); 
-		UNPROTECT(1);
-	    }
-	}
-	break;
-    case GE_CopyState:
-	break;
-    case GE_CheckPlot:
-	PROTECT(valid = allocVector(LGLSXP, 1));
-	LOGICAL(valid)[0] = TRUE;
-	UNPROTECT(1);
-	result = valid;
-    case GE_SaveSnapshotState:
-	break;
-    case GE_RestoreSnapshotState:
-	break;
-    case GE_ScalePS:
-	/*
-	 * data is a numeric scale factor
-	 */
-	PROTECT(scale = allocVector(REALSXP, 1));
-	REAL(scale)[0] = REAL(gridStateElement(dd, GSS_SCALE))[0]*
-	    REAL(data)[0];
-	setGridStateElement(dd, GSS_SCALE, scale);
-	UNPROTECT(1);
-	break;
-    }
-    return result;
-}
-
diff --git a/com.oracle.truffle.r.native/library/grid/src/unit.c b/com.oracle.truffle.r.native/library/grid/src/unit.c
deleted file mode 100644
index 2d9459ed7bfbbaba33433da90a2a2a31792f3459..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/unit.c
+++ /dev/null
@@ -1,1923 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003-2013 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include "grid.h"
-#include <math.h>
-#include <float.h>
-#include <string.h>
-
-int isUnitArithmetic(SEXP ua) {
-    return inherits(ua, "unit.arithmetic");
-}
-
-int isUnitList(SEXP ul) {
-    return inherits(ul, "unit.list");
-}
-
-/* Function to build a single-value unit SEXP internally.
- * Cannot build units requiring data as yet.
- */
-SEXP unit(double value, int unit) 
-{
-    SEXP u, units, classname;
-    PROTECT(u = ScalarReal(value));
-    PROTECT(units = ScalarInteger(unit));
-    /* NOTE that we do not set the "unit" attribute */
-    setAttrib(u, install("valid.unit"), units);
-    setAttrib(u, install("data"), R_NilValue);
-    PROTECT(classname = mkString("unit"));
-    classgets(u, classname);
-    UNPROTECT(3);
-    return u;
-}
-
-/* Accessor functions for unit objects
- */
-
-/* 
- * This is an attempt to extract a single numeric value from
- * a unit.  This is ONLY designed for use on "simple" units
- * (i.e., NOT unitLists or unitArithmetics)
- */
-double unitValue(SEXP unit, int index) {
-    /* Recycle values if necessary (used in unit arithmetic)
-     */
-    int n = LENGTH(unit);
-    return numeric(unit, index % n);
-}
-
-int unitUnit(SEXP unit, int index) {
-    SEXP units = getAttrib(unit, install("valid.unit"));
-    /* Recycle units if necessary 
-     */
-    int n = LENGTH(units);
-    return INTEGER(units)[index % n];
-}
-
-SEXP unitData(SEXP unit, int index) {
-    SEXP result;
-    SEXP data = getAttrib(unit, install("data"));
-    if (isNull(data))
-	result = R_NilValue;
-    else if(TYPEOF(data) == VECSXP) {
-	/* Recycle data if necessary 
-	 */
-	int n = LENGTH(data);
-	result = VECTOR_ELT(data, index % n);
-    } else {
-	warning("unit attribute 'data' is of incorrect type");
-	return R_NilValue;
-    }
-    return result;
-}
-
-/* Accessor functions for unit arithmetic object
- */
-const char* fName(SEXP ua) {
-    return CHAR(STRING_ELT(getListElement(ua, "fname"), 0));
-}
-
-SEXP arg1(SEXP ua) {
-    return getListElement(ua, "arg1");
-}
-
-SEXP arg2(SEXP ua) {
-    return getListElement(ua, "arg2");
-}
-
-int fNameMatch(SEXP ua, char *aString) {
-    return !strcmp(fName(ua), aString);
-}
-
-int addOp(SEXP ua) {
-    return fNameMatch(ua, "+");
-}
-
-int minusOp(SEXP ua) {
-    return fNameMatch(ua, "-");
-}
-
-int timesOp(SEXP ua) {
-    return fNameMatch(ua, "*");
-}
-
-int fOp(SEXP ua) {
-    return addOp(ua) || minusOp(ua) || timesOp(ua);
-}
-
-int minFunc(SEXP ua) {
-    return fNameMatch(ua, "min");
-}
-    
-int maxFunc(SEXP ua) {
-    return fNameMatch(ua, "max");
-}
-
-int sumFunc(SEXP ua) {
-    return fNameMatch(ua, "sum");
-}
-
-/* Functions in lattice.c should use this to determine the length
- * of a unit/unitArithmetic object rather than just LENGTH.
- */
-int unitLength(SEXP u) 
-{
-    int result = 0;
-    if (isUnitList(u))
-	result = LENGTH(u);
-    else if (isUnitArithmetic(u))
-	if (fOp(u)) {
-	    if (timesOp(u)) {
-		/*
-		 * arg1 is always the numeric vector
-		 */
-		int n1 = LENGTH(arg1(u));
-		int n2 = unitLength(arg2(u));
-		result = (n1 > n2) ? n1 : n2;
-	    } else {  /* must be "+" or "-" */
-		int n1 = unitLength(arg1(u));
-		int n2 = unitLength(arg2(u));
-		result = (n1 > n2) ? n1 : n2;
-	    }
-	} else /* must be "min" or "max" or "sum" */
-	  result = 1;  /* unitLength(arg1(u)); */
-    else /* Must be a unit object */
-	result = LENGTH(u);
-    return result;
-}
-
-
-/**************************
- * Code for handling "null" units
- **************************
- */
-
-/* Global mode indicators:
- * The value returned for a "null" unit depends on ...
- * (i) whether layout is calling for evaluation of a "pure null" unit
- *     (in which case, the value of the "null" unit is returned)
- * (ii) the sort of arithmetic that is being performed
- *      (in which case, an "identity" value is returned)
- */
-
-/* 
- * Evaluate a "null" _value_ dependent on the evaluation context
- */
-static double evaluateNullUnit(double value, double thisCM,
-			       int nullLayoutMode, int nullArithmeticMode) {
-    double result = value;
-    if (!nullLayoutMode)
-	switch (nullArithmeticMode) {
-	case L_plain:
-	case L_adding:
-	case L_subtracting:
-	case L_summing:
-	    result = 0;
-	    break;
-	case L_multiplying:
-	    result = 0;
-	    break;
-	case L_maximising:
-	    result = 0;
-	    break;
-	case L_minimising:
-	    result = thisCM;
-	    break;
-	}
-    return result;
-}
-
-/*
- * Evaluate a "null" _unit_ 
- * This is used by layout code to get a single "null" _value_
- * from a pureNullUnit (which may be a unitList or a unitArithmetic)
- *
- * This must ONLY be called on a unit which has passed the 
- * pureNullUnit test below.
- */
-double pureNullUnitValue(SEXP unit, int index)
-{
-    double result = 0;
-    if (isUnitArithmetic(unit)) {
-	int i;
-	if (addOp(unit)) {
-	    result = pureNullUnitValue(arg1(unit), index) + 
-		pureNullUnitValue(arg2(unit), index);
-	}
-	else if (minusOp(unit)) {
-	    result = pureNullUnitValue(arg1(unit), index) - 
-		pureNullUnitValue(arg2(unit), index);
-	}
-	else if (timesOp(unit)) {
-	    result = REAL(arg1(unit))[index] * 
-		pureNullUnitValue(arg2(unit), index);
-	}
-	else if (minFunc(unit)) {
-	    int n = unitLength(arg1(unit));
-	    double temp = DBL_MAX;
-	    result = pureNullUnitValue(arg1(unit), 0);
-	    for (i=1; i<n; i++) {
-		temp = pureNullUnitValue(arg1(unit), i);
-		if (temp < result)
-		    result = temp;
-	    }
-	} 
-	else if (maxFunc(unit)) {
-	    int n = unitLength(arg1(unit));
-	    double temp = DBL_MIN;
-	    result = pureNullUnitValue(arg1(unit), 0);
-	    for (i=1; i<n; i++) {
-		temp = pureNullUnitValue(arg1(unit), i);
-		if (temp > result)
-		    result = temp;
-	    }
-	} 
-	else if (sumFunc(unit)) {
-	    int n = unitLength(arg1(unit));
-	    result = 0.0;
-	    for (i=0; i<n; i++) {
-		result += pureNullUnitValue(arg1(unit), i);
-	    }
-	}
-	else 
-	    error(_("unimplemented unit function"));
-    } else if (isUnitList(unit)) {
-	/*
-	 * Recycle if necessary;  it is up to the calling code
-	 * to limit indices to unit length if desired
-	 */
-	int n = unitLength(unit);
-	result = pureNullUnitValue(VECTOR_ELT(unit, index % n), 0);
-    } else
-	result = unitValue(unit, index);
-    return result;
-}
-
-int pureNullUnitArithmetic(SEXP unit, int index, pGEDevDesc dd);
-
-int pureNullUnit(SEXP unit, int index, pGEDevDesc dd) {
-    int result;
-    if (isUnitArithmetic(unit)) 
-	result = pureNullUnitArithmetic(unit, index, dd);
-    else if (isUnitList(unit)) {
-	/*
-	 * Recycle if necessary;  it is up to the calling code
-	 * to limit indices to unit length if desired
-	 */
-	int n = unitLength(unit);
-	result = pureNullUnit(VECTOR_ELT(unit, index % n), 0, dd);
-    } else {  /* Just a plain unit */
-	/* Special case:  if "grobwidth" or "grobheight" unit
-	 * and width/height(grob) is pure null
-	 */
-	if (unitUnit(unit, index) == L_GROBWIDTH) {
-	    SEXP grob, updatedgrob, width;
-	    SEXP widthPreFn, widthFn, widthPostFn, findGrobFn;
-	    SEXP R_fcall0, R_fcall1, R_fcall2, R_fcall3;
-	    SEXP savedgpar, savedgrob;
-	    /*
-	     * The data could be a gPath to a grob
-	     * In this case, need to find the grob first, and in order
-	     * to do that correctly, need to call pre/postDraw code 
-	     */
-	    PROTECT(grob = unitData(unit, index));
-	    PROTECT(savedgpar = gridStateElement(dd, GSS_GPAR));
-	    PROTECT(savedgrob = gridStateElement(dd, GSS_CURRGROB));
-	    PROTECT(widthPreFn = findFun(install("preDraw"), 
-					 R_gridEvalEnv));
-	    PROTECT(widthFn = findFun(install("width"), R_gridEvalEnv));
-	    PROTECT(widthPostFn = findFun(install("postDraw"), 
-					  R_gridEvalEnv));
-	    if (inherits(grob, "gPath")) {
-		if (isNull(savedgrob)) {
-		    PROTECT(findGrobFn = findFun(install("findGrobinDL"), 
-						 R_gridEvalEnv));
-		    PROTECT(R_fcall0 = lang2(findGrobFn, 
-					     getListElement(grob, "name")));
-		    grob = eval(R_fcall0, R_gridEvalEnv);
-		} else {
-		    PROTECT(findGrobFn =findFun(install("findGrobinChildren"), 
-						R_gridEvalEnv));
-		    PROTECT(R_fcall0 = lang3(findGrobFn, 
-					     getListElement(grob, "name"),
-					     getListElement(savedgrob, 
-							    "children")));
-		    grob = eval(R_fcall0, R_gridEvalEnv);
-		}
-		UNPROTECT(2);
-	    }
-	    PROTECT(R_fcall1 = lang2(widthPreFn, grob));
-            PROTECT(updatedgrob = eval(R_fcall1, R_gridEvalEnv));
-	    PROTECT(R_fcall2 = lang2(widthFn, updatedgrob));
-	    PROTECT(width = eval(R_fcall2, R_gridEvalEnv));
-	    result = pureNullUnit(width, 0, dd);
-	    PROTECT(R_fcall3 = lang2(widthPostFn, updatedgrob));
-	    eval(R_fcall3, R_gridEvalEnv);
-	    setGridStateElement(dd, GSS_GPAR, savedgpar);
-	    setGridStateElement(dd, GSS_CURRGROB, savedgrob);
-	    UNPROTECT(11);
-	} else if (unitUnit(unit, index) == L_GROBHEIGHT) {
-	    SEXP grob, updatedgrob, height;
-	    SEXP heightPreFn, heightFn, heightPostFn, findGrobFn;
-	    SEXP R_fcall0, R_fcall1, R_fcall2, R_fcall3;
-	    SEXP savedgpar, savedgrob;
-	    /*
-	     * The data could be a gPath to a grob
-	     * In this case, need to find the grob first, and in order
-	     * to do that correctly, need to call pre/postDraw code 
-	     */
-	    PROTECT(grob = unitData(unit, index));
-	    PROTECT(savedgpar = gridStateElement(dd, GSS_GPAR));
-	    PROTECT(savedgrob = gridStateElement(dd, GSS_CURRGROB));
-	    PROTECT(heightPreFn = findFun(install("preDraw"), 
-					 R_gridEvalEnv));
-	    PROTECT(heightFn = findFun(install("height"), R_gridEvalEnv));
-	    PROTECT(heightPostFn = findFun(install("postDraw"), 
-					  R_gridEvalEnv));
-	    if (inherits(grob, "gPath")) {
-		if (isNull(savedgrob)) {
-		    PROTECT(findGrobFn = findFun(install("findGrobinDL"), 
-						 R_gridEvalEnv));
-		    PROTECT(R_fcall0 = lang2(findGrobFn, 
-					     getListElement(grob, "name")));
-		    grob = eval(R_fcall0, R_gridEvalEnv);
-		} else {
-		    PROTECT(findGrobFn =findFun(install("findGrobinChildren"), 
-						R_gridEvalEnv));
-		    PROTECT(R_fcall0 = lang3(findGrobFn, 
-					     getListElement(grob, "name"),
-					     getListElement(savedgrob, 
-							    "children")));
-		    grob = eval(R_fcall0, R_gridEvalEnv);
-		}
-		UNPROTECT(2);
-	    }
-	    PROTECT(R_fcall1 = lang2(heightPreFn, grob));
-	    PROTECT(updatedgrob = eval(R_fcall1, R_gridEvalEnv));
-	    PROTECT(R_fcall2 = lang2(heightFn, updatedgrob));
-	    PROTECT(height = eval(R_fcall2, R_gridEvalEnv));
-	    result = pureNullUnit(height, 0, dd);
-	    PROTECT(R_fcall3 = lang2(heightPostFn, updatedgrob));
-	    eval(R_fcall3, R_gridEvalEnv);
-	    setGridStateElement(dd, GSS_GPAR, savedgpar);
-	    setGridStateElement(dd, GSS_CURRGROB, savedgrob);
-	    UNPROTECT(11);
-	} else
-	    result = unitUnit(unit, index) == L_NULL;
-    }
-    return result;    
-}
-
-int pureNullUnitArithmetic(SEXP unit, int index, pGEDevDesc dd) {
-    /* 
-     * Initialised to shut up compiler
-     */
-    int result = 0;
-    if (addOp(unit) || minusOp(unit)) {
-	result = pureNullUnit(arg1(unit), index, dd) &&
-	    pureNullUnit(arg2(unit), index, dd);
-    }
-    else if (timesOp(unit)) {
-	result = pureNullUnit(arg2(unit), index, dd);
-    }
-    else if (minFunc(unit) || maxFunc(unit) || sumFunc(unit)) {
-	int n = unitLength(arg1(unit));
-	int i = 0;
-	result = 1;
-	while (result && i<n) {
-	    result = result && pureNullUnit(arg1(unit), i, dd);
-	    i += 1;
-	}
-    } 
-    else 
-	error(_("unimplemented unit function"));
-    return result;
-}
-
-/**************************
- * Code for handling "grobwidth" units
- **************************
- */
-
-/* NOTE:  this code calls back to R code to perform 
- * set.gpar operations, which will impact on grid state variables
- * BUT that's ok(ish) because we save and restore the relevant state
- * variables in here so that the overall effect is NULL.
- *
- * FIXME:  OTOH, the calls back to R Code may also perform
- * viewport operations.  Again, we restore state as much as possible,
- * but this can "pollute" the viewport tree in some cases.
- */
-
-double evaluateGrobUnit(double value, SEXP grob,
-			double vpwidthCM, double vpheightCM,
-			int nullLMode, int nullAMode,
-			/*
-			 * Evaluation type
-			 * 0 = x, 1 = y, 2 = width, 3 = height
-			 */
-			int evalType,
-			pGEDevDesc dd) 
-{
-    double vpWidthCM, vpHeightCM;
-    double rotationAngle;
-    LViewportContext vpc;
-    R_GE_gcontext gc;
-    LTransform transform, savedTransform;
-    SEXP currentvp, currentgp;
-    SEXP preFn,  postFn, findGrobFn;
-    SEXP evalFnx = R_NilValue, evalFny = R_NilValue;
-    SEXP R_fcall0, R_fcall1, R_fcall2x, R_fcall2y, R_fcall3;
-    SEXP savedgpar, savedgrob, updatedgrob;
-    SEXP unitx = R_NilValue, unity = R_NilValue;
-    double result = 0.0;
-    Rboolean protectedGrob = FALSE;
-    /*
-     * We are just doing calculations, not drawing, so
-     * we don't want anything recorded on the graphics engine DL
-     *
-     * FIXME:  This should probably be done via a GraphicsEngine.h
-     * function call rather than directly playing with dd->recordGraphics
-     */
-    Rboolean record = dd->recordGraphics;
-    dd->recordGraphics = FALSE;
-    /*
-     * Save the current viewport transform 
-     * (use to convert location relative to current viewport)
-     */
-    currentvp = gridStateElement(dd, GSS_VP);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 savedTransform, &rotationAngle);
-    /* 
-     * Save the current gpar state and restore it at the end
-     */
-    PROTECT(savedgpar = gridStateElement(dd, GSS_GPAR));
-    /*
-     * Save the current grob and restore it at the end
-     */
-    PROTECT(savedgrob = gridStateElement(dd, GSS_CURRGROB));
-    /*
-     * Set up for calling R functions 
-     */
-    PROTECT(preFn = findFun(install("preDraw"), R_gridEvalEnv));
-    switch(evalType) {
-    case 0:
-    case 1:
-	PROTECT(evalFnx = findFun(install("xDetails"), R_gridEvalEnv));
-	PROTECT(evalFny = findFun(install("yDetails"), R_gridEvalEnv));
-	break;
-    case 2:
-	PROTECT(evalFnx = findFun(install("width"), R_gridEvalEnv));
-	break;
-    case 3:
-	PROTECT(evalFny = findFun(install("height"), R_gridEvalEnv));
-	break;
-    case 4:
-	PROTECT(evalFny = findFun(install("ascentDetails"), R_gridEvalEnv));
-        break;
-    case 5:
-	PROTECT(evalFny = findFun(install("descentDetails"), R_gridEvalEnv));
-        break;
-    }
-    PROTECT(postFn = findFun(install("postDraw"), R_gridEvalEnv));
-    /*
-     * If grob is actually a gPath, use it to find an actual grob
-     */
-    if (inherits(grob, "gPath")) {
-	/* 
-	 * If the current grob is NULL then we are at the top level
-	 * and we search the display list, otherwise we search the 
-	 * children of the current grob
-	 *
-	 * NOTE: assume here that only gPath of depth == 1 are valid
-	 */
-	if (isNull(savedgrob)) {
-	    PROTECT(findGrobFn = findFun(install("findGrobinDL"), 
-					 R_gridEvalEnv));
-	    PROTECT(R_fcall0 = lang2(findGrobFn, 
-				     getListElement(grob, "name")));
-	    PROTECT(grob = eval(R_fcall0, R_gridEvalEnv));
-	} else {
-	    PROTECT(findGrobFn = findFun(install("findGrobinChildren"), 
-					 R_gridEvalEnv));
-	    PROTECT(R_fcall0 = lang3(findGrobFn, 
-				     getListElement(grob, "name"),
-				     getListElement(savedgrob, "children")));
-	    PROTECT(grob = eval(R_fcall0, R_gridEvalEnv));
-	}
-	/*
-	 * Flag to make sure we UNPROTECT these at the end
-	 */
-	protectedGrob = TRUE;
-    }
-    /* Call preDraw(grob) 
-     */
-    PROTECT(R_fcall1 = lang2(preFn, grob));
-    PROTECT(updatedgrob = eval(R_fcall1, R_gridEvalEnv));
-    /* 
-     * The call to preDraw may have pushed viewports and/or
-     * enforced gpar settings, SO we need to re-establish the
-     * current viewport and gpar settings before evaluating the
-     * width unit.
-     * 
-     * NOTE:  we are really relying on the grid state to be coherent
-     * when we do stuff like this (i.e., not to have changed since
-     * we started evaluating the unit [other than the changes we may
-     * have deliberately made above by calling preDraw]).  In other
-     * words we are relying on no other drawing occurring at the 
-     * same time as we are doing this evaluation.  In other other
-     * words, we are relying on there being only ONE process
-     * (i.e., NOT multi-threaded).
-     */
-    currentvp = gridStateElement(dd, GSS_VP);
-    currentgp = gridStateElement(dd, GSS_GPAR);
-    getViewportTransform(currentvp, dd, 
-			 &vpWidthCM, &vpHeightCM, 
-			 transform, &rotationAngle);
-    fillViewportContextFromViewport(currentvp, &vpc);
-    /* Call whatever(grob)
-     * to get the unit representing the x/y/width/height
-     */
-    switch (evalType) {
-    case 0:
-    case 1:
-	/*
-	 * When evaluating grobX/grobY, the value of the unit
-	 * is an angle that gets passed to xDetails/yDetails
-	 */
-	{
-	    SEXP val;
-	    PROTECT(val = ScalarReal(value));
-	    PROTECT(R_fcall2x = lang3(evalFnx, updatedgrob, val));
-	    PROTECT(unitx = eval(R_fcall2x, R_gridEvalEnv));
-	    PROTECT(R_fcall2y = lang3(evalFny, updatedgrob, val));
-	    PROTECT(unity = eval(R_fcall2y, R_gridEvalEnv));
-	}
-	break;
-    case 2:
-	PROTECT(R_fcall2x = lang2(evalFnx, updatedgrob));
-	PROTECT(unitx = eval(R_fcall2x, R_gridEvalEnv));
-	break;
-    case 3:
-    case 4:
-    case 5:
-	PROTECT(R_fcall2y = lang2(evalFny, updatedgrob));
-	PROTECT(unity = eval(R_fcall2y, R_gridEvalEnv));
-	break;
-    }
-    /* 
-     * Transform the unit
-     * NOTE:  We transform into INCHES so can produce final answer in terms
-     * of NPC for original context
-     */
-    /* Special case for "null" units
-     */
-    gcontextFromgpar(currentgp, 0, &gc, dd);
-    switch(evalType) {
-    case 0:
-    case 1:
-	if (evalType && pureNullUnit(unity, 0, dd)) {
-	    result = evaluateNullUnit(pureNullUnitValue(unity, 0), 
-				      vpWidthCM,
-				      nullLMode, nullAMode);
-	} else if (pureNullUnit(unitx, 0, dd)) {
-	    result = evaluateNullUnit(pureNullUnitValue(unitx, 0), 
-				      vpWidthCM,
-				      nullLMode, nullAMode);
-	} else {
-	    /*
-	     * Transform to device (to allow for viewports in grob)
-	     * then adjust relative to current viewport.
-	     */
-	    double xx, yy;
-	    LLocation lin, lout;
-	    LTransform invt;
-	    invTransform(savedTransform, invt);
-	    transformLocn(unitx, unity, 0,
-			  vpc, &gc,
-			  vpWidthCM, vpHeightCM, dd,
-			  transform, &xx, &yy);
-	    location(xx, yy, lin);
-	    trans(lin, invt, lout);
-	    xx = locationX(lout);
-	    yy = locationY(lout);
-	    if (evalType)
-		result = yy;
-	    else
-		result = xx;
-	}
-	break;
-    case 2:
-	if (pureNullUnit(unitx, 0, dd)) {
-	    result = evaluateNullUnit(pureNullUnitValue(unitx, 0), 
-				      vpWidthCM,
-				      nullLMode, nullAMode);
-	} else {
-	    result = transformWidthtoINCHES(unitx, 0, vpc, &gc,
-					    vpWidthCM, vpHeightCM,
-					    dd);
-	}
-	break;
-    case 3:
-    case 4:
-    case 5:
-	if (pureNullUnit(unity, 0, dd)) {
-	    result = evaluateNullUnit(pureNullUnitValue(unity, 0), 
-				      vpWidthCM,
-				      nullLMode, nullAMode);
-	} else {
-	    result = transformHeighttoINCHES(unity, 0, vpc, &gc,
-					     vpWidthCM, vpHeightCM,
-					     dd);
-	}
-	break;
-    }
-    /* Call postDraw(grob)
-     */
-    PROTECT(R_fcall3 = lang2(postFn, updatedgrob));
-    eval(R_fcall3, R_gridEvalEnv);
-    /* 
-     * Restore the saved gpar state and grob
-     */
-    setGridStateElement(dd, GSS_GPAR, savedgpar);
-    setGridStateElement(dd, GSS_CURRGROB, savedgrob);
-    if (protectedGrob) 
-	UNPROTECT(3);
-    switch(evalType) {
-    case 0:
-    case 1:
-	UNPROTECT(14);
-	break;
-    case 2:
-    case 3:
-    case 4:
-    case 5:
-	UNPROTECT(10);
-    }
-    /* Return the transformed width
-     */
-    /*
-     * If there is an error or user-interrupt in the above
-     * evaluation, dd->recordGraphics is set to TRUE
-     * on all graphics devices (see GEonExit(); called in errors.c)
-     */
-    dd->recordGraphics = record;
-    return result;
-}
-
-double evaluateGrobXUnit(double value, SEXP grob, 
-			 double vpheightCM, double vpwidthCM,
-			 int nullLMode, int nullAMode,
-			 pGEDevDesc dd) 
-{
-    return evaluateGrobUnit(value, grob, vpheightCM, vpwidthCM, 
-			    nullLMode, nullAMode, 0, dd);
-}
-
-double evaluateGrobYUnit(double value, SEXP grob, 
-			 double vpheightCM, double vpwidthCM,
-			 int nullLMode, int nullAMode,
-			 pGEDevDesc dd) 
-{
-    return evaluateGrobUnit(value, grob, vpheightCM, vpwidthCM, 
-			    nullLMode, nullAMode, 1, dd);
-}
-
-double evaluateGrobWidthUnit(SEXP grob, 
-			     double vpheightCM, double vpwidthCM,
-			     int nullLMode, int nullAMode,
-			     pGEDevDesc dd) 
-{
-    return evaluateGrobUnit(1, grob, vpheightCM, vpwidthCM, 
-			    nullLMode, nullAMode, 2, dd);
-}
-
-double evaluateGrobHeightUnit(SEXP grob, 
-			     double vpheightCM, double vpwidthCM,
-			     int nullLMode, int nullAMode,
-			     pGEDevDesc dd) 
-{
-    return evaluateGrobUnit(1, grob, vpheightCM, vpwidthCM, 
-			    nullLMode, nullAMode, 3, dd);
-}
-
-double evaluateGrobAscentUnit(SEXP grob, 
-                              double vpheightCM, double vpwidthCM,
-                              int nullLMode, int nullAMode,
-                              pGEDevDesc dd) 
-{
-    return evaluateGrobUnit(1, grob, vpheightCM, vpwidthCM, 
-			    nullLMode, nullAMode, 4, dd);
-}
-
-double evaluateGrobDescentUnit(SEXP grob, 
-                               double vpheightCM, double vpwidthCM,
-                               int nullLMode, int nullAMode,
-                               pGEDevDesc dd) 
-{
-    return evaluateGrobUnit(1, grob, vpheightCM, vpwidthCM, 
-			    nullLMode, nullAMode, 5, dd);
-}
-
-/**************************
- * TRANSFORMATIONS
- **************************
- */
-    
-/* Map a value from arbitrary units to INCHES */
-
-/*
- * NULL units are a special case
- * If L_nullLayoutMode = 1 then the value returned is a NULL unit value
- * Otherwise it is an INCHES value
- */
-double transform(double value, int unit, SEXP data,
-		 double scalemin, double scalemax,
-		 const pGEcontext gc,
-		 double thisCM, double otherCM,
-		 int nullLMode, int nullAMode, pGEDevDesc dd)
-{
-    double asc, dsc, wid;
-    double result = value;
-    switch (unit) {
-    case L_NPC:      
-	result = (result * thisCM)/2.54; /* 2.54 cm per inch */
-	break;
-    case L_CM: 
-	result = result/2.54;
-	break;
-    case L_INCHES: 
-	break;
-    /* FIXME:  The following two assume that the pointsize specified
-     * by the user is actually the pointsize provided by the
-     * device.  This is NOT a safe assumption
-     * One possibility would be to do a call to GReset(), just so
-     * that mapping() gets called, just so that things like
-     * xNDCPerLine are up-to-date, THEN call GStrHeight("M")
-     * or somesuch.
-     */
-    case L_CHAR:
-    case L_MYCHAR:  /* FIXME: Remove this when I can */
-	result = (result * gc->ps * gc->cex)/72; /* 72 points per inch */
-	break;	
-    case L_LINES:
-    case L_MYLINES: /* FIXME: Remove this when I can */
-	result = (result * gc->ps * gc->cex * gc->lineheight)/72;
-	break;
-    case L_SNPC:        
-	if (thisCM <= otherCM)
-	    result = (result * thisCM)/2.54;
-	else                     
-	    result = (result * otherCM)/2.54;
-	break;
-    case L_MM:
-	result = (result/10)/2.54;
-	break;
-	/* Maybe an opportunity for some constants below here (!) 
-	 */
-    case L_POINTS:
-	result = result/72.27;
-	break;
-    case L_PICAS:
-	result = (result*12)/72.27;
-	break;
-    case L_BIGPOINTS:
-	result = result/72; 
-	break;
-    case L_DIDA:
-	result = result/1157*1238/72.27;
-	break;
-    case L_CICERO:
-	result = result*12/1157*1238/72.27;
-	break;
-    case L_SCALEDPOINTS:
-	result = result/65536/72.27;
-	break;
-    case L_STRINGWIDTH:
-    case L_MYSTRINGWIDTH: /* FIXME: Remove this when I can */
-	if (isExpression(data))
-	    result = result*
-		fromDeviceWidth(GEExpressionWidth(VECTOR_ELT(data, 0), gc, dd),
-				GE_INCHES, dd);
-	else
-	    result = result*
-		fromDeviceWidth(GEStrWidth(CHAR(STRING_ELT(data, 0)), 
-					   getCharCE(STRING_ELT(data, 0)), 
-					   gc, dd),
-				GE_INCHES, dd);
-	break;
-    case L_STRINGHEIGHT:
-    case L_MYSTRINGHEIGHT: /* FIXME: Remove this when I can */
-	if (isExpression(data))
-	    result = result*
-		fromDeviceHeight(GEExpressionHeight(VECTOR_ELT(data, 0), 
-						    gc, dd),
-				 GE_INCHES, dd);
-	else
-	    /* FIXME: what encoding is this? */
-	    result = result*
-		fromDeviceHeight(GEStrHeight(CHAR(STRING_ELT(data, 0)), -1,
-					     gc, dd),
-				 GE_INCHES, dd);
-	break;
-    case L_STRINGASCENT:        
-	if (isExpression(data))
-            GEExpressionMetric(VECTOR_ELT(data, 0), gc, 
-                               &asc, &dsc, &wid,
-                               dd);
-	else
-            GEStrMetric(CHAR(STRING_ELT(data, 0)), 
-                        getCharCE(STRING_ELT(data, 0)), gc,
-                        &asc, &dsc, &wid,
-                        dd);
-        result = result*fromDeviceHeight(asc, GE_INCHES, dd);
-	break;
-    case L_STRINGDESCENT:        
-	if (isExpression(data))
-            GEExpressionMetric(VECTOR_ELT(data, 0), gc, 
-                               &asc, &dsc, &wid,
-                               dd);
-	else
-            GEStrMetric(CHAR(STRING_ELT(data, 0)), 
-                        getCharCE(STRING_ELT(data, 0)), gc,
-                        &asc, &dsc, &wid,
-                        dd);
-        result = result*fromDeviceHeight(dsc, GE_INCHES, dd);
-	break;
-    case L_GROBX:
-	result = evaluateGrobXUnit(value, data, thisCM, otherCM,
-				   nullLMode, nullAMode, dd);
-	break;	
-    case L_GROBY:
-	result = evaluateGrobYUnit(value, data, otherCM, thisCM,
-				   nullLMode, nullAMode, dd);
-	break;	
-    case L_GROBWIDTH:
-	result = value*evaluateGrobWidthUnit(data, thisCM, otherCM,
-					     nullLMode, nullAMode, dd);
-	break;
-    case L_GROBHEIGHT:
-	result = value*evaluateGrobHeightUnit(data, otherCM, thisCM,
-					      nullLMode, nullAMode, dd);
-	break;
-    case L_GROBASCENT:
-	result = value*evaluateGrobAscentUnit(data, otherCM, thisCM,
-					      nullLMode, nullAMode, dd);
-	break;
-    case L_GROBDESCENT:
-	result = value*evaluateGrobDescentUnit(data, otherCM, thisCM,
-                                               nullLMode, nullAMode, dd);
-	break;
-    case L_NULL:
-	result = evaluateNullUnit(result, thisCM, nullLMode, nullAMode);
-	break;
-    default:
-	error(_("invalid unit or unit not yet implemented"));
-    }
-    /*
-     * For physical units, scale the result by GSS_SCALE (a "zoom" factor)
-     */
-    switch (unit) {
-    case L_INCHES:
-    case L_CM:
-    case L_MM:
-    case L_POINTS:
-    case L_PICAS:
-    case L_BIGPOINTS:
-    case L_DIDA:
-    case L_CICERO:
-    case L_SCALEDPOINTS:
-      result = result * REAL(gridStateElement(dd, GSS_SCALE))[0];
-      break;
-    default:
-      /*
-       * No need to scale relative coordinates (NPC, NATIVE, NULL)
-       * CHAR and LINES already scaled because of scaling in gcontextFromGPar()
-       * Ditto STRINGWIDTH/HEIGHT
-       * GROBWIDTH/HEIGHT recurse into here so scaling already done
-       */
-      break;
-    }
-    return result;
-}
-
-/* FIXME:  scales are only linear at the moment */
-double transformLocation(double location, int unit, SEXP data,
-			 double scalemin, double scalemax,
-			 const pGEcontext gc,
-			 double thisCM, double otherCM,
-			 int nullLMode, int nullAMode, pGEDevDesc dd)
-{
-    double result = location;
-    switch (unit) {
-    case L_NATIVE:
-	/* It is invalid to create a viewport with identical limits on scale
-         * so we are protected from divide-by-zero
-         */
-	result = ((result - scalemin)/(scalemax - scalemin))*thisCM/2.54;
-	break;
-    default:
-	result = transform(location, unit, data, scalemin, scalemax,
-			   gc, thisCM, otherCM, nullLMode, nullAMode, dd);
-    }
-    return result;
-}
-
-double transformXArithmetic(SEXP x, int index,
-			    LViewportContext vpc,
-			    const pGEcontext gc,
-			    double widthCM, double heightCM,
-			    int nullLMode, pGEDevDesc dd);
-
-double transformX(SEXP x, int index,
-		  LViewportContext vpc,
-		  const pGEcontext gc,
-		  double widthCM, double heightCM,
-		  int nullLMode, int nullAMode, pGEDevDesc dd)
-{
-    double result;
-    int unit;
-    SEXP data;
-    if (isUnitArithmetic(x)) 
-	result = transformXArithmetic(x, index, vpc, gc,
-				      widthCM, heightCM, nullLMode, dd);
-    else if (isUnitList(x)) {
-	int n = unitLength(x);
-	result = transformX(VECTOR_ELT(x, index % n), 0, vpc, gc,
-			    widthCM, heightCM, nullLMode, nullAMode, dd);
-    } else {  /* Just a plain unit */
-	int nullamode;
-	if (nullAMode == 0) 
-	    nullamode = L_plain;
-	else 
-	    nullamode = nullAMode;
-	result = unitValue(x, index);
-	unit = unitUnit(x, index);
-	PROTECT(data = unitData(x, index));
-	result = transformLocation(result, unit, data, 
-				   vpc.xscalemin, vpc.xscalemax, gc,
-				   widthCM, heightCM, 
-				   nullLMode, 
-				   nullamode,
-				   dd);
-	UNPROTECT(1);
-    }
-    return result;
-}
-
-double transformYArithmetic(SEXP y, int index,
-			    LViewportContext vpc,
-			    const pGEcontext gc,
-			    double widthCM, double heightCM,
-			    int nullLMode, pGEDevDesc dd);
-
-double transformY(SEXP y, int index, 
-		  LViewportContext vpc,
-		  const pGEcontext gc,
-		  double widthCM, double heightCM,
-		  int nullLMode, int nullAMode, pGEDevDesc dd)
-{
-    double result;
-    int unit;
-    SEXP data;
-    if (isUnitArithmetic(y))
-	result = transformYArithmetic(y, index, vpc, gc,
-				      widthCM, heightCM, nullLMode, dd);
-    else if (isUnitList(y)) {
-	int n = unitLength(y);
-	result = transformY(VECTOR_ELT(y, index % n), 0, vpc, gc,
-			    widthCM, heightCM, nullLMode, nullAMode, dd);
-    } else { /* Just a unit object */
-	int nullamode;
-	if (nullAMode == 0) 
-	    nullamode = L_plain;
-	else 
-	    nullamode = nullAMode;
-	result = unitValue(y, index);
-	unit = unitUnit(y, index);
-	PROTECT(data = unitData(y, index));
-	result = transformLocation(result, unit, data, 
-				   vpc.yscalemin, vpc.yscalemax, gc,
-				   heightCM, widthCM, 
-				   nullLMode, 
-				   nullamode,
-				   dd);
-	UNPROTECT(1);
-    } 
-    return result;
-}
-
-double transformDimension(double dim, int unit, SEXP data,
-			  double scalemin, double scalemax,
-			  const pGEcontext gc,
-			  double thisCM, double otherCM,
-			  int nullLMode, int nullAMode,
-			  pGEDevDesc dd)
-{
-    double result = dim;
-    switch (unit) {
-    case L_NATIVE:
-	/* It is invalid to create a viewport with identical limits on scale
-         * so we are protected from divide-by-zero
-         */
-	result = ((dim)/(scalemax - scalemin))*thisCM/2.54;
-	break;
-    default:
-	result = transform(dim, unit, data, scalemin, scalemax, gc,
-			   thisCM, otherCM, nullLMode, nullAMode, dd);
-    }
-    return result;
-}
-
-double transformWidthArithmetic(SEXP width, int index,
-				LViewportContext vpc,
-				const pGEcontext gc,
-				double widthCM, double heightCM,
-				int nullLMode, pGEDevDesc dd);
-
-double transformWidth(SEXP width, int index, 
-		      LViewportContext vpc,
-		      const pGEcontext gc,
-		      double widthCM, double heightCM,
-		      int nullLMode, int nullAMode, pGEDevDesc dd)
-{
-    double result;
-    int unit;
-    SEXP data;
-    if (isUnitArithmetic(width))
-	result = transformWidthArithmetic(width, index, vpc, gc,
-					  widthCM, heightCM, nullLMode, dd);
-    else if (isUnitList(width)) {
-	int n = unitLength(width);
-	result = transformWidth(VECTOR_ELT(width, index % n), 0, vpc, gc,
-				widthCM, heightCM, nullLMode, nullAMode, dd);
-    } else { /* Just a unit object */
-	int nullamode;
-	if (nullAMode == 0) 
-	    nullamode = L_plain;
-	else 
-	    nullamode = nullAMode;
-	result = unitValue(width, index);
-	unit = unitUnit(width, index);
-	PROTECT(data = unitData(width, index));
-	result = transformDimension(result, unit, data, 
-				    vpc.xscalemin, vpc.xscalemax, gc,
-				    widthCM, heightCM, 
-				    nullLMode, 
-				    nullamode,
-				    dd);
-	UNPROTECT(1);
-    }
-    return result;
-}
-
-double transformHeightArithmetic(SEXP height, int index,
-				 LViewportContext vpc,
-				 const pGEcontext gc,
-				 double widthCM, double heightCM,
-				 int nullLMode, pGEDevDesc dd);
-
-double transformHeight(SEXP height, int index,
-		       LViewportContext vpc,
-		       const pGEcontext gc,
-		       double widthCM, double heightCM,
-		       int nullLMode, int nullAMode, pGEDevDesc dd)
-{
-    double result;
-    int unit;
-    SEXP data;
-    if (isUnitArithmetic(height))
-	result = transformHeightArithmetic(height, index, vpc, gc,
-					   widthCM, heightCM, nullLMode, dd);
-    else if (isUnitList(height)) {
-	int n = unitLength(height);
-	result = transformHeight(VECTOR_ELT(height, index % n), 0, vpc, gc,
-				 widthCM, heightCM, nullLMode, nullAMode, dd);
-    } else { /* Just a unit object */
-	int nullamode;
-	if (nullAMode == 0) 
-	    nullamode = L_plain;
-	else 
-	    nullamode = nullAMode;
-	result = unitValue(height, index);
-	unit = unitUnit(height, index);
-	PROTECT(data = unitData(height, index));
-	result = transformDimension(result, unit, data, 
-				    vpc.yscalemin, vpc.yscalemax, gc,
-				    heightCM, widthCM, 
-				    nullLMode, 
-				    nullamode,
-				    dd);
-	UNPROTECT(1);
-    }
-    return result;
-}
-
-double transformXArithmetic(SEXP x, int index,
-			    LViewportContext vpc,
-			    const pGEcontext gc,
-			    double widthCM, double heightCM,
-			    int nullLMode, pGEDevDesc dd)
-{
-    int i;
-    double result = 0;
-    if (addOp(x)) {
-	result = transformX(arg1(x), index, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_adding,
-			    dd) +
-	    transformX(arg2(x), index, vpc, gc,
-		       widthCM, heightCM, 
-		       nullLMode, L_adding,
-		       dd);
-    }
-    else if (minusOp(x)) {
-	result = transformX(arg1(x), index, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_subtracting,
-			    dd) -
-	    transformX(arg2(x), index, vpc, gc,
-		       widthCM, heightCM, 
-		       nullLMode, L_subtracting,
-		       dd);
-    }
-    else if (timesOp(x)) {
-	result = REAL(arg1(x))[index % LENGTH(arg1(x))] *
-	    transformX(arg2(x), index, vpc, gc,
-		       widthCM, heightCM, 
-		       nullLMode, L_multiplying, dd);
-    }
-    else if (minFunc(x)) {
-	int n = unitLength(arg1(x));
-	double temp = DBL_MAX;
-	result = transformX(arg1(x), 0, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_minimising, 
-			    dd);
-	for (i=1; i<n; i++) {
-	    temp = transformX(arg1(x), i, vpc, gc,
-			      widthCM, heightCM, 
-			      nullLMode, L_minimising, 
-			      dd);
-	    if (temp < result)
-		result = temp;
-	}
-    } 
-    else if (maxFunc(x)) {
-	int n = unitLength(arg1(x));
-	double temp = DBL_MIN;
-	result = transformX(arg1(x), 0, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_maximising, 
-			    dd);
-	for (i=1; i<n; i++) {
-	    temp = transformX(arg1(x), i, vpc, gc,
-			      widthCM, heightCM, 
-			      nullLMode, L_maximising, 
-			      dd);
-	    if (temp > result)
-		result = temp;
-	}
-    }
-    else if (sumFunc(x)) {
-	int n = unitLength(arg1(x));
-	result = 0.0;
-	for (i=0; i<n; i++) {
-	    result += transformX(arg1(x), i, vpc, gc,
-				 widthCM, heightCM, 
-				 nullLMode, L_summing, dd);
-	}
-    }
-    else 
-	error(_("unimplemented unit function"));
-    return result;
-}
-
-double transformYArithmetic(SEXP y, int index,
-			    LViewportContext vpc,
-			    const pGEcontext gc,
-			    double widthCM, double heightCM,
-			    int nullLMode, pGEDevDesc dd)
-{
-    int i;
-    double result = 0;
-    if (addOp(y)) {
-	result = transformY(arg1(y), index, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_adding,
-			    dd) +
-	    transformY(arg2(y), index, vpc, gc,
-		       widthCM, heightCM, 
-		       nullLMode, L_adding,
-		       dd);
-    }
-    else if (minusOp(y)) {
-	result = transformY(arg1(y), index, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_subtracting,
-			    dd) -
-	    transformY(arg2(y), index, vpc, gc,
-		       widthCM, heightCM, 
-		       nullLMode, L_subtracting,
-		       dd);
-    }
-    else if (timesOp(y)) {
-	result = REAL(arg1(y))[index % LENGTH(arg1(y))] *
-	    transformY(arg2(y), index, vpc, gc,
-		       widthCM, heightCM, 
-		       nullLMode, L_multiplying, dd);
-    }
-    else if (minFunc(y)) {
-	int n = unitLength(arg1(y));
-	double temp = DBL_MAX;
-	result = transformY(arg1(y), 0, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_minimising, 
-			    dd);
-	for (i=1; i<n; i++) {
-	    temp = transformY(arg1(y), i, vpc, gc,
-			      widthCM, heightCM, 
-			      nullLMode, L_minimising, 
-			      dd);
-	    if (temp < result)
-		result = temp;
-	}
-    } 
-    else if (maxFunc(y)) {
-	int n = unitLength(arg1(y));
-	double temp = DBL_MIN;
-	result = transformY(arg1(y), 0, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_maximising, 
-			    dd);
-	for (i=1; i<n; i++) {
-	    temp = transformY(arg1(y), i, vpc, gc,
-			      widthCM, heightCM, 
-			      nullLMode, L_maximising, 
-			      dd);
-	    if (temp > result)
-		result = temp;
-	}
-    }
-    else if (sumFunc(y)) {
-	int n = unitLength(arg1(y));
-	result = 0.0;
-	for (i=0; i<n; i++) {
-	    result += transformY(arg1(y), i, vpc, gc,
-				 widthCM, heightCM, 
-				 nullLMode, L_summing, dd);
-	}
-    }
-    else 
-	error(_("unimplemented unit function"));
-    return result;
-}
-
-double transformWidthArithmetic(SEXP width, int index,
-				LViewportContext vpc,
-				const pGEcontext gc,
-				double widthCM, double heightCM,
-				int nullLMode, pGEDevDesc dd)
-{
-    int i;
-    double result = 0;
-    if (addOp(width)) {
-	result = transformWidth(arg1(width), index, vpc, gc,
-				widthCM, heightCM, 
-				nullLMode, L_adding,
-				dd) +
-	    transformWidth(arg2(width), index, vpc, gc,
-			   widthCM, heightCM, 
-			   nullLMode, L_adding,
-			   dd);
-    }
-    else if (minusOp(width)) {
-	result = transformWidth(arg1(width), index, vpc, gc,
-				widthCM, heightCM, 
-				nullLMode, L_subtracting,
-				dd) -
-	    transformWidth(arg2(width), index, vpc, gc,
-			   widthCM, heightCM, 
-			   nullLMode, L_subtracting,
-			   dd);
-    }
-    else if (timesOp(width)) {
-	result = REAL(arg1(width))[index % LENGTH(arg1(width))] *
-	    transformWidth(arg2(width), index, vpc, gc,
-			   widthCM, heightCM, 
-			   nullLMode, L_multiplying, dd);
-    }
-    else if (minFunc(width)) {
-	int n = unitLength(arg1(width));
-	double temp = DBL_MAX;
-	result = transformWidth(arg1(width), 0, vpc, gc,
-				widthCM, heightCM, 
-				nullLMode, L_minimising, 
-				dd);
-	for (i=1; i<n; i++) {
-	    temp = transformWidth(arg1(width), i, vpc, gc,
-				  widthCM, heightCM, 
-				  nullLMode, L_minimising, 
-				  dd);
-	    if (temp < result)
-		result = temp;
-	}
-    } 
-    else if (maxFunc(width)) {
-	int n = unitLength(arg1(width));
-	double temp = DBL_MIN;
-	result = transformWidth(arg1(width), 0, vpc, gc,
-				widthCM, heightCM, 
-				nullLMode, L_maximising, 
-				dd);
-	for (i=1; i<n; i++) {
-	    temp = transformWidth(arg1(width), i, vpc, gc,
-				  widthCM, heightCM, 
-				  nullLMode, L_maximising, 
-				  dd);
-	    if (temp > result)
-		result = temp;
-	}
-    }
-    else if (sumFunc(width)) {
-	int n = unitLength(arg1(width));
-	result = 0.0;
-	for (i=0; i<n; i++) {
-	    result += transformWidth(arg1(width), i, vpc, gc,
-				     widthCM, heightCM, 
-				     nullLMode, L_summing, dd);
-	}
-    }
-    else 
-	error(_("unimplemented unit function"));
-    return result;
-}
-
-double transformHeightArithmetic(SEXP height, int index,
-				 LViewportContext vpc,
-				 const pGEcontext gc,
-				 double widthCM, double heightCM,
-				 int nullLMode, pGEDevDesc dd)
-{
-    int i;
-    double result = 0;
-    if (addOp(height)) {
-	result = transformHeight(arg1(height), index, vpc, gc,
-				 widthCM, heightCM, 
-				 nullLMode, L_adding,
-				 dd) +
-	    transformHeight(arg2(height), index, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_adding,
-			    dd);
-    }
-    else if (minusOp(height)) {
-	result = transformHeight(arg1(height), index, vpc, gc,
-				 widthCM, heightCM, 
-				 nullLMode, L_subtracting,
-				 dd) -
-	    transformHeight(arg2(height), index, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_subtracting,
-			    dd);
-    }
-    else if (timesOp(height)) {
-	result = REAL(arg1(height))[index % LENGTH(arg1(height))] *
-	    transformHeight(arg2(height), index, vpc, gc,
-			    widthCM, heightCM, 
-			    nullLMode, L_multiplying, dd);
-    }
-    else if (minFunc(height)) {
-	int n = unitLength(arg1(height));
-	double temp = DBL_MAX;
-	result = transformHeight(arg1(height), 0, vpc, gc,
-				 widthCM, heightCM, 
-				 nullLMode, L_minimising, 
-				 dd);
-	for (i=1; i<n; i++) {
-	    temp = transformHeight(arg1(height), i, vpc, gc,
-				   widthCM, heightCM, 
-				   nullLMode, L_minimising, 
-				   dd);
-	    if (temp < result)
-		result = temp;
-	}
-    } 
-    else if (maxFunc(height)) {
-	int n = unitLength(arg1(height));
-	double temp = DBL_MIN;
-	result = transformHeight(arg1(height), 0, vpc, gc,
-				 widthCM, heightCM, 
-				 nullLMode, L_maximising, 
-				 dd);
-	for (i=1; i<n; i++) {
-	    temp = transformHeight(arg1(height), i, vpc, gc,
-				   widthCM, heightCM, 
-				   nullLMode, L_maximising, 
-				   dd);
-	    if (temp > result)
-		result = temp;
-	}
-    }
-    else if (sumFunc(height)) {
-	int n = unitLength(arg1(height));
-	result = 0.0;
-	for (i=0; i<n; i++) {
-	    result += transformHeight(arg1(height), i, vpc, gc,
-				      widthCM, heightCM, 
-				      nullLMode, L_summing, dd);
-	}
-    }
-    else 
-	error(_("unimplemented unit function"));
-    return result;
-}
-
-/* Code for transforming a location in INCHES using a transformation matrix.
- * We work in INCHES so that rotations can be incorporated within the
- * transformation matrix (i.e., the units are the same in both x- and
- * y-directions).
- * INCHES rather than CM because the R graphics engine only has INCHES.
- */
-
-/* The original transform[X | Y | Width | Height] functions
- * were written to transform to NPC.  Rather than muck with them,
- * I am just wrappering them to get the new transformation to INCHES
- * In other words, the reason for the apparent inefficiency here
- * is historical.
- */
-
-/* It is even more inefficient-looking now because I ended up mucking
- * with transform() to return INCHES (to fix bug if width/heightCM == 0)
- * and by then there was too much code that called transformXtoINCHES
- * to be bothered changing calls to it
- */
-
-/* The difference between transform*toINCHES and transformLocn/Dimn 
- * is that the former are just converting from one coordinate system
- * to INCHES;  the latter are converting from INCHES relative to
- * the parent to INCHES relative to the device.
- */
-double transformXtoINCHES(SEXP x, int index, 
-			  LViewportContext vpc, 
-			  const pGEcontext gc,
-			  double widthCM, double heightCM,
-			  pGEDevDesc dd)
-{
-    return transformX(x, index, vpc, gc,
-		      widthCM, heightCM, 0, 0, dd);
-}
-
-double transformYtoINCHES(SEXP y, int index, 
-			  LViewportContext vpc,
-			  const pGEcontext gc,
-			  double widthCM, double heightCM,
-			  pGEDevDesc dd)
-{
-    return transformY(y, index, vpc, gc,
-		      widthCM, heightCM, 0, 0, dd);
-}
-
-void transformLocn(SEXP x, SEXP y, int index, 
-		   LViewportContext vpc,
-		   const pGEcontext gc,
-		   double widthCM, double heightCM,
-		   pGEDevDesc dd,
-		   LTransform t,
-		   double *xx, double *yy)
-{
-    LLocation lin, lout;
-    /* x and y are unit objects (i.e., values in any old coordinate
-     * system) so the first step is to convert them both to CM
-     */
-    *xx = transformXtoINCHES(x, index, vpc, gc,
-			     widthCM, heightCM, dd);
-    *yy = transformYtoINCHES(y, index, vpc, gc,
-			     widthCM, heightCM, dd);
-    location(*xx, *yy, lin);
-    trans(lin, t, lout);
-    *xx = locationX(lout);
-    *yy = locationY(lout);
-}
-
-double transformWidthtoINCHES(SEXP w, int index,
-			      LViewportContext vpc,
-			      const pGEcontext gc,
-			      double widthCM, double heightCM,
-			      pGEDevDesc dd)
-{
-    return transformWidth(w, index, vpc, gc,
-			  widthCM, heightCM, 0, 0, dd);
-}
-
-double transformHeighttoINCHES(SEXP h, int index,
-			       LViewportContext vpc,
-			       const pGEcontext gc,
-			       double widthCM, double heightCM,
-			       pGEDevDesc dd)
-{
-    return transformHeight(h, index, vpc, gc,
-			   widthCM, heightCM, 0, 0, dd);
-}
-
-void transformDimn(SEXP w, SEXP h, int index, 
-		   LViewportContext vpc,
-		   const pGEcontext gc,
-		   double widthCM, double heightCM,
-		   pGEDevDesc dd,
-		   double rotationAngle,
-		   double *ww, double *hh)
-{
-    LLocation din, dout;
-    LTransform r;
-    *ww = transformWidthtoINCHES(w, index, vpc, gc,
-				 widthCM, heightCM, dd);
-    *hh = transformHeighttoINCHES(h, index, vpc, gc,
-				  widthCM, heightCM, dd);
-    location(*ww, *hh, din);
-    rotation(rotationAngle, r);
-    trans(din, r, dout);
-    *ww = locationX(dout);
-    *hh = locationY(dout);
-}
-
-/*
- * ****************************
- * Inverse Transformations
- * ****************************
- */
-
-/*
- * Take a value in inches within the viewport and convert to some
- * other coordinate system
- */
-
-double transformFromINCHES(double value, int unit, 
-			   const pGEcontext gc,
-			   double thisCM, double otherCM,
-			   pGEDevDesc dd)
-{
-    /*      
-     * Convert to NPC
-     */
-    double result = value;
-    switch (unit) {
-    case L_NPC:      
-	result = result/(thisCM/2.54);
-	break;
-    case L_CM: 
-	result = result*2.54;
-	break;
-    case L_INCHES: 
-	break;
-    /* FIXME:  The following two assume that the pointsize specified
-     * by the user is actually the pointsize provided by the
-     * device.  This is NOT a safe assumption
-     * One possibility would be to do a call to GReset(), just so
-     * that mapping() gets called, just so that things like
-     * xNDCPerLine are up-to-date, THEN call GStrHeight("M")
-     * or somesuch.
-     */
-    case L_CHAR:
-	result = (result*72)/(gc->ps*gc->cex);
-	break;	
-    case L_LINES:
-	result = (result*72)/(gc->ps*gc->cex*gc->lineheight);
-	break;
-    case L_MM:
-	result = result*2.54*10;
-	break;
-	/* Maybe an opportunity for some constants below here (!) 
-	 */
-    case L_POINTS:
-	result = result*72.27;
-	break;
-    case L_PICAS:
-	result = result/12*72.27;
-	break;
-    case L_BIGPOINTS:
-	result = result*72; 
-	break;
-    case L_DIDA:
-	result = result/1238*1157*72.27;
-	break;
-    case L_CICERO:
-	result = result/1238*1157*72.27/12;
-	break;
-    case L_SCALEDPOINTS:
-	result = result*65536*72.27;
-	break;
-	/*
-	 * I'm not sure the remaining ones makes any sense.
-	 * For simplicity, these are just forbidden for now.
-	 */
-    case L_SNPC:        
-    case L_MYCHAR:
-    case L_MYLINES:
-    case L_STRINGWIDTH:
-    case L_MYSTRINGWIDTH:
-    case L_STRINGHEIGHT:
-    case L_MYSTRINGHEIGHT:
-    case L_GROBX:
-    case L_GROBY:
-    case L_GROBWIDTH:
-    case L_GROBHEIGHT:
-    case L_NULL:
-    default:
-	error(_("invalid unit or unit not yet implemented"));
-    }
-    /*
-     * For physical units, reverse the scale by GSS_SCALE (a "zoom" factor)
-     */
-    switch (unit) {
-    case L_INCHES:
-    case L_CM:
-    case L_MM:
-    case L_POINTS:
-    case L_PICAS:
-    case L_BIGPOINTS:
-    case L_DIDA:
-    case L_CICERO:
-    case L_SCALEDPOINTS:
-      result = result / REAL(gridStateElement(dd, GSS_SCALE))[0];
-      break;
-    default:
-      /*
-       * No need to scale relative coordinates (NPC, NATIVE, NULL)
-       * All other units forbidden anyway
-       */
-      break;
-    }
-    return result;
-}
-
-/* 
- * This corresponds to transform[X|Y]toINCHES() because
- * it works only within the current viewport, BUT
- * it is much simpler because it is supplied with a 
- * double value in INCHES (rather than a unit object in
- * an arbitrary unit).
- *
- * For conceptual symmetry, it should probably return a
- * unit object, but it only returns a double value.
- * The construction of a unit object with the appropriate
- * unit must be performed by the calling function (or higher).
- * This is probably easiest done right up in R code.
- */
-double transformXYFromINCHES(double location, int unit, 
-			     double scalemin, double scalemax,
-			     const pGEcontext gc,
-			     double thisCM, double otherCM,
-			     pGEDevDesc dd)
-{
-    double result = location;
-    /* Special case if "thisCM == 0":
-     * If converting FROM relative unit, result will already be zero 
-     * so leave it there.
-     * If converting FROM absolute unit that is zero, ditto.
-     * Otherwise (converting FROM non-zero absolute unit), 
-     * converting to relative unit is an error.
-     */
-    if ((unit == L_NATIVE || unit == L_NPC) &&
-        thisCM < 1e-6) {
-        if (result != 0)
-            error(_("Viewport has zero dimension(s)"));
-    } else {
-        switch (unit) {
-        case L_NATIVE:
-            result = scalemin + (result/(thisCM/2.54))*(scalemax - scalemin);
-            break;        
-        default:
-            result = transformFromINCHES(location, unit, gc,
-                                         thisCM, otherCM, dd);
-        }
-    }
-    return result;
-}
-
-double transformWidthHeightFromINCHES(double dimension, int unit, 
-				      double scalemin, double scalemax,
-				      const pGEcontext gc,
-				      double thisCM, double otherCM,
-				      pGEDevDesc dd)
-{
-    double result = dimension;
-    /* Special case if "thisCM == 0":
-     * If converting FROM relative unit, result will already be zero 
-     * so leave it there.
-     * If converting FROM absolute unit that is zero, ditto.
-     * Otherwise (converting FROM non-zero absolute unit), 
-     * converting to relative unit is an error.
-     */
-    if ((unit == L_NATIVE || unit == L_NPC) &&
-        thisCM < 1e-6) {
-        if (result != 0)
-            error(_("Viewport has zero dimension(s)"));
-    } else {
-        switch (unit) {
-        case L_NATIVE:       
-            result = (result/(thisCM/2.54))*(scalemax - scalemin);
-            break;
-        default:
-            result = transformFromINCHES(dimension, unit, gc,
-                                         thisCM, otherCM, dd);
-        }
-    }
-    return result;
-}
-
-/*
- * Special case conversion from relative unit to relative unit,
- * only used when relevant widthCM or heightCM is zero, so
- * we cannot transform thru INCHES (or we get divide-by-zero)
- *
- * Protected from divide-by-zero here because viewport with
- * identical scale limits is disallowed.
- */
-double transformXYtoNPC(double x, int from, double min, double max)
-{
-    double result = x;
-    switch (from) {
-    case L_NPC:
-        break;
-    case L_NATIVE:
-        result = (x - min)/(max - min);
-        break;
-    default:
-        error(_("Unsupported unit conversion"));
-    }
-    return(result);
-}
-
-double transformWHtoNPC(double x, int from, double min, double max)
-{
-    double result = x;
-    switch (from) {
-    case L_NPC:
-        break;
-    case L_NATIVE:
-        result = x/(max - min);
-        break;
-    default:
-        error(_("Unsupported unit conversion"));
-    }
-    return(result);
-}
-
-double transformXYfromNPC(double x, int to, double min, double max)
-{
-    double result = x;
-    switch (to) {
-    case L_NPC:
-        break;
-    case L_NATIVE:
-        result = min + x*(max - min);
-        break;
-    default:
-        error(_("Unsupported unit conversion"));
-    }
-    return(result);
-}
-
-double transformWHfromNPC(double x, int to, double min, double max)
-{
-    double result = x;
-    switch (to) {
-    case L_NPC:
-        break;
-    case L_NATIVE:
-        result = x*(max - min);
-        break;
-    default:
-        error(_("Unsupported unit conversion"));
-    }
-    return(result);
-}
-
-/* Attempt to make validating units faster
- */
-typedef struct {
-    char *name;
-    int code;
-} UnitTab;
-
-/* NOTE this table must match the order in grid.h
- */
-static UnitTab UnitTable[] = {
-    { "npc",            0 },
-    { "cm",             1 },
-    { "inches",         2 },
-    { "lines",          3 },
-    { "native",         4 },
-    { "null",           5 },
-    { "snpc",           6 },
-    { "mm",             7 },
-    { "points",         8 },
-    { "picas",          9 },
-    { "bigpts",        10 },
-    { "dida",          11 },
-    { "cicero",        12 },
-    { "scaledpts",     13 },
-    { "strwidth",      14 },
-    { "strheight",     15 },
-    { "strascent",     16 },
-    { "strdescent",    17 },
-
-    { "char",          18 },
-    { "grobx",         19 },
-    { "groby",         20 },
-    { "grobwidth",     21 },
-    { "grobheight",    22 },
-    { "grobascent",    23 },
-    { "grobdescent",   24 },
-
-    { "mylines",       103 },
-    { "mychar",        104 },
-    { "mystrwidth",    105 },
-    { "mystrheight",   106 },
-
-    /*
-     * Some pseudonyms 
-     */
-    { "centimetre",  1001 },
-    { "centimetres", 1001 },
-    { "centimeter",  1001 },
-    { "centimeters", 1001 },
-    { "in",          1002 },
-    { "inch",        1002 },
-    { "line",        1003 },
-    { "millimetre",  1007 },
-    { "millimetres", 1007 },
-    { "millimeter",  1007 },
-    { "millimeters", 1007 },
-    { "point",       1008 },
-    { "pt",          1008 },
-
-    { NULL,            -1 }
-};
-
-int convertUnit(SEXP unit, int index) 
-{
-    int i = 0;
-    int result = 0;
-    int found = 0;
-    while (result >= 0 && !found) {
-	if (UnitTable[i].name == NULL) 
-	    result = -1;
-	else {
-	    found = !strcmp(CHAR(STRING_ELT(unit, index)), UnitTable[i].name);
-	    if (found) {
-		result = UnitTable[i].code;
-                /* resolve pseudonyms */
-                if (result > 1000) {
-                    result = result - 1000;
-                }
-            }
-	}
-	i += 1;
-    }
-    if (result < 0)
-	error(_("Invalid unit"));
-    return result;
-}
-	    
-SEXP validUnits(SEXP units) 
-{
-    int i;
-    int n = LENGTH(units);
-    SEXP answer = R_NilValue;
-    if (n > 0) {
-	if (isString(units)) {
-	    PROTECT(answer = allocVector(INTSXP, n));
-	    for (i = 0; i<n; i++) 
-		INTEGER(answer)[i] = convertUnit(units, i);
-	    UNPROTECT(1);
-	} else {
-	    error(_("'units' must be character"));
-	}
-    } else {
-	error(_("'units' must be of length > 0"));
-    }
-    return answer;
-}
-    
-
-
diff --git a/com.oracle.truffle.r.native/library/grid/src/util.c b/com.oracle.truffle.r.native/library/grid/src/util.c
deleted file mode 100644
index 3780cb11c9824eea61f87bf416e1f2ec9f6f496a..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/util.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003-8 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include "grid.h"
-#include <string.h>
-
-/* Get the list element named str, or return NULL.
- * Copied from the Writing R Extensions manual (which copied it from nls)
- */
-SEXP getListElement(SEXP list, char *str)
-{
-  SEXP elmt = R_NilValue;
-  SEXP names = getAttrib(list, R_NamesSymbol);
-  int i;
-
-  for (i = 0; i < length(list); i++)
-    if(strcmp(CHAR(STRING_ELT(names, i)), str) == 0) {
-      elmt = VECTOR_ELT(list, i);
-      break;
-    }
-  return elmt;
-}
-
-void setListElement(SEXP list, char *str, SEXP value)
-{
-  SEXP names = getAttrib(list, R_NamesSymbol);
-  int i;
-
-  for (i = 0; i < length(list); i++)
-    if(strcmp(CHAR(STRING_ELT(names, i)), str) == 0) {
-      SET_VECTOR_ELT(list, i, value);
-      break;
-    }
-}
-
-/* The lattice R code checks values to make sure that they are numeric
- * BUT we do not know whether the values are integer or real
- * SO we have to be careful when extracting numeric values.
- * This function assumes that x is numeric (obviously).
- */
-double numeric(SEXP x, int index)
-{
-    if (isReal(x))
-	return REAL(x)[index];
-    else if (isInteger(x))
-	return INTEGER(x)[index];
-    return NA_REAL;
-}
-
-/***********************
- * Stuff for rectangles
- ***********************/
-
-/* Fill a rectangle struct
- */
-void rect(double x1, double x2, double x3, double x4,
-	  double y1, double y2, double y3, double y4,
-	  LRect *r)
-{
-    r->x1 = x1;
-    r->x2 = x2;
-    r->x3 = x3;
-    r->x4 = x4;
-    r->y1 = y1;
-    r->y2 = y2;
-    r->y3 = y3;
-    r->y4 = y4;
-}
-
-void copyRect(LRect r1, LRect *r)
-{
-    r->x1 = r1.x1;
-    r->x2 = r1.x2;
-    r->x3 = r1.x3;
-    r->x4 = r1.x4;
-    r->y1 = r1.y1;
-    r->y2 = r1.y2;
-    r->y3 = r1.y3;
-    r->y4 = r1.y4;
-}
-
-/* Do two lines intersect ?
- * Algorithm from Paul Bourke
- * (http://www.swin.edu.au/astronomy/pbourke/geometry/lineline2d/index.html)
- */
-int linesIntersect(double x1, double x2, double x3, double x4,
-		   double y1, double y2, double y3, double y4)
-{
-    double result = 0;
-    double denom = (y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1);
-    double ua = ((x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3));
-    /* If the lines are parallel ...
-     */
-    if (denom == 0) {
-	/* If the lines are coincident ...
-	 */
-	if (ua == 0) {
-	    /* If the lines are vertical ...
-	     */
-	    if (x1 == x2) {
-		/* Compare y-values
-		 */
-		if (!((y1 < y3 && fmax2(y1, y2) < fmin2(y3, y4)) ||
-		      (y3 < y1 && fmax2(y3, y4) < fmin2(y1, y2))))
-		    result = 1;
-	    } else {
-		/* Compare x-values
-		 */
-		if (!((x1 < x3 && fmax2(x1, x2) < fmin2(x3, x4)) ||
-		      (x3 < x1 && fmax2(x3, x4) < fmin2(x1, x2))))
-		    result = 1;
-	    }
-	}
-    }
-    /* ... otherwise, calculate where the lines intersect ...
-     */
-    else {
-	double ub = ((x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3));
-	ua = ua/denom;
-	ub = ub/denom;
-	/* Check for overlap
-	 */
-	if ((ua > 0 && ua < 1) && (ub > 0 && ub < 1))
-	    result = 1;
-    }
-    return (int) result;
-}
-
-int edgesIntersect(double x1, double x2, double y1, double y2,
-		   LRect r)
-{
-    int result = 0;
-    if (linesIntersect(x1, x2, r.x1, r.x2, y1, y2, r.y1, r.y2) ||
-	linesIntersect(x1, x2, r.x2, r.x3, y1, y2, r.y2, r.y3) ||
-	linesIntersect(x1, x2, r.x3, r.x4, y1, y2, r.y3, r.y4) ||
-	linesIntersect(x1, x2, r.x4, r.x1, y1, y2, r.y4, r.y1))
-	result = 1;
-    return result;
-}
-
-/* Do two rects intersect ?
- * For each edge in r1, does the edge intersect with any edge in r2 ?
- * FIXME:  Should add first check for non-intersection of
- * bounding boxes of rects (?)
- */
-int intersect(LRect r1, LRect r2)
-{
-    int result = 0;
-    if (edgesIntersect(r1.x1, r1.x2, r1.y1, r1.y2, r2) ||
-	edgesIntersect(r1.x2, r1.x3, r1.y2, r1.y3, r2) ||
-	edgesIntersect(r1.x3, r1.x4, r1.y3, r1.y4, r2) ||
-	edgesIntersect(r1.x4, r1.x1, r1.y4, r1.y1, r2))
-	result = 1;
-    return result;
-}
-
-/* Calculate the bounding rectangle for a string.
- * x and y assumed to be in INCHES.
- */
-void textRect(double x, double y, SEXP text, int i,
-	      const pGEcontext gc,
-	      double xadj, double yadj,
-	      double rot, pGEDevDesc dd, LRect *r)
-{
-    /* NOTE that we must work in inches for the angles to be correct
-     */
-    LLocation bl, br, tr, tl;
-    LLocation tbl, tbr, ttr, ttl;
-    LTransform thisLocation, thisRotation, thisJustification;
-    LTransform tempTransform, transform;
-    double w, h;
-    if (isExpression(text)) {
-	SEXP expr = VECTOR_ELT(text, i % LENGTH(text));
-	w = fromDeviceWidth(GEExpressionWidth(expr, gc, dd),
-			    GE_INCHES, dd);
-	h = fromDeviceHeight(GEExpressionHeight(expr, gc, dd),
-			     GE_INCHES, dd);
-    } else {
-	const char* string = CHAR(STRING_ELT(text, i % LENGTH(text)));
-	w = fromDeviceWidth(GEStrWidth(string,
-				       (gc->fontface == 5) ? CE_SYMBOL :
-				       getCharCE(STRING_ELT(text, i % LENGTH(text))),
-				       gc, dd),
-			    GE_INCHES, dd);
-	h = fromDeviceHeight(GEStrHeight(string,
-					 (gc->fontface == 5) ? CE_SYMBOL :
-					 getCharCE(STRING_ELT(text, i % LENGTH(text))),
-					 gc, dd),
-			     GE_INCHES, dd);
-    }
-    location(0, 0, bl);
-    location(w, 0, br);
-    location(w, h, tr);
-    location(0, h, tl);
-    translation(-xadj*w, -yadj*h, thisJustification);
-    translation(x, y, thisLocation);
-    if (rot != 0)
-	rotation(rot, thisRotation);
-    else
-	identity(thisRotation);
-    /* Position relative to origin of rotation THEN rotate.
-     */
-    multiply(thisJustification, thisRotation, tempTransform);
-    /* Translate to (x, y)
-     */
-    multiply(tempTransform, thisLocation, transform);
-    trans(bl, transform, tbl);
-    trans(br, transform, tbr);
-    trans(tr, transform, ttr);
-    trans(tl, transform, ttl);
-    rect(locationX(tbl), locationX(tbr), locationX(ttr), locationX(ttl),
-	 locationY(tbl), locationY(tbr), locationY(ttr), locationY(ttl),
-	 r);
-    /* For debugging, the following prints out an R statement to draw the
-     * bounding box
-     */
-    /*
-    Rprintf("\ngrid.lines(c(%f, %f, %f, %f, %f), c(%f, %f, %f, %f, %f), default.units=\"inches\")\n",
-	locationX(tbl), locationX(tbr), locationX(ttr), locationX(ttl),
-	 locationX(tbl),
-	 locationY(tbl), locationY(tbr), locationY(ttr), locationY(ttl),
-	 locationY(tbl)
-	 );
-    */
-}
-
-/***********************
- * Stuff for making persistent graphical objects
- ***********************/
-
-/* Will have already created an SEXP in R.  This just stores the
- * SEXP in an external reference so that I can get multiple
- * references to it.
- */
-SEXP L_CreateSEXPPtr(SEXP s)
-{
-    /* Allocate a list of length one on the R heap
-     */
-    SEXP data, result;
-    PROTECT(data = allocVector(VECSXP, 1));
-    SET_VECTOR_ELT(data, 0, s);
-    result = R_MakeExternalPtr(data, R_NilValue, data);
-    UNPROTECT(1);
-    return result;
-}
-
-SEXP L_GetSEXPPtr(SEXP sp)
-{
-    SEXP data = R_ExternalPtrAddr(sp);
-    /* Check for NULL ptr
-     * This can occur if, for example, a grid grob is saved
-     * and then loaded.  The saved grob has its ptr null'ed
-     */
-    if (data == NULL)
-	error("grid grob object is empty");
-    return VECTOR_ELT(data, 0);
-}
-
-SEXP L_SetSEXPPtr(SEXP sp, SEXP s)
-{
-    SEXP data = R_ExternalPtrAddr(sp);
-    /* Check for NULL ptr
-     * This can occur if, for example, a grid grob is saved
-     * and then loaded.  The saved grob has its ptr null'ed
-     */
-    if (data == NULL)
-	error("grid grob object is empty");
-    SET_VECTOR_ELT(data, 0, s);
-    return R_NilValue;
-}
-
diff --git a/com.oracle.truffle.r.native/library/grid/src/viewport.c b/com.oracle.truffle.r.native/library/grid/src/viewport.c
deleted file mode 100644
index 29004412aef8ccd9d4f1cabfc16e731742c30b1d..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/library/grid/src/viewport.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- *  R : A Computer Language for Statistical Data Analysis
- *  Copyright (C) 2001-3 Paul Murrell
- *                2003-5 The R Core Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, a copy is available at
- *  http://www.r-project.org/Licenses/
- */
-
-#include "grid.h"
-#include <string.h>
-
-extern int gridRegisterIndex;
-
-/* Some access methods for viewports */
-SEXP viewportX(SEXP vp) {
-    return VECTOR_ELT(vp, VP_X);
-}
-
-SEXP viewportY(SEXP vp) {
-    return VECTOR_ELT(vp, VP_Y);
-}
-
-SEXP viewportWidth(SEXP vp) {
-    return VECTOR_ELT(vp, VP_WIDTH);
-}
-
-SEXP viewportHeight(SEXP vp) {
-    return VECTOR_ELT(vp, VP_HEIGHT);
-}
-
-Rboolean viewportClip(SEXP vp) {
-    return LOGICAL(VECTOR_ELT(vp, VP_CLIP))[0];
-}
-
-double viewportXScaleMin(SEXP vp) {
-    return numeric(VECTOR_ELT(vp, VP_XSCALE), 0);
-}
-
-double viewportXScaleMax(SEXP vp) {
-    return numeric(VECTOR_ELT(vp, VP_XSCALE), 1);
-}
-
-double viewportYScaleMin(SEXP vp) {
-    return numeric(VECTOR_ELT(vp, VP_YSCALE), 0);
-}
-
-double viewportYScaleMax(SEXP vp) {
-    return numeric(VECTOR_ELT(vp, VP_YSCALE), 1);
-}
-
-double viewportAngle(SEXP vp) {
-    return numeric(VECTOR_ELT(vp, VP_ANGLE), 0);
-}
-
-SEXP viewportLayout(SEXP vp) {
-    return VECTOR_ELT(vp, VP_LAYOUT);
-}
-
-double viewportHJust(SEXP vp) {
-    return REAL(VECTOR_ELT(vp, VP_VALIDJUST))[0];
-}
-
-double viewportVJust(SEXP vp) {
-    return REAL(VECTOR_ELT(vp, VP_VALIDJUST))[1];
-}
-
-SEXP viewportLayoutPosRow(SEXP vp) {
-    return VECTOR_ELT(vp, VP_VALIDLPOSROW);
-}
-
-SEXP viewportLayoutPosCol(SEXP vp) {
-    return VECTOR_ELT(vp, VP_VALIDLPOSCOL);
-}
-
-SEXP viewportgpar(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_GPAR);
-}
-
-const char* viewportFontFamily(SEXP vp) {
-    return CHAR(STRING_ELT(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_FONTFAMILY),
-			   0));
-}
-
-int viewportFont(SEXP vp) {
-    return INTEGER(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_FONT))[0];
-}
-
-double viewportFontSize(SEXP vp) {
-    return REAL(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_FONTSIZE))[0];
-}
-
-double viewportLineHeight(SEXP vp) {
-    return REAL(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_LINEHEIGHT))[0];
-}
-
-double viewportCex(SEXP vp) {
-    return numeric(VECTOR_ELT(VECTOR_ELT(vp, PVP_GPAR), GP_CEX), 0);
-}
-
-SEXP viewportTransform(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_TRANS);
-}
-
-SEXP viewportLayoutWidths(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_WIDTHS);
-}
-
-SEXP viewportLayoutHeights(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_HEIGHTS);
-}
-
-SEXP viewportWidthCM(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_WIDTHCM);
-}
-
-SEXP viewportHeightCM(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_HEIGHTCM);
-}
-
-SEXP viewportRotation(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_ROTATION);
-}
-
-SEXP viewportClipRect(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_CLIPRECT);
-}
-
-SEXP viewportParent(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_PARENT);
-}
-
-SEXP viewportChildren(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_CHILDREN);
-}
-
-SEXP viewportDevWidthCM(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_DEVWIDTHCM);
-}
-
-SEXP viewportDevHeightCM(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_DEVHEIGHTCM);
-}
-
-SEXP viewportParentGPar(SEXP vp) {
-    return VECTOR_ELT(vp, PVP_PARENTGPAR);
-}
-
-void fillViewportLocationFromViewport(SEXP vp, LViewportLocation *vpl) 
-{
-    vpl->x = viewportX(vp);
-    vpl->y = viewportY(vp);
-    vpl->width = viewportWidth(vp);
-    vpl->height = viewportHeight(vp);
-    vpl->hjust = viewportHJust(vp);
-    vpl->vjust = viewportVJust(vp);
-}
-
-void fillViewportContextFromViewport(SEXP vp, 
-				     LViewportContext *vpc)
-{
-    vpc->xscalemin = viewportXScaleMin(vp);
-    vpc->xscalemax = viewportXScaleMax(vp);
-    vpc->yscalemin = viewportYScaleMin(vp);
-    vpc->yscalemax = viewportYScaleMax(vp);
-}
-
-void copyViewportContext(LViewportContext vpc1, LViewportContext *vpc2)
-{
-    vpc2->xscalemin = vpc1.xscalemin;
-    vpc2->xscalemax = vpc1.xscalemax;
-    vpc2->yscalemin = vpc1.yscalemin;
-    vpc2->yscalemax = vpc1.yscalemax;
-}
-
-void gcontextFromViewport(SEXP vp, const pGEcontext gc, pGEDevDesc dd) {
-    gcontextFromgpar(viewportgpar(vp), 0, gc, dd);
-}
-
-/* The idea is to produce a transformation for this viewport which
- * will take any location in INCHES and turn it into a location on the 
- * Device in INCHES.
- * The reason for working in INCHES is because we want to be able to
- * do rotations as part of the transformation.
- * If "incremental" is true, then we just work from the "current"
- * values of the parent.  Otherwise, we have to recurse and recalculate
- * everything from scratch.
- */
-void calcViewportTransform(SEXP vp, SEXP parent, Rboolean incremental,
-			   pGEDevDesc dd)
-{
-    int i, j;
-    double vpWidthCM, vpHeightCM, rotationAngle;
-    double parentWidthCM, parentHeightCM;
-    double xINCHES, yINCHES;
-    double xadj, yadj;
-    double parentAngle;
-    LViewportLocation vpl;
-    LViewportContext vpc, parentContext;
-    R_GE_gcontext gc, parentgc;
-    LTransform thisLocation, thisRotation, thisJustification, thisTransform;
-    LTransform tempTransform, parentTransform, transform;
-    SEXP currentWidthCM, currentHeightCM, currentRotation;
-    SEXP currentTransform;
-    /* This should never be true when we are doing an incremental
-     * calculation
-     */
-    if (isNull(parent)) {
-	/* We have a top-level viewport; the parent is the device
-	 */
-	getDeviceSize(dd, &parentWidthCM, &parentHeightCM);
-	/* For a device the transform is the identity transform
-	 */
-	identity(parentTransform);
-	/* For a device, xmin=0, ymin=0, xmax=1, ymax=1, and
-	 */
-	parentContext.xscalemin = 0;
-	parentContext.yscalemin = 0;
-	parentContext.xscalemax = 1;
-	parentContext.yscalemax = 1;
-	/* FIXME:  How do I figure out the device fontsize ?
-	 * From ps.options etc, ... ?
-	 * FIXME:  How do I figure out the device lineheight ??
-	 * FIXME:  How do I figure out the device cex ??
-	 * FIXME:  How do I figure out the device font ??
-	 * FIXME:  How do I figure out the device fontfamily ??
-	 */
-	parentgc.ps = 10;
-	parentgc.lineheight = 1.2;
-	parentgc.cex = 1;
-	parentgc.fontface = 1;
-	parentgc.fontfamily[0] = '\0';
-	/* The device is not rotated
-	 */
-	parentAngle = 0;
-	fillViewportLocationFromViewport(vp, &vpl);
-    } else {
-	/* Get parent transform (etc ...)
-	 * If necessary, recalculate the parent transform (etc ...)
-	 */
-	if (!incremental)
-	    calcViewportTransform(parent, viewportParent(parent), 0, dd);
-	/* Get information required to transform viewport location
-	 */
-	parentWidthCM = REAL(viewportWidthCM(parent))[0];
-	parentHeightCM = REAL(viewportHeightCM(parent))[0];
-	parentAngle = REAL(viewportRotation(parent))[0];
-	for (i=0; i<3; i++)
-	    for (j=0; j<3; j++)
-		parentTransform[i][j] = 
-		    REAL(viewportTransform(parent))[i +3*j];
-	fillViewportContextFromViewport(parent, &parentContext);
-	/* 
-	 * Don't get gcontext from parent because the most recent
-	 * previous gpar setting may have come from a gTree
-	 * So we look at this viewport's parentgpar slot instead
-	 * 
-	 * WAS gcontextFromViewport(parent, &parentgc);
-	 */
-	gcontextFromgpar(viewportParentGPar(vp), 0, &parentgc, dd);
-	/* In order for the vp to get its vpl from a layout
-	 * it must have specified a layout.pos and the parent
-	 * must have a layout
-	 * FIXME:  Actually, in addition, layout.pos.row and
-	 * layout.pos.col must be valid for the layout
-	 */
-	if ((isNull(viewportLayoutPosRow(vp)) && 
-	     isNull(viewportLayoutPosCol(vp))) ||
-	    isNull(viewportLayout(parent)))
-	    fillViewportLocationFromViewport(vp, &vpl);
-	else if (checkPosRowPosCol(vp, parent))
-	    calcViewportLocationFromLayout(viewportLayoutPosRow(vp),
-					   viewportLayoutPosCol(vp),
-					   parent,
-					   &vpl);
-    }
-    /* NOTE that we are not doing a transformLocn here because
-     * we just want locations and dimensions (in INCHES) relative to 
-     * the parent, NOT relative to the device.
-     */
-    /* First, convert the location of the viewport into CM
-     */
-    xINCHES = transformXtoINCHES(vpl.x, 0, parentContext, &parentgc,
-				 parentWidthCM, parentHeightCM, 
-				 dd);
-    yINCHES = transformYtoINCHES(vpl.y, 0, parentContext, &parentgc,
-				 parentWidthCM, parentHeightCM, 
-				 dd);
-    /* Calculate the width and height of the viewport in CM too
-     * so that any viewports within this one can do transformations
-     */
-    vpWidthCM = transformWidthtoINCHES(vpl.width, 0, parentContext, &parentgc,
-				       parentWidthCM, parentHeightCM,
-				       dd)*2.54;
-    vpHeightCM = transformHeighttoINCHES(vpl.height, 0, parentContext, 
-					 &parentgc,
-					 parentWidthCM, 
-					 parentHeightCM, 
-					 dd)*2.54;
-    /* Fall out if location or size are non-finite
-     */
-    if (!R_FINITE(xINCHES) || 
-	!R_FINITE(yINCHES) || 
-	!R_FINITE(vpWidthCM) || 
-	!R_FINITE(vpHeightCM))
-	error(_("non-finite location and/or size for viewport"));
-    /* Determine justification required
-     */
-    justification(vpWidthCM, vpHeightCM, vpl.hjust, vpl.vjust,
-		  &xadj, &yadj);
-    /* Next, produce the transformation to add the location of
-     * the viewport to the location.
-     */
-    /* Produce transform for this viewport
-     */
-    translation(xINCHES, yINCHES, thisLocation);
-    if (viewportAngle(vp) != 0)
-	rotation(viewportAngle(vp), thisRotation);
-    else
-	identity(thisRotation);
-    translation(xadj/2.54, yadj/2.54, thisJustification);
-    /* Position relative to origin of rotation THEN rotate.
-     */
-    multiply(thisJustification, thisRotation, tempTransform);
-    /* Translate to bottom-left corner.
-     */
-    multiply(tempTransform, thisLocation, thisTransform);
-    /* Combine with parent's transform
-     */
-    multiply(thisTransform, parentTransform, transform);
-    /* Sum up the rotation angles
-     */
-    rotationAngle = parentAngle + viewportAngle(vp);
-    /* Finally, allocate the rows and columns for this viewport's
-     * layout if it has one
-     */
-    if (!isNull(viewportLayout(vp))) {
-	fillViewportContextFromViewport(vp, &vpc);
-	gcontextFromViewport(vp, &gc, dd);
-	calcViewportLayout(vp, vpWidthCM, vpHeightCM, vpc, &gc, dd);
-    }
-    /* Record all of the answers in the viewport
-     * (the layout calculations are done within calcViewportLayout)
-     */
-    PROTECT(currentWidthCM = ScalarReal(vpWidthCM));
-    PROTECT(currentHeightCM = ScalarReal(vpHeightCM));
-    PROTECT(currentRotation = ScalarReal(rotationAngle));
-    PROTECT(currentTransform = allocMatrix(REALSXP, 3, 3));
-    for (i=0; i<3; i++)
-	for (j=0; j<3; j++)
-	    REAL(currentTransform)[i + 3*j] = transform[i][j];
-    SET_VECTOR_ELT(vp, PVP_WIDTHCM, currentWidthCM);
-    SET_VECTOR_ELT(vp, PVP_HEIGHTCM, currentHeightCM);
-    SET_VECTOR_ELT(vp, PVP_ROTATION, currentRotation);
-    SET_VECTOR_ELT(vp, PVP_TRANS, currentTransform);
-    UNPROTECT(4);
-}
-
-void initVP(pGEDevDesc dd)
-{
-    SEXP vpfnname, vpfn, vp;
-    SEXP xscale, yscale;
-    SEXP currentgp = gridStateElement(dd, GSS_GPAR);
-    SEXP gsd = (SEXP) dd->gesd[gridRegisterIndex]->systemSpecific;
-    PROTECT(vpfnname = findFun(install("grid.top.level.vp"), R_gridEvalEnv));
-    PROTECT(vpfn = lang1(vpfnname));
-    PROTECT(vp = eval(vpfn, R_GlobalEnv));
-    /* 
-     * Set the "native" scale of the top viewport to be the
-     * natural device coordinate system (e.g., points in 
-     * postscript, pixels in X11, ...)
-     */
-    PROTECT(xscale = allocVector(REALSXP, 2));
-    REAL(xscale)[0] = dd->dev->left;
-    REAL(xscale)[1] = dd->dev->right;
-    SET_VECTOR_ELT(vp, VP_XSCALE, xscale);
-    PROTECT(yscale = allocVector(REALSXP, 2));
-    REAL(yscale)[0] = dd->dev->bottom;
-    REAL(yscale)[1] = dd->dev->top;
-    SET_VECTOR_ELT(vp, VP_YSCALE, yscale);
-    SET_VECTOR_ELT(vp, PVP_GPAR, currentgp);
-    vp = doSetViewport(vp, TRUE, TRUE, dd);
-    SET_VECTOR_ELT(gsd, GSS_VP, vp);
-    UNPROTECT(5);
-}
-
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
index 2821716614aecf0854f0b63cd0fee013341867f0..60e4558d819e7d54cd818d58f21d2f0d22d30f1e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.r.library.graphics.GraphicsCCalls;
 import com.oracle.truffle.r.library.graphics.GraphicsCCalls.C_Par;
 import com.oracle.truffle.r.library.graphics.GraphicsCCalls.C_PlotXY;
 import com.oracle.truffle.r.library.grid.GridFunctionsFactory.InitGridNodeGen;
+import com.oracle.truffle.r.library.grid.GridFunctionsFactory.ValidUnitsNodeGen;
 import com.oracle.truffle.r.library.methods.MethodsListDispatchFactory.R_M_setPrimitiveMethodsNodeGen;
 import com.oracle.truffle.r.library.methods.MethodsListDispatchFactory.R_externalPtrPrototypeObjectNodeGen;
 import com.oracle.truffle.r.library.methods.MethodsListDispatchFactory.R_getClassFromCacheNodeGen;
@@ -511,6 +512,8 @@ public class ForeignFunctions {
                 // grid
                 case "L_initGrid":
                     return InitGridNodeGen.create();
+                case "L_validUnits":
+                    return ValidUnitsNodeGen.create();
 
                 // parallel
                 case "mc_is_child":
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RVersionNumber.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RVersionNumber.java
index 7f3cc835154e1a2accd58dfa0cc79cf677fc79c0..4dcd65278766088267f90a7368a449b0761ec549 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RVersionNumber.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RVersionNumber.java
@@ -33,9 +33,9 @@ package com.oracle.truffle.r.runtime;
 public class RVersionNumber {
     public static final String MAJOR = "3";
     public static final String MINOR = "3";
-    public static final String PATCH = "1";
+    public static final String PATCH = "2";
 
-    public static final int R_VERSION = (3 << 16) + (3 << 8) + 1;
+    public static final int R_VERSION = (3 << 16) + (3 << 8) + 2;
 
     public static final String MAJOR_MINOR = MAJOR + "." + MINOR;
     public static final String MINOR_PATCH = MINOR + "." + PATCH;
@@ -43,8 +43,8 @@ public class RVersionNumber {
     public static final String R_HYPHEN_FULL = "R-" + FULL;
 
     public static final String RELEASE_YEAR = "2016";
-    public static final String RELEASE_MONTH = "06";
-    public static final String RELEASE_DAY = "21";
+    public static final String RELEASE_MONTH = "10";
+    public static final String RELEASE_DAY = "11";
 
     public static final String VERSION_STRING = "FastR version " + FULL + " (" + RELEASE_YEAR + "-" + RELEASE_MONTH + "-" + RELEASE_DAY + ")";
 
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 872652954e2863f1c016e2ffffbaf8ebebd4cfa8..2ea3673fc769138890b6339c11d97967f096c9e9 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -158,7 +158,7 @@ Class: numeric
 #{ gen<-function(object) 0; setGeneric("gen"); res<-print(gen); removeGeneric("gen"); res }
 function (object)
 standardGeneric("gen")
-<environment: 0x7fd033a4a478>
+<environment: 0x7fe323e45660>
 attr(,"generic")
 [1] "gen"
 attr(,"generic")attr(,"package")
@@ -192,7 +192,7 @@ standardGeneric for "gen" defined from package ".GlobalEnv"
 
 function (object)
 standardGeneric("gen")
-<environment: 0x7fd033a4a478>
+<environment: 0x7fe323e45660>
 Methods may be defined for arguments: object
 Use  showMethods("gen")  for currently available ones.
 
@@ -219,7 +219,7 @@ Creating a generic function for ‘diag<-’ from package ‘base’ in the glob
 ##com.oracle.truffle.r.test.S4.TestS4.testMethods#Ignored.OutputFormatting#
 #{ setGeneric("gen", function(object) standardGeneric("gen")); res<-print(gen); removeGeneric("gen"); res }
 function(object) standardGeneric("gen")
-<environment: 0x7f89ecc1b028>
+<environment: 0x7fba68bbb3c0>
 attr(,"generic")
 [1] "gen"
 attr(,"generic")attr(,"package")
@@ -246,7 +246,7 @@ standardGeneric for "gen" defined from package ".GlobalEnv"
 
 function (object)
 standardGeneric("gen")
-<environment: 0x7f89ecc1b028>
+<environment: 0x7fba68bbb3c0>
 Methods may be defined for arguments: object
 Use  showMethods("gen")  for currently available ones.
 
@@ -1200,7 +1200,7 @@ Error in .Primitive(c("c", "b")) : string argument required
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_Primitive.testPrimitive1#Ignored.ImplementationError#
 #argv <- list('c');.Primitive(argv[[1]]);
-function (..., recursive = FALSE)  .Primitive("c")
+function (...)  .Primitive("c")
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_RNGkind.testArgsCast#Output.IgnoreErrorMessage#
 #.Internal(RNGkind('abc', NULL))
@@ -9433,7 +9433,7 @@ numeric(0)
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_bitwiseAnd.testBitwiseFunctions#Output.IgnoreErrorContext#Output.IgnoreErrorMessage#
 #{ bitwAnd(NULL, NULL) }
-Error in bitwAnd(NULL, NULL) : negative length vectors are not allowed
+Error in bitwAnd(NULL, NULL) : unimplemented type 'NULL' in 'bitwAnd'
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_bitwiseAnd.testBitwiseFunctions#Output.IgnoreErrorContext#Output.IgnoreErrorMessage#
 #{ bitwAnd(c(), c(1,2,3)) }
@@ -10225,7 +10225,7 @@ x y
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine#Output.ContainsReferences#
 #{ e1 <- new.env(); c(e1, 3) }
 [[1]]
-<environment: 0x7f926afe0180>
+<environment: 0x7fd3828cdf80>
 
 [[2]]
 [1] 3
@@ -10234,10 +10234,10 @@ x y
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine#Output.ContainsReferences#
 #{ e1 <- new.env(); e2 <- new.env(); c(e1, e2) }
 [[1]]
-<environment: 0x7fbbab815ae0>
+<environment: 0x7f90e9ba4ae0>
 
 [[2]]
-<environment: 0x7fbbab816698>
+<environment: 0x7f90e9ba6698>
 
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine#
@@ -15497,7 +15497,7 @@ character(0)
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_date.testDate#Ignored.Unknown#
 #{date()}
-[1] "Mon Oct 31 22:14:56 2016"
+[1] "Wed Nov  9 20:10:56 2016"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_delayedAssign.testDelayedAssign#
 #{ delayedAssign("x", a+b); a <- 1 ; b <- 3 ; x }
@@ -20781,7 +20781,7 @@ description       class        mode        text      opened    can read
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_getNamespaceVersion.testgetNamespaceVersion1#
 #argv <- structure(list(ns = 'stats'), .Names = 'ns');do.call('getNamespaceVersion', argv)
 version
-"3.3.1"
+"3.3.2"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_getRestart.testgetRestart1#
 #argv <- list(2L); .Internal(.getRestart(argv[[1]]))
@@ -28537,9 +28537,10 @@ character(0)
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_listfiles.testlistfiles3#Ignored.Unknown#
 #argv <- list('.', '^CITATION.*', FALSE, FALSE, TRUE, FALSE, FALSE, FALSE); .Internal(list.files(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]]))
-[1] "com.oracle.truffle.r.native/gnur/R-3.3.1/library/base/CITATION"
-[2] "com.oracle.truffle.r.native/gnur/R-3.3.1/src/library/base/inst/CITATION"
+[1] "com.oracle.truffle.r.native/gnur/R-3.3.2/library/base/CITATION"
+[2] "com.oracle.truffle.r.native/gnur/R-3.3.2/src/library/base/inst/CITATION"
 [3] "library/base/CITATION"
+[4] "rlibs/lattice/CITATION"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_listfiles.testlistfiles4#
 #argv <- list('mgcv', NULL, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE); .Internal(list.files(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]]))
@@ -32610,20 +32611,20 @@ Error in argv[[4]] : subscript out of bounds
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_newenv.testnewenv#Output.ContainsReferences#
 #e <- new.env(); e; parent.env(new.env(TRUE, e))
-<environment: 0x7fb18c6c5e30>
-<environment: 0x7fb18c6c5e30>
+<environment: 0x7fb9e3fb6a08>
+<environment: 0x7fb9e3fb6a08>
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_newenv.testnewenv#Output.ContainsReferences#
 #new.env()
-<environment: 0x7ff8dc57e710>
+<environment: 0x7f8d3b3a26e8>
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_newenv.testnewenv#Output.ContainsReferences#
 #new.env(1,,2)
-<environment: 0x7fe42e9ef318>
+<environment: 0x7fd0f3598898>
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_newenv.testnewenv#Output.ContainsReferences#
 #new.env(logical(),new.env(),1000)
-<environment: 0x7ff3714fcd58>
+<environment: 0x7fa403368158>
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_newenv.testnewenv#Output.ContainsReferences#
 #parent.env(new.env())
@@ -37990,7 +37991,7 @@ Error in parent.env(c(1, 2, 3)) : argument is not an environment
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_parentenvassign.testParentEnv#Output.ContainsReferences#
 #e <- new.env(); e2 <- new.env(); parent.env(e) <- e2; parent.env(e)
-<environment: 0x7fc92a598f48>
+<environment: 0x7f834630df48>
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_parentenvassign.testParentEnv#Output.IgnoreErrorContext#
 #e <- new.env(); parent.env(e) <- 44
@@ -39553,7 +39554,7 @@ function (e1, e2)  .Primitive("+")
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_printfunction.testprintfunction3#Ignored.Unknown#
 #argv <- list(.Primitive('c'), TRUE); .Internal(print.function(argv[[1]], argv[[2]]))
-function (..., recursive = FALSE)  .Primitive("c")
+function (...)  .Primitive("c")
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_printfunction.testprintfunction4#
 #argv <- list(.Primitive('.Internal'), TRUE); .Internal(print.function(argv[[1]], argv[[2]]))
@@ -44434,59 +44435,59 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote("bar"), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 10 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 10 00 00 00 01 00 04 00
 [26] 09 00 00 00 03 62 61 72
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote('asdf'), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 10 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 10 00 00 00 01 00 04 00
 [26] 09 00 00 00 04 61 73 64 66
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote('baz'), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 10 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 10 00 00 00 01 00 04 00
 [26] 09 00 00 00 03 62 61 7a
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#Ignored.ImplementationError#
 #options(keep.source=FALSE); serialize(quote((a %asdf% b)), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 01 28 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00
 [51] 06 25 61 73 64 66 25 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00
 [76] 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 62 00 00 00 fe 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#Ignored.ImplementationError#
 #options(keep.source=FALSE); serialize(quote((a+b)), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 01 28 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00
 [51] 01 2b 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00 00 00 02 00 00
 [76] 00 01 00 04 00 09 00 00 00 01 62 00 00 00 fe 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(111+11), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 01 2b 00 00 00 02 00 00 00 0e 00 00 00 01 40 5b c0 00 00 00 00
 [51] 00 00 00 00 02 00 00 00 0e 00 00 00 01 40 26 00 00 00 00 00 00 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(111+8i), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 01 2b 00 00 00 02 00 00 00 0e 00 00 00 01 40 5b c0 00 00 00 00
 [51] 00 00 00 00 02 00 00 00 0f 00 00 00 01 00 00 00 00 00 00 00 00 40 20 00 00
 [76] 00 00 00 00 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(111L), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 0d 00 00 00 01 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 0d 00 00 00 01 00 00 00
 [26] 6f
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(FALSE), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 0a 00 00 00 01 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 0a 00 00 00 01 00 00 00
 [26] 00
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(NA_character_ + NA_complex_ + NA_integer_ + NA_real_), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 01 2b 00 00 00 02 00 00 00 06 00 00 01 ff 00 00 00 02 00 00 00
  [51] 06 00 00 01 ff 00 00 00 02 00 00 00 10 00 00 00 01 00 00 00 09 ff ff ff ff
  [76] 00 00 00 02 00 00 00 0f 00 00 00 01 7f f0 00 00 00 00 07 a2 7f f0 00 00 00
@@ -44496,32 +44497,32 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(NA_character_), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 10 00 00 00 01 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 10 00 00 00 01 00 00 00
 [26] 09 ff ff ff ff
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(NA_complex_), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 0f 00 00 00 01 7f f0 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 0f 00 00 00 01 7f f0 00
 [26] 00 00 00 07 a2 7f f0 00 00 00 00 07 a2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(NA_integer_), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 0d 00 00 00 01 80 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 0d 00 00 00 01 80 00 00
 [26] 00
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(NA_real_), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 0e 00 00 00 01 7f f0 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 0e 00 00 00 01 7f f0 00
 [26] 00 00 00 07 a2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(TRUE), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 0a 00 00 00 01 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 0a 00 00 00 01 00 00 00
 [26] 01
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(a(b(c(d(function (e, ...) { f(g)$h.i}))))), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 01 61 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00
  [51] 01 62 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01 63 00 00
  [76] 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01 64 00 00 00 02 00 00
@@ -44537,27 +44538,27 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(a+b), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 01 2b 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00 00
 [51] 00 02 00 00 00 01 00 04 00 09 00 00 00 01 62 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(f(g)$h.i), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 01 24 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00
 [51] 01 66 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 67 00 00 00 fe 00 00
 [76] 00 02 00 00 00 01 00 04 00 09 00 00 00 03 68 2e 69 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(foo(a,b,c)), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 03 66 6f 6f 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61
 [51] 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 62 00 00 00 02 00 00 00 01
 [76] 00 04 00 09 00 00 00 01 63 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function() new("foo", x)), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 00 fe 00 00 00 02
  [51] 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 03 6e 65 77 00 00 00 02 00 00
  [76] 00 10 00 00 00 01 00 04 00 09 00 00 00 03 66 6f 6f 00 00 00 02 00 00 00 01
@@ -44565,7 +44566,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#Ignored.ImplementationError#
 #options(keep.source=FALSE); serialize(quote(function(x) { `+`(`(`("BAR"), x) }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 fb 00 00 00 fe 00 00 00 02 00 00 00 06
  [76] 00 00 00 01 00 04 00 09 00 00 00 01 7b 00 00 00 02 00 00 00 06 00 00 00 01
@@ -44576,7 +44577,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x) { new("BAR", x) }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 fb 00 00 00 fe 00 00 00 02 00 00 00 06
  [76] 00 00 00 01 00 04 00 09 00 00 00 01 7b 00 00 00 02 00 00 00 06 00 00 00 01
@@ -44586,7 +44587,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x, ...) { new("BAR", x) }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 fb 00 00 04 02 00 00 00 01 00 04 00 09
  [76] 00 00 00 03 2e 2e 2e 00 00 00 fb 00 00 00 fe 00 00 00 02 00 00 00 06 00 00
@@ -44597,7 +44598,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x,y) { TRUE }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 fb 00 00 04 02 00 00 00 01 00 04 00 09
  [76] 00 00 00 01 79 00 00 00 fb 00 00 00 fe 00 00 00 02 00 00 00 06 00 00 00 01
@@ -44606,7 +44607,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x,y) { new("BAR", x) }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 fb 00 00 04 02 00 00 00 01 00 04 00 09
  [76] 00 00 00 01 79 00 00 00 fb 00 00 00 fe 00 00 00 02 00 00 00 06 00 00 00 01
@@ -44617,7 +44618,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x,y,...) { 1 }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 fb 00 00 04 02 00 00 00 01 00 04 00 09
  [76] 00 00 00 01 79 00 00 00 fb 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 03
@@ -44627,7 +44628,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x,y=1,...) { NA }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 fb 00 00 04 02 00 00 00 01 00 04 00 09
  [76] 00 00 00 01 79 00 00 00 0e 00 00 00 01 3f f0 00 00 00 00 00 00 00 00 04 02
@@ -44638,7 +44639,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x={1 + a},y,...) { !!NA }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01
  [76] 7b 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01 2b 00 00 00
@@ -44652,7 +44653,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x={1 + a},y,...) { !1+5i }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01
  [76] 7b 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01 2b 00 00 00
@@ -44668,7 +44669,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x={1 + a},y,...) { NA }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01
  [76] 7b 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01 2b 00 00 00
@@ -44681,7 +44682,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(function(x={1 + a},y=c(1,2,3),z="foo",...) { !1+5i }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 08 66 75 6e 63 74 69 6f 6e 00 00 00 02 00 00 04 02 00 00 00 01
  [51] 00 04 00 09 00 00 00 01 78 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01
  [76] 7b 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01 2b 00 00 00
@@ -44701,7 +44702,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(if (a * 2 < 199) b + foo(x,y,foo=z+1,bar=)), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 02 69 66 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00
  [51] 00 01 3c 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01 2a 00
  [76] 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00 00 00 02 00 00 00 0e 00
@@ -44718,14 +44719,14 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(if (a) b else c), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 02 69 66 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00
 [51] 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 62 00 00 00 02 00 00 00 01 00
 [76] 04 00 09 00 00 00 01 63 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(if (a) {b} else {c}), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 02 69 66 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00
  [51] 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 01 7b 00 00 00 02 00
  [76] 00 00 01 00 04 00 09 00 00 00 01 62 00 00 00 fe 00 00 00 02 00 00 00 06 00
@@ -44734,7 +44735,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(if ({a}) {b} else {c}), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 02 69 66 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00
  [51] 00 01 7b 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00 00 00 fe 00
  [76] 00 00 02 00 00 00 06 00 00 02 ff 00 00 00 02 00 00 00 01 00 04 00 09 00 00
@@ -44743,7 +44744,7 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(repeat {b; if (c) next else break}), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 06 72 65 70 65 61 74 00 00 00 02 00 00 00 06 00 00 00 01 00 04
  [51] 00 09 00 00 00 01 7b 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 62 00
  [76] 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00 02 69 66 00 00 00 02
@@ -44754,18 +44755,18 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(while (a) b), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
 [26] 09 00 00 00 05 77 68 69 6c 65 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00
 [51] 01 61 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 62 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote(x), connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 01 00 04 00 09 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 01 00 04 00 09 00 00 00
 [26] 01 78
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); serialize(quote({ foo(a,b,c) }), connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 06 00 00 00 01 00 04 00
  [26] 09 00 00 00 01 7b 00 00 00 02 00 00 00 06 00 00 00 01 00 04 00 09 00 00 00
  [51] 03 66 6f 6f 00 00 00 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00 00 00 02
  [76] 00 00 00 01 00 04 00 09 00 00 00 01 62 00 00 00 02 00 00 00 01 00 04 00 09
@@ -44773,60 +44774,60 @@ Error in seq.int(argv[[1]], argv[[2]], argv[[3]]) :
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- defaultPrototype(); serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 01 00 19
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 01 00 19
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- list(enclos = new.env(hash=FALSE)); serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 02 13 00 00 00 01 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 02 13 00 00 00 01 00 00 00
 [26] 04 00 00 00 00 00 00 00 fd 00 00 00 fe 00 00 00 fe 00 00 00 fe 00 00 04 02
 [51] 00 00 00 01 00 04 00 09 00 00 00 05 6e 61 6d 65 73 00 00 00 10 00 00 00 01
 [76] 00 04 00 09 00 00 00 06 65 6e 63 6c 6f 73 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- new.env(hash=FALSE); serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
 [26] fd 00 00 00 fe 00 00 00 fe 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- new.env(hash=FALSE); val$a <- 'foo'; serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
 [26] fd 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 01 61 00 00 00 10 00 00 00
 [51] 01 00 04 00 09 00 00 00 03 66 6f 6f 00 00 00 fe 00 00 00 fe 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- new.env(hash=FALSE); val$b <- 123; serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
 [26] fd 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 01 62 00 00 00 0e 00 00 00
 [51] 01 40 5e c0 00 00 00 00 00 00 00 00 fe 00 00 00 fe 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- new.env(hash=FALSE); val$c <- 1233L; serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
 [26] fd 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 01 63 00 00 00 0d 00 00 00
 [51] 01 00 00 04 d1 00 00 00 fe 00 00 00 fe 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- new.env(hash=FALSE); val$d <- TRUE; serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
 [26] fd 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 01 64 00 00 00 0a 00 00 00
 [51] 01 00 00 00 01 00 00 00 fe 00 00 00 fe 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- new.env(hash=FALSE); val$e <- 5+9i; serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
 [26] fd 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 01 65 00 00 00 0f 00 00 00
 [51] 01 40 14 00 00 00 00 00 00 40 22 00 00 00 00 00 00 00 00 00 fe 00 00 00 fe
 [76] 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #options(keep.source=FALSE); val <- new.env(hash=FALSE); val$f <- NA; serialize(val, connection=NULL)
- [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
+ [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 00 00 04 00 00 00 00 00 00 00
 [26] fd 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 01 66 00 00 00 0a 00 00 00
 [51] 01 80 00 00 00 00 00 00 fe 00 00 00 fe 00 00 00 fe
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_serialize.testserialize#
 #setClass('foo', slots = c(x='numeric', y='numeric')); t1 <- new('foo', x=4, y=c(77,88)); options(keep.source=FALSE); serialize(t1, connection=NULL)
-  [1] 58 0a 00 00 00 02 00 03 03 01 00 02 03 00 00 01 03 19 00 00 04 02 00 00 00
+  [1] 58 0a 00 00 00 02 00 03 03 02 00 02 03 00 00 01 03 19 00 00 04 02 00 00 00
  [26] 01 00 04 00 09 00 00 00 01 78 00 00 00 0e 00 00 00 01 40 10 00 00 00 00 00
  [51] 00 00 00 04 02 00 00 00 01 00 04 00 09 00 00 00 01 79 00 00 00 0e 00 00 00
  [76] 02 40 53 40 00 00 00 00 00 40 56 00 00 00 00 00 00 00 00 04 02 00 00 00 01
@@ -51173,25 +51174,25 @@ Error in tracemem(NULL) : cannot trace NULL
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.list#Output.ContainsReferences#
 #v <- list(1,10,100); tracemem(v); x <- v; x[[1]]<-42;
-[1] "<0x7ffa23d66a40>"
-tracemem[0x7ffa23d66a40 -> 0x7ffa23d668d8]:
+[1] "<0x7f878bbeec90>"
+tracemem[0x7f878bbeec90 -> 0x7f878bbeeb28]:
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.retracemem#Output.ContainsReferences#
 #v <- c(1,10,100); tracemem(v); x <- v[-1]; retracemem(x, retracemem(v)); u <- x; u[[1]] <- 42;
-[1] "<0x7f877ed86040>"
-tracemem[<0x7f877ed86040> -> 0x7f877c8d7150]:
-tracemem[0x7f877c8d7150 -> 0x7f877c8d7188]:
+[1] "<0x7faf1a058090>"
+tracemem[<0x7faf1a058090> -> 0x7faf191a98a8]:
+tracemem[0x7faf191a98a8 -> 0x7faf191a98e0]:
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.vectors#Output.ContainsReferences#
 #v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; untracemem(v); y[[2]] <- 84
-[1] "<0x7f893adfda40>"
-tracemem[0x7f893adfda40 -> 0x7f893adfd890]:
+[1] "<0x7ff2cd448c90>"
+tracemem[0x7ff2cd448c90 -> 0x7ff2cd448ae0]:
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.vectors#Output.ContainsReferences#
 #v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; y[[2]] <- 84
-[1] "<0x7f89f6d86c40>"
-tracemem[0x7f89f6d86c40 -> 0x7f89f6d86a90]:
-tracemem[0x7f89f6d86c40 -> 0x7f89f6d86a00]:
+[1] "<0x7f818486bc90>"
+tracemem[0x7f818486bc90 -> 0x7f818486bae0]:
+tracemem[0x7f818486bc90 -> 0x7f818486ba50]:
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_trigamma.testtrigamma1#Ignored.Unknown#
 #argv <- list(structure(c(9.16602362697115, 1.16602362697115, 3.16602362697115, 6.16602362697115, 6.16602362697115, 2.16602362697115, 8.16602362697115, 1.16602362697115, 7.16602362697115, 19.1660236269712, 2.16602362697115), .Names = c('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11')));trigamma(argv[[1]]);
@@ -57260,7 +57261,7 @@ Error: attempt to apply non-function
 function (x, where = -1, envir = if (missing(frame)) as.environment(where) else sys.frame(frame),
     frame, mode = "any", inherits = TRUE)
 .Internal(exists(x, envir, mode, inherits))
-<bytecode: 0x7fe8c9979ae0>
+<bytecode: 0x7fcbd1979320>
 <environment: namespace:base>
 
 ##com.oracle.truffle.r.test.functions.TestFunctions.testFunctionPrinting#
@@ -99034,8 +99035,8 @@ Error in `[[<-`(`*tmp*`, 1 + (0+1i), 1, value = 7) :
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testComplexIndex#Ignored.Unstable#Output.IgnoreErrorContext#
 #{ x<-c(1,2,3,4); dim(x)<-c(2,2); x[[1+1i, 1]]<-NULL }
-Error in `[[<-`(`*tmp*`, 1 + (0+1i), 1, value = NULL) :
-  invalid subscript type 'complex'
+Error in x[[1 + (0+1i), 1]] <- NULL :
+  more elements supplied than there are to replace
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testComplexIndex#Output.IgnoreErrorMessage#
 #{ x<-c(1,2,3,4); dim(x)<-c(2,2); x[[1+1i, 1]]<-c(7,42) }
@@ -100331,7 +100332,7 @@ Error in z[[list()]] <- 42 :
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testListIndex#Ignored.Unknown#Output.IgnoreErrorContext#
 #{ z<-1:4; z[[list()]]<-NULL }
 Error in z[[list()]] <- NULL :
-  more elements supplied than there are to replace
+  attempt to select less than one element in OneIndex
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testListIndex#Output.IgnoreErrorMessage#
 #{ z<-1:4; z[[list()]]<-integer() }
@@ -101944,7 +101945,7 @@ Error in b[[0]] <- NULL :
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ b<-3:5; dim(b) <- c(1,3) ; b[[c(1)]] <- NULL ; b }
 Error in b[[c(1)]] <- NULL :
-  more elements supplied than there are to replace
+  incompatible types (from NULL to integer) in [[ assignment
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorContext#
 #{ b<-3:5; dim(b) <- c(1,3) ; b[[c(1,2)]] <- NULL ; b }
@@ -102466,17 +102467,17 @@ NULL
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ x <- c(1) ; x[[NA]] <- NULL ; x }
 Error in x[[NA]] <- NULL :
-  attempt to select less than one element in integerOneIndex
+  more elements supplied than there are to replace
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ x <- c(1); x[[-4]] <- NULL }
 Error in x[[-4]] <- NULL :
-  more elements supplied than there are to replace
+  attempt to select less than one element in integerOneIndex
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ x <- c(1,2) ; x[[NA]] <- NULL ; x }
 Error in x[[NA]] <- NULL :
-  more elements supplied than there are to replace
+  attempt to select more than one element in integerOneIndex
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ x <- c(1,2,3) ; x[[NA]] <- NULL ; x }
@@ -103050,7 +103051,7 @@ Error in x[[0]] <- NULL :
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ x<-1:4; x[[1]]<-NULL; x }
 Error in x[[1]] <- NULL :
-  incompatible types (from NULL to integer) in [[ assignment
+  more elements supplied than there are to replace
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#
 #{ x<-1:4; x[[1]]<-c(1,1); x }
@@ -103349,7 +103350,7 @@ Error in x[[-4]] <- 7 :
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ x<-c(1,2,3); x[[-4]]<-NULL }
 Error in x[[-4]] <- NULL :
-  attempt to select more than one element in integerOneIndex
+  more elements supplied than there are to replace
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#
 #{ x<-c(1,2,3,4); dim(x)<-c(2,2); x[1,1]<-NULL; x }
@@ -103368,7 +103369,7 @@ Error in x[[1, 1]] <- NULL :
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ x<-c(1,2,3,4); dim(x)<-c(2,2); x[[1]]<-NULL; x }
 Error in x[[1]] <- NULL :
-  incompatible types (from NULL to double) in [[ assignment
+  more elements supplied than there are to replace
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testMoreVectorsOther#Output.IgnoreErrorMessage#
 #{ x<-c(1,2,3,4); dim(x)<-c(2,2); x[[as.raw(1), 1]]<-NULL }
@@ -107301,8 +107302,7 @@ Error in b[2] <- v :
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testScalarUpdate#Ignored.Unstable#
 #{ f <- function(b,v) { b[[2]] <- v ; b } ; f(c("a","b"),"d") ; f(c("a","b"),NULL) }
-Error in b[[2]] <- v :
-  incompatible types (from NULL to character) in [[ assignment
+Error in b[[2]] <- v : more elements supplied than there are to replace
 
 ##com.oracle.truffle.r.test.library.base.TestSimpleVectors.testScalarUpdate#
 #{ f <- function(b,v) { b[[2]] <- v ; b } ; f(list(TRUE,NA),FALSE) ; f(3,3) }
diff --git a/mx.fastr/copyrights/gnu_r_murrel_core.copyright.star.regex b/mx.fastr/copyrights/gnu_r_murrel_core.copyright.star.regex
new file mode 100644
index 0000000000000000000000000000000000000000..6498dd0ea467db1e78e810f79f49ad8fff826efb
--- /dev/null
+++ b/mx.fastr/copyrights/gnu_r_murrel_core.copyright.star.regex
@@ -0,0 +1 @@
+/\*\n \* This material is distributed under the GNU General Public License\n \* Version 2. You may review the terms of this license at\n \* http://www.gnu.org/licenses/gpl-2.0.html\n \*\n \* Copyright \(C\) 2001-3 Paul Murrell\n \* Copyright \(c\) (?:[1-2][09][0-9][0-9]-)?[1-2][09][0-9][0-9], The R Core Team\n \* Copyright \(c\) (?:(20[0-9][0-9]), )?(20[0-9][0-9]), Oracle and/or its affiliates\n \*\n \* All rights reserved.\n \*/\n.*
diff --git a/mx.fastr/copyrights/gnu_r_murrell_core.copyright.star b/mx.fastr/copyrights/gnu_r_murrell_core.copyright.star
new file mode 100644
index 0000000000000000000000000000000000000000..00d32c02206649adf788534cfcaf573f2f506660
--- /dev/null
+++ b/mx.fastr/copyrights/gnu_r_murrell_core.copyright.star
@@ -0,0 +1,11 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 2001-3 Paul Murrell
+ * Copyright (c) 1998-2013, The R Core Team
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 126f5fb24e595d2360f8667fbbe4bc06dd809ac8..204b1889bef3b1be2f1fd565c36f48e20bcef9f5 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -25,6 +25,7 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesC
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/fastrgd/FastRGraphicsDevice.java,gnu_r_graphics.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/NullGraphicsDevice.java,gnu_r_graphics.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/pdf/PdfGraphicsDevice.java,gnu_r_graphics.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java,gnu_r_murrel_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Arithmetic.java,gnu_r_gentleman_ihaka.copyright
@@ -82,17 +83,6 @@ com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c,gnu_r.copyright
 com.oracle.truffle.r.native/include/src/libintl.h,no.copyright
 com.oracle.truffle.r.native/library/base/src/registration.c,no.copyright
 com.oracle.truffle.r.native/library/grDevices/src/gzio.c,gnu_r_gentleman_ihaka.copyright
-com.oracle.truffle.r.native/library/grid/src/gpar.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/grid.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/grid.h,no.copyright
-com.oracle.truffle.r.native/library/grid/src/just.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/layout.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/matrix.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/register.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/state.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/unit.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/util.c,no.copyright
-com.oracle.truffle.r.native/library/grid/src/viewport.c,no.copyright
 com.oracle.truffle.r.native/library/methods/src/methods_dummy.c,no.copyright
 com.oracle.truffle.r.native/library/parallel/src/glpi.h,no.copyright
 com.oracle.truffle.r.native/library/parallel/src/rngstream.c,no.copyright
diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py
index eb145f15c27e02aedfa50ffe523d45476ad36c99..d0711cbe700ca57526a8c095ebd5ab1c0c3c6fc9 100644
--- a/mx.fastr/mx_fastr.py
+++ b/mx.fastr/mx_fastr.py
@@ -60,7 +60,7 @@ def r_path():
 
 def r_version():
     # Could figure this out dynamically
-    return 'R-3.3.1'
+    return 'R-3.3.2'
 
 def get_default_jdk():
     if _mx_graal:
diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py
index 63ef682bce091569d03d3224022cd192b0b5428a..ca56e3bcf90a8d49e67b6bcafeac06575c2e1972 100644
--- a/mx.fastr/suite.py
+++ b/mx.fastr/suite.py
@@ -60,9 +60,9 @@ suite = {
   # explicitly referenced in the Parser annotation processor.
   "libraries" : {
     "GNUR" : {
-        "path" : "libdownloads/R-3.3.1.tar.gz",
-        "urls" : ["http://cran.rstudio.com/src/base/R-3/R-3.3.1.tar.gz"],
-        "sha1" : "df853188d3e2b1c2d32393016401c432a5192c4d",
+        "path" : "libdownloads/R-3.3.2.tar.gz",
+        "urls" : ["http://cran.rstudio.com/src/base/R-3/R-3.3.2.tar.gz"],
+        "sha1" : "0e39e9c2d28fe6bab9c55ca23e08ba8727fd2fca",
         "resource" : "true"
     },