Reimplement FC_LANG as FcTypeLang, freeze patterns, other cleanup
[platform/upstream/fontconfig.git] / src / fcname.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcname.c,v 1.12 2002/08/19 19:32:05 keithp Exp $
3  *
4  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include "fcint.h"
30
31 static const FcObjectType _FcBaseObjectTypes[] = {
32     { FC_FAMILY,        FcTypeString, },
33     { FC_STYLE,         FcTypeString, },
34     { FC_SLANT,         FcTypeInteger, },
35     { FC_WEIGHT,        FcTypeInteger, },
36     { FC_SIZE,          FcTypeDouble, },
37     { FC_ASPECT,        FcTypeDouble, },
38     { FC_PIXEL_SIZE,    FcTypeDouble, },
39     { FC_SPACING,       FcTypeInteger, },
40     { FC_FOUNDRY,       FcTypeString, },
41 /*    { FC_CORE,                FcTypeBool, }, */
42     { FC_ANTIALIAS,     FcTypeBool, },
43     { FC_HINTING,       FcTypeBool, },
44     { FC_VERTICAL_LAYOUT,   FcTypeBool, },
45     { FC_AUTOHINT,      FcTypeBool, },
46     { FC_GLOBAL_ADVANCE,    FcTypeBool, },
47 /*    { FC_XLFD,                FcTypeString, }, */
48     { FC_FILE,          FcTypeString, },
49     { FC_INDEX,         FcTypeInteger, },
50     { FC_RASTERIZER,    FcTypeString, },
51     { FC_OUTLINE,       FcTypeBool, },
52     { FC_SCALABLE,      FcTypeBool, },
53     { FC_DPI,           FcTypeDouble },
54     { FC_RGBA,          FcTypeInteger, },
55     { FC_SCALE,         FcTypeDouble, },
56 /*    { FC_RENDER,      FcTypeBool, },*/
57     { FC_MINSPACE,      FcTypeBool, },
58     { FC_CHAR_WIDTH,    FcTypeInteger },
59     { FC_CHAR_HEIGHT,   FcTypeInteger },
60     { FC_MATRIX,        FcTypeMatrix },
61     { FC_CHARSET,       FcTypeCharSet },
62     { FC_LANG,          FcTypeLangSet },
63 };
64
65 #define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
66
67 typedef struct _FcObjectTypeList    FcObjectTypeList;
68
69 struct _FcObjectTypeList {
70     const FcObjectTypeList  *next;
71     const FcObjectType      *types;
72     int                     ntypes;
73 };
74
75 static const FcObjectTypeList _FcBaseObjectTypesList = {
76     0,
77     _FcBaseObjectTypes,
78     NUM_OBJECT_TYPES
79 };
80
81 static const FcObjectTypeList   *_FcObjectTypes = &_FcBaseObjectTypesList;
82
83 FcBool
84 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
85 {
86     FcObjectTypeList    *l;
87
88     l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
89     if (!l)
90         return FcFalse;
91     l->types = types;
92     l->ntypes = ntypes;
93     l->next = _FcObjectTypes;
94     _FcObjectTypes = l;
95     return FcTrue;
96 }
97
98 FcBool
99 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
100 {
101     const FcObjectTypeList      *l, **prev;
102
103     for (prev = &_FcObjectTypes; 
104          (l = *prev); 
105          prev = (const FcObjectTypeList **) &(l->next))
106     {
107         if (l->types == types && l->ntypes == ntypes)
108         {
109             *prev = l->next;
110             free ((void *) l);
111             return FcTrue;
112         }
113     }
114     return FcFalse;
115 }
116
117 const FcObjectType *
118 FcNameGetObjectType (const char *object)
119 {
120     int                     i;
121     const FcObjectTypeList  *l;
122     const FcObjectType      *t;
123     
124     for (l = _FcObjectTypes; l; l = l->next)
125     {
126         for (i = 0; i < l->ntypes; i++)
127         {
128             t = &l->types[i];
129             if (!strcmp (object, t->object))
130                 return t;
131         }
132     }
133     return 0;
134 }
135
136 static const FcConstant _FcBaseConstants[] = {
137     { (FcChar8 *) "light",          "weight",   FC_WEIGHT_LIGHT, },
138     { (FcChar8 *) "medium",         "weight",   FC_WEIGHT_MEDIUM, },
139     { (FcChar8 *) "demibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
140     { (FcChar8 *) "bold",           "weight",   FC_WEIGHT_BOLD, },
141     { (FcChar8 *) "black",          "weight",   FC_WEIGHT_BLACK, },
142
143     { (FcChar8 *) "roman",          "slant",    FC_SLANT_ROMAN, },
144     { (FcChar8 *) "italic",         "slant",    FC_SLANT_ITALIC, },
145     { (FcChar8 *) "oblique",        "slant",    FC_SLANT_OBLIQUE, },
146
147     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
148     { (FcChar8 *) "mono",           "spacing",  FC_MONO, },
149     { (FcChar8 *) "charcell",       "spacing",  FC_CHARCELL, },
150
151     { (FcChar8 *) "none",           "rgba",         FC_RGBA_NONE },
152     { (FcChar8 *) "rgb",            "rgba",         FC_RGBA_RGB, },
153     { (FcChar8 *) "bgr",            "rgba",         FC_RGBA_BGR, },
154     { (FcChar8 *) "vrgb",           "rgba",         FC_RGBA_VRGB },
155     { (FcChar8 *) "vbgr",           "rgba",         FC_RGBA_VBGR },
156 };
157
158 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
159
160 typedef struct _FcConstantList FcConstantList;
161
162 struct _FcConstantList {
163     const FcConstantList    *next;
164     const FcConstant        *consts;
165     int                     nconsts;
166 };
167
168 static const FcConstantList _FcBaseConstantList = {
169     0,
170     _FcBaseConstants,
171     NUM_FC_CONSTANTS
172 };
173
174 static const FcConstantList     *_FcConstants = &_FcBaseConstantList;
175
176 FcBool
177 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
178 {
179     FcConstantList      *l;
180
181     l = (FcConstantList *) malloc (sizeof (FcConstantList));
182     if (!l)
183         return FcFalse;
184     l->consts = consts;
185     l->nconsts = nconsts;
186     l->next = _FcConstants;
187     _FcConstants = l;
188     return FcTrue;
189 }
190
191 FcBool
192 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
193 {
194     const FcConstantList        *l, **prev;
195
196     for (prev = &_FcConstants; 
197          (l = *prev); 
198          prev = (const FcConstantList **) &(l->next))
199     {
200         if (l->consts == consts && l->nconsts == nconsts)
201         {
202             *prev = l->next;
203             free ((void *) l);
204             return FcTrue;
205         }
206     }
207     return FcFalse;
208 }
209
210 const FcConstant *
211 FcNameGetConstant (FcChar8 *string)
212 {
213     const FcConstantList    *l;
214     int                     i;
215     
216     for (l = _FcConstants; l; l = l->next)
217     {
218         for (i = 0; i < l->nconsts; i++)
219             if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
220                 return &l->consts[i];
221     }
222     return 0;
223 }
224
225 FcBool
226 FcNameConstant (FcChar8 *string, int *result)
227 {
228     const FcConstant    *c;
229
230     if ((c = FcNameGetConstant(string)))
231     {
232         *result = c->value;
233         return FcTrue;
234     }
235     return FcFalse;
236 }
237
238 FcBool
239 FcNameBool (FcChar8 *v, FcBool *result)
240 {
241     char    c0, c1;
242
243     c0 = *v;
244     if (isupper (c0))
245         c0 = tolower (c0);
246     if (c0 == 't' || c0 == 'y' || c0 == '1')
247     {
248         *result = FcTrue;
249         return FcTrue;
250     }
251     if (c0 == 'f' || c0 == 'n' || c0 == '0')
252     {
253         *result = FcFalse;
254         return FcTrue;
255     }
256     if (c0 == 'o')
257     {
258         c1 = v[1];
259         if (isupper (c1))
260             c1 = tolower (c1);
261         if (c1 == 'n')
262         {
263             *result = FcTrue;
264             return FcTrue;
265         }
266         if (c1 == 'f')
267         {
268             *result = FcFalse;
269             return FcTrue;
270         }
271     }
272     return FcFalse;
273 }
274
275 static FcValue
276 FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
277 {
278     FcValue     v;
279
280     v.type = type;
281     switch (v.type) {
282     case FcTypeInteger:
283         if (!FcNameConstant (string, &v.u.i))
284             v.u.i = atoi ((char *) string);
285         break;
286     case FcTypeString:
287         v.u.s = string;
288         break;
289     case FcTypeBool:
290         if (!FcNameBool (string, &v.u.b))
291             v.u.b = FcFalse;
292         break;
293     case FcTypeDouble:
294         v.u.d = strtod ((char *) string, 0);
295         break;
296     case FcTypeMatrix:
297         v.u.m = m;
298         sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
299         break;
300     case FcTypeCharSet:
301         v.u.c = FcNameParseCharSet (string);
302         break;
303     case FcTypeLangSet:
304         v.u.l = FcNameParseLangSet (string);
305         break;
306     default:
307         break;
308     }
309     return v;
310 }
311
312 static const FcChar8 *
313 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
314 {
315     FcChar8    c;
316     
317     while ((c = *cur))
318     {
319         if (c == '\\')
320         {
321             ++cur;
322             if (!(c = *cur))
323                 break;
324         }
325         else if (strchr (delim, c))
326             break;
327         ++cur;
328         *save++ = c;
329     }
330     *save = 0;
331     *last = *cur;
332     if (*cur)
333         cur++;
334     return cur;
335 }
336
337 FcPattern *
338 FcNameParse (const FcChar8 *name)
339 {
340     FcChar8             *save;
341     FcPattern           *pat;
342     double              d;
343     FcChar8             *e;
344     FcChar8             delim;
345     FcValue             v;
346     FcMatrix            m;
347     const FcObjectType  *t;
348     const FcConstant    *c;
349
350     save = malloc (strlen ((char *) name) + 1);
351     if (!save)
352         goto bail0;
353     pat = FcPatternCreate ();
354     if (!pat)
355         goto bail1;
356
357     for (;;)
358     {
359         name = FcNameFindNext (name, "-,:", save, &delim);
360         if (save[0])
361         {
362             if (!FcPatternAddString (pat, FC_FAMILY, save))
363                 goto bail2;
364         }
365         if (delim != ',')
366             break;
367     }
368     if (delim == '-')
369     {
370         for (;;)
371         {
372             name = FcNameFindNext (name, "-,:", save, &delim);
373             d = strtod ((char *) save, (char **) &e);
374             if (e != save)
375             {
376                 if (!FcPatternAddDouble (pat, FC_SIZE, d))
377                     goto bail2;
378             }
379             if (delim != ',')
380                 break;
381         }
382     }
383     while (delim == ':')
384     {
385         name = FcNameFindNext (name, "=_:", save, &delim);
386         if (save[0])
387         {
388             if (delim == '=' || delim == '_')
389             {
390                 t = FcNameGetObjectType ((char *) save);
391                 for (;;)
392                 {
393                     name = FcNameFindNext (name, ":,", save, &delim);
394                     if (t)
395                     {
396                         v = FcNameConvert (t->type, save, &m);
397                         if (!FcPatternAdd (pat, t->object, v, FcTrue))
398                         {
399                             switch (v.type) {
400                             case FcTypeCharSet:
401                                 FcCharSetDestroy ((FcCharSet *) v.u.c);
402                                 break;
403                             case FcTypeLangSet:
404                                 FcLangSetDestroy ((FcLangSet *) v.u.l);
405                                 break;
406                             default:
407                                 break;
408                             }
409                             goto bail2;
410                         }
411                         switch (v.type) {
412                         case FcTypeCharSet:
413                             FcCharSetDestroy ((FcCharSet *) v.u.c);
414                             break;
415                         case FcTypeLangSet:
416                             FcLangSetDestroy ((FcLangSet *) v.u.l);
417                             break;
418                         default:
419                             break;
420                         }
421                     }
422                     if (delim != ',')
423                         break;
424                 }
425             }
426             else
427             {
428                 if ((c = FcNameGetConstant (save)))
429                 {
430                     if (!FcPatternAddInteger (pat, c->object, c->value))
431                         goto bail2;
432                 }
433             }
434         }
435     }
436
437     free (save);
438     return pat;
439
440 bail2:
441     FcPatternDestroy (pat);
442 bail1:
443     free (save);
444 bail0:
445     return 0;
446 }
447 static FcBool
448 FcNameUnparseString (FcStrBuf       *buf, 
449                      const FcChar8  *string,
450                      const FcChar8  *escape)
451 {
452     FcChar8 c;
453     while ((c = *string++))
454     {
455         if (escape && strchr ((char *) escape, (char) c))
456         {
457             if (!FcStrBufChar (buf, escape[0]))
458                 return FcFalse;
459         }
460         if (!FcStrBufChar (buf, c))
461             return FcFalse;
462     }
463     return FcTrue;
464 }
465
466 static FcBool
467 FcNameUnparseValue (FcStrBuf    *buf,
468                     FcValue     v,
469                     FcChar8     *escape)
470 {
471     FcChar8     temp[1024];
472     
473     switch (v.type) {
474     case FcTypeVoid:
475         return FcTrue;
476     case FcTypeInteger:
477         sprintf ((char *) temp, "%d", v.u.i);
478         return FcNameUnparseString (buf, temp, 0);
479     case FcTypeDouble:
480         sprintf ((char *) temp, "%g", v.u.d);
481         return FcNameUnparseString (buf, temp, 0);
482     case FcTypeString:
483         return FcNameUnparseString (buf, v.u.s, escape);
484     case FcTypeBool:
485         return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
486     case FcTypeMatrix:
487         sprintf ((char *) temp, "%g %g %g %g", 
488                  v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
489         return FcNameUnparseString (buf, temp, 0);
490     case FcTypeCharSet:
491         return FcNameUnparseCharSet (buf, v.u.c);
492     case FcTypeLangSet:
493         return FcNameUnparseLangSet (buf, v.u.l);
494     case FcTypeFTFace:
495         return FcTrue;
496     }
497     return FcFalse;
498 }
499
500 static FcBool
501 FcNameUnparseValueList (FcStrBuf        *buf,
502                         FcValueList     *v,
503                         FcChar8         *escape)
504 {
505     while (v)
506     {
507         if (!FcNameUnparseValue (buf, v->value, escape))
508             return FcFalse;
509         if ((v = v->next))
510             if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
511                 return FcFalse;
512     }
513     return FcTrue;
514 }
515
516 #define FC_ESCAPE_FIXED    "\\-:,"
517 #define FC_ESCAPE_VARIABLE "\\=_:,"
518
519 FcChar8 *
520 FcNameUnparse (FcPattern *pat)
521 {
522     FcStrBuf                buf;
523     FcChar8                 buf_static[8192];
524     int                     i;
525     FcPatternElt            *e;
526     const FcObjectTypeList  *l;
527     const FcObjectType      *o;
528
529     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
530     e = FcPatternFindElt (pat, FC_FAMILY);
531     if (e)
532     {
533         if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
534             goto bail0;
535     }
536     e = FcPatternFindElt (pat, FC_SIZE);
537     if (e)
538     {
539         if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
540             goto bail0;
541         if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
542             goto bail0;
543     }
544     for (l = _FcObjectTypes; l; l = l->next)
545     {
546         for (i = 0; i < l->ntypes; i++)
547         {
548             o = &l->types[i];
549             if (!strcmp (o->object, FC_FAMILY) || 
550                 !strcmp (o->object, FC_SIZE) ||
551                 !strcmp (o->object, FC_FILE))
552                 continue;
553             
554             e = FcPatternFindElt (pat, o->object);
555             if (e)
556             {
557                 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
558                     goto bail0;
559                 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, (FcChar8 *) FC_ESCAPE_VARIABLE))
560                     goto bail0;
561                 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
562                     goto bail0;
563                 if (!FcNameUnparseValueList (&buf, e->values, 
564                                              (FcChar8 *) FC_ESCAPE_VARIABLE))
565                     goto bail0;
566             }
567         }
568     }
569     return FcStrBufDone (&buf);
570 bail0:
571     FcStrBufDestroy (&buf);
572     return 0;
573 }