3
3
* Character-based parser for Css definitions
4
4
* Author - Iago Rubio <iagorubio(at)users.sourceforge.net>
5
* - Bronisław Białek <after89(at)gmail.com>
5
6
**************************************************************************/
15
16
typedef enum eCssKinds {
16
K_NONE = -1, K_CLASS, K_SELECTOR, K_ID
17
K_NONE = -1, K_SELECTOR, K_ID, K_CLASS
19
20
static kindOption CssKinds [] = {
20
{ TRUE, 'c', "class", "classes" },
21
{ TRUE, 's', "selector", "selectors" },
22
{ TRUE, 'v', "variable", "identities" }
21
{ TRUE, 's', "struct", "selectors" },
22
{ TRUE, 'v', "variable", "identities" },
23
{ TRUE, 'c', "class", "classes" }
25
26
typedef enum _CssParserState { /* state of parsing */
61
62
*cp == '#'; /* allow ids */
64
static CssParserState parseCssDeclaration( const unsigned char **position, cssKind kind )
65
static CssParserState parseCssDeclaration( const unsigned char **position, cssKind kind, const char *aname)
67
const unsigned char *cp = *position;
66
68
vString *name = vStringNew ();
67
const unsigned char *cp = *position;
69
vStringCopyS(name, aname);
69
71
/* pick to the end of line including children and sibling
70
72
* if declaration is multiline go for the next line */
71
73
while ( isCssDeclarationAllowedChar(cp) ||
72
74
*cp == '\0' ) /* track the end of line into the loop */
74
if( (int) *cp == '\0' )
78
makeCssSimpleTag(name, kind, TRUE);
80
return P_STATE_AT_END;
85
78
makeCssSimpleTag(name, kind, TRUE);
87
80
return P_STATE_NONE;
82
else if( *cp == '{' || *cp == '\0' )
83
{ /* assume that line end is the same as a starting definition (i.e. the { is on the next line */
91
84
makeCssSimpleTag(name, kind, TRUE);
93
86
return P_STATE_IN_DEFINITION;
106
99
static CssParserState parseCssLine( const unsigned char *line, CssParserState state )
102
vString *stack = vStringNew ();
110
104
while( *line != '\0' ) /* fileReadLine returns NULL terminated strings */
112
while (isspace ((int) *line))
106
vStringClear (stack);
107
while (state == P_STATE_NONE &&
108
(isspace ((int) *line) || isalnum ((int) *line) || ( *line == '*' && *(line-1) != '/' )))
110
if ((stack->length > 0 && isspace((int) *line)) || isalnum ((int) *line) || *line == '*') {
111
vStringPut(stack, (int) *line);
116
vStringTerminate (stack);
116
120
case P_STATE_NONE:
117
/* pick first char if alphanumeric is a selector */
118
if( isalnum ((int) *line) )
119
state = parseCssDeclaration( &line, K_SELECTOR );
120
else if( *line == '.' ) /* a class */
121
state = parseCssDeclaration( &line, K_CLASS );
121
if( *line == '.' ) /* a class */
122
state = parseCssDeclaration( &line, K_CLASS, vStringValue(stack) );
122
123
else if( *line == '#' ) /* an id */
123
state = parseCssDeclaration( &line, K_ID );
124
state = parseCssDeclaration( &line, K_ID, vStringValue(stack) );
124
125
else if( *line == '@' ) /* at-rules, we'll ignore them */
146
147
else if( *line == '*' && *(line-1) == '/' ) /* multi-line comment */
147
148
state = P_STATE_IN_COMMENT;
149
else if ( stack->length > 0 )
150
state = parseCssDeclaration( &line, K_SELECTOR, vStringValue(stack) );
149
153
case P_STATE_IN_COMMENT:
150
154
if( *line == '/' && *(line-1) == '*')