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