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