#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "Xlibint.h"
#include "Xcmsint.h"
#include <X11/Xos.h>
#include <sys/stat.h>
#include <stdio.h>
#include <ctype.h>
#define XK_LATIN1
#include <X11/keysymdef.h>
#include "Cv.h"
static Status LoadColornameDB(void);
#ifndef XCMSDB
#define XCMSDB "/usr/lib/X11/Xcms.txt"
#endif
#ifndef isgraph
# define isgraph(c) (isprint((c)) && !isspace((c)))
#endif
#ifndef XCMSDB_MAXLINELEN
# define XCMSDB_MAXLINELEN 256
#endif
#define FORMAT_VERSION "0.1"
#define START_TOKEN "XCMS_COLORDB_START"
#define END_TOKEN "XCMS_COLORDB_END"
#define DELIM_CHAR '\t'
#define NOT_VISITED 0x0
#define VISITED 0x1
#define CYCLE 0xFFFF
#define XcmsDbInitNone -1
#define XcmsDbInitFailure 0
#define XcmsDbInitSuccess 1
typedef struct _XcmsPair {
const char *first;
const char *second;
int flag;
} XcmsPair;
static int XcmsColorDbState = XcmsDbInitNone;
static int nEntries;
static char *strings;
static XcmsPair *pairs;
static const char whitePtStr[] = "WhitePoint";
static XcmsColorSpace *
_XcmsColorSpaceOfString(
XcmsCCC ccc,
const char *color_string)
{
XcmsColorSpace **papColorSpaces;
int n;
char *pchar;
if ((pchar = strchr(color_string, ':')) == NULL) {
return(XcmsFailure);
}
n = (int)(pchar - color_string);
if (ccc == NULL) {
return(NULL);
}
papColorSpaces = _XcmsDIColorSpaces;
if (papColorSpaces != NULL) {
while (*papColorSpaces != NULL) {
if (strncmp((*papColorSpaces)->prefix, color_string, n) == 0 &&
!((*papColorSpaces)->prefix)[n]) {
return(*papColorSpaces);
}
papColorSpaces++;
}
}
papColorSpaces = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
if (papColorSpaces != NULL) {
while (*papColorSpaces != NULL) {
if (strncmp((*papColorSpaces)->prefix, color_string, n) == 0 &&
!((*papColorSpaces)->prefix)[n]) {
return(*papColorSpaces);
}
papColorSpaces++;
}
}
return(NULL);
}
static int
_XcmsParseColorString(
XcmsCCC ccc,
const char *color_string,
XcmsColor *pColor)
{
XcmsColorSpace *pColorSpace;
char string_buf[64];
char *string_lowered;
int len;
int res;
if (ccc == NULL) {
return(0);
}
if ((len = strlen(color_string)) >= sizeof(string_buf)) {
string_lowered = (char *) Xmalloc(len+1);
} else {
string_lowered = string_buf;
}
_XcmsCopyISOLatin1Lowered(string_lowered, color_string);
if (*string_lowered == '#') {
if ((pColorSpace = _XcmsColorSpaceOfString(ccc, "rgb:")) != NULL) {
res = (*pColorSpace->parseString)(string_lowered, pColor);
if (len >= sizeof(string_buf)) Xfree(string_lowered);
return res;
}
}
if ((pColorSpace = _XcmsColorSpaceOfString(ccc, string_lowered)) != NULL) {
res = (*pColorSpace->parseString)(string_lowered, pColor);
if (len >= sizeof(string_buf)) Xfree(string_lowered);
return res;
}
if (len >= sizeof(string_buf)) Xfree(string_lowered);
return(0);
}
static int
FirstCmp(const void *p1, const void *p2)
{
return(strcmp(((XcmsPair *)p1)->first, ((XcmsPair *)p2)->first));
}
static void
SetNoVisit(void)
{
int i;
XcmsPair *pair = pairs;
for (i = 0; i < nEntries; i++, pair++) {
if (pair->flag != CYCLE) {
pair->flag = NOT_VISITED;
}
}
}
static int
field2(
char *pBuf,
char delim,
char **p1,
char **p2)
{
*p1 = *p2 = NULL;
while (!isgraph(*pBuf)) {
if ((*pBuf != '\n') || (*pBuf != '\0')) {
return(XcmsFailure);
}
if (isspace(*pBuf) || (*pBuf == delim)) {
pBuf++;
}
}
*p1 = pBuf;
while (isprint(*pBuf) && (*pBuf != delim)) {
pBuf++;
}
if ((*pBuf == '\n') || (*pBuf == '\0')) {
return(XcmsFailure);
}
if ((*pBuf == ' ') || (*pBuf == delim)) {
*pBuf++ = '\0';
} else {
return(XcmsFailure);
}
while (!isgraph(*pBuf)) {
if ((*pBuf == '\n') || (*pBuf == '\0')) {
return(XcmsFailure);
}
if (isspace(*pBuf) || (*pBuf == delim)) {
pBuf++;
}
}
*p2 = pBuf;
while (isprint(*pBuf) && (*pBuf != delim)) {
pBuf++;
}
if (*pBuf != '\0') {
*pBuf = '\0';
}
return(XcmsSuccess);
}
static Status
_XcmsLookupColorName(
XcmsCCC ccc,
const char **name,
XcmsColor *pColor)
{
Status retval = 0;
char name_lowered_64[64];
char *name_lowered;
register int i, j, left, right;
int len;
const char *tmpName;
XcmsPair *pair = NULL;
if (XcmsColorDbState == XcmsDbInitFailure) {
return(XcmsFailure);
}
if (XcmsColorDbState == XcmsDbInitNone) {
if (!LoadColornameDB()) {
return(XcmsFailure);
}
}
SetNoVisit();
tmpName = *name;
Retry:
if ((len = strlen(tmpName)) > 63) {
name_lowered = (char *) Xmalloc(len+1);
} else {
name_lowered = name_lowered_64;
}
_XcmsCopyISOLatin1Lowered(name_lowered, tmpName);
for (i = 0, j = 0; j < len; j++) {
if (!isspace(name_lowered[j])) {
name_lowered[i++] = name_lowered[j];
}
}
name_lowered[i] = '\0';
left = 0;
right = nEntries - 1;
while (left <= right) {
i = (left + right) >> 1;
pair = &pairs[i];
j = strcmp(name_lowered, pair->first);
if (j < 0)
right = i - 1;
else if (j > 0)
left = i + 1;
else {
break;
}
}
if (len > 63) Xfree(name_lowered);
if (left > right) {
if (retval == 2) {
if (*name != tmpName) {
*name = tmpName;
}
return(_XCMS_NEWNAME);
}
return(XcmsFailure);
}
if (pair->flag == CYCLE) {
return(XcmsFailure);
}
if (pair->flag == VISITED) {
pair->flag = CYCLE;
return(XcmsFailure);
}
if (_XcmsParseColorString(ccc, pair->second, pColor) == XcmsSuccess) {
return(XcmsSuccess);
} else {
tmpName = pair->second;
pair->flag = VISITED;
retval = 2;
goto Retry;
}
}
static int
RemoveSpaces(
char *pString)
{
int i, count = 0;
char *cptr;
cptr = pString;
for (i = strlen(pString); i; i--, cptr++) {
if (!isspace(*cptr)) {
*pString++ = *cptr;
count++;
}
}
*pString = '\0';
return(count);
}
static int
stringSectionSize(
FILE *stream,
int *pNumEntries,
int *pSectionSize)
{
char buf[XCMSDB_MAXLINELEN];
char token[XCMSDB_MAXLINELEN];
char token2[XCMSDB_MAXLINELEN];
char *pBuf;
char *f1;
char *f2;
int i;
*pNumEntries = 0;
*pSectionSize = 0;
while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
if ((sscanf(buf, "%s %s", token, token2))
&& (strcmp(token, START_TOKEN) == 0)) {
if (strcmp(token2, FORMAT_VERSION) != 0) {
return(XcmsFailure);
}
break;
}
}
if (pBuf == NULL) {
return(XcmsFailure);
}
while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
if ((sscanf(buf, "%s", token)) && (strcmp(token, END_TOKEN) == 0)) {
break;
}
if (field2(buf, DELIM_CHAR, &f1, &f2) != XcmsSuccess) {
return(XcmsFailure);
}
(*pNumEntries)++;
(*pSectionSize) += (i = strlen(f1)) + 1;
for (; i; i--, f1++) {
if (isspace(*f1)) {
(*pSectionSize)--;
}
}
(*pSectionSize) += (i = strlen(f2)) + 1;
for (; i; i--, f2++) {
if (isspace(*f2)) {
(*pSectionSize)--;
}
}
}
return(XcmsSuccess);
}
static Status
ReadColornameDB(
FILE *stream,
XcmsPair *pRec,
char *pString)
{
char buf[XCMSDB_MAXLINELEN];
char token[XCMSDB_MAXLINELEN];
char token2[XCMSDB_MAXLINELEN];
char *f1;
char *f2;
char *pBuf;
while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
if ((sscanf(buf, "%s %s", token, token2))
&& (strcmp(token, START_TOKEN) == 0)) {
if (strcmp(token2, FORMAT_VERSION) != 0) {
return(XcmsFailure);
}
break;
}
}
if (pBuf == NULL) {
return(XcmsFailure);
}
while ((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
if ((sscanf(buf, "%s", token)) && (strcmp(token, END_TOKEN) == 0)) {
break;
}
if (field2(buf, DELIM_CHAR, &f1, &f2) != XcmsSuccess) {
continue;
}
pRec->first = pString;
_XcmsCopyISOLatin1Lowered(pString, f1);
pString += (1 + RemoveSpaces(pString));
pRec->second = pString;
_XcmsCopyISOLatin1Lowered(pString, f2);
pString += RemoveSpaces(pString) + 1;
pRec++;
}
return(XcmsSuccess);
}
static Status
LoadColornameDB(void)
{
int size;
FILE *stream;
const char *pathname;
struct stat txt;
int length;
if ((pathname = getenv("XCMSDB")) == NULL) {
pathname = XCMSDB;
}
#ifdef __UNIXOS2__
pathname = __XOS2RedirRoot(pathname);
#endif
length = strlen(pathname);
if ((length == 0) || (length >= (BUFSIZ - 5))){
XcmsColorDbState = XcmsDbInitFailure;
return(XcmsFailure);
}
if (stat(pathname, &txt)) {
XcmsColorDbState = XcmsDbInitFailure;
return(XcmsFailure);
}
if ((stream = _XFopenFile (pathname, "r")) == NULL) {
XcmsColorDbState = XcmsDbInitFailure;
return(XcmsFailure);
}
if (stringSectionSize(stream, &nEntries, &size) != XcmsSuccess ||
nEntries == 0) {
(void) fclose(stream);
XcmsColorDbState = XcmsDbInitFailure;
return(XcmsFailure);
}
rewind(stream);
strings = (char *) Xmalloc(size);
pairs = (XcmsPair *)Xcalloc(nEntries, sizeof(XcmsPair));
ReadColornameDB(stream, pairs, strings);
(void) fclose(stream);
qsort((char *)pairs, nEntries, sizeof(XcmsPair), FirstCmp);
XcmsColorDbState = XcmsDbInitSuccess;
return(XcmsSuccess);
}
void
_XcmsCopyISOLatin1Lowered(
char *dst,
const char *src)
{
register unsigned char *dest;
register const unsigned char *source;
for (dest = (unsigned char *)dst, source = (const unsigned char *)src;
*source;
source++, dest++)
{
if ((*source >= XK_A) && (*source <= XK_Z))
*dest = *source + (XK_a - XK_A);
else if ((*source >= XK_Agrave) && (*source <= XK_Odiaeresis))
*dest = *source + (XK_agrave - XK_Agrave);
else if ((*source >= XK_Ooblique) && (*source <= XK_Thorn))
*dest = *source + (XK_oslash - XK_Ooblique);
else
*dest = *source;
}
*dest = '\0';
}
Status
_XcmsResolveColorString (
XcmsCCC ccc,
const char **color_string,
XcmsColor *pColor_exact_return,
XcmsColorFormat result_format)
{
XcmsColor dbWhitePt;
XcmsColor *pClientWhitePt;
int retval;
const char *strptr = whitePtStr;
if (ccc == NULL || (*color_string)[0] == '\0' || pColor_exact_return == NULL) {
return(XcmsFailure);
}
if (_XcmsParseColorString(ccc, *color_string, pColor_exact_return)
== 1) {
if (result_format != XcmsUndefinedFormat
&& pColor_exact_return->format != result_format) {
return(XcmsConvertColors(ccc, pColor_exact_return, 1,
result_format, (Bool *)NULL));
} else {
return(XcmsSuccess);
}
}
retval = _XcmsLookupColorName(ccc, color_string, pColor_exact_return);
if (retval != XcmsSuccess) {
return(_XCMS_NEWNAME);
}
if (pColor_exact_return->format == XcmsUndefinedFormat) {
return(XcmsFailure);
}
if (result_format == XcmsUndefinedFormat) {
result_format = pColor_exact_return->format;
}
if ((ClientWhitePointOfCCC(ccc))->format == XcmsUndefinedFormat) {
pClientWhitePt = ScreenWhitePointOfCCC(ccc);
} else {
pClientWhitePt = ClientWhitePointOfCCC(ccc);
}
if (XCMS_DD_ID(pColor_exact_return->format)) {
if (XCMS_DD_ID(result_format)) {
return(_XcmsDDConvertColors(ccc, pColor_exact_return,
1, result_format, (Bool *) NULL));
} else {
if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
pClientWhitePt, ScreenWhitePointOfCCC(ccc))) {
return((*ccc->whitePtAdjProc)(ccc, ScreenWhitePointOfCCC(ccc),
pClientWhitePt, result_format,
pColor_exact_return, 1, (Bool *) NULL));
} else {
if (_XcmsDDConvertColors(ccc, pColor_exact_return, 1,
XcmsCIEXYZFormat, (Bool *) NULL) == XcmsFailure) {
return(XcmsFailure);
}
return(_XcmsDIConvertColors(ccc, pColor_exact_return,
pClientWhitePt, 1, result_format));
}
}
} else {
if (_XcmsLookupColorName(ccc, &strptr, &dbWhitePt) != 1) {
memcpy((char *)&dbWhitePt,
(char *)&ccc->pPerScrnInfo->screenWhitePt,
sizeof(XcmsColor));
}
if (XCMS_DD_ID(result_format)) {
if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
&dbWhitePt, ScreenWhitePointOfCCC(ccc))) {
return((*ccc->whitePtAdjProc)(ccc, &dbWhitePt,
ScreenWhitePointOfCCC(ccc), result_format,
pColor_exact_return, 1, (Bool *)NULL));
} else {
if (pColor_exact_return->format != XcmsCIEXYZFormat) {
if (_XcmsDIConvertColors(ccc, pColor_exact_return,
&dbWhitePt, 1, XcmsCIEXYZFormat) == XcmsFailure) {
return(XcmsFailure);
}
}
return (_XcmsDDConvertColors(ccc, pColor_exact_return, 1,
result_format, (Bool *)NULL));
}
} else {
if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
&dbWhitePt, pClientWhitePt)) {
return((*ccc->whitePtAdjProc)(ccc, &dbWhitePt,
pClientWhitePt, result_format,
pColor_exact_return, 1, (Bool *)NULL));
} else if (_XcmsEqualWhitePts(ccc,
&dbWhitePt, pClientWhitePt)) {
if (pColor_exact_return->format == result_format) {
return(XcmsSuccess);
} else {
return (_XcmsDIConvertColors(ccc, pColor_exact_return,
&dbWhitePt, 1, result_format));
}
} else {
if (pColor_exact_return->format != XcmsCIEXYZFormat) {
if (_XcmsDIConvertColors(ccc, pColor_exact_return,
&dbWhitePt, 1, XcmsCIEXYZFormat) == XcmsFailure) {
return(XcmsFailure);
}
}
if (result_format == XcmsCIEXYZFormat) {
return(XcmsSuccess);
} else {
return(_XcmsDIConvertColors(ccc, pColor_exact_return,
pClientWhitePt, 1, result_format));
}
}
}
}
}