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