Annotation of embedaddon/strongswan/src/libstrongswan/collections/enumerator.c, revision 1.1.1.2

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>
1.1.1.2 ! misho      30: #elif defined(WIN32)
        !            31: #include <fileapi.h>
1.1       misho      32: #endif /* HAVE_GLOB_H */
                     33: 
                     34: #include <utils/debug.h>
                     35: 
                     36: /*
                     37:  * Described in header.
                     38:  */
                     39: bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
                     40: {
                     41:        va_list args;
                     42:        bool result;
                     43: 
                     44:        if (!enumerator->venumerate)
                     45:        {
                     46:                DBG1(DBG_LIB, "!!! ENUMERATE DEFAULT: venumerate() missing !!!");
                     47:                return FALSE;
                     48:        }
                     49:        va_start(args, enumerator);
                     50:        result = enumerator->venumerate(enumerator, args);
                     51:        va_end(args);
                     52:        return result;
                     53: }
                     54: 
                     55: METHOD(enumerator_t, enumerate_empty, bool,
                     56:        enumerator_t *enumerator, va_list args)
                     57: {
                     58:        return FALSE;
                     59: }
                     60: 
                     61: /*
                     62:  * Described in header
                     63:  */
                     64: enumerator_t* enumerator_create_empty()
                     65: {
                     66:        enumerator_t *this;
                     67: 
                     68:        INIT(this,
                     69:                .enumerate = enumerator_enumerate_default,
                     70:                .venumerate = _enumerate_empty,
                     71:                .destroy = (void*)free,
                     72:        );
                     73:        return this;
                     74: }
                     75: 
                     76: /**
                     77:  * Enumerator implementation for directory enumerator
                     78:  */
                     79: typedef struct {
                     80:        /** implements enumerator_t */
                     81:        enumerator_t public;
                     82:        /** directory handle */
                     83:        DIR *dir;
                     84:        /** absolute path of current file */
                     85:        char full[PATH_MAX];
                     86:        /** where directory part of full ends and relative file gets written */
                     87:        char *full_end;
                     88: } dir_enum_t;
                     89: 
                     90: METHOD(enumerator_t, destroy_dir_enum, void,
                     91:        dir_enum_t *this)
                     92: {
                     93:        closedir(this->dir);
                     94:        free(this);
                     95: }
                     96: 
                     97: METHOD(enumerator_t, enumerate_dir_enum, bool,
                     98:        dir_enum_t *this, va_list args)
                     99: {
                    100:        struct dirent *entry = readdir(this->dir);
                    101:        struct stat *st;
                    102:        size_t remaining;
                    103:        char **relative, **absolute;
                    104:        int len;
                    105: 
                    106:        VA_ARGS_VGET(args, relative, absolute, st);
                    107: 
                    108:        if (!entry)
                    109:        {
                    110:                return FALSE;
                    111:        }
                    112:        if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
                    113:        {
                    114:                return this->public.enumerate(&this->public, relative, absolute, st);
                    115:        }
                    116:        if (relative)
                    117:        {
                    118:                *relative = entry->d_name;
                    119:        }
                    120:        if (absolute || st)
                    121:        {
                    122:                remaining = sizeof(this->full) - (this->full_end - this->full);
                    123:                len = snprintf(this->full_end, remaining, "%s", entry->d_name);
                    124:                if (len < 0 || len >= remaining)
                    125:                {
                    126:                        DBG1(DBG_LIB, "buffer too small to enumerate file '%s'",
                    127:                                 entry->d_name);
                    128:                        return FALSE;
                    129:                }
                    130:                if (absolute)
                    131:                {
                    132:                        *absolute = this->full;
                    133:                }
                    134:                if (st && stat(this->full, st))
                    135:                {
                    136:                        /* try lstat() e.g. if a symlink is not valid anymore */
                    137:                        if ((errno != ENOENT && errno != ENOTDIR) || lstat(this->full, st))
                    138:                        {
                    139:                                DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full,
                    140:                                         strerror(errno));
                    141:                                return FALSE;
                    142:                        }
                    143:                }
                    144:        }
                    145:        return TRUE;
                    146: }
                    147: 
                    148: /*
                    149:  * Described in header
                    150:  */
                    151: enumerator_t* enumerator_create_directory(const char *path)
                    152: {
                    153:        dir_enum_t *this;
                    154:        int len;
                    155: 
                    156:        INIT(this,
                    157:                .public = {
                    158:                        .enumerate = enumerator_enumerate_default,
                    159:                        .venumerate = _enumerate_dir_enum,
                    160:                        .destroy = _destroy_dir_enum,
                    161:                },
                    162:        );
                    163: 
                    164:        if (*path == '\0')
                    165:        {
                    166:                path = "./";
                    167:        }
                    168:        len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
                    169:        if (len < 0 || len >= sizeof(this->full)-1)
                    170:        {
                    171:                DBG1(DBG_LIB, "path string '%s' too long", path);
                    172:                free(this);
                    173:                return NULL;
                    174:        }
                    175:        /* append a '/' if not already done */
1.1.1.2 ! misho     176:        if (!path_is_separator(this->full[len-1]))
1.1       misho     177:        {
1.1.1.2 ! misho     178:                this->full[len++] = DIRECTORY_SEPARATOR[0];
1.1       misho     179:                this->full[len] = '\0';
                    180:        }
                    181:        this->full_end = &this->full[len];
                    182: 
                    183:        this->dir = opendir(path);
                    184:        if (!this->dir)
                    185:        {
                    186:                DBG1(DBG_LIB, "opening directory '%s' failed: %s", path,
                    187:                         strerror(errno));
                    188:                free(this);
                    189:                return NULL;
                    190:        }
                    191:        return &this->public;
                    192: }
                    193: 
                    194: #ifdef HAVE_GLOB_H
                    195: 
                    196: /**
                    197:  * Enumerator implementation for glob enumerator
                    198:  */
                    199: typedef struct {
                    200:        /** implements enumerator_t */
                    201:        enumerator_t public;
                    202:        /** glob data */
                    203:        glob_t glob;
                    204:        /** iteration count */
                    205:        u_int pos;
                    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: 
1.1.1.2 ! misho     276: #elif defined(WIN32) /* HAVE_GLOB_H */
        !           277: 
        !           278: /**
        !           279:  * Enumerator implementation for glob enumerator on Windows
        !           280:  */
        !           281: typedef struct {
        !           282:        /** implements enumerator_t */
        !           283:        enumerator_t public;
        !           284:        /** search handle */
        !           285:        HANDLE handle;
        !           286:        /** current file path */
        !           287:        char path[PATH_MAX];
        !           288:        /** base path */
        !           289:        char *base;
        !           290: } glob_enum_t;
        !           291: 
        !           292: METHOD(enumerator_t, destroy_glob_enum, void,
        !           293:        glob_enum_t *this)
        !           294: {
        !           295:        if (this->handle != INVALID_HANDLE_VALUE)
        !           296:        {
        !           297:                FindClose(this->handle);
        !           298:        }
        !           299:        free(this->base);
        !           300:        free(this);
        !           301: }
        !           302: 
        !           303: /**
        !           304:  * Create the combined path from the given file data
        !           305:  */
        !           306: static bool combine_glob_path(glob_enum_t *this, WIN32_FIND_DATA *data)
        !           307: {
        !           308:        if (snprintf(this->path, sizeof(this->path), "%s%s%s", this->base,
        !           309:                                 DIRECTORY_SEPARATOR, data->cFileName) >= sizeof(this->path))
        !           310:        {
        !           311:                DBG1(DBG_LIB, "path for '%s' too long, ignored", data->cFileName);
        !           312:                return FALSE;
        !           313:        }
        !           314:        return TRUE;
        !           315: }
        !           316: 
        !           317: /**
        !           318:  * Return the path and stat data for the current file
        !           319:  */
        !           320: static bool enumerate_glob_enum_data(glob_enum_t *this, va_list args)
        !           321: {
        !           322:        struct stat *st;
        !           323:        char **file;
        !           324: 
        !           325:        VA_ARGS_VGET(args, file, st);
        !           326: 
        !           327:        if (file)
        !           328:        {
        !           329:                *file = this->path;
        !           330:        }
        !           331:        if (st && stat(this->path, st))
        !           332:        {
        !           333:                DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->path,
        !           334:                         strerror(errno));
        !           335:                return FALSE;
        !           336:        }
        !           337:        return TRUE;
        !           338: }
        !           339: 
        !           340: METHOD(enumerator_t, enumerate_glob_enum, bool,
        !           341:        glob_enum_t *this, va_list args)
        !           342: {
        !           343:        WIN32_FIND_DATA data;
        !           344: 
        !           345:        do
        !           346:        {
        !           347:                if (!FindNextFile(this->handle, &data))
        !           348:                {
        !           349:                        return FALSE;
        !           350:                }
        !           351:        }
        !           352:        while (!combine_glob_path(this, &data));
        !           353: 
        !           354:        return enumerate_glob_enum_data(this, args);
        !           355: }
        !           356: 
        !           357: METHOD(enumerator_t, enumerate_glob_enum_first, bool,
        !           358:        glob_enum_t *this, va_list args)
        !           359: {
        !           360:        if (enumerate_glob_enum_data(this, args))
        !           361:        {
        !           362:                this->public.venumerate = _enumerate_glob_enum;
        !           363:                return TRUE;
        !           364:        }
        !           365:        return FALSE;
        !           366: }
        !           367: 
        !           368: /*
        !           369:  * Described in header
        !           370:  */
        !           371: enumerator_t *enumerator_create_glob(const char *pattern)
        !           372: {
        !           373:        glob_enum_t *this;
        !           374:        WIN32_FIND_DATA data;
        !           375: 
        !           376:        if (!pattern)
        !           377:        {
        !           378:                return enumerator_create_empty();
        !           379:        }
        !           380: 
        !           381:        INIT(this,
        !           382:                .public = {
        !           383:                        .enumerate = enumerator_enumerate_default,
        !           384:                        .venumerate = _enumerate_glob_enum_first,
        !           385:                        .destroy = _destroy_glob_enum,
        !           386:                },
        !           387:                .base = path_dirname(pattern),
        !           388:        );
        !           389: 
        !           390:        this->handle = FindFirstFile(pattern, &data);
        !           391:        if (this->handle == INVALID_HANDLE_VALUE)
        !           392:        {
        !           393:                if (GetLastError() == ERROR_FILE_NOT_FOUND ||
        !           394:                        GetLastError() == ERROR_PATH_NOT_FOUND)
        !           395:                {
        !           396:                        DBG1(DBG_LIB, "no files found matching '%s'", pattern);
        !           397:                }
        !           398:                else
        !           399:                {
        !           400:                        DBG1(DBG_LIB, "FindFirstFile failed for pattern '%s' (%d)", pattern,
        !           401:                                 GetLastError());
        !           402:                }
        !           403:                destroy_glob_enum(this);
        !           404:                return enumerator_create_empty();
        !           405:        }
        !           406:        else if (!combine_glob_path(this, &data))
        !           407:        {       /* check the next file if we can't combine the path for the first one */
        !           408:                this->public.venumerate = _enumerate_glob_enum;
        !           409:        }
        !           410:        return &this->public;
        !           411: }
        !           412: 
