2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
17 #define SECTION_SEP_CHAR '/'
19 #define STATE_INIT_COMMENT 1
20 #define STATE_STD_LINE 2
21 #define STATE_GET_OBRACE 3
26 struct profile_node
*root_section
;
27 struct profile_node
*current_section
;
30 static char *skip_over_blanks(char *cp
)
32 while (*cp
&& isspace((int) (*cp
)))
37 static void strip_line(char *line
)
39 char *p
= line
+ strlen(line
);
40 while (p
> line
&& (p
[-1] == '\n' || p
[-1] == '\r'))
44 static void parse_quoted_string(char *str
)
50 for (to
= from
= str
; *from
&& *from
!= '"'; to
++, from
++) {
74 static errcode_t
parse_init_state(struct parse_state
*state
)
76 state
->state
= STATE_INIT_COMMENT
;
77 state
->group_level
= 0;
79 return profile_create_node("(root)", 0, &state
->root_section
);
82 static errcode_t
parse_std_line(char *line
, struct parse_state
*state
)
84 char *cp
, ch
, *tag
, *value
;
87 struct profile_node
*node
;
88 int do_subsection
= 0;
93 cp
= skip_over_blanks(line
);
94 if (cp
[0] == ';' || cp
[0] == '#')
101 if (state
->group_level
> 0)
102 return PROF_SECTION_NOTOP
;
106 return PROF_SECTION_SYNTAX
;
108 retval
= profile_find_node_subsection(state
->root_section
,
110 &state
->current_section
);
111 if (retval
== PROF_NO_SECTION
) {
112 retval
= profile_add_node(state
->root_section
,
114 &state
->current_section
);
121 * Finish off the rest of the line.
125 profile_make_node_final(state
->current_section
);
129 * A space after ']' should not be fatal
131 cp
= skip_over_blanks(cp
);
133 return PROF_SECTION_SYNTAX
;
137 if (state
->group_level
== 0)
138 return PROF_EXTRA_CBRACE
;
140 profile_make_node_final(state
->current_section
);
141 retval
= profile_get_node_parent(state
->current_section
,
142 &state
->current_section
);
145 state
->group_level
--;
149 * Parse the relations
152 cp
= strchr(cp
, '=');
154 return PROF_RELATION_SYNTAX
;
156 return PROF_RELATION_SYNTAX
;
159 /* Look for whitespace on left-hand side. */
160 while (p
< cp
&& !isspace((int)*p
))
163 /* Found some sort of whitespace. */
165 /* If we have more non-whitespace, it's an error. */
167 if (!isspace((int)*p
))
168 return PROF_RELATION_SYNTAX
;
172 cp
= skip_over_blanks(cp
+1);
174 if (value
[0] == '"') {
176 parse_quoted_string(value
);
177 } else if (value
[0] == 0) {
179 state
->state
= STATE_GET_OBRACE
;
180 } else if (value
[0] == '{' && *(skip_over_blanks(value
+1)) == 0)
183 cp
= value
+ strlen(value
) - 1;
184 while ((cp
> value
) && isspace((int) (*cp
)))
188 p
= strchr(tag
, '*');
191 retval
= profile_add_node(state
->current_section
,
192 tag
, 0, &state
->current_section
);
196 profile_make_node_final(state
->current_section
);
197 state
->group_level
++;
200 p
= strchr(tag
, '*');
203 profile_add_node(state
->current_section
, tag
, value
, &node
);
205 profile_make_node_final(node
);
209 static errcode_t
parse_line(char *line
, struct parse_state
*state
)
213 switch (state
->state
) {
214 case STATE_INIT_COMMENT
:
217 state
->state
= STATE_STD_LINE
;
220 return parse_std_line(line
, state
);
221 case STATE_GET_OBRACE
:
222 cp
= skip_over_blanks(line
);
224 return PROF_MISSING_OBRACE
;
225 state
->state
= STATE_STD_LINE
;
231 errcode_t
profile_parse_file(FILE *f
, struct profile_node
**root
)
233 #define BUF_SIZE 2048
236 struct parse_state state
;
238 bptr
= malloc (BUF_SIZE
);
242 retval
= parse_init_state(&state
);
248 if (fgets(bptr
, BUF_SIZE
, f
) == NULL
)
250 #ifndef PROFILE_SUPPORTS_FOREIGN_NEWLINES
251 retval
= parse_line(bptr
, &state
);
253 /* Solaris Kerberos: check if an unconfigured file */
254 if (strstr(bptr
, "___"))
255 retval
= PROF_NO_PROFILE
;
263 if (strlen(bptr
) >= BUF_SIZE
- 1) {
264 /* The string may have foreign newlines and
265 gotten chopped off on a non-newline
266 boundary. Seek backwards to the last known
269 char *c
= bptr
+ strlen (bptr
);
270 for (offset
= 0; offset
> -BUF_SIZE
; offset
--) {
271 if (*c
== '\r' || *c
== '\n') {
273 fseek (f
, offset
, SEEK_CUR
);
280 /* First change all newlines to \n */
281 for (p
= bptr
; *p
!= '\0'; p
++) {
285 /* Then parse all lines */
287 end
= bptr
+ strlen (bptr
);
292 newline
= strchr (p
, '\n');
296 /* parse_line modifies contents of p */
297 newp
= p
+ strlen (p
) + 1;
298 retval
= parse_line (p
, &state
);
309 *root
= state
.root_section
;
316 * Return TRUE if the string begins or ends with whitespace
318 static int need_double_quotes(char *str
)
324 if (isspace((int) (*str
)) ||isspace((int) (*(str
+ strlen(str
) - 1))))
326 if (strchr(str
, '\n') || strchr(str
, '\t') || strchr(str
, '\b'))
332 * Output a string with double quotes, doing appropriate backquoting
333 * of characters as necessary.
335 static void output_quoted_string(char *str
, void (*cb
)(const char *,void *),
347 while ((ch
= *str
++)) {
362 /* This would be a lot faster if we scanned
363 forward for the next "interesting"
383 /* Errors should be returned, not ignored! */
384 static void dump_profile(struct profile_node
*root
, int level
,
385 void (*cb
)(const char *, void *), void *data
)
388 struct profile_node
*p
;
395 retval
= profile_find_node_relation(root
, 0, &iter
,
399 for (i
=0; i
< level
; i
++)
401 if (need_double_quotes(value
)) {
404 output_quoted_string(value
, cb
, data
);
416 retval
= profile_find_node_subsection(root
, 0, &iter
,
420 if (level
== 0) { /* [xxx] */
424 cb(profile_is_node_final(p
) ? "*" : "", data
);
426 dump_profile(p
, level
+1, cb
, data
);
428 } else { /* xxx = { ... } */
429 for (i
=0; i
< level
; i
++)
434 dump_profile(p
, level
+1, cb
, data
);
435 for (i
=0; i
< level
; i
++)
438 cb(profile_is_node_final(p
) ? "*" : "", data
);
444 static void dump_profile_to_file_cb(const char *str
, void *data
)
449 errcode_t
profile_write_tree_file(struct profile_node
*root
, FILE *dstfile
)
451 dump_profile(root
, 0, dump_profile_to_file_cb
, dstfile
);
461 static void add_data_to_buffer(struct prof_buf
*b
, const void *d
, size_t len
)
465 if (b
->max
- b
->cur
< len
) {
469 newsize
= b
->max
+ (b
->max
>> 1) + len
+ 1024;
470 newptr
= realloc(b
->base
, newsize
);
471 if (newptr
== NULL
) {
478 memcpy(b
->base
+ b
->cur
, d
, len
);
479 b
->cur
+= len
; /* ignore overflow */
482 static void dump_profile_to_buffer_cb(const char *str
, void *data
)
484 add_data_to_buffer((struct prof_buf
*)data
, str
, strlen(str
));
487 errcode_t
profile_write_tree_to_buffer(struct profile_node
*root
,
490 struct prof_buf prof_buf
= { 0, 0, 0, 0 };
492 dump_profile(root
, 0, dump_profile_to_buffer_cb
, &prof_buf
);
497 add_data_to_buffer(&prof_buf
, "", 1); /* append nul */
498 if (prof_buf
.max
- prof_buf
.cur
> (prof_buf
.max
>> 3)) {
499 char *newptr
= realloc(prof_buf
.base
, prof_buf
.cur
);
501 prof_buf
.base
= newptr
;
503 *buf
= prof_buf
.base
;