view buddytime/recurse.c @ 1028:314cfd774bc4

s/purple.guifications.org/plugins.guifications.org/
author Paul Aurich <paul@darkrain42.org>
date Thu, 06 Aug 2009 12:30:12 -0700
parents db4ad6aa002f
children 81a5336b6c5b
line wrap: on
line source

/*************************************************************************
 * Recursion module
 * by Martijn van Oosterhout <kleptog@svana.org> (C) April 2006
 * Licenced under the GNU General Public Licence version 2.
 *
 * Provides a function to recurse a directory and call a callback for each
 * file found.
 *************************************************************************/

#define _GNU_SOURCE
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#include "recurse.h"

#if 1
/* GLibc specific version. In this version, the entries are sorted */
/* We assume dirname ends in a /, prefix also unless empty */
static int
recurse_directory_int(char *dirname, char *prefix, DirRecurseMatch func, void *data)
{
    struct dirent **namelist;
    int ents;
    struct dirent *ent;
    int i;
    int ret = 0;

    if((ents = scandir(dirname, &namelist, 0, alphasort)) < 0)
        return -1;

    for (i = 0; i < ents; i++)
    {
        char *ptr;
        struct stat s;

        ent = namelist[i];
        asprintf(&ptr, "%s%s", dirname, ent->d_name);
        if(stat(ptr, &s) < 0)
        {
            free(ptr);
            continue;
        }

        if(S_ISREG(s.st_mode))
        {
            free(ptr);
            asprintf(&ptr, "%s%s", prefix, ent->d_name);
            ret = func(ptr, data);
        }
        else if(S_ISDIR(s.st_mode))
        {
            char *newdirname, *newprefix;

            if(ent->d_name[0] != '.')
            {
                asprintf(&newdirname, "%s%s/", dirname, ent->d_name);
                asprintf(&newprefix, "%s%s/", prefix, ent->d_name);
                ret = recurse_directory_int(newdirname, newprefix, func, data);
                free(newdirname);
                free(newprefix);
            }
        }
        free(ptr);
        if(ret < 0)
            break;
    }
    free(namelist);
    return 0;
}
#else
/* generic version, here they are unsorted */
/* We assume dirname ends in a /, prefix also unless empty */
static int
recurse_directory_int(char *dirname, char *prefix, DirRecurseMatch func, void *data)
{
    DIR *dir;
    struct dirent *ent;
    int ret = 0;

    dir = opendir(dirname);
    if(!dir)
        return -1;
    while ((ent = readdir(dir)) != NULL)
    {
        char *ptr;
        struct stat s;

        asprintf(&ptr, "%s%s", dirname, ent->d_name);
        if(stat(ptr, &s) < 0)
        {
            free(ptr);
            continue;
        }

        if(S_ISREG(s.st_mode))
        {
            free(ptr);
            asprintf(&ptr, "%s%s", prefix, ent->d_name);
            ret = func(ptr, data);
        }
        else if(S_ISDIR(s.st_mode))
        {
            char *newdirname, *newprefix;

            if(ent->d_name[0] != '.')
            {
                asprintf(&newdirname, "%s%s/", dirname, ent->d_name);
                asprintf(&newprefix, "%s%s/", prefix, ent->d_name);
                ret = recurse_directory_int(newdirname, newprefix, func, data);
                free(newdirname);
                free(newprefix);
            }
        }
        free(ptr);
        if(ret < 0)
            break;
    }
    closedir(dir);
    return ret;
}
#endif

int
recurse_directory(char *dirname, DirRecurseMatch func, void *data)
{
    char *newdirname = NULL;
    int ret;

    if(dirname[strlen(dirname) - 1] != '/')
        asprintf(&newdirname, "%s/", dirname);

    ret = recurse_directory_int(newdirname ? newdirname : dirname, "", func, data);

    if(newdirname)
        free(newdirname);
    return ret;
}