#define _XOPEN_SOURCE …
#define _DEFAULT_SOURCE
#include "m_pd.h"
#include "g_canvas.h"
#include "s_stuff.h"
#include "s_utf8.h"
#include "m_private_utils.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#ifdef _WIN32
# include <windows.h>
# include <direct.h>
# include <io.h>
#else
# include <glob.h>
# include <ftw.h>
#endif
#ifdef _MSC_VER
# include <BaseTsd.h>
typedef unsigned int mode_t;
typedef SSIZE_T ssize_t;
#define wstat …
#endif
#ifndef S_ISREG
#define S_ISREG …
#endif
#ifndef S_ISDIR
#define S_ISDIR …
#endif
#ifndef X_FILE_DEBUG
#define X_FILE_DEBUG …
#endif
#ifdef _WIN32
static int do_delete_ucs2(wchar_t*pathname) {
struct stat sb;
if (!wstat(pathname, &sb) && (S_ISDIR(sb.st_mode))) {
return !(RemoveDirectoryW(pathname));
} else {
return !(DeleteFileW(pathname));
}
}
static int sys_stat(const char *pathname, struct stat *statbuf) {
uint16_t ucs2buf[MAX_PATH];
u8_utf8toucs2(ucs2buf, MAX_PATH, pathname, strlen(pathname));
return wstat(ucs2buf, statbuf);
}
static int sys_rename(const char *oldpath, const char *newpath) {
uint16_t src[MAX_PATH], dst[MAX_PATH];
u8_utf8toucs2(src, MAX_PATH, oldpath, MAX_PATH);
u8_utf8toucs2(dst, MAX_PATH, newpath, MAX_PATH);
return _wrename(src, dst);
}
static int sys_mkdir(const char *pathname, mode_t mode) {
uint16_t ucs2name[MAX_PATH];
(void)mode;
u8_utf8toucs2(ucs2name, MAX_PATH, pathname, MAX_PATH);
return !(CreateDirectoryW(ucs2name, 0));
}
static int sys_remove(const char *pathname) {
uint16_t ucs2buf[MAXPDSTRING];
u8_utf8toucs2(ucs2buf, MAXPDSTRING, pathname, MAXPDSTRING);
return do_delete_ucs2(ucs2buf);
}
static char* sys_getcwd(char *buf) {
uint16_t ucs2buf[MAXPDSTRING];
memset(ucs2buf, 0, sizeof(ucs2buf));
if (!_wgetcwd(ucs2buf, MAXPDSTRING))
return 0;
u8_ucs2toutf8(buf, MAXPDSTRING-1, ucs2buf, -1);
buf[MAXPDSTRING-1] = 0;
sys_unbashfilename(buf, buf);
return buf;
}
static int sys_chdir(const char *path) {
uint16_t ucs2buf[MAXPDSTRING];
u8_utf8toucs2(ucs2buf, MAXPDSTRING, path, MAXPDSTRING);
return _wchdir(ucs2buf);
}
#else
static int sys_stat(const char *pathname, struct stat *statbuf) { … }
static int sys_rename(const char *oldpath, const char *newpath) { … }
static int sys_mkdir(const char *pathname, mode_t mode) { … }
static int sys_remove(const char *pathname) { … }
static char* sys_getcwd(char *buf) { … }
static int sys_chdir(const char *path) { … }
#endif
static char*do_expandpath(const char *from, char *to, int bufsize)
{ … }
static char*do_pathnormalize(const char *from, char *to) { … }
static char*do_expandunbash(const char *from, char *to, int bufsize) { … }
static int str_endswith(char* str, char* end){ … }
static t_symbol*do_splitpath(const char*path, int*argc, t_atom**argv) { … }
static t_symbol*do_joinpath(t_symbol*prefix, int argc, t_atom*argv, t_symbol*suffix) { … }
#ifdef _WIN32
static const char*do_errmsg(char*buffer, size_t bufsize) {
char errcode[10];
char*s;
wchar_t wbuf[MAXPDSTRING];
DWORD err = GetLastError();
DWORD count = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, err, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), wbuf, MAXPDSTRING, NULL);
if (!count || !WideCharToMultiByte(CP_UTF8, 0, wbuf, count+1, buffer, bufsize, 0, 0))
*buffer = '\0';
s=buffer + strlen(buffer)-1;
while(('\r' == *s || '\n' == *s) && s>buffer)
*s--=0;
pd_snprintf(errcode, sizeof(errcode), " [%ld]", err);
errcode[sizeof(errcode)-1] = 0;
strcat(buffer, errcode);
return buffer;
}
#else
static const char*do_errmsg(char*buffer, size_t bufsize) { … }
#endif
t_file_handler;
#define x_fd …
#define x_mode …
t_file_handle;
static int do_checkpathname(t_file_handle*x, const char*path) { … }
t_canvas*do_getparentcanvas(t_file_handle*x, int parentlevel, int*effectivelevel) { … }
static int do_parse_creationmode(t_atom*ap) { … }
static void do_parse_args(t_file_handle*x, int argc, t_atom*argv) { … }
static t_file_handle* do_file_handle_new(t_class*cls, t_symbol*s, int argc, t_atom*argv, int verbose, mode_t creationmode) { … }
static int do_file_open(t_file_handle*x, const char* filename, int mode) { … }
static void file_set_verbosity(t_file_handle*x, t_float f) { … }
static void file_set_creationmode(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
t_class *file_define_class;
static int file_handle_getdefine(t_file_handle*x) { … }
static void file_handle_close(t_file_handle*x) { … }
static int file_handle_checkopen(t_file_handle*x, const char*cmd) { … }
static void file_handle_do_read(t_file_handle*x, t_float f) { … }
static void file_handle_do_write(t_file_handle*x, int argc, t_atom*argv) { … }
static void file_handle_list(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
static void file_handle_set(t_file_handle*x, t_symbol*s) { … }
static void file_handle_seek(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
static void file_handle_open(t_file_handle*x, t_symbol*file, t_symbol*smode) { … }
static void file_handle_free(t_file_handle*x) { … }
static int do_file_stat(t_file_handle*x, const char*filename, struct stat*sb, int*is_symlink) { … }
static void do_dataout_symbol(t_file_handle*x, const char*selector, t_symbol*s) { … }
static void do_dataout_float(t_file_handle*x, const char*selector, t_float f) { … }
static void do_dataout_time(t_file_handle*x, const char*selector, time_t t) { … }
static void file_stat_symbol(t_file_handle*x, t_symbol*filename) { … }
static void file_size_symbol(t_file_handle*x, t_symbol*filename) { … }
static void file_isfile_symbol(t_file_handle*x, t_symbol*filename) { … }
static void file_isdirectory_symbol(t_file_handle*x, t_symbol*filename) { … }
#ifdef _WIN32
static void file_glob_symbol(t_file_handle*x, t_symbol*spattern) {
WIN32_FIND_DATAW FindFileData;
HANDLE hFind;
uint16_t ucs2pattern[MAXPDSTRING];
char pattern[MAXPDSTRING];
int nostartdot=0, noendtilde=0, onlydirs=0;
char *filepattern, *strin, *strout;
int pathpatternlength=0;
int matchdot=0;
do_expandunbash(spattern->s_name, pattern, MAXPDSTRING);
if(!strcmp(".", pattern) || !strcmp("./", pattern)
|| str_endswith(pattern, "/.") || str_endswith(pattern, "/./"))
matchdot=1;
else if(!strcmp("..", pattern) || !strcmp("../", pattern)
|| str_endswith(pattern, "/..") || str_endswith(pattern, "/../"))
matchdot=2;
if (matchdot) {
struct stat sb;
if (!do_file_stat(0, pattern, &sb, 0)) {
t_atom outv[2];
size_t end = strlen(pattern);
if('/' == pattern[end-1])
pattern[end-1]=0;
SETSYMBOL(outv+0, gensym(pattern));
SETFLOAT(outv+1, S_ISDIR(sb.st_mode));
outlet_list(x->x_dataout, gensym("list"), 2, outv);
} else {
outlet_bang(x->x_infoout);
}
return;
}
filepattern=strrchr(pattern, '/');
if(filepattern && !filepattern[1]) {
onlydirs=1;
while('/' == *filepattern && filepattern>pattern) {
*filepattern--=0;
}
filepattern=strrchr(pattern, '/');
}
if(!filepattern)
filepattern=pattern;
else {
filepattern++;
pathpatternlength=filepattern-pattern;
}
nostartdot=('.' != *filepattern);
strin=filepattern;
strout=filepattern;
while(*strin) {
char c = *strin++;
*strout++ = c;
if('*' == c) {
while('?' == *strin || '*' == *strin)
strin++;
}
}
*strout=0;
if (strout>pattern) {
switch(strout[-1]) {
case '~':
case '*':
case '?':
noendtilde=0;
break;
default:
noendtilde=1;
}
}
u8_utf8toucs2(ucs2pattern, MAXPDSTRING, pattern, MAXPDSTRING);
hFind = FindFirstFileW(ucs2pattern, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
outlet_bang(x->x_infoout);
return;
}
do {
t_symbol*s;
t_atom outv[2];
int len = 0;
int isdir = !!(FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes);
if (matchdot!=1 && !wcscmp(L"." , FindFileData.cFileName))
continue;
if (matchdot!=2 && !wcscmp(L".." , FindFileData.cFileName))
continue;
u8_ucs2toutf8(filepattern, MAXPDSTRING-pathpatternlength, FindFileData.cFileName, MAX_PATH);
len = strlen(filepattern);
if(onlydirs && !isdir)
continue;
if(nostartdot && '.' == filepattern[0])
continue;
if(noendtilde && '~' == filepattern[len-1])
continue;
s = gensym(pattern);
SETSYMBOL(outv+0, s);
SETFLOAT(outv+1, isdir);
outlet_list(x->x_dataout, gensym("list"), 2, outv);
} while (FindNextFileW(hFind, &FindFileData) != 0);
FindClose(hFind);
}
#else
static void file_glob_symbol(t_file_handle*x, t_symbol*spattern) { … }
#endif
static void file_which_doit(t_file_handle*x, t_symbol*s, int depth) { … }
static void file_which_list(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
static void file_patchpath_list(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
static void file_mkdir_symbol(t_file_handle*x, t_symbol*dir) { … }
#ifdef _WIN32
static int file_do_delete_recursive_ucs2(uint16_t*path) {
WIN32_FIND_DATAW FindFileData;
HANDLE hFind;
uint16_t pattern[MAX_PATH];
swprintf(pattern, MAX_PATH, L"%ls/*", path);
hFind = FindFirstFileW(pattern, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
return 1;
}
do {
int isdir = !!(FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes);
swprintf(pattern, MAX_PATH, L"%ls/%ls", path, FindFileData.cFileName);
if(!isdir) {
DeleteFileW(pattern);
} else {
if(!wcscmp(L".", FindFileData.cFileName))continue;
if(!wcscmp(L"..", FindFileData.cFileName))continue;
file_do_delete_recursive_ucs2(pattern);
}
} while (FindNextFileW(hFind, &FindFileData) != 0);
FindClose(hFind);
return do_delete_ucs2(path);
}
static int file_do_delete_recursive(const char*path) {
uint16_t ucs2path[MAXPDSTRING];
u8_utf8toucs2(ucs2path, MAXPDSTRING, path, MAXPDSTRING);
return file_do_delete_recursive_ucs2(ucs2path);
}
#else
static int nftw_cb(const char *path, const struct stat *s, int flag, struct FTW *f) { … }
static int file_do_delete_recursive(const char*pathname) { … }
#endif
static void file_delete_symbol(t_file_handle*x, t_symbol*path) { … }
static void file_delete_recursive(t_file_handle*x, t_symbol*path) { … }
static int file_do_copy(const char*source, const char*destination, int mode) { … }
static int file_do_move(const char*source, const char*destination, int mode) { … }
static void file_do_copymove(t_file_handle*x,
const char*verb, int (*fun)(const char*,const char*,int),
t_symbol*s, int argc, t_atom*argv) { … }
static void file_copy_list(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
static void file_move_list(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
static void file_cwd_bang(t_file_handle*x) { … }
static void file_cwd_symbol(t_file_handle*x, t_symbol*path) { … }
static void file_split_symbol(t_file_handle*x, t_symbol*path) { … }
static void file_join_list(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
static void file_splitext_symbol(t_file_handle*x, t_symbol*path) { … }
static void file_splitname_symbol(t_file_handle*x, t_symbol*path) { … }
static void file_normalize_symbol(t_file_handle*x, t_symbol*path) { … }
static void file_isabsolute_symbol(t_file_handle*x, t_symbol*path) { … }
t_class *file_handle_class, *file_which_class, *file_glob_class, *file_patchpath_class;
t_class *file_stat_class, *file_size_class, *file_isfile_class, *file_isdirectory_class;
t_class *file_mkdir_class, *file_delete_class, *file_copy_class, *file_move_class;
t_class *file_split_class,*file_join_class,*file_splitext_class, *file_splitname_class;
t_class *file_normalize_class, *file_isabsolute_class, *file_cwd_class;
#define FILE_PD_NEW(verb, verbose, creationmode) …
static void file_define_ignore(t_file_handle*x, t_symbol*s, int argc, t_atom*argv) { … }
static t_file_handle*file_define_new(t_symbol*s, int argc, t_atom*argv) { … }
static void file_define_free(t_file_handle*x) { … }
static t_file_handle*file_handle_new(t_symbol*s, int argc, t_atom*argv) { … }
FILE_PD_NEW(which, 0, 0);
FILE_PD_NEW(patchpath, 0, 0);
FILE_PD_NEW(glob, 0, 0);
FILE_PD_NEW(stat, 0, 0);
FILE_PD_NEW(size, 0, 0);
FILE_PD_NEW(isfile, 0, 0);
FILE_PD_NEW(isdirectory, 0, 0);
FILE_PD_NEW(mkdir, 0, 0777);
FILE_PD_NEW(delete, 0, 0);
FILE_PD_NEW(copy, 0, 0);
FILE_PD_NEW(move, 0, 0);
FILE_PD_NEW(cwd, 1, 0);
FILE_PD_NEW(split, 0, 0);
FILE_PD_NEW(join, 0, 0);
FILE_PD_NEW(splitext, 0, 0);
FILE_PD_NEW(splitname, 0, 0);
FILE_PD_NEW(isabsolute, 0, 0);
FILE_PD_NEW(normalize, 1, 0);
static t_pd *fileobj_new(t_symbol *s, int argc, t_atom*argv)
{ … }
t_filenew_flag;
static t_class*file_class_new(const char*name
, t_file_handle* (*ctor)(t_symbol*,int,t_atom*), void (*dtor)(t_file_handle*)
, void (*symfun)(t_file_handle*, t_symbol*)
, t_filenew_flag flag
) { … }
void x_file_setup(void)
{ … }