Annotation of embedaddon/strongswan/src/libstrongswan/collections/enumerator.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2017 Tobias Brunner
! 3: * Copyright (C) 2007 Martin Willi
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #include "enumerator.h"
! 18:
! 19: #include <sys/types.h>
! 20: #include <sys/stat.h>
! 21: #include <unistd.h>
! 22: #include <limits.h>
! 23: #include <stdio.h>
! 24: #include <dirent.h>
! 25: #include <errno.h>
! 26: #include <string.h>
! 27:
! 28: #ifdef HAVE_GLOB_H
! 29: #include <glob.h>
! 30: #endif /* HAVE_GLOB_H */
! 31:
! 32: #include <utils/debug.h>
! 33:
! 34: /*
! 35: * Described in header.
! 36: */
! 37: bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
! 38: {
! 39: va_list args;
! 40: bool result;
! 41:
! 42: if (!enumerator->venumerate)
! 43: {
! 44: DBG1(DBG_LIB, "!!! ENUMERATE DEFAULT: venumerate() missing !!!");
! 45: return FALSE;
! 46: }
! 47: va_start(args, enumerator);
! 48: result = enumerator->venumerate(enumerator, args);
! 49: va_end(args);
! 50: return result;
! 51: }
! 52:
! 53: METHOD(enumerator_t, enumerate_empty, bool,
! 54: enumerator_t *enumerator, va_list args)
! 55: {
! 56: return FALSE;
! 57: }
! 58:
! 59: /*
! 60: * Described in header
! 61: */
! 62: enumerator_t* enumerator_create_empty()
! 63: {
! 64: enumerator_t *this;
! 65:
! 66: INIT(this,
! 67: .enumerate = enumerator_enumerate_default,
! 68: .venumerate = _enumerate_empty,
! 69: .destroy = (void*)free,
! 70: );
! 71: return this;
! 72: }
! 73:
! 74: /**
! 75: * Enumerator implementation for directory enumerator
! 76: */
! 77: typedef struct {
! 78: /** implements enumerator_t */
! 79: enumerator_t public;
! 80: /** directory handle */
! 81: DIR *dir;
! 82: /** absolute path of current file */
! 83: char full[PATH_MAX];
! 84: /** where directory part of full ends and relative file gets written */
! 85: char *full_end;
! 86: } dir_enum_t;
! 87:
! 88: METHOD(enumerator_t, destroy_dir_enum, void,
! 89: dir_enum_t *this)
! 90: {
! 91: closedir(this->dir);
! 92: free(this);
! 93: }
! 94:
! 95: METHOD(enumerator_t, enumerate_dir_enum, bool,
! 96: dir_enum_t *this, va_list args)
! 97: {
! 98: struct dirent *entry = readdir(this->dir);
! 99: struct stat *st;
! 100: size_t remaining;
! 101: char **relative, **absolute;
! 102: int len;
! 103:
! 104: VA_ARGS_VGET(args, relative, absolute, st);
! 105:
! 106: if (!entry)
! 107: {
! 108: return FALSE;
! 109: }
! 110: if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
! 111: {
! 112: return this->public.enumerate(&this->public, relative, absolute, st);
! 113: }
! 114: if (relative)
! 115: {
! 116: *relative = entry->d_name;
! 117: }
! 118: if (absolute || st)
! 119: {
! 120: remaining = sizeof(this->full) - (this->full_end - this->full);
! 121: len = snprintf(this->full_end, remaining, "%s", entry->d_name);
! 122: if (len < 0 || len >= remaining)
! 123: {
! 124: DBG1(DBG_LIB, "buffer too small to enumerate file '%s'",
! 125: entry->d_name);
! 126: return FALSE;
! 127: }
! 128: if (absolute)
! 129: {
! 130: *absolute = this->full;
! 131: }
! 132: if (st && stat(this->full, st))
! 133: {
! 134: /* try lstat() e.g. if a symlink is not valid anymore */
! 135: if ((errno != ENOENT && errno != ENOTDIR) || lstat(this->full, st))
! 136: {
! 137: DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full,
! 138: strerror(errno));
! 139: return FALSE;
! 140: }
! 141: }
! 142: }
! 143: return TRUE;
! 144: }
! 145:
! 146: /*
! 147: * Described in header
! 148: */
! 149: enumerator_t* enumerator_create_directory(const char *path)
! 150: {
! 151: dir_enum_t *this;
! 152: int len;
! 153:
! 154: INIT(this,
! 155: .public = {
! 156: .enumerate = enumerator_enumerate_default,
! 157: .venumerate = _enumerate_dir_enum,
! 158: .destroy = _destroy_dir_enum,
! 159: },
! 160: );
! 161:
! 162: if (*path == '\0')
! 163: {
! 164: path = "./";
! 165: }
! 166: len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
! 167: if (len < 0 || len >= sizeof(this->full)-1)
! 168: {
! 169: DBG1(DBG_LIB, "path string '%s' too long", path);
! 170: free(this);
! 171: return NULL;
! 172: }
! 173: /* append a '/' if not already done */
! 174: if (this->full[len-1] != '/')
! 175: {
! 176: this->full[len++] = '/';
! 177: this->full[len] = '\0';
! 178: }
! 179: this->full_end = &this->full[len];
! 180:
! 181: this->dir = opendir(path);
! 182: if (!this->dir)
! 183: {
! 184: DBG1(DBG_LIB, "opening directory '%s' failed: %s", path,
! 185: strerror(errno));
! 186: free(this);
! 187: return NULL;
! 188: }
! 189: return &this->public;
! 190: }
! 191:
! 192: #ifdef HAVE_GLOB_H
! 193:
! 194: /**
! 195: * Enumerator implementation for glob enumerator
! 196: */
! 197: typedef struct {
! 198: /** implements enumerator_t */
! 199: enumerator_t public;
! 200: /** glob data */
! 201: glob_t glob;
! 202: /** iteration count */
! 203: u_int pos;
! 204: /** absolute path of current file */
! 205: char full[PATH_MAX];
! 206: } glob_enum_t;
! 207:
! 208: METHOD(enumerator_t, destroy_glob_enum, void,
! 209: glob_enum_t *this)
! 210: {
! 211: globfree(&this->glob);
! 212: free(this);
! 213: }
! 214:
! 215: METHOD(enumerator_t, enumerate_glob_enum, bool,
! 216: glob_enum_t *this, va_list args)
! 217: {
! 218: struct stat *st;
! 219: char *match;
! 220: char **file;
! 221:
! 222: VA_ARGS_VGET(args, file, st);
! 223:
! 224: if (this->pos >= this->glob.gl_pathc)
! 225: {
! 226: return FALSE;
! 227: }
! 228: match = this->glob.gl_pathv[this->pos++];
! 229: if (file)
! 230: {
! 231: *file = match;
! 232: }
! 233: if (st && stat(match, st))
! 234: {
! 235: DBG1(DBG_LIB, "stat() on '%s' failed: %s", match,
! 236: strerror(errno));
! 237: return FALSE;
! 238: }
! 239: return TRUE;
! 240: }
! 241:
! 242: /*
! 243: * Described in header
! 244: */
! 245: enumerator_t* enumerator_create_glob(const char *pattern)
! 246: {
! 247: glob_enum_t *this;
! 248: int status;
! 249:
! 250: if (!pattern)
! 251: {
! 252: return enumerator_create_empty();
! 253: }
! 254:
! 255: INIT(this,
! 256: .public = {
! 257: .enumerate = enumerator_enumerate_default,
! 258: .venumerate = _enumerate_glob_enum,
! 259: .destroy = _destroy_glob_enum,
! 260: },
! 261: );
! 262:
! 263: status = glob(pattern, GLOB_ERR, NULL, &this->glob);
! 264: if (status == GLOB_NOMATCH)
! 265: {
! 266: DBG1(DBG_LIB, "no files found matching '%s'", pattern);
! 267: }
! 268: else if (status != 0)
! 269: {
! 270: DBG1(DBG_LIB, "expanding file pattern '%s' failed: %s", pattern,
! 271: strerror(errno));
! 272: }
! 273: return &this->public;
! 274: }
! 275:
! 276: #else /* HAVE_GLOB_H */
! 277:
! 278: enumerator_t* enumerator_create_glob(const char *pattern)
! 279: {
! 280: return NULL;
! 281: }
! 282:
! 283: #endif /* HAVE_GLOB_H */
! 284:
! 285: /**
! 286: * Enumerator implementation for token enumerator
! 287: */
! 288: typedef struct {
! 289: /** implements enumerator_t */
! 290: enumerator_t public;
! 291: /** string to parse */
! 292: char *string;
! 293: /** current position */
! 294: char *pos;
! 295: /** separator chars */
! 296: const char *sep;
! 297: /** trim chars */
! 298: const char *trim;
! 299: } token_enum_t;
! 300:
! 301: METHOD(enumerator_t, destroy_token_enum, void,
! 302: token_enum_t *this)
! 303: {
! 304: free(this->string);
! 305: free(this);
! 306: }
! 307:
! 308: METHOD(enumerator_t, enumerate_token_enum, bool,
! 309: token_enum_t *this, va_list args)
! 310: {
! 311: const char *sep, *trim;
! 312: char *pos = NULL, *tmp, **token;
! 313: bool last = FALSE;
! 314:
! 315: VA_ARGS_VGET(args, token);
! 316:
! 317: /* trim leading characters/separators */
! 318: while (*this->pos)
! 319: {
! 320: trim = this->trim;
! 321: while (*trim)
! 322: {
! 323: if (*trim == *this->pos)
! 324: {
! 325: this->pos++;
! 326: break;
! 327: }
! 328: trim++;
! 329: }
! 330: sep = this->sep;
! 331: while (*sep)
! 332: {
! 333: if (*sep == *this->pos)
! 334: {
! 335: this->pos++;
! 336: break;
! 337: }
! 338: sep++;
! 339: }
! 340: if (!*trim && !*sep)
! 341: {
! 342: break;
! 343: }
! 344: }
! 345:
! 346: switch (*this->pos)
! 347: {
! 348: case '"':
! 349: case '\'':
! 350: {
! 351: /* read quoted token */
! 352: tmp = strchr(this->pos + 1, *this->pos);
! 353: if (tmp)
! 354: {
! 355: *token = this->pos + 1;
! 356: *tmp = '\0';
! 357: this->pos = tmp + 1;
! 358: return TRUE;
! 359: }
! 360: /* unterminated string, FALL-THROUGH */
! 361: }
! 362: default:
! 363: {
! 364: /* find nearest separator */
! 365: sep = this->sep;
! 366: while (*sep)
! 367: {
! 368: tmp = strchr(this->pos, *sep);
! 369: if (tmp && (pos == NULL || tmp < pos))
! 370: {
! 371: pos = tmp;
! 372: }
! 373: sep++;
! 374: }
! 375: *token = this->pos;
! 376: if (pos)
! 377: {
! 378: *pos = '\0';
! 379: this->pos = pos + 1;
! 380: }
! 381: else
! 382: {
! 383: last = TRUE;
! 384: pos = this->pos = strchr(this->pos, '\0');
! 385: }
! 386: break;
! 387: }
! 388: }
! 389:
! 390: /* trim trailing characters */
! 391: pos--;
! 392: while (pos >= *token)
! 393: {
! 394: trim = this->trim;
! 395: while (*trim)
! 396: {
! 397: if (*trim == *pos)
! 398: {
! 399: *(pos--) = '\0';
! 400: break;
! 401: }
! 402: trim++;
! 403: }
! 404: if (!*trim)
! 405: {
! 406: break;
! 407: }
! 408: }
! 409:
! 410: if (!last || pos >= *token)
! 411: {
! 412: return TRUE;
! 413: }
! 414: return FALSE;
! 415: }
! 416:
! 417: /*
! 418: * Described in header
! 419: */
! 420: enumerator_t* enumerator_create_token(const char *string, const char *sep,
! 421: const char *trim)
! 422: {
! 423: token_enum_t *this;
! 424:
! 425: INIT(this,
! 426: .public = {
! 427: .enumerate = enumerator_enumerate_default,
! 428: .venumerate = _enumerate_token_enum,
! 429: .destroy = _destroy_token_enum,
! 430: },
! 431: .string = strdup(string),
! 432: .sep = sep,
! 433: .trim = trim,
! 434: );
! 435: this->pos = this->string;
! 436:
! 437: return &this->public;
! 438: }
! 439:
! 440: /**
! 441: * Enumerator for nested enumerations
! 442: */
! 443: typedef struct {
! 444: enumerator_t public;
! 445: enumerator_t *outer;
! 446: enumerator_t *inner;
! 447: enumerator_t *(*create_inner)(void *outer, void *data);
! 448: void *data;
! 449: void (*destructor)(void *data);
! 450: } nested_enumerator_t;
! 451:
! 452:
! 453: METHOD(enumerator_t, enumerate_nested, bool,
! 454: nested_enumerator_t *this, va_list args)
! 455: {
! 456: while (TRUE)
! 457: {
! 458: while (!this->inner)
! 459: {
! 460: void *outer;
! 461:
! 462: if (!this->outer->enumerate(this->outer, &outer))
! 463: {
! 464: return FALSE;
! 465: }
! 466: this->inner = this->create_inner(outer, this->data);
! 467: if (this->inner && !this->inner->venumerate)
! 468: {
! 469: DBG1(DBG_LIB, "!!! ENUMERATE NESTED: venumerate() missing !!!");
! 470: return FALSE;
! 471: }
! 472: }
! 473: if (this->inner->venumerate(this->inner, args))
! 474: {
! 475: return TRUE;
! 476: }
! 477: this->inner->destroy(this->inner);
! 478: this->inner = NULL;
! 479: }
! 480: }
! 481:
! 482: METHOD(enumerator_t, destroy_nested, void,
! 483: nested_enumerator_t *this)
! 484: {
! 485: if (this->destructor)
! 486: {
! 487: this->destructor(this->data);
! 488: }
! 489: DESTROY_IF(this->inner);
! 490: this->outer->destroy(this->outer);
! 491: free(this);
! 492: }
! 493:
! 494: /*
! 495: * Described in header
! 496: */
! 497: enumerator_t *enumerator_create_nested(enumerator_t *outer,
! 498: enumerator_t *(inner_constructor)(void *outer, void *data),
! 499: void *data, void (*destructor)(void *data))
! 500: {
! 501: nested_enumerator_t *this;
! 502:
! 503: INIT(this,
! 504: .public = {
! 505: .enumerate = enumerator_enumerate_default,
! 506: .venumerate = _enumerate_nested,
! 507: .destroy = _destroy_nested,
! 508: },
! 509: .outer = outer,
! 510: .create_inner = inner_constructor,
! 511: .data = data,
! 512: .destructor = destructor,
! 513: );
! 514: return &this->public;
! 515: }
! 516:
! 517: /**
! 518: * Enumerator for filtered enumerator
! 519: */
! 520: typedef struct {
! 521: enumerator_t public;
! 522: enumerator_t *orig;
! 523: void *data;
! 524: bool (*filter)(void*,enumerator_t*,va_list);
! 525: void (*destructor)(void *data);
! 526: } filter_enumerator_t;
! 527:
! 528: METHOD(enumerator_t, destroy_filter, void,
! 529: filter_enumerator_t *this)
! 530: {
! 531: if (this->destructor)
! 532: {
! 533: this->destructor(this->data);
! 534: }
! 535: this->orig->destroy(this->orig);
! 536: free(this);
! 537: }
! 538:
! 539: METHOD(enumerator_t, enumerate_filter, bool,
! 540: filter_enumerator_t *this, va_list args)
! 541: {
! 542: bool result = FALSE;
! 543:
! 544: if (this->filter(this->data, this->orig, args))
! 545: {
! 546: result = TRUE;
! 547: }
! 548: return result;
! 549: }
! 550:
! 551: /*
! 552: * Described in header
! 553: */
! 554: enumerator_t *enumerator_create_filter(enumerator_t *orig,
! 555: bool (*filter)(void *data, enumerator_t *orig, va_list args),
! 556: void *data, void (*destructor)(void *data))
! 557: {
! 558: filter_enumerator_t *this;
! 559:
! 560: INIT(this,
! 561: .public = {
! 562: .enumerate = enumerator_enumerate_default,
! 563: .venumerate = _enumerate_filter,
! 564: .destroy = _destroy_filter,
! 565: },
! 566: .orig = orig,
! 567: .filter = filter,
! 568: .data = data,
! 569: .destructor = destructor,
! 570: );
! 571: return &this->public;
! 572: }
! 573:
! 574: /**
! 575: * Enumerator for cleaner enumerator
! 576: */
! 577: typedef struct {
! 578: enumerator_t public;
! 579: enumerator_t *wrapped;
! 580: void (*cleanup)(void *data);
! 581: void *data;
! 582: } cleaner_enumerator_t;
! 583:
! 584: METHOD(enumerator_t, destroy_cleaner, void,
! 585: cleaner_enumerator_t *this)
! 586: {
! 587: this->cleanup(this->data);
! 588: this->wrapped->destroy(this->wrapped);
! 589: free(this);
! 590: }
! 591:
! 592: METHOD(enumerator_t, enumerate_cleaner, bool,
! 593: cleaner_enumerator_t *this, va_list args)
! 594: {
! 595: if (!this->wrapped->venumerate)
! 596: {
! 597: DBG1(DBG_LIB, "!!! CLEANER ENUMERATOR: venumerate() missing !!!");
! 598: return FALSE;
! 599: }
! 600: return this->wrapped->venumerate(this->wrapped, args);
! 601: }
! 602:
! 603: /*
! 604: * Described in header
! 605: */
! 606: enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
! 607: void (*cleanup)(void *data), void *data)
! 608: {
! 609: cleaner_enumerator_t *this;
! 610:
! 611: INIT(this,
! 612: .public = {
! 613: .enumerate = enumerator_enumerate_default,
! 614: .venumerate = _enumerate_cleaner,
! 615: .destroy = _destroy_cleaner,
! 616: },
! 617: .wrapped = wrapped,
! 618: .cleanup = cleanup,
! 619: .data = data,
! 620: );
! 621: return &this->public;
! 622: }
! 623:
! 624: /**
! 625: * Enumerator for single enumerator
! 626: */
! 627: typedef struct {
! 628: enumerator_t public;
! 629: void *item;
! 630: void (*cleanup)(void *item);
! 631: bool done;
! 632: } single_enumerator_t;
! 633:
! 634: METHOD(enumerator_t, destroy_single, void,
! 635: single_enumerator_t *this)
! 636: {
! 637: if (this->cleanup)
! 638: {
! 639: this->cleanup(this->item);
! 640: }
! 641: free(this);
! 642: }
! 643:
! 644: METHOD(enumerator_t, enumerate_single, bool,
! 645: single_enumerator_t *this, va_list args)
! 646: {
! 647: void **item;
! 648:
! 649: VA_ARGS_VGET(args, item);
! 650: if (this->done)
! 651: {
! 652: return FALSE;
! 653: }
! 654: *item = this->item;
! 655: this->done = TRUE;
! 656: return TRUE;
! 657: }
! 658:
! 659: /*
! 660: * Described in header
! 661: */
! 662: enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
! 663: {
! 664: single_enumerator_t *this;
! 665:
! 666: INIT(this,
! 667: .public = {
! 668: .enumerate = enumerator_enumerate_default,
! 669: .venumerate = _enumerate_single,
! 670: .destroy = _destroy_single,
! 671: },
! 672: .item = item,
! 673: .cleanup = cleanup,
! 674: );
! 675: return &this->public;
! 676: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>