00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00027 #include <ctype.h>
00028 #include <errno.h>
00029 #include <fcntl.h>
00030 #include <sys/stat.h>
00031 #include <sys/types.h>
00032 #include <unistd.h>
00033
00034 #include "treeconf_int.h"
00035
00036 RCSTAG("@(#)$Id: tc_load.c,v 1.4 2005/06/07 04:53:50 klmitch Exp $");
00037
00043 #define Q_O -3
00044
00050 #define Q_X -2
00051
00057 #define Q_S -1
00058
00066 static int xform[] = {
00067 '\a', '\b', Q_S, Q_S, '\033', '\f', Q_S, Q_S, Q_S,
00068 Q_S, Q_S, Q_S, Q_S, '\n', Q_S, Q_S, Q_S, Q_S,
00069 Q_S, '\t', Q_S, '\v', Q_S, Q_X, Q_S, Q_S
00070 };
00071
00082 #define xlate(c) (islower((c)) ? xform[(int)(c - 'a')] : \
00083 ((c >= '0' && c <= '7') ? Q_O : Q_S))
00084
00095 #define accum(buf, c) do { \
00096 if (buf ## _pos >= sizeof(buf) - 1) \
00097 _tc_doerror(ENOSPC); \
00098 else \
00099 buf[buf ## _pos++] = (c); \
00100 } while (0)
00101
00109 #define clear(buf) (buf ## _pos = 0)
00110
00119 #define finish(buf) (buf[buf ## _pos] = '\0')
00120
00129 #define cunget(chr) do { \
00130 if (buf_pos <= 0) \
00131 _tc_doerror(EINVAL); \
00132 count++; \
00133 buf_pos--; \
00134 c = (chr); \
00135 } while (0)
00136
00143 #define FL_DQUOTE 0x0001
00144
00151 #define FL_SQUOTE 0x0002
00152
00158 #define FL_CQUOTE 0x0004
00159
00166 #define FL_OCTCHR 0x0008
00167
00174 #define FL_HEXCHR 0x0010
00175
00182 #define FL_QUOTEMASK (FL_DQUOTE | FL_SQUOTE | FL_CQUOTE | \
00183 FL_OCTCHR | FL_HEXCHR)
00184
00190 #define FL_SPACE 0x0020
00191
00200 #define quoted() (flags & FL_QUOTEMASK)
00201
00202 unsigned int
00203 tc_load(const char *file, void *v_ctx)
00204 {
00205 treeconf_ctx_t *ctx = (treeconf_ctx_t *)v_ctx;
00206 treeconf_node_t *parent = 0;
00207 char buf[TC_BUFSIZE], nambuf[TC_NAMSIZE], valbuf[TC_BUFSIZE];
00208 enum {
00209 comm_none, comm_nl, comm_slash, comm_star, comm_c
00210 } comm_state = comm_none;
00211 enum {
00212 st_init, st_parent, st_close, st_varname, st_equals, st_value
00213 } state = st_init;
00214 unsigned int err = 0, flags = FL_SPACE;
00215 int count = 0, buf_pos = 0, nambuf_pos = 0, valbuf_pos = 0, fd;
00216 int c, q = 0, siz = 0;
00217
00218 initialize_trcf_error_table();
00219
00220
00221 if (!file || !*file || !tx_verify(ctx))
00222 return EINVAL;
00223
00224
00225 if ((fd = open(file, O_RDONLY)) < 0)
00226 return errno;
00227
00228
00229 while (1) {
00230 if (!count) {
00231 if (!(count = read(fd, buf, sizeof(buf))))
00232 break;
00233 else if (count < 0)
00234 _tc_doerror(errno);
00235 buf_pos = 0;
00236 }
00237 c = buf[buf_pos++];
00238 count--;
00239
00240 if (!quoted()) {
00241 if (comm_state == comm_none) {
00242 if (c == '#')
00243 comm_state = comm_nl;
00244 else if (c == '/')
00245 comm_state = comm_slash;
00246 } else if (comm_state == comm_slash) {
00247 if (c == '/')
00248 comm_state = comm_nl;
00249 else if (c == '*')
00250 comm_state = comm_c;
00251 else {
00252 comm_state = comm_none;
00253 cunget('/');
00254 }
00255 } else if (comm_state == comm_c && c == '*')
00256 comm_state = comm_star;
00257 else if (comm_state == comm_star) {
00258 if (c == '/') {
00259 comm_state = comm_none;
00260 c = ' ';
00261 } else if (c != '*')
00262 comm_state = comm_c;
00263 } else if (comm_state == comm_nl && c == '\n')
00264 comm_state = comm_none;
00265
00266
00267 if (comm_state != comm_none)
00268 continue;
00269 }
00270
00271
00272 if (c == '"' && !((flags & FL_QUOTEMASK) & ~FL_DQUOTE)) {
00273 flags ^= FL_DQUOTE;
00274 continue;
00275 } else if (c == '\'' && !((flags & FL_QUOTEMASK) & ~FL_SQUOTE)) {
00276 flags ^= FL_SQUOTE;
00277 continue;
00278 } else if (c == '\\' && !((flags & FL_QUOTEMASK) & ~FL_DQUOTE)) {
00279 flags |= FL_CQUOTE;
00280 continue;
00281 } else if (flags & FL_OCTCHR) {
00282 if (c >= '0' && c <= '7') {
00283 q = (q << 3) | (c - '0');
00284
00285 if (--siz)
00286 continue;
00287
00288 c = q;
00289 } else
00290 cunget(q);
00291
00292 flags &= ~FL_OCTCHR;
00293 } else if (flags & FL_HEXCHR) {
00294 if (isxdigit(c)) {
00295 if (isdigit(c))
00296 q = (q << 4) | (c - '0');
00297 else if (c >= 'a' && c <= 'f')
00298 q = (q << 4) | (c - 'a' + 0x0a);
00299 else if (c >= 'A' && c <= 'F')
00300 q = (q << 4) | (c - 'A' + 0x0a);
00301
00302 if (--siz)
00303 continue;
00304
00305 c = q;
00306 } else
00307 cunget(q);
00308
00309 flags &= ~FL_HEXCHR;
00310 } else if (flags & FL_CQUOTE)
00311 switch ((q = xlate(c))) {
00312 case Q_S:
00313 break;
00314 case Q_X:
00315 flags |= FL_HEXCHR;
00316 q = 0;
00317 siz = 2;
00318 continue;
00319 break;
00320 case Q_O:
00321 flags |= FL_OCTCHR;
00322 q = (c - '0');
00323 siz = (q <= 3) ? 1 : 2;
00324 continue;
00325 break;
00326 default:
00327 c = q;
00328 break;
00329 }
00330
00331 if (flags & FL_SPACE) {
00332 if (quoted() || !isspace(c))
00333 flags &= ~FL_SPACE;
00334 else
00335 continue;
00336 }
00337
00338 switch (state) {
00339 case st_init:
00340 if (!quoted() && c == '[') {
00341 clear(nambuf);
00342 state = st_parent;
00343 flags |= FL_SPACE;
00344 } else if (quoted() || isalpha(c) || c == '_') {
00345 clear(nambuf);
00346 accum(nambuf, c);
00347 state = st_varname;
00348 } else if (!isspace(c))
00349 err = EINVAL;
00350 break;
00351
00352 case st_parent:
00353 if (!quoted() && (c == ']' || isspace(c))) {
00354 finish(nambuf);
00355
00356 if (!nambuf[0])
00357 parent = 0;
00358 else if ((err = tc_find(ctx, nambuf, &parent, 0)))
00359 goto error;
00360
00361 state = (c == ']') ? st_init : st_close;
00362 flags |= FL_SPACE;
00363 } else
00364 accum(nambuf, c);
00365 break;
00366
00367 case st_varname:
00368 if (!quoted() && c == '=') {
00369 finish(nambuf);
00370 clear(valbuf);
00371 state = st_value;
00372 flags |= FL_SPACE;
00373 } else if (!quoted() && c == ';') {
00374 finish(nambuf);
00375
00376 if ((err = tc_set(ctx, nambuf, 0, parent)))
00377 goto error;
00378
00379 state = st_init;
00380 flags |= FL_SPACE;
00381 } else if (!quoted() && isspace(c)) {
00382 finish(nambuf);
00383
00384 state = st_equals;
00385 flags |= FL_SPACE;
00386 } else
00387 accum(nambuf, c);
00388 break;
00389
00390 case st_close:
00391 if (quoted() || c != ']')
00392 _tc_doerror(EINVAL);
00393 else {
00394 state = st_init;
00395 flags |= FL_SPACE;
00396 }
00397 break;
00398
00399 case st_equals:
00400 if (quoted() || (c != '=' && c != ';'))
00401 _tc_doerror(EINVAL);
00402 else if (c == ';') {
00403 if ((err = tc_set(ctx, nambuf, 0, parent)))
00404 goto error;
00405
00406 state = st_init;
00407 flags |= FL_SPACE;
00408 } else {
00409 clear(valbuf);
00410 state = st_value;
00411 flags |= FL_SPACE;
00412 }
00413 break;
00414
00415 case st_value:
00416 if (!quoted() && c == ';') {
00417 finish(valbuf);
00418
00419 if ((err = tc_set(ctx, nambuf, valbuf, parent)))
00420 goto error;
00421 state = st_init;
00422 flags |= FL_SPACE;
00423 } else if (!quoted() && isspace(c)) {
00424 accum(valbuf, ' ');
00425 flags |= FL_SPACE;
00426 } else
00427 accum(valbuf, c);
00428 break;
00429 }
00430
00431 flags &= ~FL_CQUOTE;
00432 }
00433
00434 if (comm_state != comm_none || quoted())
00435 err = EINVAL;
00436
00437 error:
00438 close(fd);
00439
00440 return err;
00441 }