Add ref counting to font config patterns so that FcFontSort return values
[platform/upstream/fontconfig.git] / src / fcname.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcname.c,v 1.7 2002/06/03 08:31:15 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_XLFD,                FcTypeString, }, */
44     { FC_FILE,          FcTypeString, },
45     { FC_INDEX,         FcTypeInteger, },
46     { FC_RASTERIZER,    FcTypeString, },
47     { FC_OUTLINE,       FcTypeBool, },
48     { FC_SCALABLE,      FcTypeBool, },
49     { FC_RGBA,          FcTypeInteger, },
50     { FC_SCALE,         FcTypeDouble, },
51 /*    { FC_RENDER,      FcTypeBool, },*/
52     { FC_MINSPACE,      FcTypeBool, },
53     { FC_CHAR_WIDTH,    FcTypeInteger },
54     { FC_CHAR_HEIGHT,   FcTypeInteger },
55     { FC_MATRIX,        FcTypeMatrix },
56     { FC_CHARSET,       FcTypeCharSet },
57     { FC_LANG,          FcTypeString },
58 };
59
60 #define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
61
62 typedef struct _FcObjectTypeList    FcObjectTypeList;
63
64 struct _FcObjectTypeList {
65     const FcObjectTypeList  *next;
66     const FcObjectType      *types;
67     int                     ntypes;
68 };
69
70 static const FcObjectTypeList _FcBaseObjectTypesList = {
71     0,
72     _FcBaseObjectTypes,
73     NUM_OBJECT_TYPES
74 };
75
76 static const FcObjectTypeList   *_FcObjectTypes = &_FcBaseObjectTypesList;
77
78 FcBool
79 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
80 {
81     FcObjectTypeList    *l;
82
83     l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
84     if (!l)
85         return FcFalse;
86     l->types = types;
87     l->ntypes = ntypes;
88     l->next = _FcObjectTypes;
89     _FcObjectTypes = l;
90     return FcTrue;
91 }
92
93 FcBool
94 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
95 {
96     const FcObjectTypeList      *l, **prev;
97
98     for (prev = &_FcObjectTypes; 
99          (l = *prev); 
100          prev = (const FcObjectTypeList **) &(l->next))
101     {
102         if (l->types == types && l->ntypes == ntypes)
103         {
104             *prev = l->next;
105             free ((void *) l);
106             return FcTrue;
107         }
108     }
109     return FcFalse;
110 }
111
112 const FcObjectType *
113 FcNameGetObjectType (const char *object)
114 {
115     int                     i;
116     const FcObjectTypeList  *l;
117     const FcObjectType      *t;
118     
119     for (l = _FcObjectTypes; l; l = l->next)
120     {
121         for (i = 0; i < l->ntypes; i++)
122         {
123             t = &l->types[i];
124             if (!strcmp (object, t->object))
125                 return t;
126         }
127     }
128     return 0;
129 }
130
131 static const FcConstant _FcBaseConstants[] = {
132     { (FcChar8 *) "light",          "weight",   FC_WEIGHT_LIGHT, },
133     { (FcChar8 *) "medium",         "weight",   FC_WEIGHT_MEDIUM, },
134     { (FcChar8 *) "demibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
135     { (FcChar8 *) "bold",           "weight",   FC_WEIGHT_BOLD, },
136     { (FcChar8 *) "black",          "weight",   FC_WEIGHT_BLACK, },
137
138     { (FcChar8 *) "roman",          "slant",    FC_SLANT_ROMAN, },
139     { (FcChar8 *) "italic",         "slant",    FC_SLANT_ITALIC, },
140     { (FcChar8 *) "oblique",        "slant",    FC_SLANT_OBLIQUE, },
141
142     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
143     { (FcChar8 *) "mono",           "spacing",  FC_MONO, },
144     { (FcChar8 *) "charcell",       "spacing",  FC_CHARCELL, },
145
146     { (FcChar8 *) "none",           "rgba",         FC_RGBA_NONE },
147     { (FcChar8 *) "rgb",            "rgba",         FC_RGBA_RGB, },
148     { (FcChar8 *) "bgr",            "rgba",         FC_RGBA_BGR, },
149     { (FcChar8 *) "vrgb",           "rgba",         FC_RGBA_VRGB },
150     { (FcChar8 *) "vbgr",           "rgba",         FC_RGBA_VBGR },
151 };
152
153 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
154
155 typedef struct _FcConstantList FcConstantList;
156
157 struct _FcConstantList {
158     const FcConstantList    *next;
159     const FcConstant        *consts;
160     int                     nconsts;
161 };
162
163 static const FcConstantList _FcBaseConstantList = {
164     0,
165     _FcBaseConstants,
166     NUM_FC_CONSTANTS
167 };
168
169 static const FcConstantList     *_FcConstants = &_FcBaseConstantList;
170
171 FcBool
172 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
173 {
174     FcConstantList      *l;
175
176     l = (FcConstantList *) malloc (sizeof (FcConstantList));
177     if (!l)
178         return FcFalse;
179     l->consts = consts;
180     l->nconsts = nconsts;
181     l->next = _FcConstants;
182     _FcConstants = l;
183     return FcTrue;
184 }
185
186 FcBool
187 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
188 {
189     const FcConstantList        *l, **prev;
190
191     for (prev = &_FcConstants; 
192          (l = *prev); 
193          prev = (const FcConstantList **) &(l->next))
194     {
195         if (l->consts == consts && l->nconsts == nconsts)
196         {
197             *prev = l->next;
198             free ((void *) l);
199             return FcTrue;
200         }
201     }
202     return FcFalse;
203 }
204
205 const FcConstant *
206 FcNameGetConstant (FcChar8 *string)
207 {
208     const FcConstantList    *l;
209     int                     i;
210     
211     for (l = _FcConstants; l; l = l->next)
212     {
213         for (i = 0; i < l->nconsts; i++)
214             if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
215                 return &l->consts[i];
216     }
217     return 0;
218 }
219
220 FcBool
221 FcNameConstant (FcChar8 *string, int *result)
222 {
223     const FcConstant    *c;
224
225     if ((c = FcNameGetConstant(string)))
226     {
227         *result = c->value;
228         return FcTrue;
229     }
230     return FcFalse;
231 }
232
233 FcBool
234 FcNameBool (FcChar8 *v, FcBool *result)
235 {
236     char    c0, c1;
237
238     c0 = *v;
239     if (isupper (c0))
240         c0 = tolower (c0);
241     if (c0 == 't' || c0 == 'y' || c0 == '1')
242     {
243         *result = FcTrue;
244         return FcTrue;
245     }
246     if (c0 == 'f' || c0 == 'n' || c0 == '0')
247     {
248         *result = FcFalse;
249         return FcTrue;
250     }
251     if (c0 == 'o')
252     {
253         c1 = v[1];
254         if (isupper (c1))
255             c1 = tolower (c1);
256         if (c1 == 'n')
257         {
258             *result = FcTrue;
259             return FcTrue;
260         }
261         if (c1 == 'f')
262         {
263             *result = FcFalse;
264             return FcTrue;
265         }
266     }
267     return FcFalse;
268 }
269
270 static FcValue
271 FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
272 {
273     FcValue     v;
274
275     v.type = type;
276     switch (v.type) {
277     case FcTypeInteger:
278         if (!FcNameConstant (string, &v.u.i))
279             v.u.i = atoi ((char *) string);
280         break;
281     case FcTypeString:
282         v.u.s = string;
283         break;
284     case FcTypeBool:
285         if (!FcNameBool (string, &v.u.b))
286             v.u.b = FcFalse;
287         break;
288     case FcTypeDouble:
289         v.u.d = strtod ((char *) string, 0);
290         break;
291     case FcTypeMatrix:
292         v.u.m = m;
293         sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
294         break;
295     case FcTypeCharSet:
296         v.u.c = FcNameParseCharSet (string);
297         break;
298     default:
299         break;
300     }
301     return v;
302 }
303
304 static const FcChar8 *
305 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
306 {
307     FcChar8    c;
308     
309     while ((c = *cur))
310     {
311         if (c == '\\')
312         {
313             ++cur;
314             if (!(c = *cur))
315                 break;
316         }
317         else if (strchr (delim, c))
318             break;
319         ++cur;
320         *save++ = c;
321     }
322     *save = 0;
323     *last = *cur;
324     if (*cur)
325         cur++;
326     return cur;
327 }
328
329 FcPattern *
330 FcNameParse (const FcChar8 *name)
331 {
332     FcChar8             *save;
333     FcPattern           *pat;
334     double              d;
335     FcChar8             *e;
336     FcChar8             delim;
337     FcValue             v;
338     FcMatrix            m;
339     const FcObjectType  *t;
340     const FcConstant    *c;
341
342     save = malloc (strlen ((char *) name) + 1);
343     if (!save)
344         goto bail0;
345     pat = FcPatternCreate ();
346     if (!pat)
347         goto bail1;
348
349     for (;;)
350     {
351         name = FcNameFindNext (name, "-,:", save, &delim);
352         if (save[0])
353         {
354             if (!FcPatternAddString (pat, FC_FAMILY, save))
355                 goto bail2;
356         }
357         if (delim != ',')
358             break;
359     }
360     if (delim == '-')
361     {
362         for (;;)
363         {
364             name = FcNameFindNext (name, "-,:", save, &delim);
365             d = strtod ((char *) save, (char **) &e);
366             if (e != save)
367             {
368                 if (!FcPatternAddDouble (pat, FC_SIZE, d))
369                     goto bail2;
370             }
371             if (delim != ',')
372                 break;
373         }
374     }
375     while (delim == ':')
376     {
377         name = FcNameFindNext (name, "=_:", save, &delim);
378         if (save[0])
379         {
380             if (delim == '=' || delim == '_')
381             {
382                 t = FcNameGetObjectType ((char *) save);
383                 for (;;)
384                 {
385                     name = FcNameFindNext (name, ":,", save, &delim);
386                     if (save[0] && t)
387                     {
388                         v = FcNameConvert (t->type, save, &m);
389                         if (!FcPatternAdd (pat, t->object, v, FcTrue))
390                         {
391                             if (v.type == FcTypeCharSet)
392                                 FcCharSetDestroy ((FcCharSet *) v.u.c);
393                             goto bail2;
394                         }
395                         if (v.type == FcTypeCharSet)
396                             FcCharSetDestroy ((FcCharSet *) v.u.c);
397                     }
398                     if (delim != ',')
399                         break;
400                 }
401             }
402             else
403             {
404                 if ((c = FcNameGetConstant (save)))
405                 {
406                     if (!FcPatternAddInteger (pat, c->object, c->value))
407                         goto bail2;
408                 }
409             }
410         }
411     }
412
413     free (save);
414     return pat;
415
416 bail2:
417     FcPatternDestroy (pat);
418 bail1:
419     free (save);
420 bail0:
421     return 0;
422 }
423 static FcBool
424 FcNameUnparseString (FcStrBuf       *buf, 
425                      const FcChar8  *string,
426                      const FcChar8  *escape)
427 {
428     FcChar8 c;
429     while ((c = *string++))
430     {
431         if (escape && strchr ((char *) escape, (char) c))
432         {
433             if (!FcStrBufChar (buf, escape[0]))
434                 return FcFalse;
435         }
436         if (!FcStrBufChar (buf, c))
437             return FcFalse;
438     }
439     return FcTrue;
440 }
441
442 static FcBool
443 FcNameUnparseValue (FcStrBuf    *buf,
444                     FcValue     v,
445                     FcChar8     *escape)
446 {
447     FcChar8     temp[1024];
448     
449     switch (v.type) {
450     case FcTypeVoid:
451         return FcTrue;
452     case FcTypeInteger:
453         sprintf ((char *) temp, "%d", v.u.i);
454         return FcNameUnparseString (buf, temp, 0);
455     case FcTypeDouble:
456         sprintf ((char *) temp, "%g", v.u.d);
457         return FcNameUnparseString (buf, temp, 0);
458     case FcTypeString:
459         return FcNameUnparseString (buf, v.u.s, escape);
460     case FcTypeBool:
461         return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
462     case FcTypeMatrix:
463         sprintf ((char *) temp, "%g %g %g %g", 
464                  v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
465         return FcNameUnparseString (buf, temp, 0);
466     case FcTypeCharSet:
467         return FcNameUnparseCharSet (buf, v.u.c);
468     case FcTypeFTFace:
469         return FcTrue;
470     }
471     return FcFalse;
472 }
473
474 static FcBool
475 FcNameUnparseValueList (FcStrBuf        *buf,
476                         FcValueList     *v,
477                         FcChar8         *escape)
478 {
479     while (v)
480     {
481         if (!FcNameUnparseValue (buf, v->value, escape))
482             return FcFalse;
483         if ((v = v->next))
484             if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
485                 return FcFalse;
486     }
487     return FcTrue;
488 }
489
490 #define FC_ESCAPE_FIXED    "\\-:,"
491 #define FC_ESCAPE_VARIABLE "\\=_:,"
492
493 FcChar8 *
494 FcNameUnparse (FcPattern *pat)
495 {
496     FcStrBuf                buf;
497     FcChar8                 buf_static[8192];
498     int                     i;
499     FcPatternElt            *e;
500     const FcObjectTypeList  *l;
501     const FcObjectType      *o;
502
503     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
504     e = FcPatternFindElt (pat, FC_FAMILY);
505     if (e)
506     {
507         if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
508             goto bail0;
509     }
510     e = FcPatternFindElt (pat, FC_SIZE);
511     if (e)
512     {
513         if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
514             goto bail0;
515         if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
516             goto bail0;
517     }
518     for (l = _FcObjectTypes; l; l = l->next)
519     {
520         for (i = 0; i < l->ntypes; i++)
521         {
522             o = &l->types[i];
523             if (!strcmp (o->object, FC_FAMILY) || 
524                 !strcmp (o->object, FC_SIZE) ||
525                 !strcmp (o->object, FC_FILE))
526                 continue;
527             
528             e = FcPatternFindElt (pat, o->object);
529             if (e)
530             {
531                 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
532                     goto bail0;
533                 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, (FcChar8 *) FC_ESCAPE_VARIABLE))
534                     goto bail0;
535                 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
536                     goto bail0;
537                 if (!FcNameUnparseValueList (&buf, e->values, 
538                                              (FcChar8 *) FC_ESCAPE_VARIABLE))
539                     goto bail0;
540             }
541         }
542     }
543     return FcStrBufDone (&buf);
544 bail0:
545     FcStrBufDestroy (&buf);
546     return 0;
547 }