likle / cwalk

Path library for C/C++. Cross-Platform for Linux, FreeBSD, Windows and MacOS. Supports UNIX and Windows path styles on those platforms.
https://likle.github.io/cwalk/
MIT License
250 stars 39 forks source link

Provide some handling examples / rethink interface #15

Closed bgrieco closed 4 years ago

bgrieco commented 4 years ago

My problem was to receive an absolute path ("C:\bla\ble\bli\blo\blu") and create it. Since the directories in the middle may not exist, either, I have to iterate through the path and create the directories as they appear.

At the end, the solution ended like this:

// This is a co-routine for the create Dir function
// it uses a double buffer approach to concatenate the paths
// because the cwalk library requires using a path1, path2, output_buffer architecture
char * co_append_path(char * path , char *path_end, bool initialize)
{
    static char buf1[PATH_BUF_SIZE];
    static char buf2[PATH_BUF_SIZE];
    static char *ind[2] = { buf1,buf2 };
    static int src_buf;

#define dest_buf (1-src_buf)

    if (initialize)
    {
        int rootLen = 0;
        src_buf = 0;
        buf1[0] = 0;
        buf2[0] = 0;

        cwk_path_get_root(path, &rootLen);
        strncpy_s(ind[src_buf], PATH_BUF_SIZE, path, rootLen);
    }
    else
    {
        char sep = *path_end;
        *path_end = 0;
        cwk_path_get_absolute(ind[src_buf], path, ind[dest_buf], PATH_BUF_SIZE); 
        *path_end = sep;
        src_buf = dest_buf;
    }

    return ind[src_buf];
}

// newDir must be in absolute format
int createDir(char *newDir)
{

    char *p;
    struct cwk_segment segment;

    p = co_append_path(newDir, NULL, true);

    if (!cwk_path_get_first_segment(newDir, &segment))
    {
        return -1;
    }

    do { 
        p = co_append_path((char*)segment.begin,(char*)segment.end,false);
        if (dirExists(p))
        {
            printf("dir Exists [%s]\n",p);
        }
        else
        {
            printf("dir does not Exist [%s]\n", p);
            //create it
        }
    } while (cwk_path_get_next_segment(&segment));

    return 0;
}

I needed to create this strange co-routine in order to deal with the source1,source2, target API style that you created. Also, what #9 required makes sense, specially because you return indexes some times, so adding something from another path with begin+length, makes sense on your API.

How would you solve my problem? Is there something that I'm missing?

likle commented 4 years ago

Hi @bgrieco !

Thanks for submitting this issue. I agree that #9 would make sense, but I unfortunatelly didn't have time yet to implement it.

As far as I understand you'd like to ensure the existence of an absolute path. If you'd like to do that with cwalk, you could use something like this:

bool ensure_directory_exists(const char *path)
{
  char subpath[FILENAME_MAX];
  bool result;
  struct cwk_segment segment;
  size_t subpath_size;

  result = cwk_path_get_first_segment(path, &segment);
  while (result) {
    subpath_size = segment.end - segment.path;
    memcpy(subpath, segment.path, subpath_size);
    subpath[subpath_size] = '\0';
    if (!directory_exists(subpath)) {
      if (!create_directory(subpath)) {
        return false;
      }
    }
    result = cwk_path_get_next_segment(&segment);
  }

  return true;
}

and if you need directory_exists and create_directory as well:

#include <cwalk.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <memory.h>
#include <stdio.h>

#if defined(_WIN32)
#include <direct.h>
static bool create_directory(const char *path)
{
  return _mkdir(path) == 0;
}
#else
static bool create_directory(const char *path)
{
  return mkdir(path, 0777) == 0;
}
#endif

static bool directory_exists(const char *path)
{
  struct stat info;

  if (stat(path, &info) != 0) {
    return false;
  } else if (info.st_mode & S_IFDIR) {
    return true;
  } else {
    return false;
  }
}

I tested this on Linux (Ubuntu) and Windows. Does that help you?

bgrieco commented 4 years ago

Thanks Likle,

I modified a little bit your solution

    strcpy_s(path_cpy, PATH_BUF_SIZE, path);
    result = cwk_path_get_first_segment(path_cpy, &segment);
    while (result) {
        subpath_size = segment.end - segment.path;
        temp = *segment.end;
        *((char*)(segment.end)) = '\0';
        if (!directory_exists(path_cpy)) 
        {
            if (create_directory(path_cpy)) 
                return -2;
        }
        *((char*)(segment.end)) = temp;
        result = cwk_path_get_next_segment(&segment);
    }

So that you iterate over a copy of the path, instead of copying the path at ever iteration. Also, as a old C programmer, I prefer having functions returning ints, 0 for OK and -something for errors, but that's just me :-)

likle commented 4 years ago

Awesome! Let me know if there is anything else I can do to help 😊