]> granicus.if.org Git - graphviz/commitdiff
renaming color -> inkpot
authorellson <devnull@localhost>
Wed, 24 Sep 2008 17:16:08 +0000 (17:16 +0000)
committerellson <devnull@localhost>
Wed, 24 Sep 2008 17:16:08 +0000 (17:16 +0000)
lib/inkpot/inkpot.h [new file with mode: 0644]
lib/inkpot/inkpot_scheme.c [new file with mode: 0644]
lib/inkpot/inkpot_xlate.c [new file with mode: 0644]

diff --git a/lib/inkpot/inkpot.h b/lib/inkpot/inkpot.h
new file mode 100644 (file)
index 0000000..5879e9d
--- /dev/null
@@ -0,0 +1,90 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#ifndef COLOR_H
+#define COLOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MIN
+#define MIN(a,b)    ((a)<(b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b)    ((a)>(b)?(a):(b))
+#endif
+
+typedef enum {
+       INKPOT_SUCCESS=0,
+       INKPOT_MALLOC_FAIL,
+       INKPOT_COLOR_UNKNOWN,
+       INKPOT_SCHEME_UNKNOWN,
+       INKPOT_MAX_ONE_INDEXED_SCHEME
+} inkpot_status_t;
+
+typedef struct inkpot_s inkpot_t;
+
+/* possible representations of color in gvcolor_t */
+typedef enum {
+       HSVA_DOUBLE,
+       RGBA_DOUBLE,
+       RGBA_WORD,
+       RGBA_BYTE,
+       CMYK_BYTE,
+       COLOR_STRING,
+       COLOR_INDEX
+} color_type_t;
+
+/* gvcolor_t can hold a color spec in a choice or representations */
+typedef struct gvcolor_s {
+    union {
+       double HSVA[4];
+       double RGBA[4];
+       int rrggbbaa[4];
+       unsigned char rgba[4];
+       unsigned char cmyk[4];
+       char *string;
+       int index;
+    } u;
+    color_type_t type;
+} gvcolor_t;
+
+extern inkpot_status_t inkpot_init( inkpot_t **inkpot );
+extern inkpot_status_t inkpot_clear( inkpot_t *inkpot );
+extern inkpot_status_t inkpot_add( inkpot_t *inkpot, const char *scheme );
+
+extern inkpot_status_t inkpot_find( inkpot_t *inkpot, const char *color );
+extern inkpot_status_t inkpot_find_default( inkpot_t *inkpot);
+extern void inkpot_get_rgba( inkpot_t *inkpot,
+       unsigned int *r, unsigned int *g, unsigned int *b, unsigned int *a);
+extern void inkpot_get_hsva( inkpot_t *inkpot,
+       unsigned int *h, unsigned int *s, unsigned int *v, unsigned int *a);
+
+extern void inkpot_print_schemes( inkpot_t *inkpot );
+extern void inkpot_print_names( inkpot_t *inkpot );
+extern void inkpot_print_values( inkpot_t *inkpot );
+extern void inkpot_print_rgba( inkpot_t *inkpot );
+
+extern int setColorScheme (const char* s);
+extern inkpot_status_t colorxlate(const char *str, gvcolor_t * color, color_type_t target_type);
+extern char *canontoken(const char *str);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* COLOR_H */
diff --git a/lib/inkpot/inkpot_scheme.c b/lib/inkpot/inkpot_scheme.c
new file mode 100644 (file)
index 0000000..7e396b2
--- /dev/null
@@ -0,0 +1,479 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+ *      This software is part of the graphviz package      *
+ *                http://www.graphviz.org/                 *
+ *                                                         *
+ *            Copyright (c) 1994-2004 AT&T Corp.           *
+ *                and is licensed under the                *
+ *            Common Public License, Version 1.0           *
+ *                      by AT&T Corp.                      *
+ *                                                         *
+ *        Information and Software Systems Research        *
+ *              AT&T Research, Florham Park NJ             *
+ **********************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "inkpot.h"
+#include "inkpot_tables.h"
+
+static int string_cmpf (const char *k, const char *b)
+{
+    for ( ; *k && *b; k++, b++) {
+       if (*k > *b) return 1;
+       if (*k < *b) return -1;
+    }
+    if (*k) return 1;  /* if the next char in key is not '\0', then key is longer */
+    if (*b) return -1;  /* if the next char in base is not '\0', then base is longer */
+    return 0;
+}
+
+static int inkpot_scheme_name_cmpf ( const void *key, const void *base)
+{
+    const char *k = (const char*)key;
+    const char *b = &TAB_STRINGS[((inkpot_scheme_name_t *)base)->string_idx];
+
+    return string_cmpf(k, b);
+}
+
+static inkpot_scheme_name_t *inkpot_find_scheme_name ( const char *scheme )
+{
+    if (scheme == NULL)
+        return NULL;
+    return (inkpot_scheme_name_t *) bsearch(
+            (void*)scheme, (void*)TAB_SCHEMES_NAME,
+            SZT_SCHEMES_NAME, sizeof(inkpot_scheme_name_t),
+            inkpot_scheme_name_cmpf); 
+}
+
+static int inkpot_scheme_index_cmpf ( const void *key, const void *base)
+{
+    const char *k = (const char*)key;
+    const char *b = &TAB_STRINGS[((inkpot_scheme_index_t *)base)->string_idx];
+
+    return string_cmpf(k, b);
+}
+
+static inkpot_scheme_index_t *inkpot_find_scheme_index ( const char *scheme )
+{
+    if (scheme == NULL)
+        return NULL;
+    return (inkpot_scheme_index_t *) bsearch(
+            (void*)scheme, (void*)TAB_SCHEMES_INDEX,
+            SZT_SCHEMES_INDEX, sizeof(inkpot_scheme_index_t),
+            inkpot_scheme_index_cmpf); 
+}
+
+inkpot_status_t inkpot_clear ( inkpot_t *inkpot)
+{
+    inkpot->scheme_bits = 0;  /* clear schemes */
+    inkpot->scheme_index = NULL;
+    inkpot->name = NULL;     /* clear cached value */
+    return INKPOT_SUCCESS;
+}
+
+inkpot_status_t inkpot_init ( inkpot_t **inkpot)
+{
+    *inkpot = malloc(sizeof(inkpot_t));
+    if (*inkpot == NULL)
+       return INKPOT_MALLOC_FAIL;
+    return inkpot_clear ( *inkpot );
+}
+
+inkpot_status_t inkpot_add ( inkpot_t *inkpot, const char *scheme )
+{
+    inkpot_scheme_name_t *inkpot_scheme_name;
+    inkpot_scheme_index_t *inkpot_scheme_index;
+    IDX_SCHEMES_NAME idx;
+
+    if (scheme == NULL)
+       return INKPOT_SCHEME_UNKNOWN;
+    inkpot_scheme_name = inkpot_find_scheme_name(scheme);
+    if (inkpot_scheme_name) {
+        idx = inkpot_scheme_name - TAB_SCHEMES_NAME;
+        if (! inkpot->scheme_bits) {
+            inkpot->default_scheme_name_idx = idx; /* first scheme is default */
+            inkpot->default_value_idx = TAB_NAMES[inkpot_scheme_name->default_name_idx].value_idx;
+            inkpot->first_name_idx = inkpot_scheme_name->first_name_idx;
+            inkpot->last_name_idx = inkpot_scheme_name->last_name_idx;
+        }
+        else {
+                inkpot->first_name_idx = MIN(inkpot->first_name_idx, inkpot_scheme_name->first_name_idx);
+                inkpot->last_name_idx = MAX(inkpot->last_name_idx, inkpot_scheme_name->last_name_idx);
+        }
+       if (! (inkpot->scheme_bits & (1 << idx))) {
+               inkpot->scheme_bits |= 1 << idx;
+               inkpot->name = NULL;     /* clear cached value */
+       }
+    }
+    else {
+       inkpot_scheme_index = inkpot_find_scheme_index(scheme);
+       if (! inkpot_scheme_index)
+            return INKPOT_SCHEME_UNKNOWN;
+       if (inkpot->scheme_index != inkpot_scheme_index) {
+            if (inkpot->scheme_index)
+                return INKPOT_MAX_ONE_INDEXED_SCHEME;
+            inkpot->scheme_index = inkpot_scheme_index;
+           if (! inkpot->scheme_bits ) {
+               /* Set a default color from an index scheme only if no named schemes
+                * have been specified yet. Will be overwritten by the default of the
+                * first name scheme if given later */
+               inkpot->default_value_idx = TAB_IXVALUES[inkpot_scheme_index->first_value_idx];
+           }
+           inkpot->name = NULL;     /* clear cached value */
+       }
+    }
+    return INKPOT_SUCCESS;
+}
+static int inkpot_name_cmpf ( const void *key, const void *base)
+{
+    const char *k = (const char*)key;
+    const char *b = &TAB_STRINGS[((inkpot_name_t *)base)->string_idx];
+
+    return string_cmpf(k, b);
+}
+
+static inkpot_status_t inkpot_find_name ( inkpot_t *inkpot, const char *color )
+{
+    inkpot_name_t *name;
+    const char *last_name;
+    IDX_NAMES j;
+    IDX_STRINGS k;
+
+    if (inkpot == NULL)
+        return INKPOT_SCHEME_UNKNOWN;
+    if (name == NULL)
+        return INKPOT_COLOR_UNKNOWN;
+    if (! inkpot->name  /* if we can't use the last result */
+               || ! ((last_name = &TAB_STRINGS[inkpot->name->string_idx]))
+               || ( last_name[0] != color[0] )
+               || ( strcmp(last_name, color) != 0)) {
+        name = (inkpot_name_t *) bsearch(  /* then do a fresh search */
+            (void*)color, (void*)(&TAB_NAMES[inkpot->first_name_idx]),
+            inkpot->last_name_idx + 1 - inkpot->first_name_idx,
+            sizeof(inkpot_name_t), inkpot_name_cmpf); 
+       if (name == NULL) 
+            return INKPOT_COLOR_UNKNOWN;
+       
+       j = name - TAB_NAMES;
+       k = TAB_NAMES[j].string_idx;
+       while ( j < SZT_NAMES && k == TAB_NAMES[j].string_idx && ! (inkpot->scheme_bits & TAB_NAMES[j].scheme_bits)) {
+           /* There can be multiple entries for the same
+             * color string with different values. Linearly search
+             * through them for the first one in the requested scheme(s) */
+            j++;
+       }
+       if (k != TAB_NAMES[j].string_idx || j == SZT_NAMES)
+           return INKPOT_COLOR_UNKNOWN;
+       inkpot->name = &TAB_NAMES[j];  /* cache name resolution */
+    }
+    inkpot->value = &TAB_VALUES[inkpot->name->value_idx];
+    return INKPOT_SUCCESS;
+}
+
+static inkpot_status_t inkpot_find_index ( inkpot_t *inkpot, int index )
+{
+    inkpot_scheme_index_t *scheme_index;
+    IDX_SCHEMES_INDEX j;
+    IDX_IXVALUES first, last;
+
+    scheme_index = inkpot->scheme_index;
+    if (!scheme_index)
+        return INKPOT_SCHEME_UNKNOWN;
+
+    first = scheme_index->first_value_idx;
+    j = scheme_index - TAB_SCHEMES_INDEX;
+    if (++j >= SZT_SCHEMES_INDEX)
+       last = SZT_IXVALUES;
+    else
+       last = TAB_SCHEMES_INDEX[j].first_value_idx;
+
+    /* clip user-provided index to fit available range */
+    index = MAX(index, 0);
+    index = MIN(index, (last-1-first));
+    index += first;
+
+    assert(index < SZT_IXVALUES);
+    assert(TAB_IXVALUES[index] < SZT_VALUES);
+    inkpot->value = &TAB_VALUES[TAB_IXVALUES[index]];
+    return INKPOT_SUCCESS;
+}
+
+inkpot_status_t inkpot_find( inkpot_t *inkpot, const char *color )
+{
+    int index;
+    inkpot_status_t rc = INKPOT_COLOR_UNKNOWN;
+
+    if (color && sscanf(color, "%d", &index) == 1)
+        rc = inkpot_find_index(inkpot, index);
+
+    if (rc != INKPOT_SUCCESS)
+        rc = inkpot_find_name(inkpot, color);
+
+    return rc;
+}
+
+inkpot_status_t inkpot_find_default( inkpot_t *inkpot )
+{
+    inkpot->value = &TAB_VALUES[inkpot->default_value_idx];
+    return INKPOT_SUCCESS;
+}
+
+static int inkpot_value_cmpf ( const void *key, const void *base)
+{
+    inkpot_value_t *cv_key = (inkpot_value_t*)key;
+    inkpot_value_t *cv_base = (inkpot_value_t*)base;
+
+    if (cv_key->r > cv_base->r) return 1;
+    if (cv_key->r < cv_base->r) return -1;
+    if (cv_key->g > cv_base->g) return 1;
+    if (cv_key->g < cv_base->g) return -1;
+    if (cv_key->b > cv_base->b) return 1;
+    if (cv_key->b < cv_base->b) return -1;
+    if (cv_key->a > cv_base->a) return 1;
+    if (cv_key->a < cv_base->a) return -1;
+    return 0;
+}
+
+static int inkpot_find_value ( inkpot_t *inkpot ) 
+{
+    inkpot_value_t *rc, *value = inkpot->value;
+    inkpot_name_t *name;
+    inkpot_scheme_index_t *scheme_index;
+    IDX_VALUES value_idx;
+    IDX_NAMES i;
+    IDX_IXVALUES k, first, last;
+    IDX_SCHEMES_INDEX j;
+
+    if (! inkpot->value->is_named) {
+       rc = (inkpot_value_t *) bsearch(
+            (void*)(value), (void*)TAB_VALUES,
+            SZT_VALUES, sizeof(inkpot_value_t),
+            inkpot_value_cmpf); 
+        if (rc)
+           inkpot->value->is_named = 1;
+    }
+    if (inkpot->value->is_named) {
+       value_idx = value - TAB_VALUES;
+        for (i = value->toname_idx; i < SZT_NAMES; i++) {
+            name = &TAB_NAMES[TAB_NAMES[i].toname_idx];
+            if (name->value_idx != value_idx)
+                break;
+            if (name->scheme_bits & inkpot->scheme_bits) {
+               inkpot->name = name;
+               return INKPOT_SUCCESS;
+            }
+        }
+        scheme_index = inkpot->scheme_index;
+        if (scheme_index) {
+
+           first = scheme_index->first_value_idx;
+           j = scheme_index - TAB_SCHEMES_INDEX;
+           if (++j >= SZT_SCHEMES_INDEX)
+               last = SZT_IXVALUES;
+           else
+               last = TAB_SCHEMES_INDEX[j].first_value_idx;
+
+            for (k = first; k < last; k++) {
+                if (TAB_IXVALUES[k] == value_idx) {
+                   inkpot->name = NULL;
+                   inkpot->index = k - first;
+                    return INKPOT_SUCCESS;
+                }
+            }
+        }
+    }
+    return INKPOT_COLOR_UNKNOWN;
+}
+
+void inkpot_get_rgba ( inkpot_t *inkpot, unsigned int *r, unsigned int *g, unsigned int *b, unsigned int *a)
+{
+    unsigned char *t = &(inkpot->value->r);
+
+    if (r) *r = *t; t++;
+    if (g) *g = *t; t++;
+    if (b) *b = *t; t++;
+    if (a) *a = *t; t++;
+}
+
+void inkpot_get_hsva ( inkpot_t *inkpot, unsigned int *h, unsigned int *s, unsigned int *v, unsigned int *a)
+{
+    unsigned char *t = &(inkpot->value->a);
+
+    if (a) *a = *t; t++;
+    if (h) *h = *t; t++;
+    if (s) *s = *t; t++;
+    if (v) *v = *t; t++;
+}
+
+inkpot_status_t inkpot_xlate(inkpot_t *from_scheme, inkpot_t *to_scheme)
+{
+    return inkpot_find_value(to_scheme);
+}
+
+void inkpot_print_schemes( inkpot_t *inkpot )
+{
+    IDX_SCHEMES_NAME i;
+
+    fprintf(stderr, "schemes:\n");
+    for (i = 0; i < SZT_SCHEMES_NAME; i++) {
+        if ((1<<i) & inkpot->scheme_bits) {
+            fprintf (stderr, "%s", &TAB_STRINGS[TAB_SCHEMES_NAME[i].string_idx]);
+            if (i == inkpot->default_scheme_name_idx) 
+                fprintf (stderr, " (default)");
+            fprintf (stderr, "\n");
+        }
+    }
+    if (inkpot->scheme_index)
+        fprintf (stderr, "%s (indexed)\n", &TAB_STRINGS[inkpot->scheme_index->string_idx]);
+    fprintf(stderr, "\n");
+}
+
+static void inkpot_print_scheme_names( inkpot_t *inkpot, int scheme_bits)
+{
+    IDX_SCHEMES_NAME i;
+    int found = 0;
+
+    fprintf(stderr, "(");
+    for (i = 0; i < SZT_SCHEMES_NAME; i++) {
+        if ((1 << i) & scheme_bits) {
+            if (found++)
+                fprintf(stderr, " ");
+            fprintf (stderr, "%s", &TAB_STRINGS[TAB_SCHEMES_NAME[i].string_idx]);
+        }
+    }
+    fprintf(stderr, ")");
+}
+
+static void inkpot_print_rgba_value( inkpot_value_t *value )
+{
+    fprintf (stderr, "%d,%d,%d,%d",
+       value->r, value->g, value->b, value->a);
+}
+
+void inkpot_print_rgba( inkpot_t *inkpot )
+{
+    inkpot_print_rgba_value( inkpot->value );
+}
+
+static void inkpot_print_hsva_value(inkpot_value_t *value )
+{
+    fprintf (stderr, " %d,%d,%d,%d\n",
+       value->h, value->s, value->v, value->a);
+}
+
+void inkpot_print_hsva( inkpot_t *inkpot )
+{
+    inkpot_print_hsva_value( inkpot->value );
+}
+
+void inkpot_print_names( inkpot_t *inkpot )
+{
+    inkpot_name_t *name;
+    inkpot_value_t *value;
+    inkpot_scheme_index_t *scheme_index;
+    IDX_NAMES i;
+    IDX_SCHEMES_INDEX j;
+    BIT_SCHEMES_NAME inkpot_scheme_bits, scheme_bits;
+    IDX_IXVALUES k, first, last;
+
+    fprintf(stderr, "names:\n");
+    inkpot_scheme_bits = inkpot->scheme_bits;
+    if (inkpot_scheme_bits) {
+        for (i = 0; i < SZT_NAMES; i++) {
+            name = &TAB_NAMES[i];
+           scheme_bits = name->scheme_bits & inkpot_scheme_bits;
+            if (scheme_bits) {
+                value = &TAB_VALUES[name->value_idx];
+                fprintf(stderr, "%s", &TAB_STRINGS[TAB_NAMES[i].string_idx]);
+               inkpot_print_scheme_names(inkpot, scheme_bits);
+               fprintf(stderr, " ");
+               inkpot_print_rgba_value(value);
+               fprintf(stderr, "\n");
+            }
+        }
+    }
+    scheme_index = inkpot->scheme_index;
+    if (scheme_index) {
+
+       first = scheme_index->first_value_idx;
+       j = scheme_index - TAB_SCHEMES_INDEX;
+       if (++j >= SZT_SCHEMES_INDEX)
+           last = SZT_IXVALUES;
+       else
+           last = TAB_SCHEMES_INDEX[j].first_value_idx;
+
+       for (k = first; k < last; k++) {
+           value = &TAB_VALUES[TAB_IXVALUES[j]];
+           fprintf (stderr, "%d(%s) ", k - first , &TAB_STRINGS[scheme_index->string_idx]);
+           inkpot_print_rgba_value(value);
+           fprintf(stderr, "\n");
+       }
+    }
+    fprintf(stderr, "\n");
+}
+
+void inkpot_print_values( inkpot_t *inkpot )
+{
+    inkpot_value_t *value;
+    inkpot_name_t *name;
+    inkpot_scheme_index_t *scheme_index;
+    IDX_VALUES i;
+    IDX_NAMES t;
+    BIT_SCHEMES_NAME scheme_bits;
+    IDX_SCHEMES_INDEX j;
+    IDX_IXVALUES k, first, last;
+    int found;
+
+    fprintf(stderr, "values:\n");
+    for (i = 0; i < SZT_VALUES; i++) {
+        value = &TAB_VALUES[i];
+        found = 0;
+        for (t = value->toname_idx; t < SZT_NAMES; t++) {
+            name = &TAB_NAMES[TAB_NAMES[t].toname_idx];
+            if (name->value_idx != i)
+                break;
+            scheme_bits = name->scheme_bits & inkpot->scheme_bits;
+            if (scheme_bits) {
+                if (found++)
+                    fprintf(stderr, " ");
+                else
+                   inkpot_print_rgba_value(value);
+                fprintf(stderr, " %s", &TAB_STRINGS[name->string_idx]);
+               inkpot_print_scheme_names(inkpot, scheme_bits);
+            }
+        }
+        scheme_index = inkpot->scheme_index;
+        if (scheme_index) {
+
+           first = scheme_index->first_value_idx;
+           j = scheme_index - TAB_SCHEMES_INDEX;
+           if (++j >= SZT_SCHEMES_INDEX)
+               last = SZT_IXVALUES;
+           else
+               last = TAB_SCHEMES_INDEX[j].first_value_idx;
+
+            for (k = first; k < last; k++) {
+                if (TAB_IXVALUES[k] == i) {
+                    if (found++)
+                        fprintf(stderr, " ");
+                    else {
+                       inkpot_print_rgba_value(value);
+                        fprintf(stderr, " ");
+                   }
+                    fprintf(stderr, "%d(%s)", k - first, &TAB_STRINGS[scheme_index->string_idx]);
+                    break;
+                }
+            }
+        }
+        if (found)
+            fprintf(stderr, "\n");
+    }
+    fprintf(stderr, "\n");
+}
diff --git a/lib/inkpot/inkpot_xlate.c b/lib/inkpot/inkpot_xlate.c
new file mode 100644 (file)
index 0000000..9f9068f
--- /dev/null
@@ -0,0 +1,480 @@
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef WIN32
+#include "compat.h"
+#endif
+
+#include "inkpot.h"
+
+static inkpot_t *inkpot;
+static const char *colorscheme;
+
+#ifdef WIN32
+extern int strcasecmp(const char *s1, const char *s2);
+extern int strncasecmp(const char *s1, const char *s2, unsigned int n);
+#endif
+
+static void hsv2rgb(double h, double s, double v, double *r, double *g, double *b)
+{
+    int i;
+    double f, p, q, t;
+
+    if (s <= 0.0) {            /* achromatic */
+       *r = v;
+       *g = v;
+       *b = v;
+    } else {
+       if (h >= 1.0)
+           h = 0.0;
+       h = 6.0 * h;
+       i = (int) h;
+       f = h - (double) i;
+       p = v * (1 - s);
+       q = v * (1 - (s * f));
+       t = v * (1 - (s * (1 - f)));
+       switch (i) {
+       case 0:
+           *r = v;
+           *g = t;
+           *b = p;
+           break;
+       case 1:
+           *r = q;
+           *g = v;
+           *b = p;
+           break;
+       case 2:
+           *r = p;
+           *g = v;
+           *b = t;
+           break;
+       case 3:
+           *r = p;
+           *g = q;
+           *b = v;
+           break;
+       case 4:
+           *r = t;
+           *g = p;
+           *b = v;
+           break;
+       case 5:
+           *r = v;
+           *g = p;
+           *b = q;
+           break;
+       }
+    }
+}
+
+static void rgb2hsv(double r, double g, double b, double *h, double *s, double *v)
+{
+
+    double rgbmin, rgbmax;
+    double rc, bc, gc;
+    double ht = 0.0, st = 0.0;
+
+    rgbmin = MIN(r, MIN(g, b));
+    rgbmax = MAX(r, MAX(g, b));
+
+    if (rgbmax > 0.0)
+       st = (rgbmax - rgbmin) / rgbmax;
+
+    if (st > 0.0) {
+       rc = (rgbmax - r) / (rgbmax - rgbmin);
+       gc = (rgbmax - g) / (rgbmax - rgbmin);
+       bc = (rgbmax - b) / (rgbmax - rgbmin);
+       if (r == rgbmax)
+           ht = bc - gc;
+       else if (g == rgbmax)
+           ht = 2 + rc - bc;
+       else if (b == rgbmax)
+           ht = 4 + gc - rc;
+       ht = ht * 60.0;
+       if (ht < 0.0)
+           ht += 360.0;
+    }
+    *h = ht / 360.0;
+    *v = rgbmax;
+    *s = st;
+}
+
+static void rgb2cmyk(double r, double g, double b, double *c, double *m, double *y, double *k)
+{
+    *c = 1.0 - r;
+    *m = 1.0 - g;
+    *y = 1.0 - b;
+    *k = *c < *m ? *c : *m;
+    *k = *y < *k ? *y : *k;
+    *c -= *k;
+    *m -= *k;
+    *y -= *k;
+}
+
+char *canontoken(const char *str)
+{
+    static char *canon;
+    static int allocated;
+    const char *p;
+    char *q, c;
+    int len;
+
+    p = str;
+    len = strlen(str);
+    if (len >= allocated) {
+       allocated = len + 1 + 10;
+       canon = realloc(canon, allocated);
+       if (!canon)
+           return NULL;
+    }
+    q = canon;
+    while ((c = *p++)) {
+       /* if (isalnum(c) == FALSE) */
+           /* continue; */
+       if (isupper(c))
+           c = tolower(c);
+       *q++ = c;
+    }
+    *q = '\0';
+    return canon;
+}
+
+/* fullColor:
+ * Return "/prefix/str"
+ */
+static char* fullColor (const char* prefix, const char* str)
+{
+    static char *fulls;
+    static int allocated;
+    int len = strlen (prefix) + strlen (str) + 3;
+
+    if (len >= allocated) {
+       allocated = len + 10;
+       fulls = realloc(fulls, allocated);
+    }
+    sprintf (fulls, "/%s/%s", prefix, str);
+    return fulls;
+}
+
+/* resolveColor:
+ * Resolve input color str allowing color scheme namespaces.
+ *  0) "black" => "black" 
+ *    NB: This is something of a hack due to the remaining codegen.
+ *        Once these are gone, this case could be removed and all references
+ *        to "black" could be replaced by "/x11/black".
+ *  1) No initial / => 
+ *          if colorscheme is defined and no "x11", return /colorscheme/str
+ *          else return str
+ *  2) One initial / => return str+1
+ *  3) Two initial /'s =>
+ *       a) If colorscheme is defined and not "x11", return /colorscheme/(str+2)
+ *       b) else return (str+2)
+ *  4) Two /'s, not both initial => return str.
+ *
+ * Note that 1), 2), and 3b) allow the default x11 color scheme. 
+ *
+ * In other words,
+ *   xxx => /colorscheme/xxx     if colorscheme is defined and not "x11"
+ *   xxx => xxx                  otherwise
+ *   /xxx => xxx
+ *   /x11/yyy => yyy
+ *   /xxx/yyy => /xxx/yyy
+ *   //yyy => /colorscheme/yyy   if colorscheme is defined and not "x11"
+ *   //yyy => yyy                otherwise
+ * 
+ * At present, no other error checking is done. For example, 
+ * yyy could be "". This will be caught later.
+ */
+
+#define DFLT_SCHEME "x11/"      /* Must have final '/' */
+#define DFLT_SCHEME_LEN ((sizeof(DFLT_SCHEME)-1)/sizeof(char))
+#define ISNONDFLT(s) ((s) && *(s) && strncasecmp(DFLT_SCHEME, s, DFLT_SCHEME_LEN-1))
+
+static char* resolveColor (const char* str)
+{
+    const char* s;
+    const char* ss;   /* second slash */
+    const char* c2;   /* second char */
+
+    if ((*str == 'b') || !strncmp(str+1,"lack",4)) return (char*)str;
+    else if (*str == '/') {   /* if begins with '/' */
+       c2 = str+1;
+        if ((ss = strchr(c2, '/'))) {  /* if has second '/' */
+           if (*c2 == '/') {    /* if second '/' is second character */
+                   /* Do not compare against final '/' */
+               if (ISNONDFLT(colorscheme))
+                   s = fullColor (colorscheme, c2+1);
+               else
+                   s = c2+1;
+           }
+           else if (strncasecmp(DFLT_SCHEME, c2, DFLT_SCHEME_LEN)) s = str;
+           else s = ss + 1;
+       }
+       else s = c2;
+    }
+    else if (ISNONDFLT(colorscheme)) s = fullColor (colorscheme, str);
+    else s = str;
+    return canontoken(s);
+}
+
+inkpot_status_t colorxlate(const char *str, gvcolor_t * color, color_type_t target_type)
+{
+    static unsigned char *canon;
+    static int allocated;
+    unsigned char *p, *q;
+    unsigned char c;
+    double H, S, V, A, R, G, B;
+    double C, M, Y, K;
+    unsigned int r, g, b, a, h, s, v;
+    int len;
+    inkpot_status_t rc;
+    const char *key;
+
+    color->type = target_type;
+
+    rc = INKPOT_SUCCESS;
+    for (; *str == ' '; str++);        /* skip over any leading whitespace */
+    p = (unsigned char *) str;
+
+    /* test for rgb value such as: "#ff0000"
+     * or rgba value such as "#ff000080" */
+    a = 255;                   /* default alpha channel value=opaque in case not supplied */
+    if ((*p == '#')
+       && (sscanf((char *) p, "#%2x%2x%2x%2x", &r, &g, &b, &a) >= 3)) {
+       switch (target_type) {
+       case HSVA_DOUBLE:
+           R = r / 255.0;
+           G = g / 255.0;
+           B = b / 255.0;
+           A = a / 255.0;
+           rgb2hsv(R, G, B, &H, &S, &V);
+           color->u.HSVA[0] = H;
+           color->u.HSVA[1] = S;
+           color->u.HSVA[2] = V;
+           color->u.HSVA[3] = A;
+           break;
+       case RGBA_BYTE:
+           color->u.rgba[0] = r;
+           color->u.rgba[1] = g;
+           color->u.rgba[2] = b;
+           color->u.rgba[3] = a;
+           break;
+       case CMYK_BYTE:
+           R = r / 255.0;
+           G = g / 255.0;
+           B = b / 255.0;
+           rgb2cmyk(R, G, B, &C, &M, &Y, &K);
+           color->u.cmyk[0] = (int) C *255;
+           color->u.cmyk[1] = (int) M *255;
+           color->u.cmyk[2] = (int) Y *255;
+           color->u.cmyk[3] = (int) K *255;
+           break;
+       case RGBA_WORD:
+           color->u.rrggbbaa[0] = r * 65535 / 255;
+           color->u.rrggbbaa[1] = g * 65535 / 255;
+           color->u.rrggbbaa[2] = b * 65535 / 255;
+           color->u.rrggbbaa[3] = a * 65535 / 255;
+           break;
+       case RGBA_DOUBLE:
+           color->u.RGBA[0] = r / 255.0;
+           color->u.RGBA[1] = g / 255.0;
+           color->u.RGBA[2] = b / 255.0;
+           color->u.RGBA[3] = a / 255.0;
+           break;
+       case COLOR_STRING:
+           break;
+       case COLOR_INDEX:
+           break;
+       }
+       return rc;
+    }
+
+    /* test for hsv value such as: ".6,.5,.3" */
+    if (((c = *p) == '.') || isdigit(c)) {
+       len = strlen((char*)p);
+       if (len >= allocated) {
+           allocated = len + 1 + 10;
+           canon = realloc(canon, allocated);
+           if (! canon) {
+               rc = INKPOT_MALLOC_FAIL;
+               return rc;
+           }
+       }
+       q = canon;
+       while ((c = *p++)) {
+           if (c == ',')
+               c = ' ';
+           *q++ = c;
+       }
+       *q = '\0';
+
+       A = 1.0; /* default alpha channel value=opaque in case not supplied */
+       if (sscanf((char *) canon, "%lf%lf%lf%lf", &H, &S, &V, &A) >= 3) {
+           /* clip to reasonable values */
+           H = MAX(MIN(H, 1.0), 0.0);
+           S = MAX(MIN(S, 1.0), 0.0);
+           V = MAX(MIN(V, 1.0), 0.0);
+           A = MAX(MIN(A, 1.0), 0.0);
+           switch (target_type) {
+           case HSVA_DOUBLE:
+               color->u.HSVA[0] = H;
+               color->u.HSVA[1] = S;
+               color->u.HSVA[2] = V;
+               color->u.HSVA[3] = A;
+               break;
+           case RGBA_BYTE:
+               hsv2rgb(H, S, V, &R, &G, &B);
+               color->u.rgba[0] = (int) (R * 255);
+               color->u.rgba[1] = (int) (G * 255);
+               color->u.rgba[2] = (int) (B * 255);
+               color->u.rgba[3] = (int) (A * 255);
+               break;
+           case CMYK_BYTE:
+               hsv2rgb(H, S, V, &R, &G, &B);
+               rgb2cmyk(R, G, B, &C, &M, &Y, &K);
+               color->u.cmyk[0] = (int) C *255;
+               color->u.cmyk[1] = (int) M *255;
+               color->u.cmyk[2] = (int) Y *255;
+               color->u.cmyk[3] = (int) K *255;
+               break;
+           case RGBA_WORD:
+               hsv2rgb(H, S, V, &R, &G, &B);
+               color->u.rrggbbaa[0] = (int) (R * 65535);
+               color->u.rrggbbaa[1] = (int) (G * 65535);
+               color->u.rrggbbaa[2] = (int) (B * 65535);
+               color->u.rrggbbaa[3] = (int) (A * 65535);
+               break;
+           case RGBA_DOUBLE:
+               hsv2rgb(H, S, V, &R, &G, &B);
+               color->u.RGBA[0] = R;
+               color->u.RGBA[1] = G;
+               color->u.RGBA[2] = B;
+               color->u.RGBA[3] = A;
+               break;
+           case COLOR_STRING:
+               break;
+           case COLOR_INDEX:
+               break;
+           }
+           return rc;
+       }
+    }
+
+    /* test for known color name */
+//    key = resolveColor(str);
+    key = str;
+    rc = inkpot_find(inkpot, key);
+    if (rc == INKPOT_SUCCESS) {
+       switch (target_type) {
+       case HSVA_DOUBLE:
+           inkpot_get_hsva(inkpot, &h, &s, &v, &a);
+           color->u.HSVA[0] = h / 255.0;
+           color->u.HSVA[1] = s / 255.0;
+           color->u.HSVA[2] = v / 255.0;
+           color->u.HSVA[3] = a / 255.0;
+           break;
+       case RGBA_BYTE:
+           inkpot_get_rgba(inkpot, &r, &g, &b, &a);
+           color->u.rgba[0] = r;
+           color->u.rgba[1] = g;
+           color->u.rgba[2] = b;
+           color->u.rgba[3] = a;
+           break;
+       case CMYK_BYTE:
+           inkpot_get_rgba(inkpot, &r, &g, &b, &a);
+           R = r / 255.0;
+           G = g / 255.0;
+           B = b / 255.0;
+           rgb2cmyk(R, G, B, &C, &M, &Y, &K);
+           color->u.cmyk[0] = (int) C * 255;
+           color->u.cmyk[1] = (int) M * 255;
+           color->u.cmyk[2] = (int) Y * 255;
+           color->u.cmyk[3] = (int) K * 255;
+           break;
+       case RGBA_WORD:
+           inkpot_get_rgba(inkpot, &r, &g, &b, &a);
+           color->u.rrggbbaa[0] = r * 65535 / 255;
+           color->u.rrggbbaa[1] = g * 65535 / 255;
+           color->u.rrggbbaa[2] = b * 65535 / 255;
+           color->u.rrggbbaa[3] = a * 65535 / 255;
+           break;
+       case RGBA_DOUBLE:
+           inkpot_get_rgba(inkpot, &r, &g, &b, &a);
+           color->u.RGBA[0] = r / 255.0;
+           color->u.RGBA[1] = g / 255.0;
+           color->u.RGBA[2] = b / 255.0;
+           color->u.RGBA[3] = a / 255.0;
+           break;
+       case COLOR_STRING:
+           break;
+       case COLOR_INDEX:
+           break;
+       }
+       return rc;
+    }
+
+    /* if we're still here then we failed to find a valid color spec */
+    rc = INKPOT_COLOR_UNKNOWN;
+    switch (target_type) {
+    case HSVA_DOUBLE:
+       color->u.HSVA[0] = color->u.HSVA[1] = color->u.HSVA[2] = 0.0;
+       color->u.HSVA[3] = 1.0; /* opaque */
+       break;
+    case RGBA_BYTE:
+       color->u.rgba[0] = color->u.rgba[1] = color->u.rgba[2] = 0;
+       color->u.rgba[3] = 255; /* opaque */
+       break;
+    case CMYK_BYTE:
+       color->u.cmyk[0] =
+           color->u.cmyk[1] = color->u.cmyk[2] = color->u.cmyk[3] = 0;
+       break;
+    case RGBA_WORD:
+       color->u.rrggbbaa[0] = color->u.rrggbbaa[1] = color->u.rrggbbaa[2] = 0;
+       color->u.rrggbbaa[3] = 65535;   /* opaque */
+       break;
+    case RGBA_DOUBLE:
+       color->u.RGBA[0] = color->u.RGBA[1] = color->u.RGBA[2] = 0.0;
+       color->u.RGBA[3] = 1.0; /* opaque */
+       break;
+    case COLOR_STRING:
+       break;
+    case COLOR_INDEX:
+       break;
+    }
+    return rc;
+}
+
+/* setColorScheme:
+ * Set current color scheme for resolving names.
+ */
+int setColorScheme (const char* scheme)
+{
+    inkpot_status_t rc;
+
+    colorscheme = scheme;
+    rc = inkpot_init(&inkpot);
+    if (rc != INKPOT_SUCCESS)
+       return rc;
+    return inkpot_add(inkpot, scheme);
+}
+
+
+