geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

geany_css.c
Go to the documentation of this file.
1/***************************************************************************
2 * css.c
3 * Token-based parser for CSS definitions
4 * Author - Colomban Wendling <colomban@geany.org>
5 * License GPL-2
6 **************************************************************************/
7#include "general.h"
8
9#include <string.h>
10#include <ctype.h>
11
12#include "entry.h"
13#include "parse.h"
14#include "read.h"
15#include "routines.h"
16
17#define isSelectorChar(c) \
18 /* attribute selectors are handled separately */ \
19 (isalnum (c) || \
20 (c) == '_' || /* allowed char */ \
21 (c) == '-' || /* allowed char */ \
22 (c) == '+' || /* allow all sibling in a single tag */ \
23 (c) == '>' || /* allow all child in a single tag */ \
24 (c) == '|' || /* allow namespace separator */ \
25 (c) == '(' || /* allow pseudo-class arguments */ \
26 (c) == ')' || \
27 (c) == '.' || /* allow classes and selectors */ \
28 (c) == ':' || /* allow pseudo classes */ \
29 (c) == '*' || /* allow globs as P + * */ \
30 (c) == '#') /* allow ids */
31
32typedef enum eCssKinds {
35
37 { true, 'c', "class", "classes" },
38 { true, 's', "selector", "selectors" },
39 { true, 'i', "id", "identities" }
40};
41
42typedef enum {
43 /* any ASCII */
44 TOKEN_EOF = 257,
48
49typedef struct {
52} tokenInfo;
53
54
55static void parseSelector (vString *const string, const int firstChar)
56{
57 int c = firstChar;
58 do
59 {
60 vStringPut (string, (char) c);
61 c = getcFromInputFile ();
62 } while (isSelectorChar (c));
64}
65
66static void readToken (tokenInfo *const token)
67{
68 int c;
69
70 vStringClear (token->string);
71
72getNextChar:
73
74 c = getcFromInputFile ();
75 while (isspace (c))
76 c = getcFromInputFile ();
77
78 token->type = c;
79 switch (c)
80 {
81 case EOF: token->type = TOKEN_EOF; break;
82
83 case '\'':
84 case '"':
85 {
86 const int delimiter = c;
87 do
88 {
89 vStringPut (token->string, c);
90 c = getcFromInputFile ();
91 if (c == '\\')
92 c = getcFromInputFile ();
93 }
94 while (c != EOF && c != delimiter);
95 if (c != EOF)
96 vStringPut (token->string, c);
97 token->type = TOKEN_STRING;
98 break;
99 }
100
101 case '/': /* maybe comment start */
102 {
103 int d = getcFromInputFile ();
104 if (d != '*')
105 {
107 vStringPut (token->string, c);
108 token->type = c;
109 }
110 else
111 {
112 d = getcFromInputFile ();
113 do
114 {
115 c = d;
116 d = getcFromInputFile ();
117 }
118 while (d != EOF && ! (c == '*' && d == '/'));
119 goto getNextChar;
120 }
121 break;
122 }
123
124 default:
125 if (! isSelectorChar (c))
126 {
127 vStringPut (token->string, c);
128 token->type = c;
129 }
130 else
131 {
132 parseSelector (token->string, c);
133 token->type = TOKEN_SELECTOR;
134 }
135 break;
136 }
137}
138
139/* sets selector kind in @p kind if found, otherwise don't touches @p kind */
140static cssKind classifySelector (const vString *const selector)
141{
142 size_t i;
143
144 for (i = vStringLength (selector); i > 0; --i)
145 {
146 char c = vStringChar (selector, i - 1);
147 if (c == '.')
148 return K_CLASS;
149 else if (c == '#')
150 return K_ID;
151 }
152 return K_SELECTOR;
153}
154
155static void findCssTags (void)
156{
157 bool readNextToken = true;
158 tokenInfo token;
159
160 token.string = vStringNew ();
161
162 do
163 {
164 if (readNextToken)
165 readToken (&token);
166
167 readNextToken = true;
168
169 if (token.type == '@')
170 { /* At-rules, from the "@" to the next block or semicolon */
171 bool useContents;
172 readToken (&token);
173 useContents = (strcmp (vStringValue (token.string), "media") == 0 ||
174 strcmp (vStringValue (token.string), "supports") == 0);
175 while (token.type != TOKEN_EOF &&
176 token.type != ';' && token.type != '{')
177 {
178 readToken (&token);
179 }
180 /* HACK: we *eat* the opening '{' for medias and the like so that
181 * the content is parsed as if it was at the root */
182 readNextToken = useContents && token.type == '{';
183 }
184 else if (token.type == TOKEN_SELECTOR)
185 { /* collect selectors and make a tag */
186 cssKind kind = K_SELECTOR;
188 unsigned long lineNumber;
189 vString *selector = vStringNew ();
190 do
191 {
192 if (vStringLength (selector) > 0)
193 vStringPut (selector, ' ');
194 vStringCat (selector, token.string);
195
196 kind = classifySelector (token.string);
199
200 readToken (&token);
201
202 /* handle attribute selectors */
203 if (token.type == '[')
204 {
205 int depth = 1;
206 while (depth > 0 && token.type != TOKEN_EOF)
207 {
208 vStringCat (selector, token.string);
209 readToken (&token);
210 if (token.type == '[')
211 depth++;
212 else if (token.type == ']')
213 depth--;
214 }
215 if (token.type != TOKEN_EOF)
216 vStringCat (selector, token.string);
217 readToken (&token);
218 }
219 }
220 while (token.type == TOKEN_SELECTOR);
221 /* we already consumed the next token, don't read it twice */
222 readNextToken = false;
223
224 if (CssKinds[kind].enabled)
225 {
226 tagEntryInfo e;
227 initTagEntry (&e, vStringValue (selector), kind);
228
231
232 makeTagEntry (&e);
233 }
234 vStringDelete (selector);
235 }
236 else if (token.type == '{')
237 { /* skip over { ... } */
238 int depth = 1;
239 while (depth > 0 && token.type != TOKEN_EOF)
240 {
241 readToken (&token);
242 if (token.type == '{')
243 depth++;
244 else if (token.type == '}')
245 depth--;
246 }
247 }
248 }
249 while (token.type != TOKEN_EOF);
250
251 vStringDelete (token.string);
252}
253
254/* parser definition */
256{
257 static const char *const extensions [] = { "css", NULL };
258 parserDefinition* def = parserNew ("CSS");
259 def->kindTable = CssKinds;
261 def->extensions = extensions;
262 def->parser = findCssTags;
263 return def;
264}
int makeTagEntry(const tagEntryInfo *const tag)
Definition: entry.c:1675
void initTagEntry(tagEntryInfo *const e, const char *const name, int kindIndex)
Definition: entry.c:1823
unsigned long int lineNumber
Definition: geany_cobol.c:134
MIOPos filePosition
Definition: geany_cobol.c:135
static void parseSelector(vString *const string, const int firstChar)
Definition: geany_css.c:55
static void findCssTags(void)
Definition: geany_css.c:155
eCssKinds
Definition: geany_css.c:32
@ K_SELECTOR
Definition: geany_css.c:33
@ K_ID
Definition: geany_css.c:33
@ K_CLASS
Definition: geany_css.c:33
tokenType
Definition: geany_css.c:42
@ TOKEN_SELECTOR
Definition: geany_css.c:45
@ TOKEN_EOF
Definition: geany_css.c:44
@ TOKEN_STRING
Definition: geany_css.c:46
#define isSelectorChar(c)
css.c Token-based parser for CSS definitions Author - Colomban Wendling colomban@geany....
Definition: geany_css.c:17
enum eCssKinds cssKind
static cssKind classifySelector(const vString *const selector)
Definition: geany_css.c:140
parserDefinition * CssParser(void)
Definition: geany_css.c:255
static kindDefinition CssKinds[]
Definition: geany_css.c:36
static void readToken(tokenInfo *const token)
Definition: geany_css.c:66
parserDefinition * parserNew(const char *name)
Definition: parse.c:237
#define NULL
Definition: rbtree.h:150
unsigned long getInputLineNumber(void)
Definition: read.c:142
int getcFromInputFile(void)
Definition: read.c:923
MIOPos getInputFilePosition(void)
Definition: read.c:161
void ungetcToInputFile(int c)
Definition: read.c:813
#define ARRAY_SIZE(X)
Definition: routines.h:27
MIOPos:
Definition: mio.h:101
const char *const * extensions
Definition: parse.h:78
simpleParser parser
Definition: parse.h:83
kindDefinition * kindTable
Definition: parse.h:76
unsigned int kindCount
Definition: parse.h:77
MIOPos filePosition
Definition: entry.h:60
unsigned long lineNumber
Definition: entry.h:56
tokenType type
Definition: geany_css.c:50
vString * string
Definition: geany_css.c:51
struct sTokenInfo tokenInfo
vString * vStringNew(void)
Definition: vstring.c:70
void vStringDelete(vString *const string)
Definition: vstring.c:60
void vStringCat(vString *const string, const vString *const s)
Definition: vstring.c:139
#define vStringChar(vs, i)
Definition: vstring.h:29
#define vStringClear(string)
Definition: vstring.h:36
#define vStringLength(vs)
Definition: vstring.h:31
#define vStringValue(vs)
Definition: vstring.h:28
static void vStringPut(vString *const string, const int c)
Definition: vstring.h:101