/**
 *  @file   disk_deep_mkdir.c
 *  @brief  途中のディレクトリも掘る mkdir.
 *  @author tenk*
 *  @note
 *  -   win/linux(unix)用.
 *  -   Public Domain Software
 */

#include "disk_deep_mkdir.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN32
 #include <tchar.h>
 #include <io.h>
 #include <tchar.h>
#else   // win以外ではcharのみ.
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #ifndef TCHAR
  #define _T(x)     x
  #define TCHAR     char
 #endif
#endif


#ifndef FNAME_INCLUDED  // fname.h を読み込んでなかったら交替物を用意.
#ifdef _WIN32
#define FNAME_MAX_PATH      _MAX_PATH
#define FNAME_LEN(s)        _tcslen(s)
#define FNAME_SEP_CHR       _T('\\')
#define fname_cpy(d,l,s)    ((d)[(l)-1]=0, _tcsncpy((d),(s),(l)-1))

TCHAR*  fname_baseName(const TCHAR* p) {
    const TCHAR *adr = p;
    while (*p) {
        if (*p == _T(':') || *p == _T('/') || *p == _T('\\'))
            adr = p + 1;
        p = CharNext((TCHAR*)p);
    }
    return (TCHAR*)adr;
}
#else
#define FNAME_MAX_PATH      4096
#define FNAME_LEN(s)        strlen(s)
#define FNAME_SEP_CHR       '/'
#define fname_cpy(d,l,s)    ((d)[(l)-1]=0, strncpy((d),(s),(l)-1))

char*   fname_baseName(const char* p) {
    const char *adr = p;
    while (*p) {
        char c = *p++;
        if (c == ':' || c == '/')
            adr = p;
    }
    return (char*)adr;
}
#endif
#endif



#ifndef DISK_H
#ifdef _WIN32
static __inline int disk_mkdir(const TCHAR* fname) { return CreateDirectory(fname,NULL) ? 0 : -1; }
#else
static inline int disk_mkdir(const char* fname) { return mkdir(fname, 0777); }
#endif
#endif



/** 途中のディレクトリも掘る mkdir.
 */
int disk_deep_mkdir(const TCHAR *name)
{
    TCHAR   nm[ FNAME_MAX_PATH + 1 ];
    TCHAR*  e;
    TCHAR*  s;
  #ifdef _WIN32
    unsigned    atr = GetFileAttributes(name);
    if (atr != 0xFFFFFFFF) {
        if (atr & FILE_ATTRIBUTE_DIRECTORY)
            return 0;
        return -1;      // ディレクトリでないファイルだったのでアウト.
    }
  #else
    {
        struct stat s;
        stat(name, &s);
        if (s.st_mode & S_IFDIR)
            return 0;
    }
  #endif
    if (disk_mkdir(name) == 0)
        return 0;
    fname_cpy(nm, FNAME_MAX_PATH, name);
    e = nm + FNAME_LEN(nm);
    for (;;) {
        s = fname_baseName(nm);
        if (s <= nm)
            return -1;  // 失敗.
        --s;
        *s = 0;
        if (disk_mkdir(nm) == 0) {
            do {
                *s    = FNAME_SEP_CHR;
                s    += FNAME_LEN(s);
                if (s >= e)
                    return disk_mkdir(nm);
            } while (disk_mkdir(nm) == 0);
            return -1;
        }
    }
}