Home | History | Annotate | Line # | Download | only in xcms
      1 
      2 /*
      3  * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
      4  * 	All Rights Reserved
      5  *
      6  * This file is a component of an X Window System-specific implementation
      7  * of Xcms based on the TekColor Color Management System.  Permission is
      8  * hereby granted to use, copy, modify, sell, and otherwise distribute this
      9  * software and its documentation for any purpose and without fee, provided
     10  * that this copyright, permission, and disclaimer notice is reproduced in
     11  * all copies of this software and in supporting documentation.  TekColor
     12  * is a trademark of Tektronix, Inc.
     13  *
     14  * Tektronix makes no representation about the suitability of this software
     15  * for any purpose.  It is provided "as is" and with all faults.
     16  *
     17  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
     18  * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     19  * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
     20  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
     21  * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
     22  * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     23  * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
     24  *
     25  *	NAME
     26  *		XcmsColNm.c
     27  *
     28  *	DESCRIPTION
     29  *		Source for _XcmsLookupColorName().
     30  *
     31  *
     32  */
     33 
     34 #ifdef HAVE_CONFIG_H
     35 #include <config.h>
     36 #endif
     37 #include "Xlibint.h"
     38 #include "Xcmsint.h"
     39 #include <X11/Xos.h>
     40 #include <sys/stat.h>
     41 #include <stdio.h>
     42 #include <ctype.h>
     43 #include <limits.h>
     44 #define XK_LATIN1
     45 #include <X11/keysymdef.h>
     46 #include "Cv.h"
     47 
     48 /* forwards/locals */
     49 static Status LoadColornameDB(void);
     50 
     51 
     52 /*
     53  *      LOCAL DEFINES
     54  *		#define declarations local to this package.
     55  */
     56 #ifndef XCMSDB
     57 #define XCMSDB  XCMSDIR "/Xcms.txt"
     58 #endif
     59 
     60 #ifndef isgraph
     61 #  define isgraph(c)	(isprint((c)) && !isspace((c)))
     62 #endif
     63 
     64 #ifndef XCMSDB_MAXLINELEN
     65 #  define XCMSDB_MAXLINELEN	256
     66 #endif
     67 
     68 #define FORMAT_VERSION	"0.1"
     69 #define START_TOKEN	"XCMS_COLORDB_START"
     70 #define END_TOKEN	"XCMS_COLORDB_END"
     71 #define DELIM_CHAR	'\t'
     72 
     73 #define	NOT_VISITED	0x0
     74 #define	VISITED		0x1
     75 #define CYCLE		0xFFFF
     76 #define XcmsDbInitNone		-1
     77 #define XcmsDbInitFailure	0
     78 #define XcmsDbInitSuccess	1
     79 
     80 /*
     81  *      LOCAL TYPEDEFS
     82  */
     83 typedef struct _XcmsPair {
     84     const char *first;
     85     const char *second;
     86     int flag;
     87 } XcmsPair;
     88 
     89 /*
     90  *      LOCAL VARIABLES
     91  */
     92 static int XcmsColorDbState = XcmsDbInitNone;
     93 static int nEntries;
     94 static char *strings;
     95 static XcmsPair *pairs;
     96 static const char whitePtStr[] = "WhitePoint";
     97 
     98 
     99 /************************************************************************
    101  *									*
    102  *			PRIVATE ROUTINES				*
    103  *									*
    104  ************************************************************************/
    105 
    106 /*
    107  *	NAME
    108  *		_XcmsColorSpaceOfString
    109  *
    110  *	SYNOPSIS
    111  */
    112 static XcmsColorSpace *
    113 _XcmsColorSpaceOfString(
    114     XcmsCCC ccc,
    115     const char *color_string)
    116 /*
    117  *	DESCRIPTION
    118  *		Returns a pointer to the color space structure
    119  *		(XcmsColorSpace) associated with the specified color string.
    120  *
    121  *	RETURNS
    122  *		Pointer to matching XcmsColorSpace structure if found;
    123  *		otherwise NULL.
    124  *
    125  *	CAVEATS
    126  *
    127  */
    128 {
    129     XcmsColorSpace	**papColorSpaces;
    130     size_t n;
    131     char *pchar;
    132 
    133     if ((pchar = strchr(color_string, ':')) == NULL) {
    134 	return(XcmsFailure);
    135     }
    136     n = (size_t)(pchar - color_string);
    137 
    138     if (ccc == NULL) {
    139 	return(NULL);
    140     }
    141 
    142     /*
    143      * First try Device-Independent color spaces
    144      */
    145     papColorSpaces = _XcmsDIColorSpaces;
    146     if (papColorSpaces != NULL) {
    147 	while (*papColorSpaces != NULL) {
    148 	    if (strncmp((*papColorSpaces)->prefix, color_string, n) == 0 &&
    149 		!((*papColorSpaces)->prefix)[n]) {
    150 		return(*papColorSpaces);
    151 	    }
    152 	    papColorSpaces++;
    153 	}
    154     }
    155 
    156     /*
    157      * Next try Device-Dependent color spaces
    158      */
    159     papColorSpaces = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
    160     if (papColorSpaces != NULL) {
    161 	while (*papColorSpaces != NULL) {
    162 	    if (strncmp((*papColorSpaces)->prefix, color_string, n) == 0 &&
    163 		!((*papColorSpaces)->prefix)[n]) {
    164 		return(*papColorSpaces);
    165 	    }
    166 	    papColorSpaces++;
    167 	}
    168     }
    169 
    170     return(NULL);
    171 }
    172 
    173 
    174 /*
    176  *	NAME
    177  *		_XcmsParseColorString
    178  *
    179  *	SYNOPSIS
    180  */
    181 static int
    182 _XcmsParseColorString(
    183     XcmsCCC ccc,
    184     const char *color_string,
    185     XcmsColor *pColor)
    186 /*
    187  *	DESCRIPTION
    188  *		Assuming color_string contains a numerical string color
    189  *		specification, attempts to parse a string into an
    190  *		XcmsColor structure.
    191  *
    192  *	RETURNS
    193  *		0 if failed; otherwise non-zero.
    194  *
    195  *	CAVEATS
    196  *		A color string containing a numerical color specification
    197  *		must be in ISO Latin-1 encoding!
    198  */
    199 {
    200     XcmsColorSpace	*pColorSpace;
    201     char		string_buf[64];
    202     char		*string_lowered;
    203     size_t		len;
    204     int			res;
    205 
    206     if (ccc == NULL) {
    207 	return(0);
    208     }
    209 
    210     /*
    211      * While copying color_string to string_lowered, convert to lowercase
    212      */
    213     if ((len = strlen(color_string)) >= sizeof(string_buf)) {
    214 	string_lowered = Xmalloc(len+1);
    215 	if (string_lowered == NULL)
    216 	    return(XcmsFailure);
    217     } else {
    218 	string_lowered = string_buf;
    219     }
    220 
    221     _XcmsCopyISOLatin1Lowered(string_lowered, color_string);
    222 
    223     if (*string_lowered == '#') {
    224 	if ((pColorSpace = _XcmsColorSpaceOfString(ccc, "rgb:")) != NULL) {
    225 	    res = (*pColorSpace->parseString)(string_lowered, pColor);
    226 	    if (len >= sizeof(string_buf)) Xfree(string_lowered);
    227 	    return res;
    228 	}
    229     }
    230 
    231     if ((pColorSpace = _XcmsColorSpaceOfString(ccc, string_lowered)) != NULL) {
    232 	res = (*pColorSpace->parseString)(string_lowered, pColor);
    233 	if (len >= sizeof(string_buf)) Xfree(string_lowered);
    234 	return res;
    235     }
    236 
    237     if (len >= sizeof(string_buf)) Xfree(string_lowered);
    238     return(0);
    239 }
    240 
    241 
    242 /*
    244  *	NAME
    245  *		FirstCmp - Compare color names of pair recs
    246  *
    247  *	SYNOPSIS
    248  */
    249 static int
    250 FirstCmp(const void *p1, const void *p2)
    251 /*
    252  *	DESCRIPTION
    253  *		Compares the color names of XcmsColorTuples.
    254  *
    255  *	RETURNS
    256  *		0 if equal;
    257  *		< 0 if first precedes second,
    258  *		> 0 if first succeeds second.
    259  *
    260  */
    261 {
    262     return(strcmp(((const XcmsPair *)p1)->first, ((const XcmsPair *)p2)->first));
    263 }
    264 
    265 
    266 
    267 /*
    269  *	NAME
    270  *		stringSectionSize - determine memory needed for strings
    271  *
    272  *	SYNOPSIS
    273  */
    274 static void
    275 SetNoVisit(void)
    276 /*
    277  *	DESCRIPTION
    278  *
    279  *	RETURNS
    280  *		void
    281  *
    282  */
    283 {
    284     int i;
    285     XcmsPair *pair = pairs;
    286 
    287     for (i = 0; i < nEntries; i++, pair++) {
    288 	if (pair->flag != CYCLE) {
    289 	    pair->flag = NOT_VISITED;
    290 	}
    291     }
    292 }
    293 
    294 
    295 
    296 
    297 /*
    299  *	NAME
    300  *		field2 - extract two fields
    301  *
    302  *	SYNOPSIS
    303  */
    304 static int
    305 field2(
    306     char *pBuf,
    307     char delim,	/* in:  field delimiter */
    308     char **p1,	/* in/out: pointer to pointer to field 1 */
    309     char **p2)	/* in/out: pointer to pointer to field 2 */
    310 /*
    311  *	DESCRIPTION
    312  *		Extracts two fields from a "record".
    313  *
    314  *	RETURNS
    315  *		XcmsSuccess if succeeded, otherwise XcmsFailure.
    316  *
    317  */
    318 {
    319     *p1 = *p2 = NULL;
    320 
    321     /* Find Field 1 */
    322     while (!isgraph(*pBuf)) {
    323 	if ((*pBuf == '\n') || (*pBuf == '\0')) {
    324 	    return(XcmsFailure);
    325 	}
    326 	if (isspace(*pBuf) || (*pBuf == delim)) {
    327 	    pBuf++;
    328 	}
    329     }
    330     *p1 = pBuf;
    331 
    332     /* Find end of Field 2 */
    333     while (isprint(*pBuf) && (*pBuf != delim)) {
    334 	pBuf++;
    335     }
    336     if ((*pBuf == '\n') || (*pBuf == '\0')) {
    337 	return(XcmsFailure);
    338     }
    339     if ((*pBuf == ' ') || (*pBuf == delim)) {
    340 	*pBuf++ = '\0';	/* stuff end of string character */
    341     } else {
    342 	return(XcmsFailure);
    343     }
    344 
    345     /* Find Field 2 */
    346     while (!isgraph(*pBuf)) {
    347 	if ((*pBuf == '\n') || (*pBuf == '\0')) {
    348 	    return(XcmsFailure);
    349 	}
    350 	if (isspace(*pBuf) || (*pBuf == delim)) {
    351 	    pBuf++;
    352 	}
    353     }
    354     *p2 = pBuf;
    355 
    356     /* Find end of Field 2 */
    357     while (isprint(*pBuf) && (*pBuf != delim)) {
    358 	pBuf++;
    359     }
    360     if (*pBuf != '\0') {
    361 	*pBuf = '\0';	/* stuff end of string character */
    362     }
    363 
    364     return(XcmsSuccess);
    365 }
    366 
    367 
    368 /*
    370  *	NAME
    371  *		_XcmsLookupColorName - Lookup DB entry for a color name
    372  *
    373  *	SYNOPSIS
    374  */
    375 static Status
    376 _XcmsLookupColorName(
    377     XcmsCCC ccc,
    378     const char **name,
    379     XcmsColor *pColor)
    380 /*
    381  *	DESCRIPTION
    382  *		Searches for an entry in the Device-Independent Color Name
    383  *		Database for the specified string.
    384  *
    385  *	RETURNS
    386  *		XcmsFailure if failed to find a matching entry in
    387  *			the database.
    388  *		XcmsSuccess if succeeded in converting color name to
    389  *			XcmsColor.
    390  *		_XCMS_NEWNAME if succeeded in converting color string (which
    391  *			is a color name to yet another color name.  Note
    392  *			that the new name is passed back via 'name'.
    393  */
    394  {
    395     Status		retval = 0;
    396     char		name_lowered_64[64];
    397     char		*name_lowered;
    398     register int	i, j, left, right;
    399     int			len;
    400     const char		*tmpName;
    401     XcmsPair		*pair = NULL;
    402 
    403     /*
    404      * Check state of Database:
    405      *		XcmsDbInitNone
    406      *		XcmsDbInitSuccess
    407      *		XcmsDbInitFailure
    408      */
    409     if (XcmsColorDbState == XcmsDbInitFailure) {
    410 	return(XcmsFailure);
    411     }
    412     if (XcmsColorDbState == XcmsDbInitNone) {
    413 	if (!LoadColornameDB()) {
    414 	    return(XcmsFailure);
    415 	}
    416     }
    417 
    418     SetNoVisit();
    419 
    420     /*
    421      * While copying name to name_lowered, convert to lowercase
    422      */
    423 
    424     tmpName = *name;
    425 
    426 Retry:
    427     if ((len = (int)strlen(tmpName)) > 63) {
    428 	name_lowered = Xmalloc(len+1);
    429 	if (name_lowered == NULL)
    430 	    return(XcmsFailure);
    431     } else {
    432 	name_lowered = name_lowered_64;
    433     }
    434 
    435     _XcmsCopyISOLatin1Lowered(name_lowered, tmpName);
    436 
    437     /*
    438      * Now, remove spaces.
    439      */
    440     for (i = 0, j = 0; j < len; j++) {
    441 	if (!isspace(name_lowered[j])) {
    442 	    name_lowered[i++] = name_lowered[j];
    443 	}
    444     }
    445     name_lowered[i] = '\0';
    446 
    447     left = 0;
    448     right = nEntries - 1;
    449     while (left <= right) {
    450 	i = (left + right) >> 1;
    451 	pair = &pairs[i];
    452 	j = strcmp(name_lowered, pair->first);
    453 	if (j < 0)
    454 	    right = i - 1;
    455 	else if (j > 0)
    456 	    left = i + 1;
    457 	else {
    458 	    break;
    459 	}
    460     }
    461     if (len > 63) Xfree(name_lowered);
    462 
    463     if (left > right) {
    464 	if (retval == 2) {
    465 	    if (*name != tmpName) {
    466 		*name = tmpName;
    467 	    }
    468 	    return(_XCMS_NEWNAME);
    469 	}
    470 	return(XcmsFailure);
    471     }
    472 
    473     if (pair->flag == CYCLE) {
    474 	return(XcmsFailure);
    475     }
    476     if (pair->flag == VISITED) {
    477 	pair->flag = CYCLE;
    478 	return(XcmsFailure);
    479     }
    480 
    481     if (_XcmsParseColorString(ccc, pair->second, pColor) == XcmsSuccess) {
    482 	/* f2 contains a numerical string specification */
    483 	return(XcmsSuccess);
    484     } else {
    485 	/* f2 does not contain a numerical string specification */
    486 	tmpName = pair->second;
    487 	pair->flag = VISITED;
    488 	retval = 2;
    489 	goto Retry;
    490     }
    491 }
    492 
    493 
    494 /*
    496  *	NAME
    497  *		RemoveSpaces
    498  *
    499  *	SYNOPSIS
    500  */
    501 static int
    502 RemoveSpaces(
    503     char *pString)
    504 /*
    505  *	DESCRIPTION
    506  *		Removes spaces from string.
    507  *
    508  *	RETURNS
    509  *		Void
    510  *
    511  */
    512 {
    513     int i, count = 0;
    514     char *cptr;
    515 
    516     /* REMOVE SPACES */
    517     cptr = pString;
    518     for (i = (int)strlen(pString); i; i--, cptr++) {
    519 	if (!isspace(*cptr)) {
    520 	    *pString++ = *cptr;
    521 	    count++;
    522 	}
    523     }
    524     *pString = '\0';
    525     return(count);
    526 }
    527 
    528 
    529 /*
    531  *	NAME
    532  *		stringSectionSize - determine memory needed for strings
    533  *
    534  *	SYNOPSIS
    535  */
    536 static int
    537 stringSectionSize(
    538     FILE *stream,
    539     int	*pNumEntries,
    540     int	*pSectionSize)
    541 /*
    542  *	DESCRIPTION
    543  *		Determines the amount of memory required to store the
    544  *		color name strings and also the number of strings.
    545  *
    546  *	RETURNS
    547  *		XcmsSuccess if succeeded, otherwise XcmsFailure.
    548  *
    549  */
    550 {
    551     char buf[XCMSDB_MAXLINELEN];
    552     char token[XCMSDB_MAXLINELEN];
    553     char token2[XCMSDB_MAXLINELEN];
    554     char *pBuf;
    555     char *f1;
    556     char *f2;
    557     size_t i;
    558 
    559     unsigned int numEntries = 0;
    560     unsigned int sectionSize = 0;
    561 
    562     *pNumEntries = 0;
    563     *pSectionSize = 0;
    564 
    565     /*
    566      * Advance to START_TOKEN
    567      *	 Anything before is just considered as comments.
    568      */
    569 
    570     while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
    571 	if ((sscanf(buf, "%s %s", token, token2))
    572 		&& (strcmp(token, START_TOKEN) == 0)) {
    573 	    if (strcmp(token2, FORMAT_VERSION) != 0) {
    574 		/* text file not in the right format */
    575 		return(XcmsFailure);
    576 	    }
    577 	    break;
    578 	} /* else it was just a blank line or comment */
    579     }
    580 
    581     if (pBuf == NULL) {
    582 	return(XcmsFailure);
    583     }
    584 
    585     while((fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
    586 	if ((sscanf(buf, "%s", token)) && (strcmp(token, END_TOKEN) == 0)) {
    587 	    break;
    588 	}
    589 
    590 	if (field2(buf, DELIM_CHAR, &f1, &f2) != XcmsSuccess) {
    591 	    return(XcmsFailure);
    592 	}
    593 
    594 	numEntries++;
    595 	if (numEntries >= INT_MAX)
    596 	    return(XcmsFailure);
    597 
    598 	i = strlen(f1);
    599 	if (i >= INT_MAX - sectionSize)
    600 	    return(XcmsFailure);
    601 	sectionSize += i + 1;
    602 	for (; i; i--, f1++) {
    603 	    /* REMOVE SPACES FROM COUNT */
    604 	    if (isspace(*f1)) {
    605 		sectionSize--;
    606 	    }
    607 	}
    608 
    609 	i = strlen(f2);
    610 	if (i >= INT_MAX - sectionSize)
    611 	    return(XcmsFailure);
    612 	sectionSize += i + 1;
    613 	for (; i; i--, f2++) {
    614 	    /* REMOVE SPACES FROM COUNT */
    615 	    if (isspace(*f2)) {
    616 		sectionSize--;
    617 	    }
    618 	}
    619 
    620     }
    621 
    622     *pNumEntries = (int) numEntries;
    623     *pSectionSize = (int) sectionSize;
    624 
    625     return(XcmsSuccess);
    626 }
    627 
    628 
    629 /*
    631  *	NAME
    632  *		ReadColornameDB - Read the Color Name Database
    633  *
    634  *	SYNOPSIS
    635  */
    636 static Status
    637 ReadColornameDB(
    638     FILE *stream,
    639     XcmsPair *pRec,
    640     char *pString)
    641 /*
    642  *	DESCRIPTION
    643  *		Loads the Color Name Database from a text file.
    644  *
    645  *	RETURNS
    646  *		XcmsSuccess if succeeded, otherwise XcmsFailure.
    647  *
    648  */
    649 {
    650     char buf[XCMSDB_MAXLINELEN];
    651     char token[XCMSDB_MAXLINELEN];
    652     char token2[XCMSDB_MAXLINELEN];
    653     char *f1;
    654     char *f2;
    655     char *pBuf;
    656 
    657     /*
    658      * Advance to START_TOKEN
    659      *	 Anything before is just considered as comments.
    660      */
    661 
    662     while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
    663 	if ((sscanf(buf, "%s %s", token, token2))
    664 		&& (strcmp(token, START_TOKEN) == 0)) {
    665 	    if (strcmp(token2, FORMAT_VERSION) != 0) {
    666 		/* text file not in the right format */
    667 		return(XcmsFailure);
    668 	    }
    669 	    break;
    670 	} /* else it was just a blank line or comment */
    671     }
    672 
    673     if (pBuf == NULL) {
    674 	return(XcmsFailure);
    675     }
    676 
    677     /*
    678      * Process lines between START_TOKEN to END_TOKEN
    679      */
    680 
    681     while ((fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
    682 	if ((sscanf(buf, "%s", token)) && (strcmp(token, END_TOKEN) == 0)) {
    683 	    /*
    684 	     * Found END_TOKEN so break out of for loop
    685 	     */
    686 	    break;
    687 	}
    688 
    689 	/*
    690 	 * Get pairs
    691 	 */
    692 	if (field2(buf, DELIM_CHAR, &f1, &f2) != XcmsSuccess) {
    693 	    /* Invalid line */
    694 	    continue;
    695 	}
    696 
    697 	/*
    698 	 * Add strings
    699 	 */
    700 
    701 	/* Left String */
    702 	pRec->first = pString;
    703 	_XcmsCopyISOLatin1Lowered(pString, f1);
    704 	pString += (1 + RemoveSpaces(pString));
    705 	pRec->second = pString;
    706 	/* Right String */
    707 	_XcmsCopyISOLatin1Lowered(pString, f2);
    708 	pString += RemoveSpaces(pString) + 1;
    709 	pRec++;
    710 
    711     }
    712 
    713     return(XcmsSuccess);
    714 }
    715 
    716 
    717 /*
    719  *	NAME
    720  *		LoadColornameDB - Load the Color Name Database
    721  *
    722  *	SYNOPSIS
    723  */
    724 static Status
    725 LoadColornameDB(void)
    726 /*
    727  *	DESCRIPTION
    728  *		Loads the Color Name Database from a text file.
    729  *
    730  *	RETURNS
    731  *		XcmsSuccess if succeeded, otherwise XcmsFailure.
    732  *
    733  */
    734 {
    735     int size;
    736     FILE *stream;
    737     const char *pathname;
    738     struct stat txt;
    739     int length;
    740 
    741     /* use and name of this env var is not part of the standard */
    742     /* implementation-dependent feature */
    743     if ((pathname = getenv("XCMSDB")) == NULL) {
    744 	pathname = XCMSDB;
    745     }
    746 
    747     length = (int)strlen(pathname);
    748     if ((length == 0) || (length >= (BUFSIZ - 5))){
    749 	XcmsColorDbState = XcmsDbInitFailure;
    750 	return(XcmsFailure);
    751     }
    752 
    753     if (stat(pathname, &txt)) {
    754 	/* can't stat file */
    755 	XcmsColorDbState = XcmsDbInitFailure;
    756 	return(XcmsFailure);
    757     }
    758 
    759     if ((stream = _XFopenFile (pathname, "r")) == NULL) {
    760 	/* can't open file */
    761 	XcmsColorDbState = XcmsDbInitFailure;
    762 	return(XcmsFailure);
    763     }
    764 
    765     if (stringSectionSize(stream, &nEntries, &size) != XcmsSuccess ||
    766 	nEntries == 0) {
    767 	(void) fclose(stream);
    768 	XcmsColorDbState = XcmsDbInitFailure;
    769 	return(XcmsFailure);
    770     }
    771     rewind(stream);
    772 
    773     strings = Xmalloc(size);
    774     pairs = Xcalloc(nEntries, sizeof(XcmsPair));
    775     if (strings == NULL || pairs == NULL) {
    776 	free(strings);
    777 	free(pairs);
    778 	(void) fclose(stream);
    779 	XcmsColorDbState = XcmsDbInitFailure;
    780 	return(XcmsFailure);
    781     }
    782 
    783     ReadColornameDB(stream, pairs, strings);
    784     (void) fclose(stream);
    785 
    786     /*
    787      * sort the pair recs
    788      */
    789     qsort((char *)pairs, nEntries, sizeof(XcmsPair), FirstCmp);
    790 
    791     XcmsColorDbState = XcmsDbInitSuccess;
    792     return(XcmsSuccess);
    793 }
    794 
    795 
    796 /************************************************************************
    798  *									*
    799  *			API PRIVATE ROUTINES				*
    800  *									*
    801  ************************************************************************/
    802 
    803 /*
    804  *	NAME
    805  *		_XcmsCopyISOLatin1Lowered
    806  *
    807  *	SYNOPSIS
    808  */
    809 void
    810 _XcmsCopyISOLatin1Lowered(
    811     char *dst,
    812     const char *src)
    813 /*
    814  *	DESCRIPTION
    815  *		ISO Latin-1 case conversion routine
    816  *		Identical to XmuCopyISOLatin1Lowered() but provided here
    817  *		to eliminate need to link with libXmu.a.
    818  *
    819  *		IMPLEMENTORS NOTE:
    820  *		    This routine is also used in XcmsFormatOfPrefix.
    821  *
    822  *	RETURNS
    823  *		Void
    824  *
    825  */
    826 {
    827     register unsigned char *dest;
    828     register const unsigned char *source;
    829 
    830     for (dest = (unsigned char *)dst, source = (const unsigned char *)src;
    831 	 *source;
    832 	 source++, dest++)
    833     {
    834 	if ((*source >= XK_A) && (*source <= XK_Z))
    835 	    *dest = *source + (XK_a - XK_A);
    836 	else if ((*source >= XK_Agrave) && (*source <= XK_Odiaeresis))
    837 	    *dest = *source + (XK_agrave - XK_Agrave);
    838 	else if ((*source >= XK_Ooblique) && (*source <= XK_Thorn))
    839 	    *dest = *source + (XK_oslash - XK_Ooblique);
    840 	else
    841 	    *dest = *source;
    842     }
    843     *dest = '\0';
    844 }
    845 
    846 
    847 /*
    849  *	NAME
    850  *		_XcmsResolveColorString -
    851  *
    852  *	SYNOPSIS
    853  */
    854 Status
    855 _XcmsResolveColorString (
    856     XcmsCCC ccc,
    857     const char **color_string,
    858     XcmsColor *pColor_exact_return,
    859     XcmsColorFormat result_format)
    860 /*
    861  *	DESCRIPTION
    862  *		The XcmsLookupColor function finds the color specification
    863  *		associated with a color name in the Device-Independent Color
    864  *		Name Database.
    865  *	RETURNS
    866  *		XcmsFailure if failed to convert valid color string.
    867  *		XcmsSuccess if succeeded in converting color string to
    868  *			XcmsColor.
    869  *		_XCMS_NEWNAME if failed to parse the string or find it in
    870  *			the database, or if succeeded in looking it up and
    871  *			found another name which is not in the database.
    872  *			Note that the new name is returned in color_string.
    873  *
    874  *		This function returns both the color specification found in the
    875  *		database (db specification) and the color specification for the
    876  *		color displayable by the specified screen (screen
    877  *		specification).  The calling routine sets the format for these
    878  *		returned specifications in the XcmsColor format component.
    879  *		If XcmsUndefinedFormat, the specification is returned in the
    880  *		format used to store the color in the database.
    881  */
    882 {
    883     XcmsColor dbWhitePt;	/* whitePt associated with pColor_exact_return*/
    884 				/*    the screen's white point */
    885     XcmsColor *pClientWhitePt;
    886     int retval;
    887     const char *strptr = whitePtStr;
    888 
    889 /*
    890  * 0. Check for invalid arguments.
    891  */
    892     if (ccc == NULL || (*color_string)[0] == '\0' || pColor_exact_return == NULL) {
    893 	return(XcmsFailure);
    894     }
    895 
    896 /*
    897  * 1. First attempt to parse the string
    898  *    If successful, then convert the specification to the target format
    899  *    and return.
    900  */
    901     if (_XcmsParseColorString(ccc, *color_string, pColor_exact_return)
    902 	    == 1) {
    903 	if (result_format != XcmsUndefinedFormat
    904 		&& pColor_exact_return->format != result_format) {
    905 	    /* need to be converted to the target format */
    906 	    return(XcmsConvertColors(ccc, pColor_exact_return, 1,
    907 		    result_format, (Bool *)NULL));
    908 	} else {
    909 	    return(XcmsSuccess);
    910 	}
    911     }
    912 
    913 /*
    914  * 2. Attempt to find it in the DI Color Name Database
    915  */
    916 
    917     /*
    918      * a. Convert String into a XcmsColor structure
    919      *       Attempt to extract the specification for color_string from the
    920      *       DI Database (pColor_exact_return).  If the DI Database does not
    921      *	     have this entry, then return failure.
    922      */
    923     retval = _XcmsLookupColorName(ccc, color_string, pColor_exact_return);
    924 
    925     if (retval != XcmsSuccess) {
    926 	/* color_string replaced with a color name, or not found */
    927 	return(_XCMS_NEWNAME);
    928     }
    929 
    930     if (pColor_exact_return->format == XcmsUndefinedFormat) {
    931 	return(XcmsFailure);
    932     }
    933 
    934     /*
    935      * b. If result_format not defined, then assume target format
    936      *	  is the exact format.
    937      */
    938     if (result_format == XcmsUndefinedFormat) {
    939 	result_format = pColor_exact_return->format;
    940     }
    941 
    942     if ((ClientWhitePointOfCCC(ccc))->format == XcmsUndefinedFormat) {
    943 	pClientWhitePt = ScreenWhitePointOfCCC(ccc);
    944     } else {
    945 	pClientWhitePt = ClientWhitePointOfCCC(ccc);
    946     }
    947 
    948     /*
    949      * c. Convert to the target format, making adjustments for white
    950      *	  point differences as necessary.
    951      */
    952     if (XCMS_DD_ID(pColor_exact_return->format)) {
    953 	/*
    954 	 * The spec format is Device-Dependent, therefore assume the
    955 	 *    its white point is the Screen White Point.
    956 	 */
    957 	if (XCMS_DD_ID(result_format)) {
    958 	    /*
    959 	     * Target format is Device-Dependent
    960 	     *	Therefore, DD --> DD conversion
    961 	     */
    962 	    return(_XcmsDDConvertColors(ccc, pColor_exact_return,
    963 		    1, result_format, (Bool *) NULL));
    964 	} else {
    965 	    /*
    966 	     * Target format is Device-Independent
    967 	     *	Therefore, DD --> DI conversion
    968 	     */
    969 	    if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
    970 		    pClientWhitePt, ScreenWhitePointOfCCC(ccc))) {
    971 		return((*ccc->whitePtAdjProc)(ccc, ScreenWhitePointOfCCC(ccc),
    972 			pClientWhitePt, result_format,
    973 			pColor_exact_return, 1, (Bool *) NULL));
    974 	    } else {
    975 		if (_XcmsDDConvertColors(ccc, pColor_exact_return, 1,
    976 			XcmsCIEXYZFormat, (Bool *) NULL) == XcmsFailure) {
    977 		    return(XcmsFailure);
    978 		}
    979 		return(_XcmsDIConvertColors(ccc, pColor_exact_return,
    980 			pClientWhitePt, 1, result_format));
    981 	    }
    982 	}
    983     } else {
    984 	/*
    985 	 * The spec format is Device-Independent, therefore attempt
    986 	 * to find a database white point.
    987 	 *
    988 	 * If the Database does not have a white point, then assume the
    989 	 * database white point is the same as the Screen White Point.
    990 	 */
    991 
    992 	if (_XcmsLookupColorName(ccc, &strptr, &dbWhitePt) != 1) {
    993 	    memcpy((char *)&dbWhitePt,
    994 		   (char *)&ccc->pPerScrnInfo->screenWhitePt,
    995 		   sizeof(XcmsColor));
    996 	}
    997 	if (XCMS_DD_ID(result_format)) {
    998 	    /*
    999 	     * Target format is Device-Dependent
   1000 	     *	Therefore, DI --> DD conversion
   1001 	     */
   1002 	    if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
   1003 		    &dbWhitePt, ScreenWhitePointOfCCC(ccc))) {
   1004 		return((*ccc->whitePtAdjProc)(ccc, &dbWhitePt,
   1005 			ScreenWhitePointOfCCC(ccc), result_format,
   1006 			pColor_exact_return, 1, (Bool *)NULL));
   1007 	    } else {
   1008 		if (pColor_exact_return->format != XcmsCIEXYZFormat) {
   1009 		    if (_XcmsDIConvertColors(ccc, pColor_exact_return,
   1010 			    &dbWhitePt, 1, XcmsCIEXYZFormat) == XcmsFailure) {
   1011 			return(XcmsFailure);
   1012 		    }
   1013 		}
   1014 		return (_XcmsDDConvertColors(ccc, pColor_exact_return, 1,
   1015 			result_format, (Bool *)NULL));
   1016 	    }
   1017 	} else {
   1018 	    /*
   1019 	     * Target format is Device-Independent
   1020 	     *	Therefore, DI --> DI conversion
   1021 	     */
   1022 	    if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
   1023 		    &dbWhitePt, pClientWhitePt)) {
   1024 		/*
   1025 		 * The calling routine wants to resolve this color
   1026 		 * in terms if it's white point (i.e. Client White Point).
   1027 		 * Therefore, apply white adjustment for the displacement
   1028 		 * between dbWhitePt to clientWhitePt.
   1029 		 */
   1030 		return((*ccc->whitePtAdjProc)(ccc, &dbWhitePt,
   1031 			pClientWhitePt, result_format,
   1032 			pColor_exact_return, 1, (Bool *)NULL));
   1033 	    } else if (_XcmsEqualWhitePts(ccc,
   1034 		    &dbWhitePt, pClientWhitePt)) {
   1035 		/*
   1036 		 * Can use either dbWhitePt or pClientWhitePt to
   1037 		 * convert to the result_format.
   1038 		 */
   1039 		if (pColor_exact_return->format == result_format) {
   1040 		    return(XcmsSuccess);
   1041 		} else {
   1042 		    return (_XcmsDIConvertColors(ccc, pColor_exact_return,
   1043 			    &dbWhitePt, 1, result_format));
   1044 		}
   1045 	    } else {
   1046 		/*
   1047 		 * Need to convert to a white point independent color
   1048 		 * space (let's choose CIEXYZ) then convert to the
   1049 		 * target color space.  Why? Lets assume that
   1050 		 * pColor_exact_return->format and result format
   1051 		 * are white point dependent format (e.g., CIELUV, CIELAB,
   1052 		 * TekHVC ... same or any combination). If so, we'll
   1053 		 * need to convert the color with dbWhitePt to an absolute
   1054 		 * spec (i.e.  non-white point dependent) then convert that
   1055 		 * absolute value with clientWhitePt to the result_format.
   1056 		 */
   1057 		if (pColor_exact_return->format != XcmsCIEXYZFormat) {
   1058 		    if (_XcmsDIConvertColors(ccc, pColor_exact_return,
   1059 			    &dbWhitePt, 1, XcmsCIEXYZFormat) == XcmsFailure) {
   1060 			return(XcmsFailure);
   1061 		    }
   1062 		}
   1063 		if (result_format == XcmsCIEXYZFormat) {
   1064 		    return(XcmsSuccess);
   1065 		} else {
   1066 		    return(_XcmsDIConvertColors(ccc, pColor_exact_return,
   1067 			    pClientWhitePt, 1, result_format));
   1068 		}
   1069 	    }
   1070 	}
   1071     }
   1072 }
   1073