]> git.wh0rd.org - fontconfig.git/blob - src/fcformat.c
[fcformat] Refactor and restructure code for upcoming changes
[fontconfig.git] / src / fcformat.c
1 /*
2 * Copyright © 2008 Red Hat, Inc.
3 *
4 * Red Hat Author(s): Behdad Esfahbod
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 "fcint.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29
30
31 static void
32 message (const char *fmt, ...)
33 {
34 va_list args;
35 va_start (args, fmt);
36 fprintf (stderr, "Fontconfig: ");
37 vfprintf (stderr, fmt, args);
38 fprintf (stderr, "\n");
39 va_end (args);
40 }
41
42
43 typedef struct _FcFormatContext
44 {
45 const FcChar8 *format_orig;
46 const FcChar8 *format;
47 int format_len;
48 FcChar8 *scratch;
49 } FcFormatContext;
50
51 static void
52 FcFormatContextInit (FcFormatContext *c,
53 const FcChar8 *format)
54 {
55 c->format_orig = c->format = format;
56 c->format_len = strlen ((const char *) format);
57 c->scratch = malloc (c->format_len + 1);
58 }
59
60 static void
61 FcFormatContextDone (FcFormatContext *c)
62 {
63 if (c)
64 {
65 free (c->scratch);
66 }
67 }
68
69 static FcBool
70 consume_char (FcFormatContext *c,
71 FcChar8 term)
72 {
73 if (*c->format != term)
74 {
75 message ("Pattern format error: expected '%c' at %d",
76 term, c->format - c->format_orig + 1);
77 return FcFalse;
78 }
79
80 c->format++;
81 return FcTrue;
82 }
83
84 static void
85 interpret_percent (FcFormatContext *c,
86 FcPattern *pat,
87 FcStrBuf *buf)
88 {
89 int width, before;
90 FcChar8 *p;
91 FcPatternElt *e;
92
93 if (!consume_char (c, '%'))
94 return;
95
96 if (*c->format == '%') /* "%%" */
97 {
98 FcStrBufChar (buf, *c->format++);
99 return;
100 }
101
102 /* parse an optional width specifier */
103 width = strtol ((const char *) c->format, (char **) &c->format, 10);
104
105 before = buf->len;
106
107 if (!consume_char (c, '{'))
108 return;
109
110 p = (FcChar8 *) strpbrk ((const char *) c->format, "}" /* "=?:}" */);
111 if (!p)
112 {
113 message ("Pattern format missing closing brace for opening brace at %d",
114 c->format-1 - c->format_orig + 1);
115 return;
116 }
117 /* extract the element name */
118 memcpy (c->scratch, c->format, p - c->format);
119 c->scratch[p - c->format] = '\0';
120 c->format = p;
121
122 e = FcPatternObjectFindElt (pat, FcObjectFromName ((const char *) c->scratch));
123 if (e)
124 {
125 FcValueListPtr l;
126 l = FcPatternEltValues(e);
127 FcNameUnparseValueList (buf, l, '\0');
128 }
129
130 /* handle filters, if any */
131 /* XXX */
132
133 /* align to width */
134 if (!buf->failed)
135 {
136 int after, len;
137
138 after = buf->len;
139
140 len = after - before;
141
142 if (len < -width)
143 {
144 /* left align */
145 while (len++ < -width)
146 FcStrBufChar (buf, ' ');
147 }
148 else if (len < width)
149 {
150 /* right align */
151 while (len++ < width)
152 FcStrBufChar (buf, ' ');
153 len = after - before;
154 memmove (buf->buf + buf->len - len,
155 buf->buf + buf->len - width,
156 len);
157 memset (buf->buf + buf->len - width,
158 ' ',
159 width - len);
160 }
161 }
162
163 consume_char (c, '}');
164 }
165
166 static char escaped_char(const char ch)
167 {
168 switch (ch) {
169 case 'a': return '\a';
170 case 'b': return '\b';
171 case 'f': return '\f';
172 case 'n': return '\n';
173 case 'r': return '\r';
174 case 't': return '\t';
175 case 'v': return '\v';
176 default: return ch;
177 }
178 }
179
180 static void
181 interpret (FcFormatContext *c,
182 FcPattern *pat,
183 FcStrBuf *buf,
184 FcChar8 term)
185 {
186 for (; *c->format && *c->format != term;)
187 {
188 switch (*c->format)
189 {
190 case '\\':
191 c->format++; /* skip over '\\' */
192 if (*c->format)
193 FcStrBufChar (buf, escaped_char (*c->format++));
194 continue;
195 case '%':
196 interpret_percent (c, pat, buf);
197 continue;
198 }
199 FcStrBufChar (buf, *c->format++);
200 }
201 if (*c->format != term)
202 message ("Pattern format ended while looking for '%c'", term);
203 }
204
205 FcChar8 *
206 FcPatternFormat (FcPattern *pat, const FcChar8 *format)
207 {
208 FcStrBuf buf;
209 FcFormatContext c;
210
211 FcStrBufInit (&buf, 0, 0);
212 FcFormatContextInit (&c, format);
213
214 interpret (&c, pat, &buf, '\0');
215
216 FcFormatContextDone (&c);
217 return FcStrBufDone (&buf);
218 }
219
220 #define __fcformat__
221 #include "fcaliastail.h"
222 #undef __fcformat__