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