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 /************************************************************************
100  *									*
101  *			PRIVATE ROUTINES				*
102  *									*
103  ************************************************************************/
104 
105 /*
106  *	NAME
107  *		_XcmsColorSpaceOfString
108  *
109  *	SYNOPSIS
110  */
111 static XcmsColorSpace *
_XcmsColorSpaceOfString(XcmsCCC ccc,const char * color_string)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  */
179 static int
_XcmsParseColorString(XcmsCCC ccc,const char * color_string,XcmsColor * pColor)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  */
246 static int
FirstCmp(const void * p1,const void * p2)247 FirstCmp(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  */
271 static void
SetNoVisit(void)272 SetNoVisit(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  */
300 static int
field2(char * pBuf,char delim,char ** p1,char ** p2)301 field2(
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  */
370 static Status
_XcmsLookupColorName(XcmsCCC ccc,const char ** name,XcmsColor * pColor)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 
421 Retry:
422     if ((len = (int)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  */
495 static int
RemoveSpaces(char * pString)496 RemoveSpaces(
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 = (int)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  */
529 static int
stringSectionSize(FILE * stream,int * pNumEntries,int * pSectionSize)530 stringSectionSize(
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  */
628 static Status
ReadColornameDB(FILE * stream,XcmsPair * pRec,char * pString)629 ReadColornameDB(
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  */
715 static Status
LoadColornameDB(void)716 LoadColornameDB(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 = (int)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  */
802 void
_XcmsCopyISOLatin1Lowered(char * dst,const char * src)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  */
846 Status
_XcmsResolveColorString(XcmsCCC ccc,const char ** color_string,XcmsColor * pColor_exact_return,XcmsColorFormat result_format)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