1.1       misho     413: #else /* HAVE_GLOB_H */
                    414: 
                    415: enumerator_t* enumerator_create_glob(const char *pattern)
                    416: {
                    417:        return NULL;
                    418: }
                    419: 
                    420: #endif /* HAVE_GLOB_H */
                    421: 
                    422: /**
                    423:  * Enumerator implementation for token enumerator
                    424:  */
                    425: typedef struct {
                    426:        /** implements enumerator_t */
                    427:        enumerator_t public;
                    428:        /** string to parse */
                    429:        char *string;
                    430:        /** current position */
                    431:        char *pos;
                    432:        /** separator chars */
                    433:        const char *sep;
                    434:        /** trim chars */
                    435:        const char *trim;
                    436: } token_enum_t;
                    437: 
                    438: METHOD(enumerator_t, destroy_token_enum, void,
                    439:        token_enum_t *this)
                    440: {
                    441:        free(this->string);
                    442:        free(this);
                    443: }
                    444: 
                    445: METHOD(enumerator_t, enumerate_token_enum, bool,
                    446:        token_enum_t *this, va_list args)
                    447: {
                    448:        const char *sep, *trim;
                    449:        char *pos = NULL, *tmp, **token;
                    450:        bool last = FALSE;
                    451: 
                    452:        VA_ARGS_VGET(args, token);
                    453: 
                    454:        /* trim leading characters/separators */
                    455:        while (*this->pos)
                    456:        {
                    457:                trim = this->trim;
                    458:                while (*trim)
                    459:                {
                    460:                        if (*trim == *this->pos)
                    461:                        {
                    462:                                this->pos++;
                    463:                                break;
                    464:                        }
                    465:                        trim++;
                    466:                }
                    467:                sep = this->sep;
                    468:                while (*sep)
                    469:                {
                    470:                        if (*sep == *this->pos)
                    471:                        {
                    472:                                this->pos++;
                    473:                                break;
                    474:                        }
                    475:                        sep++;
                    476:                }
                    477:                if (!*trim && !*sep)
                    478:                {
                    479:                        break;
                    480:                }
                    481:        }
                    482: 
                    483:        switch (*this->pos)
                    484:        {
                    485:                case '"':
                    486:                case '\'':
                    487:                {
                    488:                        /* read quoted token */
                    489:                        tmp = strchr(this->pos + 1, *this->pos);
                    490:                        if (tmp)
                    491:                        {
                    492:                                *token = this->pos + 1;
                    493:                                *tmp = '\0';
                    494:                                this->pos = tmp + 1;
                    495:                                return TRUE;
                    496:                        }
                    497:                        /* unterminated string, FALL-THROUGH */
                    498:                }
                    499:                default:
                    500:                {
                    501:                        /* find nearest separator */
                    502:                        sep = this->sep;
                    503:                        while (*sep)
                    504:                        {
                    505:                                tmp = strchr(this->pos, *sep);
                    506:                                if (tmp && (pos == NULL || tmp < pos))
                    507:                                {
                    508:                                        pos = tmp;
                    509:                                }
                    510:                                sep++;
                    511:                        }
                    512:                        *token = this->pos;
                    513:                        if (pos)
                    514:                        {
                    515:                                *pos = '\0';
                    516:                                this->pos = pos + 1;
                    517:                        }
                    518:                        else
                    519:                        {
                    520:                                last = TRUE;
                    521:                                pos = this->pos = strchr(this->pos, '\0');
                    522:                        }
                    523:                        break;
                    524:                }
                    525:        }
                    526: 
                    527:        /* trim trailing characters */
                    528:        pos--;
                    529:        while (pos >= *token)
                    530:        {
                    531:                trim = this->trim;
                    532:                while (*trim)
                    533:                {
                    534:                        if (*trim == *pos)
                    535:                        {
                    536:                                *(pos--) = '\0';
                    537:                                break;
                    538:                        }
                    539:                        trim++;
                    540:                }
                    541:                if (!*trim)
                    542:                {
                    543:                        break;
                    544:                }
                    545:        }
                    546: 
                    547:        if (!last || pos >= *token)
                    548:        {
                    549:                return TRUE;
                    550:        }
                    551:        return FALSE;
                    552: }
                    553: 
                    554: /*
                    555:  * Described in header
                    556:  */
                    557: enumerator_t* enumerator_create_token(const char *string, const char *sep,
                    558:                                                                          const char *trim)
                    559: {
                    560:        token_enum_t *this;
                    561: 
                    562:        INIT(this,
                    563:                .public = {
                    564:                        .enumerate = enumerator_enumerate_default,
                    565:                        .venumerate = _enumerate_token_enum,
                    566:                        .destroy = _destroy_token_enum,
                    567:                },
                    568:                .string = strdup(string),
                    569:                .sep = sep,
                    570:                .trim = trim,
                    571:        );
                    572:        this->pos = this->string;
                    573: 
                    574:        return &this->public;
                    575: }
                    576: 
                    577: /**
                    578:  * Enumerator for nested enumerations
                    579:  */
                    580: typedef struct {
                    581:        enumerator_t public;
                    582:        enumerator_t *outer;
                    583:        enumerator_t *inner;
                    584:        enumerator_t *(*create_inner)(void *outer, void *data);
                    585:        void *data;
                    586:        void (*destructor)(void *data);
                    587: } nested_enumerator_t;
                    588: 
                    589: 
                    590: METHOD(enumerator_t, enumerate_nested, bool,
                    591:        nested_enumerator_t *this, va_list args)
                    592: {
                    593:        while (TRUE)
                    594:        {
                    595:                while (!this->inner)
                    596:                {
                    597:                        void *outer;
                    598: 
                    599:                        if (!this->outer->enumerate(this->outer, &outer))
                    600:                        {
                    601:                                return FALSE;
                    602:                        }
                    603:                        this->inner = this->create_inner(outer, this->data);
                    604:                        if (this->inner && !this->inner->venumerate)
                    605:                        {
                    606:                                DBG1(DBG_LIB, "!!! ENUMERATE NESTED: venumerate() missing !!!");
                    607:                                return FALSE;
                    608:                        }
                    609:                }
                    610:                if (this->inner->venumerate(this->inner, args))
                    611:                {
                    612:                        return TRUE;
                    613:                }
                    614:                this->inner->destroy(this->inner);
                    615:                this->inner = NULL;
                    616:        }
                    617: }
                    618: 
                    619: METHOD(enumerator_t, destroy_nested, void,
                    620:        nested_enumerator_t *this)
                    621: {
                    622:        if (this->destructor)
                    623:        {
                    624:                this->destructor(this->data);
                    625:        }
                    626:        DESTROY_IF(this->inner);
                    627:        this->outer->destroy(this->outer);
                    628:        free(this);
                    629: }
                    630: 
                    631: /*
                    632:  * Described in header
                    633:  */
                    634: enumerator_t *enumerator_create_nested(enumerator_t *outer,
                    635:                                        enumerator_t *(inner_constructor)(void *outer, void *data),
                    636:                                        void *data, void (*destructor)(void *data))
                    637: {
                    638:        nested_enumerator_t *this;
                    639: 
                    640:        INIT(this,
                    641:                .public = {
                    642:                        .enumerate = enumerator_enumerate_default,
                    643:                        .venumerate = _enumerate_nested,
                    644:                        .destroy = _destroy_nested,
                    645:                },
                    646:                .outer = outer,
                    647:                .create_inner = inner_constructor,
                    648:                .data = data,
                    649:                .destructor = destructor,
                    650:        );
                    651:        return &this->public;
                    652: }
                    653: 
                    654: /**
                    655:  * Enumerator for filtered enumerator
                    656:  */
                    657: typedef struct {
                    658:        enumerator_t public;
                    659:        enumerator_t *orig;
                    660:        void *data;
                    661:        bool (*filter)(void*,enumerator_t*,va_list);
                    662:        void (*destructor)(void *data);
                    663: } filter_enumerator_t;
                    664: 
                    665: METHOD(enumerator_t, destroy_filter, void,
                    666:        filter_enumerator_t *this)
                    667: {
                    668:        if (this->destructor)
                    669:        {
                    670:                this->destructor(this->data);
                    671:        }
                    672:        this->orig->destroy(this->orig);
                    673:        free(this);
                    674: }
                    675: 
                    676: METHOD(enumerator_t, enumerate_filter, bool,
                    677:        filter_enumerator_t *this, va_list args)
                    678: {
                    679:        bool result = FALSE;
                    680: 
                    681:        if (this->filter(this->data, this->orig, args))
                    682:        {
                    683:                result = TRUE;
                    684:        }
                    685:        return result;
                    686: }
                    687: 
                    688: /*
                    689:  * Described in header
                    690:  */
                    691: enumerator_t *enumerator_create_filter(enumerator_t *orig,
                    692:                        bool (*filter)(void *data, enumerator_t *orig, va_list args),
                    693:                        void *data, void (*destructor)(void *data))
                    694: {
                    695:        filter_enumerator_t *this;
                    696: 
                    697:        INIT(this,
                    698:                .public = {
                    699:                        .enumerate = enumerator_enumerate_default,
                    700:                        .venumerate = _enumerate_filter,
                    701:                        .destroy = _destroy_filter,
                    702:                },
                    703:                .orig = orig,
                    704:                .filter = filter,
                    705:                .data = data,
                    706:                .destructor = destructor,
                    707:        );
                    708:        return &this->public;
                    709: }
                    710: 
                    711: /**
                    712:  * Enumerator for cleaner enumerator
                    713:  */
                    714: typedef struct {
                    715:        enumerator_t public;
                    716:        enumerator_t *wrapped;
                    717:        void (*cleanup)(void *data);
                    718:        void *data;
                    719: } cleaner_enumerator_t;
                    720: 
                    721: METHOD(enumerator_t, destroy_cleaner, void,
                    722:        cleaner_enumerator_t *this)
                    723: {
                    724:        this->cleanup(this->data);
                    725:        this->wrapped->destroy(this->wrapped);
                    726:        free(this);
                    727: }
                    728: 
                    729: METHOD(enumerator_t, enumerate_cleaner, bool,
                    730:        cleaner_enumerator_t *this, va_list args)
                    731: {
                    732:        if (!this->wrapped->venumerate)
                    733:        {
                    734:                DBG1(DBG_LIB, "!!! CLEANER ENUMERATOR: venumerate() missing !!!");
                    735:                return FALSE;
                    736:        }
                    737:        return this->wrapped->venumerate(this->wrapped, args);
                    738: }
                    739: 
                    740: /*
                    741:  * Described in header
                    742:  */
                    743: enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
                    744:                                                                                void (*cleanup)(void *data), void *data)
                    745: {
                    746:        cleaner_enumerator_t *this;
                    747: 
                    748:        INIT(this,
                    749:                .public = {
                    750:                        .enumerate = enumerator_enumerate_default,
                    751:                        .venumerate = _enumerate_cleaner,
                    752:                        .destroy = _destroy_cleaner,
                    753:                },
                    754:                .wrapped = wrapped,
                    755:                .cleanup = cleanup,
                    756:                .data = data,
                    757:        );
                    758:        return &this->public;
                    759: }
                    760: 
                    761: /**
                    762:  * Enumerator for single enumerator
                    763:  */
                    764: typedef struct {
                    765:        enumerator_t public;
                    766:        void *item;
                    767:        void (*cleanup)(void *item);
                    768:        bool done;
                    769: } single_enumerator_t;
                    770: 
                    771: METHOD(enumerator_t, destroy_single, void,
                    772:        single_enumerator_t *this)
                    773: {
                    774:        if (this->cleanup)
                    775:        {
                    776:                this->cleanup(this->item);
                    777:        }
                    778:        free(this);
                    779: }
                    780: 
                    781: METHOD(enumerator_t, enumerate_single, bool,
                    782:        single_enumerator_t *this, va_list args)
                    783: {
                    784:        void **item;
                    785: 
                    786:        VA_ARGS_VGET(args, item);
                    787:        if (this->done)
                    788:        {
                    789:                return FALSE;
                    790:        }
                    791:        *item = this->item;
                    792:        this->done = TRUE;
                    793:        return TRUE;
                    794: }
                    795: 
                    796: /*
                    797:  * Described in header
                    798:  */
                    799: enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
                    800: {
                    801:        single_enumerator_t *this;
                    802: 
                    803:        INIT(this,
                    804:                .public = {
                    805:                        .enumerate = enumerator_enumerate_default,
                    806:                        .venumerate = _enumerate_single,
                    807:                        .destroy = _destroy_single,
                    808:                },
                    809:                .item = item,
                    810:                .cleanup = cleanup,
                    811:        );
                    812:        return &this->public;
                    813: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>