rts-plotutils.c

     
   1  //! @file rts-plotutils.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
   8  
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it 
  12  //! under the terms of the GNU General Public License as published by the 
  13  //! Free Software Foundation; either version 3 of the License, or 
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but 
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  //! more details. You should have received a copy of the GNU General Public 
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis
  23  //!
  24  //! Gnuplot's libplot interface. 
  25  
  26  // This file contains the Algol68G interface to libplot. Note that Algol68G is not
  27  // a binding for libplot. When GNU plotutils are not installed then the routines in
  28  // this file will give a runtime error when called. You can also choose to not
  29  // define them in "prelude.c". 
  30  
  31  #include "a68g.h"
  32  #include "a68g-genie.h"
  33  #include "a68g-numbers.h"
  34  #include "a68g-prelude.h"
  35  
  36  #if defined (HAVE_GNU_PLOTUTILS)
  37  
  38  #define COLOUR_MAX 65535
  39  #define COLOUR_NAMES 668
  40  
  41  struct COLOUR_INFO
  42  {
  43    char *name;
  44    int red, green, blue;
  45  };
  46  
  47  typedef struct COLOUR_INFO colour_info;
  48  
  49  const colour_info A68_COLOURS[];
  50  
  51  BOOL_T string_to_colour (NODE_T *, char *, int *);
  52  
  53  //! @brief Scans string for an integer.
  54  
  55  BOOL_T scan_int (char **z, int *k)
  56  {
  57    char *y = *z;
  58    while (y[0] != NULL_CHAR && !IS_DIGIT (y[0])) {
  59      y++;
  60    }
  61    if (y[0] != NULL_CHAR) {
  62      (*k) = strtol (y, z, 10);
  63      return (BOOL_T) (errno == 0);
  64    } else {
  65      return A68_FALSE;
  66    }
  67  }
  68  
  69  //! @brief PROC (REF FILE, STRING, STRING) make device
  70  
  71  void genie_make_device (NODE_T * p)
  72  {
  73  // Pop arguments.
  74    A68_REF ref_device, ref_page, ref_file;
  75    POP_REF (p, &ref_page);
  76    POP_REF (p, &ref_device);
  77    POP_REF (p, &ref_file);
  78    CHECK_REF (p, ref_file, M_REF_FILE);
  79    A68_FILE *file = FILE_DEREF (&ref_file);
  80    if (DEVICE_MADE (&DEVICE (file))) {
  81      diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_ALREADY_SET);
  82      exit_genie (p, A68_RUNTIME_ERROR);
  83    }
  84  // Fill in page_size.
  85    int size = a68_string_size (p, ref_page);
  86    if (INITIALISED (&(A68_PAGE_SIZE (&DEVICE (file)))) && !IS_NIL (A68_PAGE_SIZE (&DEVICE (file)))) {
  87      UNBLOCK_GC_HANDLE (&A68_PAGE_SIZE (&DEVICE (file)));
  88    }
  89    A68_PAGE_SIZE (&DEVICE (file)) = heap_generator (p, M_STRING, 1 + size);
  90    BLOCK_GC_HANDLE (&A68_PAGE_SIZE (&DEVICE (file)));
  91    ASSERT (a_to_c_string (p, DEREF (char, &A68_PAGE_SIZE (&DEVICE (file))), ref_page) != NO_TEXT);
  92  // Fill in device.
  93    size = a68_string_size (p, ref_device);
  94    if (INITIALISED (&(DEVICE (&DEVICE (file)))) && !IS_NIL (DEVICE (&DEVICE (file)))) {
  95      UNBLOCK_GC_HANDLE (&DEVICE (&DEVICE (file)));
  96    }
  97    DEVICE (&DEVICE (file)) = heap_generator (p, M_STRING, 1 + size);
  98    BLOCK_GC_HANDLE (&DEVICE (&DEVICE (file)));
  99    ASSERT (a_to_c_string (p, DEREF (char, &DEVICE (&DEVICE (file))), ref_device) != NO_TEXT);
 100    DEVICE_MADE (&DEVICE (file)) = A68_TRUE;
 101    PUSH_VALUE (p, A68_TRUE, A68_BOOL);
 102  }
 103  
 104  //! @brief Closes the plotter.
 105  
 106  BOOL_T close_device (NODE_T * p, A68_FILE * f)
 107  {
 108    CHECK_INIT (p, INITIALISED (f), M_FILE);
 109    if (!OPENED (f)) {
 110      diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
 111      exit_genie (p, A68_RUNTIME_ERROR);
 112    }
 113    if (!(DEVICE_OPENED (&DEVICE (f)))) {
 114      diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_NOT_OPEN);
 115      exit_genie (p, A68_RUNTIME_ERROR);
 116    }
 117    if (DEVICE_MADE (&DEVICE (f))) {
 118      if (!IS_NIL (DEVICE (&DEVICE (f)))) {
 119        UNBLOCK_GC_HANDLE (&(DEVICE (&DEVICE (f))));
 120      }
 121      if (!IS_NIL (A68_PAGE_SIZE (&DEVICE (f)))) {
 122        UNBLOCK_GC_HANDLE (&(A68_PAGE_SIZE (&DEVICE (f))));
 123      }
 124    }
 125    if (pl_closepl_r (PLOTTER (&DEVICE (f))) < 0) {
 126      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CLOSING_DEVICE);
 127      exit_genie (p, A68_RUNTIME_ERROR);
 128    }
 129    if (pl_deletepl_r (PLOTTER (&DEVICE (f))) < 0) {
 130      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CLOSING_DEVICE);
 131      exit_genie (p, A68_RUNTIME_ERROR);
 132    }
 133    if (STREAM (&DEVICE (f)) != NO_STREAM && fclose (STREAM (&DEVICE (f))) != 0) {
 134      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CLOSING_FILE);
 135      exit_genie (p, A68_RUNTIME_ERROR);
 136    }
 137    DEVICE_OPENED (&DEVICE (f)) = A68_FALSE;
 138    return A68_TRUE;
 139  }
 140  
 141  //! @brief Sets up the plotter prior to using it.
 142  
 143  plPlotter *set_up_device (NODE_T * p, A68_FILE * f)
 144  {
 145  // First set up the general device, then plotter-specific things.
 146    CHECK_INIT (p, INITIALISED (f), M_FILE);
 147    A68_REF ref_filename = IDENTIFICATION (f);
 148  // This one in front as to quickly select the plotter.
 149    if (DEVICE_OPENED (&DEVICE (f))) {
 150      if (DEVICE_HANDLE (&DEVICE (f)) < 0) {
 151        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 152        exit_genie (p, A68_RUNTIME_ERROR);
 153      }
 154      return PLOTTER (&DEVICE (f));
 155    }
 156  // Device not set up yet.
 157    if (!OPENED (f)) {
 158      diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
 159      exit_genie (p, A68_RUNTIME_ERROR);
 160    }
 161    if (READ_MOOD (f)) {
 162      diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "read");
 163      exit_genie (p, A68_RUNTIME_ERROR);
 164    }
 165    if (WRITE_MOOD (f)) {
 166      diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
 167      exit_genie (p, A68_RUNTIME_ERROR);
 168    }
 169    if (!DRAW (&CHANNEL (f))) {
 170      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "drawing");
 171      exit_genie (p, A68_RUNTIME_ERROR);
 172    }
 173    if (!DEVICE_MADE (&DEVICE (f))) {
 174      diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_NOT_SET);
 175      exit_genie (p, A68_RUNTIME_ERROR);
 176    }
 177    char *device_type = DEREF (char, &DEVICE (&DEVICE (f)));
 178    if (!strcmp (device_type, "X")) {
 179  #if defined (X_DISPLAY_MISSING)
 180      diagnostic (A68_RUNTIME_ERROR, p, ERROR_INVALID_PARAMETER, "X plotter missing", "");
 181      exit_genie (p, A68_RUNTIME_ERROR);
 182  #else
 183  // Supported plotter type - X Window System
 184      char *z = DEREF (char, &A68_PAGE_SIZE (&DEVICE (f))), size[BUFFER_SIZE];
 185  // Establish page size.
 186      if (!scan_int (&z, &(WINDOW_X_SIZE (&DEVICE (f))))) {
 187        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 188        exit_genie (p, A68_RUNTIME_ERROR);
 189      }
 190      if (!scan_int (&z, &(WINDOW_Y_SIZE (&DEVICE (f))))) {
 191        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 192        exit_genie (p, A68_RUNTIME_ERROR);
 193      }
 194      if (z[0] != NULL_CHAR) {
 195        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 196        exit_genie (p, A68_RUNTIME_ERROR);
 197      }
 198  // Make the X window.
 199      FD (f) = -1;
 200      PLOTTER_PARAMS (&DEVICE (f)) = pl_newplparams ();
 201      if (PLOTTER_PARAMS (&DEVICE (f)) == NULL) {
 202        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_ALLOCATE);
 203        exit_genie (p, A68_RUNTIME_ERROR);
 204      }
 205      ASSERT (a68_bufprt (size, SNPRINTF_SIZE, "%dx%d", WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f))) >= 0);
 206      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "BITMAPSIZE", size);
 207      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "BG_COLOR", (void *) "black");
 208      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "VANISH_ON_DELETE", (void *) "no");
 209      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "X_AUTO_FLUSH", (void *) "yes");
 210      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "USE_DOUBLE_BUFFERING", (void *) "no");
 211      PLOTTER (&DEVICE (f)) = pl_newpl_r ("X", NULL, NULL, stderr, PLOTTER_PARAMS (&DEVICE (f)));
 212      if (PLOTTER (&DEVICE (f)) == NULL) {
 213        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 214        exit_genie (p, A68_RUNTIME_ERROR);
 215      }
 216      if (pl_openpl_r (PLOTTER (&DEVICE (f))) < 0) {
 217        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 218        exit_genie (p, A68_RUNTIME_ERROR);
 219      }
 220      (void) pl_space_r (PLOTTER (&DEVICE (f)), 0, 0, WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f)));
 221      (void) pl_bgcolorname_r (PLOTTER (&DEVICE (f)), "black");
 222      (void) pl_colorname_r (PLOTTER (&DEVICE (f)), "white");
 223      (void) pl_pencolorname_r (PLOTTER (&DEVICE (f)), "white");
 224      (void) pl_fillcolorname_r (PLOTTER (&DEVICE (f)), "white");
 225      (void) pl_filltype_r (PLOTTER (&DEVICE (f)), 0);
 226      DRAW_MOOD (f) = A68_TRUE;
 227      DEVICE_OPENED (&DEVICE (f)) = A68_TRUE;
 228      X_COORD (&DEVICE (f)) = 0;
 229      Y_COORD (&DEVICE (f)) = 0;
 230      return PLOTTER (&DEVICE (f));
 231  #endif
 232    } else if (!strcmp (device_type, "gif")) {
 233  // Supported plotter type - pseudo GIF
 234      char *z = DEREF (char, &A68_PAGE_SIZE (&DEVICE (f))), size[BUFFER_SIZE];
 235  // Establish page size.
 236      if (!scan_int (&z, &(WINDOW_X_SIZE (&DEVICE (f))))) {
 237        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 238        exit_genie (p, A68_RUNTIME_ERROR);
 239      }
 240      if (!scan_int (&z, &(WINDOW_Y_SIZE (&DEVICE (f))))) {
 241        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 242        exit_genie (p, A68_RUNTIME_ERROR);
 243      }
 244      if (z[0] != NULL_CHAR) {
 245        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 246        exit_genie (p, A68_RUNTIME_ERROR);
 247      }
 248  // Open the output file for drawing.
 249      CHECK_REF (p, ref_filename, M_ROWS);
 250      char *filename = DEREF (char, &ref_filename);
 251      errno = 0;
 252      if ((STREAM (&DEVICE (f)) = fopen (filename, "wb")) == NO_STREAM) {
 253        diagnostic (A68_RUNTIME_ERROR, p, ERROR_CANNOT_OPEN_NAME, filename);
 254        exit_genie (p, A68_RUNTIME_ERROR);
 255      } else {
 256        READ_MOOD (f) = A68_FALSE;
 257        WRITE_MOOD (f) = A68_FALSE;
 258        CHAR_MOOD (f) = A68_FALSE;
 259        DRAW_MOOD (f) = A68_TRUE;
 260      }
 261  // Set up plotter.
 262      PLOTTER_PARAMS (&DEVICE (f)) = pl_newplparams ();
 263      if (PLOTTER_PARAMS (&DEVICE (f)) == NULL) {
 264        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_ALLOCATE);
 265        exit_genie (p, A68_RUNTIME_ERROR);
 266      }
 267      ASSERT (a68_bufprt (size, SNPRINTF_SIZE, "%dx%d", WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f))) >= 0);
 268      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "BITMAPSIZE", size);
 269      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "BG_COLOR", (void *) "black");
 270      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "GIF_ANIMATION", (void *) "no");
 271      PLOTTER (&DEVICE (f)) = pl_newpl_r ("gif", NULL, STREAM (&DEVICE (f)), stderr, PLOTTER_PARAMS (&DEVICE (f)));
 272      if (PLOTTER (&DEVICE (f)) == NULL) {
 273        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 274        exit_genie (p, A68_RUNTIME_ERROR);
 275      }
 276      if (pl_openpl_r (PLOTTER (&DEVICE (f))) < 0) {
 277        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 278        exit_genie (p, A68_RUNTIME_ERROR);
 279      }
 280      (void) pl_space_r (PLOTTER (&DEVICE (f)), 0, 0, WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f)));
 281      (void) pl_bgcolorname_r (PLOTTER (&DEVICE (f)), "black");
 282      (void) pl_colorname_r (PLOTTER (&DEVICE (f)), "white");
 283      (void) pl_pencolorname_r (PLOTTER (&DEVICE (f)), "white");
 284      (void) pl_fillcolorname_r (PLOTTER (&DEVICE (f)), "white");
 285      (void) pl_filltype_r (PLOTTER (&DEVICE (f)), 0);
 286      DRAW_MOOD (f) = A68_TRUE;
 287      DEVICE_OPENED (&DEVICE (f)) = A68_TRUE;
 288      X_COORD (&DEVICE (f)) = 0;
 289      Y_COORD (&DEVICE (f)) = 0;
 290      return PLOTTER (&DEVICE (f));
 291    } else if (!strcmp (device_type, "pnm")) {
 292  // Supported plotter type - Portable aNyMap
 293      char *z = DEREF (char, &A68_PAGE_SIZE (&DEVICE (f))), size[BUFFER_SIZE];
 294  // Establish page size.
 295      if (!scan_int (&z, &(WINDOW_X_SIZE (&DEVICE (f))))) {
 296        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 297        exit_genie (p, A68_RUNTIME_ERROR);
 298      }
 299      if (!scan_int (&z, &(WINDOW_Y_SIZE (&DEVICE (f))))) {
 300        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 301        exit_genie (p, A68_RUNTIME_ERROR);
 302      }
 303      if (z[0] != NULL_CHAR) {
 304        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 305        exit_genie (p, A68_RUNTIME_ERROR);
 306      }
 307  // Open the output file for drawing.
 308      CHECK_REF (p, ref_filename, M_ROWS);
 309      char *filename = DEREF (char, &ref_filename);
 310      errno = 0;
 311      if ((STREAM (&DEVICE (f)) = fopen (filename, "wb")) == NO_STREAM) {
 312        diagnostic (A68_RUNTIME_ERROR, p, ERROR_CANNOT_OPEN_NAME, filename);
 313        exit_genie (p, A68_RUNTIME_ERROR);
 314      } else {
 315        READ_MOOD (f) = A68_FALSE;
 316        WRITE_MOOD (f) = A68_FALSE;
 317        CHAR_MOOD (f) = A68_FALSE;
 318        DRAW_MOOD (f) = A68_TRUE;
 319      }
 320  // Set up plotter.
 321      ASSERT (a68_bufprt (size, SNPRINTF_SIZE, "%dx%d", WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f))) >= 0);
 322      PLOTTER_PARAMS (&DEVICE (f)) = pl_newplparams ();
 323      if (PLOTTER_PARAMS (&DEVICE (f)) == NULL) {
 324        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_ALLOCATE);
 325        exit_genie (p, A68_RUNTIME_ERROR);
 326      }
 327      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "BITMAPSIZE", size);
 328      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "BG_COLOR", (void *) "black");
 329      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "PNM_PORTABLE", (void *) "no");
 330      PLOTTER (&DEVICE (f)) = pl_newpl_r ("pnm", NULL, STREAM (&DEVICE (f)), stderr, PLOTTER_PARAMS (&DEVICE (f)));
 331      if (PLOTTER (&DEVICE (f)) == NULL) {
 332        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 333        exit_genie (p, A68_RUNTIME_ERROR);
 334      }
 335      if (pl_openpl_r (PLOTTER (&DEVICE (f))) < 0) {
 336        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 337        exit_genie (p, A68_RUNTIME_ERROR);
 338      }
 339      (void) pl_space_r (PLOTTER (&DEVICE (f)), 0, 0, WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f)));
 340      (void) pl_bgcolorname_r (PLOTTER (&DEVICE (f)), "black");
 341      (void) pl_colorname_r (PLOTTER (&DEVICE (f)), "white");
 342      (void) pl_pencolorname_r (PLOTTER (&DEVICE (f)), "white");
 343      (void) pl_fillcolorname_r (PLOTTER (&DEVICE (f)), "white");
 344      (void) pl_filltype_r (PLOTTER (&DEVICE (f)), 0);
 345      DRAW_MOOD (f) = A68_TRUE;
 346      DEVICE_OPENED (&DEVICE (f)) = A68_TRUE;
 347      X_COORD (&DEVICE (f)) = 0;
 348      Y_COORD (&DEVICE (f)) = 0;
 349      return PLOTTER (&DEVICE (f));
 350    } else if (!strcmp (device_type, "png")) {
 351  #if defined (X_DISPLAY_MISSING)
 352      diagnostic (A68_RUNTIME_ERROR, p, ERROR_INVALID_PARAMETER, "PNG plotter missing", "");
 353      exit_genie (p, A68_RUNTIME_ERROR);
 354  #else
 355  // Supported plotter type - PNG
 356      char *z = DEREF (char, &A68_PAGE_SIZE (&DEVICE (f))), size[BUFFER_SIZE];
 357  // Establish page size.
 358      if (!scan_int (&z, &(WINDOW_X_SIZE (&DEVICE (f))))) {
 359        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 360        exit_genie (p, A68_RUNTIME_ERROR);
 361      }
 362      if (!scan_int (&z, &(WINDOW_Y_SIZE (&DEVICE (f))))) {
 363        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 364        exit_genie (p, A68_RUNTIME_ERROR);
 365      }
 366      if (z[0] != NULL_CHAR) {
 367        diagnostic (A68_RUNTIME_ERROR, p, ERROR_PAGE_SIZE);
 368        exit_genie (p, A68_RUNTIME_ERROR);
 369      }
 370  // Open the output file for drawing.
 371      CHECK_REF (p, ref_filename, M_ROWS);
 372      char *filename = DEREF (char, &ref_filename);
 373      errno = 0;
 374      if ((STREAM (&DEVICE (f)) = fopen (filename, "wb")) == NO_STREAM) {
 375        diagnostic (A68_RUNTIME_ERROR, p, ERROR_CANNOT_OPEN_NAME, filename);
 376        exit_genie (p, A68_RUNTIME_ERROR);
 377      } else {
 378        READ_MOOD (f) = A68_FALSE;
 379        WRITE_MOOD (f) = A68_FALSE;
 380        CHAR_MOOD (f) = A68_FALSE;
 381        DRAW_MOOD (f) = A68_TRUE;
 382      }
 383  // Set up plotter.
 384      PLOTTER_PARAMS (&DEVICE (f)) = pl_newplparams ();
 385      if (PLOTTER_PARAMS (&DEVICE (f)) == NULL) {
 386        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_ALLOCATE);
 387        exit_genie (p, A68_RUNTIME_ERROR);
 388      }
 389      ASSERT (a68_bufprt (size, SNPRINTF_SIZE, "%dx%d", WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f))) >= 0);
 390      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "BITMAPSIZE", size);
 391      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "BG_COLOR", (void *) "black");
 392      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "GIF_ANIMATION", (void *) "no");
 393      PLOTTER (&DEVICE (f)) = pl_newpl_r ("png", NULL, STREAM (&DEVICE (f)), stderr, PLOTTER_PARAMS (&DEVICE (f)));
 394      if (PLOTTER (&DEVICE (f)) == NULL) {
 395        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 396        exit_genie (p, A68_RUNTIME_ERROR);
 397      }
 398      if (pl_openpl_r (PLOTTER (&DEVICE (f))) < 0) {
 399        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 400        exit_genie (p, A68_RUNTIME_ERROR);
 401      }
 402      (void) pl_space_r (PLOTTER (&DEVICE (f)), 0, 0, WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f)));
 403      (void) pl_bgcolorname_r (PLOTTER (&DEVICE (f)), "black");
 404      (void) pl_colorname_r (PLOTTER (&DEVICE (f)), "white");
 405      (void) pl_pencolorname_r (PLOTTER (&DEVICE (f)), "white");
 406      (void) pl_fillcolorname_r (PLOTTER (&DEVICE (f)), "white");
 407      (void) pl_filltype_r (PLOTTER (&DEVICE (f)), 0);
 408      DRAW_MOOD (f) = A68_TRUE;
 409      DEVICE_OPENED (&DEVICE (f)) = A68_TRUE;
 410      X_COORD (&DEVICE (f)) = 0;
 411      Y_COORD (&DEVICE (f)) = 0;
 412      return PLOTTER (&DEVICE (f));
 413  #endif
 414    } else if (!strcmp (device_type, "ps")) {
 415  #if defined (POSTSCRIPT_MISSING)
 416      diagnostic (A68_RUNTIME_ERROR, p, ERROR_INVALID_PARAMETER, "postscript plotter missing", "");
 417      exit_genie (p, A68_RUNTIME_ERROR);
 418  #else
 419  // Supported plotter type - Postscript
 420  // Open the output file for drawing.
 421      CHECK_REF (p, ref_filename, M_ROWS);
 422      char *filename = DEREF (char, &ref_filename);
 423      errno = 0;
 424      if ((STREAM (&DEVICE (f)) = fopen (filename, "w")) == NO_STREAM) {
 425        diagnostic (A68_RUNTIME_ERROR, p, ERROR_CANNOT_OPEN_NAME, filename);
 426        exit_genie (p, A68_RUNTIME_ERROR);
 427      } else {
 428        READ_MOOD (f) = A68_FALSE;
 429        WRITE_MOOD (f) = A68_FALSE;
 430        CHAR_MOOD (f) = A68_FALSE;
 431        DRAW_MOOD (f) = A68_TRUE;
 432      }
 433  // Set up ps plotter.
 434      PLOTTER_PARAMS (&DEVICE (f)) = pl_newplparams ();
 435      if (PLOTTER_PARAMS (&DEVICE (f)) == NULL) {
 436        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_ALLOCATE);
 437        exit_genie (p, A68_RUNTIME_ERROR);
 438      }
 439      (void) pl_setplparam (PLOTTER_PARAMS (&DEVICE (f)), "PAGESIZE", DEREF (char, &A68_PAGE_SIZE (&DEVICE (f))));
 440      PLOTTER (&DEVICE (f)) = pl_newpl_r ("ps", NULL, STREAM (&DEVICE (f)), stderr, PLOTTER_PARAMS (&DEVICE (f)));
 441      if (PLOTTER (&DEVICE (f)) == NULL) {
 442        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 443        exit_genie (p, A68_RUNTIME_ERROR);
 444      }
 445      if (pl_openpl_r (PLOTTER (&DEVICE (f))) < 0) {
 446        diagnostic (A68_RUNTIME_ERROR, p, ERROR_DEVICE_CANNOT_OPEN);
 447        exit_genie (p, A68_RUNTIME_ERROR);
 448      }
 449      WINDOW_X_SIZE (&DEVICE (f)) = 1000;
 450      WINDOW_Y_SIZE (&DEVICE (f)) = 1000;
 451      (void) pl_space_r (PLOTTER (&DEVICE (f)), 0, 0, WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f)));
 452      (void) pl_bgcolorname_r (PLOTTER (&DEVICE (f)), "black");
 453      (void) pl_colorname_r (PLOTTER (&DEVICE (f)), "white");
 454      (void) pl_pencolorname_r (PLOTTER (&DEVICE (f)), "white");
 455      (void) pl_fillcolorname_r (PLOTTER (&DEVICE (f)), "white");
 456      (void) pl_filltype_r (PLOTTER (&DEVICE (f)), 0);
 457      DRAW_MOOD (f) = A68_TRUE;
 458      DEVICE_OPENED (&DEVICE (f)) = A68_TRUE;
 459      X_COORD (&DEVICE (f)) = 0;
 460      Y_COORD (&DEVICE (f)) = 0;
 461      return PLOTTER (&DEVICE (f));
 462  #endif
 463    } else {
 464      diagnostic (A68_RUNTIME_ERROR, p, ERROR_INVALID_PARAMETER, "unindentified plotter", device_type);
 465      exit_genie (p, A68_RUNTIME_ERROR);
 466    }
 467    return NULL;
 468  }
 469  
 470  //! @brief PROC (REF FILE) VOID draw erase
 471  
 472  void genie_draw_clear (NODE_T * p)
 473  {
 474    A68_REF ref_file;
 475    POP_REF (p, &ref_file);
 476    CHECK_REF (p, ref_file, M_REF_FILE);
 477    A68_FILE *f = FILE_DEREF (&ref_file);
 478    plPlotter *plotter = set_up_device (p, f);
 479    (void) pl_flushpl_r (plotter);
 480    (void) pl_erase_r (plotter);
 481  }
 482  
 483  //! @brief PROC (REF FILE) VOID draw show
 484  
 485  void genie_draw_show (NODE_T * p)
 486  {
 487    A68_REF ref_file;
 488    POP_REF (p, &ref_file);
 489    CHECK_REF (p, ref_file, M_REF_FILE);
 490    A68_FILE *f = FILE_DEREF (&ref_file);
 491    plPlotter *plotter = set_up_device (p, f);
 492    (void) pl_flushpl_r (plotter);
 493  }
 494  
 495  //! @brief PROC (REF FILE) REAL draw aspect
 496  
 497  void genie_draw_aspect (NODE_T * p)
 498  {
 499    A68_REF ref_file;
 500    POP_REF (p, &ref_file);
 501    CHECK_REF (p, ref_file, M_REF_FILE);
 502    A68_FILE *f = FILE_DEREF (&ref_file);
 503    plPlotter *plotter = set_up_device (p, f);
 504    PUSH_VALUE (p, (REAL_T) WINDOW_Y_SIZE (&DEVICE (f)) / (REAL_T) WINDOW_X_SIZE (&DEVICE (f)), A68_REAL);
 505    (void) plotter;
 506  }
 507  
 508  //! @brief PROC (REF FILE, INT) VOID draw fillstyle
 509  
 510  void genie_draw_fillstyle (NODE_T * p)
 511  {
 512    A68_INT z; A68_REF ref_file;
 513    POP_OBJECT (p, &z, A68_INT);
 514    POP_REF (p, &ref_file);
 515    CHECK_REF (p, ref_file, M_REF_FILE);
 516    A68_FILE *f = FILE_DEREF (&ref_file);
 517    plPlotter *plotter = set_up_device (p, f);
 518    (void) pl_filltype_r (plotter, (int) VALUE (&z));
 519  }
 520  
 521  //! @brief PROC (INT) STRING draw get colour name
 522  
 523  void genie_draw_get_colour_name (NODE_T * p)
 524  {
 525    A68_INT z;
 526    POP_OBJECT (p, &z, A68_INT);
 527    int j = (VALUE (&z) - 1) % COLOUR_NAMES;
 528    char *str = NAME (&A68_COLOURS[j]);
 529    PUSH_REF (p, c_to_a_string (p, str, DEFAULT_WIDTH));
 530  }
 531  
 532  //! @brief PROC (REF FILE, REAL, REAL, REAL) VOID draw colour
 533  
 534  void genie_draw_colour (NODE_T * p)
 535  {
 536    A68_REAL x, y, z; A68_REF ref_file;
 537    POP_OBJECT (p, &z, A68_REAL);
 538    POP_OBJECT (p, &y, A68_REAL);
 539    POP_OBJECT (p, &x, A68_REAL);
 540    POP_REF (p, &ref_file);
 541    CHECK_REF (p, ref_file, M_REF_FILE);
 542    A68_FILE *f = FILE_DEREF (&ref_file);
 543    plPlotter *plotter = set_up_device (p, f);
 544    RED (&DEVICE (f)) = VALUE (&x);
 545    GREEN (&DEVICE (f)) = VALUE (&y);
 546    BLUE (&DEVICE (f)) = VALUE (&z);
 547    (void) pl_color_r (plotter, (int) (VALUE (&x) * COLOUR_MAX), (int) (VALUE (&y) * COLOUR_MAX), (int) (VALUE (&z) * COLOUR_MAX));
 548    (void) pl_pencolor_r (plotter, (int) (VALUE (&x) * COLOUR_MAX), (int) (VALUE (&y) * COLOUR_MAX), (int) (VALUE (&z) * COLOUR_MAX));
 549    (void) pl_fillcolor_r (plotter, (int) (VALUE (&x) * COLOUR_MAX), (int) (VALUE (&y) * COLOUR_MAX), (int) (VALUE (&z) * COLOUR_MAX));
 550  }
 551  
 552  //! @brief PROC (REF FILE, REAL, REAL, REAL) VOID draw background colour
 553  
 554  void genie_draw_background_colour (NODE_T * p)
 555  {
 556    A68_REAL x, y, z; A68_REF ref_file;
 557    POP_OBJECT (p, &z, A68_REAL);
 558    POP_OBJECT (p, &y, A68_REAL);
 559    POP_OBJECT (p, &x, A68_REAL);
 560    POP_REF (p, &ref_file);
 561    CHECK_REF (p, ref_file, M_REF_FILE);
 562    A68_FILE *f = FILE_DEREF (&ref_file);
 563    plPlotter *plotter = set_up_device (p, f);
 564    (void) pl_bgcolor_r (plotter, (int) (VALUE (&x) * COLOUR_MAX), (int) (VALUE (&y) * COLOUR_MAX), (int) (VALUE (&z) * COLOUR_MAX));
 565  }
 566  
 567  //! @brief PROC (REF FILE, STRING) VOID draw colour name
 568  
 569  void genie_draw_colour_name (NODE_T * p)
 570  {
 571    A68_REF ref_c, ref_file;
 572    POP_REF (p, &ref_c);
 573    POP_REF (p, &ref_file);
 574    CHECK_REF (p, ref_file, M_REF_FILE);
 575    A68_FILE *f = FILE_DEREF (&ref_file);
 576    A68_REF ref_name = heap_generator (p, M_C_STRING, 1 + a68_string_size (p, ref_c));
 577    char *name = DEREF (char, &ref_name);
 578    ASSERT (a_to_c_string (p, name, ref_c) != NO_TEXT);
 579    int k;
 580    if (!string_to_colour (p, name, &k)) {
 581      diagnostic (A68_RUNTIME_ERROR, p, ERROR_INVALID_PARAMETER, "unidentified colour name", name);
 582      exit_genie (p, A68_RUNTIME_ERROR);
 583    }
 584    REAL_T x = (REAL_T) (RED (&A68_COLOURS[k])) / (REAL_T) (0xff);
 585    REAL_T y = (REAL_T) (GREEN (&A68_COLOURS[k])) / (REAL_T) (0xff);
 586    REAL_T z = (REAL_T) (BLUE (&A68_COLOURS[k])) / (REAL_T) (0xff);
 587    plPlotter *plotter = set_up_device (p, f);
 588    RED (&DEVICE (f)) = x;
 589    GREEN (&DEVICE (f)) = y;
 590    BLUE (&DEVICE (f)) = z;
 591    (void) pl_color_r (plotter, (int) (x * COLOUR_MAX), (int) (y * COLOUR_MAX), (int) (z * COLOUR_MAX));
 592    (void) pl_pencolor_r (plotter, (int) (x * COLOUR_MAX), (int) (y * COLOUR_MAX), (int) (z * COLOUR_MAX));
 593    (void) pl_fillcolor_r (plotter, (int) (x * COLOUR_MAX), (int) (y * COLOUR_MAX), (int) (z * COLOUR_MAX));
 594  }
 595  
 596  //! @brief PROC (REF FILE, STRING) VOID draw background colour name
 597  
 598  void genie_draw_background_colour_name (NODE_T * p)
 599  {
 600    A68_REF ref_c, ref_file;
 601    POP_REF (p, &ref_c);
 602    POP_REF (p, &ref_file);
 603    CHECK_REF (p, ref_file, M_REF_FILE);
 604    A68_FILE *f = FILE_DEREF (&ref_file);
 605    A68_REF ref_name = heap_generator (p, M_C_STRING, 1 + a68_string_size (p, ref_c));
 606    char *name = DEREF (char, &ref_name);
 607    ASSERT (a_to_c_string (p, name, ref_c) != NO_TEXT);
 608    int k;
 609    if (!string_to_colour (p, name, &k)) {
 610      diagnostic (A68_RUNTIME_ERROR, p, ERROR_INVALID_PARAMETER, "unidentified colour name", name);
 611      exit_genie (p, A68_RUNTIME_ERROR);
 612    }
 613    REAL_T x = (REAL_T) (RED (&A68_COLOURS[k])) / (REAL_T) (0xff);
 614    REAL_T y = (REAL_T) (GREEN (&A68_COLOURS[k])) / (REAL_T) (0xff);
 615    REAL_T z = (REAL_T) (BLUE (&A68_COLOURS[k])) / (REAL_T) (0xff);
 616    plPlotter *plotter = set_up_device (p, f);
 617    RED (&DEVICE (f)) = x;
 618    GREEN (&DEVICE (f)) = y;
 619    BLUE (&DEVICE (f)) = z;
 620    (void) pl_bgcolor_r (plotter, (int) (x * COLOUR_MAX), (int) (y * COLOUR_MAX), (int) (z * COLOUR_MAX));
 621  }
 622  
 623  //! @brief PROC (REF FILE, STRING) VOID draw linestyle
 624  
 625  void genie_draw_linestyle (NODE_T * p)
 626  {
 627    A68_REF txt, ref_file;
 628    POP_REF (p, &txt);
 629    POP_REF (p, &ref_file);
 630    CHECK_REF (p, ref_file, M_REF_FILE);
 631    A68_FILE *f = FILE_DEREF (&ref_file);
 632    plPlotter *plotter = set_up_device (p, f);
 633    int size = a68_string_size (p, txt);
 634    A68_REF z_ref = heap_generator (p, M_C_STRING, 1 + size);
 635    char *z = DEREF (char, &z_ref);
 636    ASSERT (a_to_c_string (p, z, txt) != NO_TEXT);
 637    (void) pl_linemod_r (plotter, z);
 638  }
 639  
 640  //! @brief PROC (REF FILE, INT) VOID draw linewidth
 641  
 642  void genie_draw_linewidth (NODE_T * p)
 643  {
 644    A68_REAL width; A68_REF ref_file;
 645    POP_OBJECT (p, &width, A68_REAL);
 646    POP_REF (p, &ref_file);
 647    CHECK_REF (p, ref_file, M_REF_FILE);
 648    A68_FILE *f = FILE_DEREF (&ref_file);
 649    plPlotter *plotter = set_up_device (p, f);
 650    (void) pl_linewidth_r (plotter, (int) (VALUE (&width) * (REAL_T) WINDOW_Y_SIZE (&DEVICE (f))));
 651  }
 652  
 653  //! @brief PROC (REF FILE, REAL, REAL) VOID draw move
 654  
 655  void genie_draw_move (NODE_T * p)
 656  {
 657    A68_REAL x, y; A68_REF ref_file;
 658    POP_OBJECT (p, &y, A68_REAL);
 659    POP_OBJECT (p, &x, A68_REAL);
 660    POP_REF (p, &ref_file);
 661    CHECK_REF (p, ref_file, M_REF_FILE);
 662    A68_FILE *f = FILE_DEREF (&ref_file);
 663    plPlotter *plotter = set_up_device (p, f);
 664    (void) pl_fmove_r (plotter, VALUE (&x) * WINDOW_X_SIZE (&DEVICE (f)), VALUE (&y) * WINDOW_Y_SIZE (&DEVICE (f)));
 665    X_COORD (&DEVICE (f)) = VALUE (&x);
 666    Y_COORD (&DEVICE (f)) = VALUE (&y);
 667  }
 668  
 669  //! @brief PROC (REF FILE, REAL, REAL) VOID draw line
 670  
 671  void genie_draw_line (NODE_T * p)
 672  {
 673    A68_REAL x, y; A68_REF ref_file;
 674    POP_OBJECT (p, &y, A68_REAL);
 675    POP_OBJECT (p, &x, A68_REAL);
 676    POP_REF (p, &ref_file);
 677    CHECK_REF (p, ref_file, M_REF_FILE);
 678    A68_FILE *f = FILE_DEREF (&ref_file);
 679    plPlotter *plotter = set_up_device (p, f);
 680    (void) pl_fline_r (plotter, X_COORD (&DEVICE (f)) * WINDOW_X_SIZE (&DEVICE (f)), Y_COORD (&DEVICE (f)) * WINDOW_Y_SIZE (&DEVICE (f)), VALUE (&x) * WINDOW_X_SIZE (&DEVICE (f)), VALUE (&y) * WINDOW_Y_SIZE (&DEVICE (f)));
 681    X_COORD (&DEVICE (f)) = VALUE (&x);
 682    Y_COORD (&DEVICE (f)) = VALUE (&y);
 683  }
 684  
 685  //! @brief PROC (REF FILE, REAL, REAL) VOID draw point
 686  
 687  void genie_draw_point (NODE_T * p)
 688  {
 689    A68_REAL x, y; A68_REF ref_file;
 690    POP_OBJECT (p, &y, A68_REAL);
 691    POP_OBJECT (p, &x, A68_REAL);
 692    POP_REF (p, &ref_file);
 693    CHECK_REF (p, ref_file, M_REF_FILE);
 694    A68_FILE *f = FILE_DEREF (&ref_file);
 695    plPlotter *plotter = set_up_device (p, f);
 696    (void) pl_fpoint_r (plotter, VALUE (&x) * WINDOW_X_SIZE (&DEVICE (f)), VALUE (&y) * WINDOW_Y_SIZE (&DEVICE (f)));
 697    X_COORD (&DEVICE (f)) = VALUE (&x);
 698    Y_COORD (&DEVICE (f)) = VALUE (&y);
 699  }
 700  
 701  //! @brief PROC (REF FILE, REAL, REAL) VOID draw rect
 702  
 703  void genie_draw_rect (NODE_T * p)
 704  {
 705    A68_REAL x, y; A68_REF ref_file;
 706    POP_OBJECT (p, &y, A68_REAL);
 707    POP_OBJECT (p, &x, A68_REAL);
 708    POP_REF (p, &ref_file);
 709    CHECK_REF (p, ref_file, M_REF_FILE);
 710    A68_FILE *f = FILE_DEREF (&ref_file);
 711    plPlotter *plotter = set_up_device (p, f);
 712    (void) pl_fbox_r (plotter, X_COORD (&DEVICE (f)) * WINDOW_X_SIZE (&DEVICE (f)), Y_COORD (&DEVICE (f)) * WINDOW_Y_SIZE (&DEVICE (f)), VALUE (&x) * WINDOW_X_SIZE (&DEVICE (f)), VALUE (&y) * WINDOW_Y_SIZE (&DEVICE (f)));
 713    X_COORD (&DEVICE (f)) = VALUE (&x);
 714    Y_COORD (&DEVICE (f)) = VALUE (&y);
 715  }
 716  
 717  //! @brief PROC (REF FILE, REAL, REAL, REAL) VOID draw circle
 718  
 719  void genie_draw_circle (NODE_T * p)
 720  {
 721    A68_REAL x, y, r; A68_REF ref_file;
 722    POP_OBJECT (p, &r, A68_REAL);
 723    POP_OBJECT (p, &y, A68_REAL);
 724    POP_OBJECT (p, &x, A68_REAL);
 725    POP_REF (p, &ref_file);
 726    CHECK_REF (p, ref_file, M_REF_FILE);
 727    A68_FILE *f = FILE_DEREF (&ref_file);
 728    plPlotter *plotter = set_up_device (p, f);
 729    (void) pl_fcircle_r (plotter, VALUE (&x) * WINDOW_X_SIZE (&DEVICE (f)), VALUE (&y) * WINDOW_Y_SIZE (&DEVICE (f)), VALUE (&r) * MAX (WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f))));
 730    X_COORD (&DEVICE (f)) = VALUE (&x);
 731    Y_COORD (&DEVICE (f)) = VALUE (&y);
 732  }
 733  
 734  //! @brief PROC (REF FILE, REAL, REAL, REAL) VOID draw atom
 735  
 736  void genie_draw_atom (NODE_T * p)
 737  {
 738    A68_REAL x, y, r; A68_REF ref_file;
 739    POP_OBJECT (p, &r, A68_REAL);
 740    POP_OBJECT (p, &y, A68_REAL);
 741    POP_OBJECT (p, &x, A68_REAL);
 742    POP_REF (p, &ref_file);
 743    CHECK_REF (p, ref_file, M_REF_FILE);
 744    A68_FILE *f = FILE_DEREF (&ref_file);
 745    plPlotter *plotter = set_up_device (p, f);
 746    int k = (int) (VALUE (&r) * MAX (WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f))));
 747    (void) pl_filltype_r (plotter, 1);
 748    for (int j = k - 1; j >= 0; j--) {
 749      REAL_T frac = (REAL_T) j / (REAL_T) (k - 1);
 750      frac = 0.6 + 0.3 * sqrt (1.0 - frac * frac);
 751      (void) pl_color_r (plotter, (int) (frac * RED (&DEVICE (f)) * COLOUR_MAX), (int) (frac * GREEN (&DEVICE (f)) * COLOUR_MAX), (int) (frac * BLUE (&DEVICE (f)) * COLOUR_MAX));
 752      (void) pl_fcircle_r (plotter, VALUE (&x) * WINDOW_X_SIZE (&DEVICE (f)), VALUE (&y) * WINDOW_Y_SIZE (&DEVICE (f)), (REAL_T) j);
 753    }
 754    (void) pl_filltype_r (plotter, 0);
 755    X_COORD (&DEVICE (f)) = VALUE (&x);
 756    Y_COORD (&DEVICE (f)) = VALUE (&y);
 757  }
 758  
 759  //! @brief PROC (REF FILE, REAL, REAL, REAL) VOID draw atom
 760  
 761  void genie_draw_star (NODE_T * p)
 762  {
 763    A68_REAL x, y, r; A68_REF ref_file;
 764    POP_OBJECT (p, &r, A68_REAL);
 765    POP_OBJECT (p, &y, A68_REAL);
 766    POP_OBJECT (p, &x, A68_REAL);
 767    POP_REF (p, &ref_file);
 768    CHECK_REF (p, ref_file, M_REF_FILE);
 769    A68_FILE *f = FILE_DEREF (&ref_file);
 770    plPlotter *plotter = set_up_device (p, f);
 771    int k = (int) (VALUE (&r) * MAX (WINDOW_X_SIZE (&DEVICE (f)), WINDOW_Y_SIZE (&DEVICE (f))));
 772    for (int j = k; j >= 0; j--) {
 773      REAL_T z = (REAL_T) j / (REAL_T) k, frac;
 774      if (z < 0.2) {
 775        z = z / 0.2;
 776        frac = 0.5 * (1 + (cos (CONST_PI / 2 * z)));
 777      } else {
 778        z = (z - 0.2) / 0.8;
 779        frac = (1 - z) * 0.3;
 780      }
 781      (void) pl_color_r (plotter, (int) (frac * RED (&DEVICE (f)) * COLOUR_MAX), (int) (frac * GREEN (&DEVICE (f)) * COLOUR_MAX), (int) (frac * BLUE (&DEVICE (f)) * COLOUR_MAX));
 782      (void) pl_fcircle_r (plotter, VALUE (&x) * WINDOW_X_SIZE (&DEVICE (f)), VALUE (&y) * WINDOW_Y_SIZE (&DEVICE (f)), (REAL_T) j);
 783    }
 784    (void) pl_color_r (plotter, (int) (RED (&DEVICE (f)) * COLOUR_MAX), (int) (GREEN (&DEVICE (f)) * COLOUR_MAX), (int) (BLUE (&DEVICE (f)) * COLOUR_MAX));
 785    X_COORD (&DEVICE (f)) = VALUE (&x);
 786    Y_COORD (&DEVICE (f)) = VALUE (&y);
 787  }
 788  
 789  //! @brief PROC (REF FILE, CHAR, CHAR, STRING) VOID draw text
 790  
 791  void genie_draw_text (NODE_T * p)
 792  {
 793    A68_CHAR just_v, just_h; A68_REF txt, ref_file;
 794    POP_REF (p, &txt);
 795    POP_OBJECT (p, &just_v, A68_CHAR);
 796    POP_OBJECT (p, &just_h, A68_CHAR);
 797    POP_REF (p, &ref_file);
 798    CHECK_REF (p, ref_file, M_REF_FILE);
 799    A68_FILE *f = FILE_DEREF (&ref_file);
 800    plPlotter *plotter = set_up_device (p, f);
 801    int size = a68_string_size (p, txt);
 802    A68_REF z_ref = heap_generator (p, M_C_STRING, 1 + size);
 803    char *z = DEREF (char, &z_ref);
 804    ASSERT (a_to_c_string (p, z, txt) != NO_TEXT);
 805    (void) pl_alabel_r (plotter, VALUE (&just_h), VALUE (&just_v), z);
 806  }
 807  
 808  //! @brief PROC (REF FILE, STRING) VOID draw fontname
 809  
 810  void genie_draw_fontname (NODE_T * p)
 811  {
 812    A68_REF txt, ref_file;
 813    POP_REF (p, &txt);
 814    POP_REF (p, &ref_file);
 815    CHECK_REF (p, ref_file, M_REF_FILE);
 816    A68_FILE *f = FILE_DEREF (&ref_file);
 817    plPlotter *plotter = set_up_device (p, f);
 818    int size = a68_string_size (p, txt);
 819    A68_REF z_ref = heap_generator (p, M_C_STRING, 1 + size);
 820    char *z = DEREF (char, &z_ref);
 821    ASSERT (a_to_c_string (p, z, txt) != NO_TEXT);
 822    (void) pl_fontname_r (plotter, z);
 823  }
 824  
 825  //! @brief PROC (REF FILE, INT) VOID draw fontsize
 826  
 827  void genie_draw_fontsize (NODE_T * p)
 828  {
 829    A68_INT size;
 830    A68_REF ref_file;
 831    POP_OBJECT (p, &size, A68_INT);
 832    POP_REF (p, &ref_file);
 833    CHECK_REF (p, ref_file, M_REF_FILE);
 834    A68_FILE *f = FILE_DEREF (&ref_file);
 835    plPlotter *plotter = set_up_device (p, f);
 836    (void) pl_fontsize_r (plotter, (int) VALUE (&size));
 837  }
 838  
 839  //! @brief PROC (REF FILE, INT) VOID draw textangle
 840  
 841  void genie_draw_textangle (NODE_T * p)
 842  {
 843    A68_INT angle;
 844    A68_REF ref_file;
 845    A68_FILE *f;
 846    plPlotter *plotter;
 847    POP_OBJECT (p, &angle, A68_INT);
 848    POP_REF (p, &ref_file);
 849    CHECK_REF (p, ref_file, M_REF_FILE);
 850    f = FILE_DEREF (&ref_file);
 851    plotter = set_up_device (p, f);
 852    (void) pl_textangle_r (plotter, (int) VALUE (&angle));
 853  }
 854  
 855  // This part contains names for 24-bit colours recognised by libplot.
 856  // The table below is based on the "rgb.txt" file distributed with X11R6. 
 857  
 858  const colour_info A68_COLOURS[COLOUR_NAMES + 1] = {
 859    {"aliceblue", 0xf0, 0xf8, 0xff},
 860    {"aluminium", 0xaa, 0xac, 0xb7},
 861    {"aluminum", 0xaa, 0xac, 0xb7},
 862    {"antiquewhite", 0xfa, 0xeb, 0xd7},
 863    {"antiquewhite1", 0xff, 0xef, 0xdb},
 864    {"antiquewhite2", 0xee, 0xdf, 0xcc},
 865    {"antiquewhite3", 0xcd, 0xc0, 0xb0},
 866    {"antiquewhite4", 0x8b, 0x83, 0x78},
 867    {"aquamarine", 0x7f, 0xff, 0xd4},
 868    {"aquamarine1", 0x7f, 0xff, 0xd4},
 869    {"aquamarine2", 0x76, 0xee, 0xc6},
 870    {"aquamarine3", 0x66, 0xcd, 0xaa},
 871    {"aquamarine4", 0x45, 0x8b, 0x74},
 872    {"azure", 0xf0, 0xff, 0xff},
 873    {"azure1", 0xf0, 0xff, 0xff},
 874    {"azure2", 0xe0, 0xee, 0xee},
 875    {"azure3", 0xc1, 0xcd, 0xcd},
 876    {"azure4", 0x83, 0x8b, 0x8b},
 877    {"beige", 0xf5, 0xf5, 0xdc},
 878    {"bisque", 0xff, 0xe4, 0xc4},
 879    {"bisque1", 0xff, 0xe4, 0xc4},
 880    {"bisque2", 0xee, 0xd5, 0xb7},
 881    {"bisque3", 0xcd, 0xb7, 0x9e},
 882    {"bisque4", 0x8b, 0x7d, 0x6b},
 883    {"black", 0x00, 0x00, 0x00},
 884    {"blanchedalmond", 0xff, 0xeb, 0xcd},
 885    {"blue", 0x00, 0x00, 0xff},
 886    {"blue1", 0x00, 0x00, 0xff},
 887    {"blue2", 0x00, 0x00, 0xee},
 888    {"blue3", 0x00, 0x00, 0xcd},
 889    {"blue4", 0x00, 0x00, 0x8b},
 890    {"blueviolet", 0x8a, 0x2b, 0xe2},
 891    {"bondi1", 0x02, 0x48, 0x8f},
 892    {"brown", 0xa5, 0x2a, 0x2a},
 893    {"brown1", 0xff, 0x40, 0x40},
 894    {"brown2", 0xee, 0x3b, 0x3b},
 895    {"brown3", 0xcd, 0x33, 0x33},
 896    {"brown4", 0x8b, 0x23, 0x23},
 897    {"burlywood", 0xde, 0xb8, 0x87},
 898    {"burlywood1", 0xff, 0xd3, 0x9b},
 899    {"burlywood2", 0xee, 0xc5, 0x91},
 900    {"burlywood3", 0xcd, 0xaa, 0x7d},
 901    {"burlywood4", 0x8b, 0x73, 0x55},
 902    {"cadetblue", 0x5f, 0x9e, 0xa0},
 903    {"cadetblue1", 0x98, 0xf5, 0xff},
 904    {"cadetblue2", 0x8e, 0xe5, 0xee},
 905    {"cadetblue3", 0x7a, 0xc5, 0xcd},
 906    {"cadetblue4", 0x53, 0x86, 0x8b},
 907    {"chartreuse", 0x7f, 0xff, 0x00},
 908    {"chartreuse1", 0x7f, 0xff, 0x00},
 909    {"chartreuse2", 0x76, 0xee, 0x00},
 910    {"chartreuse3", 0x66, 0xcd, 0x00},
 911    {"chartreuse4", 0x45, 0x8b, 0x00},
 912    {"chocolate", 0xd2, 0x69, 0x1e},
 913    {"chocolate1", 0xff, 0x7f, 0x24},
 914    {"chocolate2", 0xee, 0x76, 0x21},
 915    {"chocolate3", 0xcd, 0x66, 0x1d},
 916    {"chocolate4", 0x8b, 0x45, 0x13},
 917    {"coral", 0xff, 0x7f, 0x50},
 918    {"coral1", 0xff, 0x72, 0x56},
 919    {"coral2", 0xee, 0x6a, 0x50},
 920    {"coral3", 0xcd, 0x5b, 0x45},
 921    {"coral4", 0x8b, 0x3e, 0x2f},
 922    {"cornflowerblue", 0x64, 0x95, 0xed},
 923    {"cornsilk", 0xff, 0xf8, 0xdc},
 924    {"cornsilk1", 0xff, 0xf8, 0xdc},
 925    {"cornsilk2", 0xee, 0xe8, 0xcd},
 926    {"cornsilk3", 0xcd, 0xc8, 0xb1},
 927    {"cornsilk4", 0x8b, 0x88, 0x78},
 928    {"cyan", 0x00, 0xff, 0xff},
 929    {"cyan1", 0x00, 0xff, 0xff},
 930    {"cyan2", 0x00, 0xee, 0xee},
 931    {"cyan3", 0x00, 0xcd, 0xcd},
 932    {"cyan4", 0x00, 0x8b, 0x8b},
 933    {"darkblue", 0x00, 0x00, 0x8b},
 934    {"darkcyan", 0x00, 0x8b, 0x8b},
 935    {"darkgoldenrod", 0xb8, 0x86, 0x0b},
 936    {"darkgoldenrod1", 0xff, 0xb9, 0x0f},
 937    {"darkgoldenrod2", 0xee, 0xad, 0x0e},
 938    {"darkgoldenrod3", 0xcd, 0x95, 0x0c},
 939    {"darkgoldenrod4", 0x8b, 0x65, 0x08},
 940    {"darkgray", 0xa9, 0xa9, 0xa9},
 941    {"darkgreen", 0x00, 0x64, 0x00},
 942    {"darkgrey", 0xa9, 0xa9, 0xa9},
 943    {"darkkhaki", 0xbd, 0xb7, 0x6b},
 944    {"darkmagenta", 0x8b, 0x00, 0x8b},
 945    {"darkolivegreen", 0x55, 0x6b, 0x2f},
 946    {"darkolivegreen1", 0xca, 0xff, 0x70},
 947    {"darkolivegreen2", 0xbc, 0xee, 0x68},
 948    {"darkolivegreen3", 0xa2, 0xcd, 0x5a},
 949    {"darkolivegreen4", 0x6e, 0x8b, 0x3d},
 950    {"darkorange", 0xff, 0x8c, 0x00},
 951    {"darkorange1", 0xff, 0x7f, 0x00},
 952    {"darkorange2", 0xee, 0x76, 0x00},
 953    {"darkorange3", 0xcd, 0x66, 0x00},
 954    {"darkorange4", 0x8b, 0x45, 0x00},
 955    {"darkorchid", 0x99, 0x32, 0xcc},
 956    {"darkorchid1", 0xbf, 0x3e, 0xff},
 957    {"darkorchid2", 0xb2, 0x3a, 0xee},
 958    {"darkorchid3", 0x9a, 0x32, 0xcd},
 959    {"darkorchid4", 0x68, 0x22, 0x8b},
 960    {"darkred", 0x8b, 0x00, 0x00},
 961    {"darksalmon", 0xe9, 0x96, 0x7a},
 962    {"darkseagreen", 0x8f, 0xbc, 0x8f},
 963    {"darkseagreen1", 0xc1, 0xff, 0xc1},
 964    {"darkseagreen2", 0xb4, 0xee, 0xb4},
 965    {"darkseagreen3", 0x9b, 0xcd, 0x9b},
 966    {"darkseagreen4", 0x69, 0x8b, 0x69},
 967    {"darkslateblue", 0x48, 0x3d, 0x8b},
 968    {"darkslategray", 0x2f, 0x4f, 0x4f},
 969    {"darkslategray1", 0x97, 0xff, 0xff},
 970    {"darkslategray2", 0x8d, 0xee, 0xee},
 971    {"darkslategray3", 0x79, 0xcd, 0xcd},
 972    {"darkslategray4", 0x52, 0x8b, 0x8b},
 973    {"darkslategrey", 0x2f, 0x4f, 0x4f},
 974    {"darkslategrey1", 0x97, 0xff, 0xff},
 975    {"darkslategrey2", 0x8d, 0xee, 0xee},
 976    {"darkslategrey3", 0x79, 0xcd, 0xcd},
 977    {"darkslategrey4", 0x52, 0x8b, 0x8b},
 978    {"darkturquoise", 0x00, 0xce, 0xd1},
 979    {"darkviolet", 0x94, 0x00, 0xd3},
 980    {"deeppink", 0xff, 0x14, 0x93},
 981    {"deeppink1", 0xff, 0x14, 0x93},
 982    {"deeppink2", 0xee, 0x12, 0x89},
 983    {"deeppink3", 0xcd, 0x10, 0x76},
 984    {"deeppink4", 0x8b, 0x0a, 0x50},
 985    {"deepskyblue", 0x00, 0xbf, 0xff},
 986    {"deepskyblue1", 0x00, 0xbf, 0xff},
 987    {"deepskyblue2", 0x00, 0xb2, 0xee},
 988    {"deepskyblue3", 0x00, 0x9a, 0xcd},
 989    {"deepskyblue4", 0x00, 0x68, 0x8b},
 990    {"dimgray", 0x69, 0x69, 0x69},
 991    {"dimgrey", 0x69, 0x69, 0x69},
 992    {"dodgerblue", 0x1e, 0x90, 0xff},
 993    {"dodgerblue1", 0x1e, 0x90, 0xff},
 994    {"dodgerblue2", 0x1c, 0x86, 0xee},
 995    {"dodgerblue3", 0x18, 0x74, 0xcd},
 996    {"dodgerblue4", 0x10, 0x4e, 0x8b},
 997    {"firebrick", 0xb2, 0x22, 0x22},
 998    {"firebrick1", 0xff, 0x30, 0x30},
 999    {"firebrick2", 0xee, 0x2c, 0x2c},
1000    {"firebrick3", 0xcd, 0x26, 0x26},
1001    {"firebrick4", 0x8b, 0x1a, 0x1a},
1002    {"floralwhite", 0xff, 0xfa, 0xf0},
1003    {"forestgreen", 0x22, 0x8b, 0x22},
1004    {"gainsboro", 0xdc, 0xdc, 0xdc},
1005    {"ghostwhite", 0xf8, 0xf8, 0xff},
1006    {"gold", 0xff, 0xd7, 0x00},
1007    {"gold1", 0xff, 0xd7, 0x00},
1008    {"gold2", 0xee, 0xc9, 0x00},
1009    {"gold3", 0xcd, 0xad, 0x00},
1010    {"gold4", 0x8b, 0x75, 0x00},
1011    {"goldenrod", 0xda, 0xa5, 0x20},
1012    {"goldenrod1", 0xff, 0xc1, 0x25},
1013    {"goldenrod2", 0xee, 0xb4, 0x22},
1014    {"goldenrod3", 0xcd, 0x9b, 0x1d},
1015    {"goldenrod4", 0x8b, 0x69, 0x14},
1016    {"gray", 0xbe, 0xbe, 0xbe},
1017    {"gray0", 0x00, 0x00, 0x00},
1018    {"gray1", 0x03, 0x03, 0x03},
1019    {"gray2", 0x05, 0x05, 0x05},
1020    {"gray3", 0x08, 0x08, 0x08},
1021    {"gray4", 0x0a, 0x0a, 0x0a},
1022    {"gray5", 0x0d, 0x0d, 0x0d},
1023    {"gray6", 0x0f, 0x0f, 0x0f},
1024    {"gray7", 0x12, 0x12, 0x12},
1025    {"gray8", 0x14, 0x14, 0x14},
1026    {"gray9", 0x17, 0x17, 0x17},
1027    {"gray10", 0x1a, 0x1a, 0x1a},
1028    {"gray11", 0x1c, 0x1c, 0x1c},
1029    {"gray12", 0x1f, 0x1f, 0x1f},
1030    {"gray13", 0x21, 0x21, 0x21},
1031    {"gray14", 0x24, 0x24, 0x24},
1032    {"gray15", 0x26, 0x26, 0x26},
1033    {"gray16", 0x29, 0x29, 0x29},
1034    {"gray17", 0x2b, 0x2b, 0x2b},
1035    {"gray18", 0x2e, 0x2e, 0x2e},
1036    {"gray19", 0x30, 0x30, 0x30},
1037    {"gray20", 0x33, 0x33, 0x33},
1038    {"gray21", 0x36, 0x36, 0x36},
1039    {"gray22", 0x38, 0x38, 0x38},
1040    {"gray23", 0x3b, 0x3b, 0x3b},
1041    {"gray24", 0x3d, 0x3d, 0x3d},
1042    {"gray25", 0x40, 0x40, 0x40},
1043    {"gray26", 0x42, 0x42, 0x42},
1044    {"gray27", 0x45, 0x45, 0x45},
1045    {"gray28", 0x47, 0x47, 0x47},
1046    {"gray29", 0x4a, 0x4a, 0x4a},
1047    {"gray30", 0x4d, 0x4d, 0x4d},
1048    {"gray31", 0x4f, 0x4f, 0x4f},
1049    {"gray32", 0x52, 0x52, 0x52},
1050    {"gray33", 0x54, 0x54, 0x54},
1051    {"gray34", 0x57, 0x57, 0x57},
1052    {"gray35", 0x59, 0x59, 0x59},
1053    {"gray36", 0x5c, 0x5c, 0x5c},
1054    {"gray37", 0x5e, 0x5e, 0x5e},
1055    {"gray38", 0x61, 0x61, 0x61},
1056    {"gray39", 0x63, 0x63, 0x63},
1057    {"gray40", 0x66, 0x66, 0x66},
1058    {"gray41", 0x69, 0x69, 0x69},
1059    {"gray42", 0x6b, 0x6b, 0x6b},
1060    {"gray43", 0x6e, 0x6e, 0x6e},
1061    {"gray44", 0x70, 0x70, 0x70},
1062    {"gray45", 0x73, 0x73, 0x73},
1063    {"gray46", 0x75, 0x75, 0x75},
1064    {"gray47", 0x78, 0x78, 0x78},
1065    {"gray48", 0x7a, 0x7a, 0x7a},
1066    {"gray49", 0x7d, 0x7d, 0x7d},
1067    {"gray50", 0x7f, 0x7f, 0x7f},
1068    {"gray51", 0x82, 0x82, 0x82},
1069    {"gray52", 0x85, 0x85, 0x85},
1070    {"gray53", 0x87, 0x87, 0x87},
1071    {"gray54", 0x8a, 0x8a, 0x8a},
1072    {"gray55", 0x8c, 0x8c, 0x8c},
1073    {"gray56", 0x8f, 0x8f, 0x8f},
1074    {"gray57", 0x91, 0x91, 0x91},
1075    {"gray58", 0x94, 0x94, 0x94},
1076    {"gray59", 0x96, 0x96, 0x96},
1077    {"gray60", 0x99, 0x99, 0x99},
1078    {"gray61", 0x9c, 0x9c, 0x9c},
1079    {"gray62", 0x9e, 0x9e, 0x9e},
1080    {"gray63", 0xa1, 0xa1, 0xa1},
1081    {"gray64", 0xa3, 0xa3, 0xa3},
1082    {"gray65", 0xa6, 0xa6, 0xa6},
1083    {"gray66", 0xa8, 0xa8, 0xa8},
1084    {"gray67", 0xab, 0xab, 0xab},
1085    {"gray68", 0xad, 0xad, 0xad},
1086    {"gray69", 0xb0, 0xb0, 0xb0},
1087    {"gray70", 0xb3, 0xb3, 0xb3},
1088    {"gray71", 0xb5, 0xb5, 0xb5},
1089    {"gray72", 0xb8, 0xb8, 0xb8},
1090    {"gray73", 0xba, 0xba, 0xba},
1091    {"gray74", 0xbd, 0xbd, 0xbd},
1092    {"gray75", 0xbf, 0xbf, 0xbf},
1093    {"gray76", 0xc2, 0xc2, 0xc2},
1094    {"gray77", 0xc4, 0xc4, 0xc4},
1095    {"gray78", 0xc7, 0xc7, 0xc7},
1096    {"gray79", 0xc9, 0xc9, 0xc9},
1097    {"gray80", 0xcc, 0xcc, 0xcc},
1098    {"gray81", 0xcf, 0xcf, 0xcf},
1099    {"gray82", 0xd1, 0xd1, 0xd1},
1100    {"gray83", 0xd4, 0xd4, 0xd4},
1101    {"gray84", 0xd6, 0xd6, 0xd6},
1102    {"gray85", 0xd9, 0xd9, 0xd9},
1103    {"gray86", 0xdb, 0xdb, 0xdb},
1104    {"gray87", 0xde, 0xde, 0xde},
1105    {"gray88", 0xe0, 0xe0, 0xe0},
1106    {"gray89", 0xe3, 0xe3, 0xe3},
1107    {"gray90", 0xe5, 0xe5, 0xe5},
1108    {"gray91", 0xe8, 0xe8, 0xe8},
1109    {"gray92", 0xeb, 0xeb, 0xeb},
1110    {"gray93", 0xed, 0xed, 0xed},
1111    {"gray94", 0xf0, 0xf0, 0xf0},
1112    {"gray95", 0xf2, 0xf2, 0xf2},
1113    {"gray96", 0xf5, 0xf5, 0xf5},
1114    {"gray97", 0xf7, 0xf7, 0xf7},
1115    {"gray98", 0xfa, 0xfa, 0xfa},
1116    {"gray99", 0xfc, 0xfc, 0xfc},
1117    {"gray100", 0xff, 0xff, 0xff},
1118    {"green", 0x00, 0xff, 0x00},
1119    {"green1", 0x00, 0xff, 0x00},
1120    {"green2", 0x00, 0xee, 0x00},
1121    {"green3", 0x00, 0xcd, 0x00},
1122    {"green4", 0x00, 0x8b, 0x00},
1123    {"greenyellow", 0xad, 0xff, 0x2f},
1124    {"grey", 0xbe, 0xbe, 0xbe},
1125    {"grey0", 0x00, 0x00, 0x00},
1126    {"grey1", 0x03, 0x03, 0x03},
1127    {"grey2", 0x05, 0x05, 0x05},
1128    {"grey3", 0x08, 0x08, 0x08},
1129    {"grey4", 0x0a, 0x0a, 0x0a},
1130    {"grey5", 0x0d, 0x0d, 0x0d},
1131    {"grey6", 0x0f, 0x0f, 0x0f},
1132    {"grey7", 0x12, 0x12, 0x12},
1133    {"grey8", 0x14, 0x14, 0x14},
1134    {"grey9", 0x17, 0x17, 0x17},
1135    {"grey10", 0x1a, 0x1a, 0x1a},
1136    {"grey11", 0x1c, 0x1c, 0x1c},
1137    {"grey12", 0x1f, 0x1f, 0x1f},
1138    {"grey13", 0x21, 0x21, 0x21},
1139    {"grey14", 0x24, 0x24, 0x24},
1140    {"grey15", 0x26, 0x26, 0x26},
1141    {"grey16", 0x29, 0x29, 0x29},
1142    {"grey17", 0x2b, 0x2b, 0x2b},
1143    {"grey18", 0x2e, 0x2e, 0x2e},
1144    {"grey19", 0x30, 0x30, 0x30},
1145    {"grey20", 0x33, 0x33, 0x33},
1146    {"grey21", 0x36, 0x36, 0x36},
1147    {"grey22", 0x38, 0x38, 0x38},
1148    {"grey23", 0x3b, 0x3b, 0x3b},
1149    {"grey24", 0x3d, 0x3d, 0x3d},
1150    {"grey25", 0x40, 0x40, 0x40},
1151    {"grey26", 0x42, 0x42, 0x42},
1152    {"grey27", 0x45, 0x45, 0x45},
1153    {"grey28", 0x47, 0x47, 0x47},
1154    {"grey29", 0x4a, 0x4a, 0x4a},
1155    {"grey30", 0x4d, 0x4d, 0x4d},
1156    {"grey31", 0x4f, 0x4f, 0x4f},
1157    {"grey32", 0x52, 0x52, 0x52},
1158    {"grey33", 0x54, 0x54, 0x54},
1159    {"grey34", 0x57, 0x57, 0x57},
1160    {"grey35", 0x59, 0x59, 0x59},
1161    {"grey36", 0x5c, 0x5c, 0x5c},
1162    {"grey37", 0x5e, 0x5e, 0x5e},
1163    {"grey38", 0x61, 0x61, 0x61},
1164    {"grey39", 0x63, 0x63, 0x63},
1165    {"grey40", 0x66, 0x66, 0x66},
1166    {"grey41", 0x69, 0x69, 0x69},
1167    {"grey42", 0x6b, 0x6b, 0x6b},
1168    {"grey43", 0x6e, 0x6e, 0x6e},
1169    {"grey44", 0x70, 0x70, 0x70},
1170    {"grey45", 0x73, 0x73, 0x73},
1171    {"grey46", 0x75, 0x75, 0x75},
1172    {"grey47", 0x78, 0x78, 0x78},
1173    {"grey48", 0x7a, 0x7a, 0x7a},
1174    {"grey49", 0x7d, 0x7d, 0x7d},
1175    {"grey50", 0x7f, 0x7f, 0x7f},
1176    {"grey51", 0x82, 0x82, 0x82},
1177    {"grey52", 0x85, 0x85, 0x85},
1178    {"grey53", 0x87, 0x87, 0x87},
1179    {"grey54", 0x8a, 0x8a, 0x8a},
1180    {"grey55", 0x8c, 0x8c, 0x8c},
1181    {"grey56", 0x8f, 0x8f, 0x8f},
1182    {"grey57", 0x91, 0x91, 0x91},
1183    {"grey58", 0x94, 0x94, 0x94},
1184    {"grey59", 0x96, 0x96, 0x96},
1185    {"grey60", 0x99, 0x99, 0x99},
1186    {"grey61", 0x9c, 0x9c, 0x9c},
1187    {"grey62", 0x9e, 0x9e, 0x9e},
1188    {"grey63", 0xa1, 0xa1, 0xa1},
1189    {"grey64", 0xa3, 0xa3, 0xa3},
1190    {"grey65", 0xa6, 0xa6, 0xa6},
1191    {"grey66", 0xa8, 0xa8, 0xa8},
1192    {"grey67", 0xab, 0xab, 0xab},
1193    {"grey68", 0xad, 0xad, 0xad},
1194    {"grey69", 0xb0, 0xb0, 0xb0},
1195    {"grey70", 0xb3, 0xb3, 0xb3},
1196    {"grey71", 0xb5, 0xb5, 0xb5},
1197    {"grey72", 0xb8, 0xb8, 0xb8},
1198    {"grey73", 0xba, 0xba, 0xba},
1199    {"grey74", 0xbd, 0xbd, 0xbd},
1200    {"grey75", 0xbf, 0xbf, 0xbf},
1201    {"grey76", 0xc2, 0xc2, 0xc2},
1202    {"grey77", 0xc4, 0xc4, 0xc4},
1203    {"grey78", 0xc7, 0xc7, 0xc7},
1204    {"grey79", 0xc9, 0xc9, 0xc9},
1205    {"grey80", 0xcc, 0xcc, 0xcc},
1206    {"grey81", 0xcf, 0xcf, 0xcf},
1207    {"grey82", 0xd1, 0xd1, 0xd1},
1208    {"grey83", 0xd4, 0xd4, 0xd4},
1209    {"grey84", 0xd6, 0xd6, 0xd6},
1210    {"grey85", 0xd9, 0xd9, 0xd9},
1211    {"grey86", 0xdb, 0xdb, 0xdb},
1212    {"grey87", 0xde, 0xde, 0xde},
1213    {"grey88", 0xe0, 0xe0, 0xe0},
1214    {"grey89", 0xe3, 0xe3, 0xe3},
1215    {"grey90", 0xe5, 0xe5, 0xe5},
1216    {"grey91", 0xe8, 0xe8, 0xe8},
1217    {"grey92", 0xeb, 0xeb, 0xeb},
1218    {"grey93", 0xed, 0xed, 0xed},
1219    {"grey94", 0xf0, 0xf0, 0xf0},
1220    {"grey95", 0xf2, 0xf2, 0xf2},
1221    {"grey96", 0xf5, 0xf5, 0xf5},
1222    {"grey97", 0xf7, 0xf7, 0xf7},
1223    {"grey98", 0xfa, 0xfa, 0xfa},
1224    {"grey99", 0xfc, 0xfc, 0xfc},
1225    {"grey100", 0xff, 0xff, 0xff},
1226    {"honeydew", 0xf0, 0xff, 0xf0},
1227    {"honeydew1", 0xf0, 0xff, 0xf0},
1228    {"honeydew2", 0xe0, 0xee, 0xe0},
1229    {"honeydew3", 0xc1, 0xcd, 0xc1},
1230    {"honeydew4", 0x83, 0x8b, 0x83},
1231    {"hotpink", 0xff, 0x69, 0xb4},
1232    {"hotpink1", 0xff, 0x6e, 0xb4},
1233    {"hotpink2", 0xee, 0x6a, 0xa7},
1234    {"hotpink3", 0xcd, 0x60, 0x90},
1235    {"hotpink4", 0x8b, 0x3a, 0x62},
1236    {"indianred", 0xcd, 0x5c, 0x5c},
1237    {"indianred1", 0xff, 0x6a, 0x6a},
1238    {"indianred2", 0xee, 0x63, 0x63},
1239    {"indianred3", 0xcd, 0x55, 0x55},
1240    {"indianred4", 0x8b, 0x3a, 0x3a},
1241    {"ivory", 0xff, 0xff, 0xf0},
1242    {"ivory1", 0xff, 0xff, 0xf0},
1243    {"ivory2", 0xee, 0xee, 0xe0},
1244    {"ivory3", 0xcd, 0xcd, 0xc1},
1245    {"ivory4", 0x8b, 0x8b, 0x83},
1246    {"khaki", 0xf0, 0xe6, 0x8c},
1247    {"khaki1", 0xff, 0xf6, 0x8f},
1248    {"khaki2", 0xee, 0xe6, 0x85},
1249    {"khaki3", 0xcd, 0xc6, 0x73},
1250    {"khaki4", 0x8b, 0x86, 0x4e},
1251    {"lavender", 0xe6, 0xe6, 0xfa},
1252    {"lavenderblush", 0xff, 0xf0, 0xf5},
1253    {"lavenderblush1", 0xff, 0xf0, 0xf5},
1254    {"lavenderblush2", 0xee, 0xe0, 0xe5},
1255    {"lavenderblush3", 0xcd, 0xc1, 0xc5},
1256    {"lavenderblush4", 0x8b, 0x83, 0x86},
1257    {"lawngreen", 0x7c, 0xfc, 0x00},
1258    {"lemonchiffon", 0xff, 0xfa, 0xcd},
1259    {"lemonchiffon1", 0xff, 0xfa, 0xcd},
1260    {"lemonchiffon2", 0xee, 0xe9, 0xbf},
1261    {"lemonchiffon3", 0xcd, 0xc9, 0xa5},
1262    {"lemonchiffon4", 0x8b, 0x89, 0x70},
1263    {"lightblue", 0xad, 0xd8, 0xe6},
1264    {"lightblue1", 0xbf, 0xef, 0xff},
1265    {"lightblue2", 0xb2, 0xdf, 0xee},
1266    {"lightblue3", 0x9a, 0xc0, 0xcd},
1267    {"lightblue4", 0x68, 0x83, 0x8b},
1268    {"lightcoral", 0xf0, 0x80, 0x80},
1269    {"lightcyan", 0xe0, 0xff, 0xff},
1270    {"lightcyan1", 0xe0, 0xff, 0xff},
1271    {"lightcyan2", 0xd1, 0xee, 0xee},
1272    {"lightcyan3", 0xb4, 0xcd, 0xcd},
1273    {"lightcyan4", 0x7a, 0x8b, 0x8b},
1274    {"lightgoldenrod", 0xee, 0xdd, 0x82},
1275    {"lightgoldenrod1", 0xff, 0xec, 0x8b},
1276    {"lightgoldenrod2", 0xee, 0xdc, 0x82},
1277    {"lightgoldenrod3", 0xcd, 0xbe, 0x70},
1278    {"lightgoldenrod4", 0x8b, 0x81, 0x4c},
1279    {"lightgoldenrodyellow", 0xfa, 0xfa, 0xd2},
1280    {"lightgray", 0xd3, 0xd3, 0xd3},
1281    {"lightgreen", 0x90, 0xee, 0x90},
1282    {"lightgrey", 0xd3, 0xd3, 0xd3},
1283    {"lightpink", 0xff, 0xb6, 0xc1},
1284    {"lightpink1", 0xff, 0xae, 0xb9},
1285    {"lightpink2", 0xee, 0xa2, 0xad},
1286    {"lightpink3", 0xcd, 0x8c, 0x95},
1287    {"lightpink4", 0x8b, 0x5f, 0x65},
1288    {"lightsalmon", 0xff, 0xa0, 0x7a},
1289    {"lightsalmon1", 0xff, 0xa0, 0x7a},
1290    {"lightsalmon2", 0xee, 0x95, 0x72},
1291    {"lightsalmon3", 0xcd, 0x81, 0x62},
1292    {"lightsalmon4", 0x8b, 0x57, 0x42},
1293    {"lightseagreen", 0x20, 0xb2, 0xaa},
1294    {"lightskyblue", 0x87, 0xce, 0xfa},
1295    {"lightskyblue1", 0xb0, 0xe2, 0xff},
1296    {"lightskyblue2", 0xa4, 0xd3, 0xee},
1297    {"lightskyblue3", 0x8d, 0xb6, 0xcd},
1298    {"lightskyblue4", 0x60, 0x7b, 0x8b},
1299    {"lightslateblue", 0x84, 0x70, 0xff},
1300    {"lightslategray", 0x77, 0x88, 0x99},
1301    {"lightslategrey", 0x77, 0x88, 0x99},
1302    {"lightsteelblue", 0xb0, 0xc4, 0xde},
1303    {"lightsteelblue1", 0xca, 0xe1, 0xff},
1304    {"lightsteelblue2", 0xbc, 0xd2, 0xee},
1305    {"lightsteelblue3", 0xa2, 0xb5, 0xcd},
1306    {"lightsteelblue4", 0x6e, 0x7b, 0x8b},
1307    {"lightyellow", 0xff, 0xff, 0xe0},
1308    {"lightyellow1", 0xff, 0xff, 0xe0},
1309    {"lightyellow2", 0xee, 0xee, 0xd1},
1310    {"lightyellow3", 0xcd, 0xcd, 0xb4},
1311    {"lightyellow4", 0x8b, 0x8b, 0x7a},
1312    {"limegreen", 0x32, 0xcd, 0x32},
1313    {"linen", 0xfa, 0xf0, 0xe6},
1314    {"magenta", 0xff, 0x00, 0xff},
1315    {"magenta1", 0xff, 0x00, 0xff},
1316    {"magenta2", 0xee, 0x00, 0xee},
1317    {"magenta3", 0xcd, 0x00, 0xcd},
1318    {"magenta4", 0x8b, 0x00, 0x8b},
1319    {"maroon", 0xb0, 0x30, 0x60},
1320    {"maroon1", 0xff, 0x34, 0xb3},
1321    {"maroon2", 0xee, 0x30, 0xa7},
1322    {"maroon3", 0xcd, 0x29, 0x90},
1323    {"maroon4", 0x8b, 0x1c, 0x62},
1324    {"mediumaquamarine", 0x66, 0xcd, 0xaa},
1325    {"mediumblue", 0x00, 0x00, 0xcd},
1326    {"mediumorchid", 0xba, 0x55, 0xd3},
1327    {"mediumorchid1", 0xe0, 0x66, 0xff},
1328    {"mediumorchid2", 0xd1, 0x5f, 0xee},
1329    {"mediumorchid3", 0xb4, 0x52, 0xcd},
1330    {"mediumorchid4", 0x7a, 0x37, 0x8b},
1331    {"mediumpurple", 0x93, 0x70, 0xdb},
1332    {"mediumpurple1", 0xab, 0x82, 0xff},
1333    {"mediumpurple2", 0x9f, 0x79, 0xee},
1334    {"mediumpurple3", 0x89, 0x68, 0xcd},
1335    {"mediumpurple4", 0x5d, 0x47, 0x8b},
1336    {"mediumseagreen", 0x3c, 0xb3, 0x71},
1337    {"mediumslateblue", 0x7b, 0x68, 0xee},
1338    {"mediumspringgreen", 0x00, 0xfa, 0x9a},
1339    {"mediumturquoise", 0x48, 0xd1, 0xcc},
1340    {"mediumvioletred", 0xc7, 0x15, 0x85},
1341    {"midnightblue", 0x19, 0x19, 0x70},
1342    {"mintcream", 0xf5, 0xff, 0xfa},
1343    {"mistyrose", 0xff, 0xe4, 0xe1},
1344    {"mistyrose1", 0xff, 0xe4, 0xe1},
1345    {"mistyrose2", 0xee, 0xd5, 0xd2},
1346    {"mistyrose3", 0xcd, 0xb7, 0xb5},
1347    {"mistyrose4", 0x8b, 0x7d, 0x7b},
1348    {"moccasin", 0xff, 0xe4, 0xb5},
1349    {"navajowhite", 0xff, 0xde, 0xad},
1350    {"navajowhite1", 0xff, 0xde, 0xad},
1351    {"navajowhite2", 0xee, 0xcf, 0xa1},
1352    {"navajowhite3", 0xcd, 0xb3, 0x8b},
1353    {"navajowhite4", 0x8b, 0x79, 0x5e},
1354    {"navy", 0x00, 0x00, 0x80},
1355    {"navyblue", 0x00, 0x00, 0x80},
1356    {"oldlace", 0xfd, 0xf5, 0xe6},
1357    {"olivedrab", 0x6b, 0x8e, 0x23},
1358    {"olivedrab1", 0xc0, 0xff, 0x3e},
1359    {"olivedrab2", 0xb3, 0xee, 0x3a},
1360    {"olivedrab3", 0x9a, 0xcd, 0x32},
1361    {"olivedrab4", 0x69, 0x8b, 0x22},
1362    {"orange", 0xff, 0xa5, 0x00},
1363    {"orange1", 0xff, 0xa5, 0x00},
1364    {"orange2", 0xee, 0x9a, 0x00},
1365    {"orange3", 0xcd, 0x85, 0x00},
1366    {"orange4", 0x8b, 0x5a, 0x00},
1367    {"orangered", 0xff, 0x45, 0x00},
1368    {"orangered1", 0xff, 0x45, 0x00},
1369    {"orangered2", 0xee, 0x40, 0x00},
1370    {"orangered3", 0xcd, 0x37, 0x00},
1371    {"orangered4", 0x8b, 0x25, 0x00},
1372    {"orchid", 0xda, 0x70, 0xd6},
1373    {"orchid1", 0xff, 0x83, 0xfa},
1374    {"orchid2", 0xee, 0x7a, 0xe9},
1375    {"orchid3", 0xcd, 0x69, 0xc9},
1376    {"orchid4", 0x8b, 0x47, 0x89},
1377    {"palegoldenrod", 0xee, 0xe8, 0xaa},
1378    {"palegreen", 0x98, 0xfb, 0x98},
1379    {"palegreen1", 0x9a, 0xff, 0x9a},
1380    {"palegreen2", 0x90, 0xee, 0x90},
1381    {"palegreen3", 0x7c, 0xcd, 0x7c},
1382    {"palegreen4", 0x54, 0x8b, 0x54},
1383    {"paleturquoise", 0xaf, 0xee, 0xee},
1384    {"paleturquoise1", 0xbb, 0xff, 0xff},
1385    {"paleturquoise2", 0xae, 0xee, 0xee},
1386    {"paleturquoise3", 0x96, 0xcd, 0xcd},
1387    {"paleturquoise4", 0x66, 0x8b, 0x8b},
1388    {"palevioletred", 0xdb, 0x70, 0x93},
1389    {"palevioletred1", 0xff, 0x82, 0xab},
1390    {"palevioletred2", 0xee, 0x79, 0x9f},
1391    {"palevioletred3", 0xcd, 0x68, 0x89},
1392    {"palevioletred4", 0x8b, 0x47, 0x5d},
1393    {"papayawhip", 0xff, 0xef, 0xd5},
1394    {"peachpuff", 0xff, 0xda, 0xb9},
1395    {"peachpuff1", 0xff, 0xda, 0xb9},
1396    {"peachpuff2", 0xee, 0xcb, 0xad},
1397    {"peachpuff3", 0xcd, 0xaf, 0x95},
1398    {"peachpuff4", 0x8b, 0x77, 0x65},
1399    {"peru", 0xcd, 0x85, 0x3f},
1400    {"pink", 0xff, 0xc0, 0xcb},
1401    {"pink1", 0xff, 0xb5, 0xc5},
1402    {"pink2", 0xee, 0xa9, 0xb8},
1403    {"pink3", 0xcd, 0x91, 0x9e},
1404    {"pink4", 0x8b, 0x63, 0x6c},
1405    {"plum", 0xdd, 0xa0, 0xdd},
1406    {"plum1", 0xff, 0xbb, 0xff},
1407    {"plum2", 0xee, 0xae, 0xee},
1408    {"plum3", 0xcd, 0x96, 0xcd},
1409    {"plum4", 0x8b, 0x66, 0x8b},
1410    {"powderblue", 0xb0, 0xe0, 0xe6},
1411    {"purple", 0xa0, 0x20, 0xf0},
1412    {"purple1", 0x9b, 0x30, 0xff},
1413    {"purple2", 0x91, 0x2c, 0xee},
1414    {"purple3", 0x7d, 0x26, 0xcd},
1415    {"purple4", 0x55, 0x1a, 0x8b},
1416    {"red", 0xff, 0x00, 0x00},
1417    {"red1", 0xff, 0x00, 0x00},
1418    {"red2", 0xee, 0x00, 0x00},
1419    {"red3", 0xcd, 0x00, 0x00},
1420    {"red4", 0x8b, 0x00, 0x00},
1421    {"rosybrown", 0xbc, 0x8f, 0x8f},
1422    {"rosybrown1", 0xff, 0xc1, 0xc1},
1423    {"rosybrown2", 0xee, 0xb4, 0xb4},
1424    {"rosybrown3", 0xcd, 0x9b, 0x9b},
1425    {"rosybrown4", 0x8b, 0x69, 0x69},
1426    {"royalblue", 0x41, 0x69, 0xe1},
1427    {"royalblue1", 0x48, 0x76, 0xff},
1428    {"royalblue2", 0x43, 0x6e, 0xee},
1429    {"royalblue3", 0x3a, 0x5f, 0xcd},
1430    {"royalblue4", 0x27, 0x40, 0x8b},
1431    {"saddlebrown", 0x8b, 0x45, 0x13},
1432    {"salmon", 0xfa, 0x80, 0x72},
1433    {"salmon1", 0xff, 0x8c, 0x69},
1434    {"salmon2", 0xee, 0x82, 0x62},
1435    {"salmon3", 0xcd, 0x70, 0x54},
1436    {"salmon4", 0x8b, 0x4c, 0x39},
1437    {"sandybrown", 0xf4, 0xa4, 0x60},
1438    {"seagreen", 0x2e, 0x8b, 0x57},
1439    {"seagreen1", 0x54, 0xff, 0x9f},
1440    {"seagreen2", 0x4e, 0xee, 0x94},
1441    {"seagreen3", 0x43, 0xcd, 0x80},
1442    {"seagreen4", 0x2e, 0x8b, 0x57},
1443    {"seashell", 0xff, 0xf5, 0xee},
1444    {"seashell1", 0xff, 0xf5, 0xee},
1445    {"seashell2", 0xee, 0xe5, 0xde},
1446    {"seashell3", 0xcd, 0xc5, 0xbf},
1447    {"seashell4", 0x8b, 0x86, 0x82},
1448    {"sienna", 0xa0, 0x52, 0x2d},
1449    {"sienna1", 0xff, 0x82, 0x47},
1450    {"sienna2", 0xee, 0x79, 0x42},
1451    {"sienna3", 0xcd, 0x68, 0x39},
1452    {"sienna4", 0x8b, 0x47, 0x26},
1453    {"skyblue", 0x87, 0xce, 0xeb},
1454    {"skyblue1", 0x87, 0xce, 0xff},
1455    {"skyblue2", 0x7e, 0xc0, 0xee},
1456    {"skyblue3", 0x6c, 0xa6, 0xcd},
1457    {"skyblue4", 0x4a, 0x70, 0x8b},
1458    {"slateblue", 0x6a, 0x5a, 0xcd},
1459    {"slateblue1", 0x83, 0x6f, 0xff},
1460    {"slateblue2", 0x7a, 0x67, 0xee},
1461    {"slateblue3", 0x69, 0x59, 0xcd},
1462    {"slateblue4", 0x47, 0x3c, 0x8b},
1463    {"slategray", 0x70, 0x80, 0x90},
1464    {"slategray1", 0xc6, 0xe2, 0xff},
1465    {"slategray2", 0xb9, 0xd3, 0xee},
1466    {"slategray3", 0x9f, 0xb6, 0xcd},
1467    {"slategray4", 0x6c, 0x7b, 0x8b},
1468    {"slategrey", 0x70, 0x80, 0x90},
1469    {"slategrey1", 0xc6, 0xe2, 0xff},
1470    {"slategrey2", 0xb9, 0xd3, 0xee},
1471    {"slategrey3", 0x9f, 0xb6, 0xcd},
1472    {"slategrey4", 0x6c, 0x7b, 0x8b},
1473    {"snow", 0xff, 0xfa, 0xfa},
1474    {"snow1", 0xff, 0xfa, 0xfa},
1475    {"snow2", 0xee, 0xe9, 0xe9},
1476    {"snow3", 0xcd, 0xc9, 0xc9},
1477    {"snow4", 0x8b, 0x89, 0x89},
1478    {"springgreen", 0x00, 0xff, 0x7f},
1479    {"springgreen1", 0x00, 0xff, 0x7f},
1480    {"springgreen2", 0x00, 0xee, 0x76},
1481    {"springgreen3", 0x00, 0xcd, 0x66},
1482    {"springgreen4", 0x00, 0x8b, 0x45},
1483    {"steelblue", 0x46, 0x82, 0xb4},
1484    {"steelblue1", 0x63, 0xb8, 0xff},
1485    {"steelblue2", 0x5c, 0xac, 0xee},
1486    {"steelblue3", 0x4f, 0x94, 0xcd},
1487    {"steelblue4", 0x36, 0x64, 0x8b},
1488    {"tan", 0xd2, 0xb4, 0x8c},
1489    {"tan1", 0xff, 0xa5, 0x4f},
1490    {"tan2", 0xee, 0x9a, 0x49},
1491    {"tan3", 0xcd, 0x85, 0x3f},
1492    {"tan4", 0x8b, 0x5a, 0x2b},
1493    {"thistle", 0xd8, 0xbf, 0xd8},
1494    {"thistle1", 0xff, 0xe1, 0xff},
1495    {"thistle2", 0xee, 0xd2, 0xee},
1496    {"thistle3", 0xcd, 0xb5, 0xcd},
1497    {"thistle4", 0x8b, 0x7b, 0x8b},
1498    {"tomato", 0xff, 0x63, 0x47},
1499    {"tomato1", 0xff, 0x63, 0x47},
1500    {"tomato2", 0xee, 0x5c, 0x42},
1501    {"tomato3", 0xcd, 0x4f, 0x39},
1502    {"tomato4", 0x8b, 0x36, 0x26},
1503    {"turquoise", 0x40, 0xe0, 0xd0},
1504    {"turquoise1", 0x00, 0xf5, 0xff},
1505    {"turquoise2", 0x00, 0xe5, 0xee},
1506    {"turquoise3", 0x00, 0xc5, 0xcd},
1507    {"turquoise4", 0x00, 0x86, 0x8b},
1508    {"violet", 0xee, 0x82, 0xee},
1509    {"violetred", 0xd0, 0x20, 0x90},
1510    {"violetred1", 0xff, 0x3e, 0x96},
1511    {"violetred2", 0xee, 0x3a, 0x8c},
1512    {"violetred3", 0xcd, 0x32, 0x78},
1513    {"violetred4", 0x8b, 0x22, 0x52},
1514    {"wheat", 0xf5, 0xde, 0xb3},
1515    {"wheat1", 0xff, 0xe7, 0xba},
1516    {"wheat2", 0xee, 0xd8, 0xae},
1517    {"wheat3", 0xcd, 0xba, 0x96},
1518    {"wheat4", 0x8b, 0x7e, 0x66},
1519    {"white", 0xff, 0xff, 0xff},
1520    {"whitesmoke", 0xf5, 0xf5, 0xf5},
1521    {"yellow", 0xff, 0xff, 0x00},
1522    {"yellow1", 0xff, 0xff, 0x00},
1523    {"yellow2", 0xee, 0xee, 0x00},
1524    {"yellow3", 0xcd, 0xcd, 0x00},
1525    {"yellow4", 0x8b, 0x8b, 0x00},
1526    {"yellowgreen", 0x9a, 0xcd, 0x32},
1527    {NO_TEXT, 0, 0, 0}
1528  };
1529  
1530  //! @brief Searches colour in the list.
1531  
1532  BOOL_T string_to_colour (NODE_T * p, char *name, int *pos)
1533  {
1534    A68_REF z_ref = heap_generator (p, M_C_STRING, (int) (1 + strlen (name)));
1535    char *z = DEREF (char, &z_ref);
1536  // First remove formatting from name: spaces and capitals are irrelevant.
1537    int j = 0;
1538    for (int i = 0; name[i] != NULL_CHAR; i++) {
1539      if (name[i] != BLANK_CHAR) {
1540        z[j++] = (char) TO_LOWER (name[i]);
1541      }
1542      z[j] = NULL_CHAR;
1543    }
1544  // Now search with the famous British Library Method.
1545    for (int i = 0; i < COLOUR_NAMES; i++) {
1546      if (!strcmp (NAME (&A68_COLOURS[i]), z)) {
1547        *pos = i;
1548        return A68_TRUE;
1549      }
1550    }
1551    return A68_FALSE;
1552  }
1553  
1554  #endif