4coder/custom/4coder_file_moving.h

640 lines
16 KiB
C

/*
* Mr. 4th Dimention - Allen Webster
*
* 21.01.2017
*
* Moving files around on the file system.
*
*/
// TOP
#if !defined(FRED_FILE_MOVING_H)
#define FRED_FILE_MOVING_H
#include <stdio.h> // include system for windows
#include <stdlib.h> // include system for linux (YAY!)
#include <stdarg.h>
#include <string.h>
//
// API
//
// System commands
static char SF_CMD[4096];
static i32 error_state = 0;
static i32 prev_error = 0;
#if defined(FM_PRINT_COMMANDS)
#define SYSTEMF_PRINTF(...) printf(__VA_ARGS__);
#else
#define SYSTEMF_PRINTF(...)
#endif
#define systemf(...) do{ \
i32 n = snprintf(SF_CMD, sizeof(SF_CMD), __VA_ARGS__); \
Assert(n < sizeof(SF_CMD)); \
SYSTEMF_PRINTF("%s\n", SF_CMD); \
prev_error = system(SF_CMD); \
if (prev_error != 0) error_state = 1; \
}while(0)
internal void fm_execute_in_dir(char *dir, char *str, char *args);
// Init
internal Arena fm_init_system();
// Timing
internal u64 fm_get_time();
#define LLU_CAST(n) (long long unsigned int)(n)
#define BEGIN_TIME_SECTION() u64 start = fm_get_time()
#define END_TIME_SECTION(n) u64 total = fm_get_time() - start; printf("%-20s: %.2llu.%.6llu\n", (n), LLU_CAST(total/1000000), LLU_CAST(total%1000000));
// Files and Folders Manipulation
internal void fm_make_folder_if_missing(Arena *arena, char *dir);
internal void fm_clear_folder(char *folder);
internal void fm_delete_file(char *file);
internal void fm_copy_file(char *file, char *newname);
internal void fm_copy_all(char *source, char *folder);
internal void fm_copy_folder(Arena *arena, char *src_dir, char *dst_dir, char *src_folder);
// File Reading and Writing
internal void fm_write_file(char *file_name, char *data, u32 size);
// Zip
internal void fm_zip(char *parent, char *folder, char *dest);
// Slash Correction
internal void fm_slash_fix(char *path);
// Memory concat helpers
internal char *fm_prepare_string_internal(Arena *arena, char *s1, ...);
#define fm_str(...) fm_prepare_string_internal(__VA_ARGS__, (void*)0)
internal char *fm_basic_string_internal(Arena *arena, char *s1, ...);
#define fm_basic_str(...) fm_basic_string_internal(__VA_ARGS__, (void*)0)
internal char **fm_prepare_list_internal(Arena *arena, char **l1, ...);
#define fm_list(...) fm_prepare_list_internal(__VA_ARGS__, (void*)0)
internal char **fm_list_one_item(Arena *arena, char *item);
// File System Navigation
internal i32 fm_get_current_directory(char *buffer, i32 max);
struct Temp_Dir{
char dir[512];
};
internal Temp_Dir fm_pushdir(char *dir);
internal void fm_popdir(Temp_Dir temp);
// Build Line
#define BUILD_LINE_MAX 4096
struct Build_Line{
char build_optionsA[BUILD_LINE_MAX];
char build_optionsB[BUILD_LINE_MAX];
char *build_options;
char *build_options_prev;
i32 build_max;
};
internal void fm_init_build_line(Build_Line *line);
internal void fm_finish_build_line(Build_Line *line);
internal void fm__swap_ptr(char **A, char **B);
#if COMPILER_CL
#define fm_add_to_line(line, str, ...) do{ \
snprintf(line.build_options, \
line.build_max, "%s "str, \
line.build_options_prev, __VA_ARGS__); \
fm__swap_ptr(&line.build_options, &line.build_options_prev); \
}while(0)
#elif COMPILER_GCC
#define fm_add_to_line(line, str, ...) do{ \
snprintf(line.build_options, line.build_max, "%s " str, \
line.build_options_prev, ##__VA_ARGS__); \
fm__swap_ptr(&line.build_options, &line.build_options_prev); \
}while(0)
#endif
// Slashes
#if OS_WINDOWS
# define SLASH "\\"
static char platform_correct_slash = '\\';
#elif OS_LINUX || OS_MAC
# define SLASH "/"
static char platform_correct_slash = '/';
#else
# error Slash not set for this platform.
#endif
// File Extensions
#if OS_WINDOWS
# define EXE ".exe"
#elif OS_LINUX || OS_MAC
# define EXE ""
#else
# error No EXE format specified for this OS
#endif
#if OS_WINDOWS
# define PDB ".pdb"
#elif OS_LINUX || OS_MAC
# define PDB ""
#else
# error No PDB format specified for this OS
#endif
#if OS_WINDOWS
# define DLL ".dll"
#elif OS_LINUX || OS_MAC
# define DLL ".so"
#else
# error No DLL format specified for this OS
#endif
#if OS_WINDOWS
# define BAT ".bat"
#elif OS_LINUX || OS_MAC
# define BAT ".sh"
#else
# error No BAT format specified for this OS
#endif
#endif
//
// Implementation
//
#if defined(FTECH_FILE_MOVING_IMPLEMENTATION) && !defined(FTECH_FILE_MOVING_IMPL_GUARD)
#define FTECH_FILE_MOVING_IMPL_GUARD
internal Arena
fm__init_memory(void){
return(make_arena_malloc(MB(512), 8));
}
//
// Windows implementation
//
#if OS_WINDOWS
typedef u32 DWORD;
typedef i32 LONG;
typedef i64 LONGLONG;
typedef char* LPTSTR;
typedef char* LPCTSTR;
typedef i32 BOOL;
typedef void* LPSECURITY_ATTRIBUTES;
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
};
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;
typedef void* HANDLE;
typedef void* PVOID;
typedef void* LPVOID;
typedef void* LPCVOID;
typedef DWORD* LPDWORD;
#if defined(_WIN64)
typedef unsigned __int64 ULONG_PTR;
#else
typedef unsigned long ULONG_PTR;
#endif
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
};
HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;
#define WINAPI
extern "C"{
DWORD WINAPI GetCurrentDirectoryA(_In_ DWORD nBufferLength, _Out_ LPTSTR lpBuffer);
BOOL WINAPI SetCurrentDirectoryA(_In_ LPCTSTR lpPathName);
BOOL WINAPI QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount);
BOOL WINAPI QueryPerformanceFrequency(_Out_ LARGE_INTEGER *lpFrequency);
BOOL WINAPI CreateDirectoryA(_In_ LPCTSTR lpPathName, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes);
BOOL WINAPI CopyFileA(_In_ LPCTSTR lpExistingFileName, _In_ LPCTSTR lpNewFileName, _In_ BOOL bFailIfExists);
HANDLE WINAPI CreateFileA(_In_ LPCTSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode,_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _In_ DWORD dwCreationDisposition, _In_ DWORD dwFlagsAndAttributes, _In_opt_ HANDLE hTemplateFile);
BOOL WINAPI WriteFile(_In_ HANDLE hFile, _In_ LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped);
BOOL WINAPI ReadFile(_In_ HANDLE hFile, _Out_ LPVOID lpBuffer, _In_ DWORD nNumberOfBytesToRead, _Out_opt_ LPDWORD lpNumberOfBytesRead, _Inout_opt_ LPOVERLAPPED lpOverlapped);
BOOL WINAPI CloseHandle(_In_ HANDLE hObject);
}
#define INVALID_HANDLE_VALUE ((HANDLE) -1)
#define GENERIC_READ 0x80000000
#define GENERIC_WRITE 0x40000000
#define GENERIC_EXECUTE 0x20000000
#define GENERIC_ALL 0x10000000
#define CREATE_NEW 1
#define CREATE_ALWAYS 2
#define OPEN_EXISTING 3
#define OPEN_ALWAYS 4
#define TRUNCATE_EXISTING 5
#define FILE_ATTRIBUTE_READONLY 0x00000001
#define FILE_ATTRIBUTE_NORMAL 0x00000080
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
global u64 perf_frequency;
internal Arena
fm_init_system(void){
LARGE_INTEGER lint;
if (QueryPerformanceFrequency(&lint)){
perf_frequency = lint.QuadPart;
}
return(fm__init_memory());
}
internal Temp_Dir
fm_pushdir(char *dir){
Temp_Dir temp = {};
GetCurrentDirectoryA(sizeof(temp.dir), temp.dir);
SetCurrentDirectoryA(dir);
return(temp);
}
internal void
fm_popdir(Temp_Dir temp){
SetCurrentDirectoryA(temp.dir);
}
internal u64
fm_get_time(){
u64 time = 0;
LARGE_INTEGER lint;
if (QueryPerformanceCounter(&lint)){
time = lint.QuadPart;
time = (time * 1000000) / perf_frequency;
}
return(time);
}
internal i32
fm_get_current_directory(char *buffer, i32 max){
i32 result = GetCurrentDirectoryA(max, buffer);
return(result);
}
internal void
fm_execute_in_dir(char *dir, char *str, char *args){
if (dir){
Temp_Dir temp = fm_pushdir(dir);
if (args){
systemf("call \"%s\" %s", str, args);
}
else{
systemf("call \"%s\"", str);
}
fm_popdir(temp);
}
else{
if (args){
systemf("call \"%s\" %s", str, args);
}
else{
systemf("call \"%s\"", str);
}
}
}
internal void
fm_slash_fix(char *path){
if (path != 0){
for (i32 i = 0; path[i]; ++i){
if (path[i] == '/') path[i] = '\\';
}
}
}
internal void
fm_make_folder_if_missing(Arena *arena, char *dir){
char *path = fm_str(arena, dir);
char *p = path;
for (; *p; ++p){
if (*p == '\\'){
*p = 0;
CreateDirectoryA(path, 0);
*p = '\\';
}
}
CreateDirectoryA(path, 0);
}
internal void
fm_clear_folder(char *folder){
fprintf(stdout, "clearing folder %s\n", folder);
fflush(stdout);
systemf("del /S /Q /F %s\\* > nul & rmdir /S /Q %s > nul & mkdir %s > nul", folder, folder, folder);
}
internal void
fm_delete_file(char *file){
systemf("del %s", file);
}
internal void
fm_copy_file(char *file, char *newname){
printf("copy %s to %s\n", file, newname);
fflush(stdout);
CopyFileA(file, newname, 0);
}
internal void
fm_copy_all(char *source, char *folder){
fprintf(stdout, "copy %s to %s\n", source, folder);
fflush(stdout);
systemf("xcopy /s /e /y /q %s %s > nul", source, folder);
}
internal void
fm_write_file(char *file_name, char *data, u32 size){
HANDLE file = CreateFileA(file_name, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (file != INVALID_HANDLE_VALUE){
DWORD written = 0;
for (;written < size;){
DWORD newly_written = 0;
if (!WriteFile(file, data + written, size - written, &newly_written, 0)){
break;
}
written += newly_written;
}
Assert(written == size);
CloseHandle(file);
}
}
internal void
fm_zip(char *parent, char *folder, char *dest){
printf("zipping %s\\%s to %s\n", parent, folder, dest);
fflush(stdout);
char cdir[512];
fm_get_current_directory(cdir, sizeof(cdir));
Temp_Dir temp = fm_pushdir(parent);
systemf("%s\\bin\\zip %s\\4ed_gobble.zip > nul", cdir, cdir);
fm_popdir(temp);
systemf("copy %s\\4ed_gobble.zip %s > nul & del %s\\4ed_gobble.zip > nul", cdir, dest, cdir);
}
//
// Unix implementation
//
#elif OS_LINUX || OS_MAC
#include <time.h>
#include <unistd.h>
internal Temp_Dir
fm_pushdir(char *dir){
Temp_Dir temp;
char *result = getcwd(temp.dir, sizeof(temp.dir));
i32 chresult = chdir(dir);
if (result == 0 || chresult != 0){
printf("trying pushdir %s\n", dir);
Assert(result != 0);
Assert(chresult == 0);
}
return(temp);
}
internal void
fm_popdir(Temp_Dir temp){
chdir(temp.dir);
}
internal Arena
fm_init_system(){
return(fm__init_memory());
}
internal u64
fm_get_time(){
struct timespec spec;
u64 result;
clock_gettime(CLOCK_MONOTONIC, &spec);
result = (spec.tv_sec * (u64)(1000000)) + (spec.tv_nsec / (u64)(1000));
return(result);
}
internal i32
fm_get_current_directory(char *buffer, i32 max){
i32 result = 0;
char *d = getcwd(buffer, max);
if (d == buffer){
result = strlen(buffer);
}
return(result);
}
internal void
fm_execute_in_dir(char *dir, char *str, char *args){
if (dir){
if (args){
Temp_Dir temp = fm_pushdir(dir);
systemf("%s %s", str, args);
fm_popdir(temp);
}
else{
Temp_Dir temp = fm_pushdir(dir);
systemf("%s", str);
fm_popdir(temp);
}
}
else{
if (args){
systemf("%s %s", str, args);
}
else{
systemf("%s", str);
}
}
}
internal void
fm_slash_fix(char *path){}
internal void
fm_make_folder_if_missing(Arena *arena, char *dir){
systemf("mkdir -p %s", dir);
}
internal void
fm_clear_folder(char *folder){
fprintf(stdout, "clearing folder %s\n", folder);
fflush(stdout);
systemf("rm -rf %s* > /dev/null", folder);
}
internal void
fm_delete_file(char *file){
systemf("rm %s", file);
}
internal void
fm_copy_file(char *file, char *newname){
systemf("cp %s %s", file, newname);
}
internal void
fm_copy_all(char *source, char *folder){
fprintf(stdout, "copy %s to %s\n", source, folder);
systemf("cp -rf %s %s > /dev/null", source, folder);
}
internal void
fm_write_file(char *file_name, char *data, u32 size){
// TODO(allen): Real unix version?
FILE *file = fopen(file_name, "wb");
if (file != 0){
fwrite(data, 1, size, file);
fclose(file);
}
}
internal void
fm_zip(char *parent, char *folder, char *file){
Temp_Dir temp = fm_pushdir(parent);
printf("PARENT DIR: %s\n", parent);
systemf("zip -r %s %s", file, folder);
fm_popdir(temp);
}
#else
#error This OS is not supported yet
#endif
internal void
fm_copy_folder(Arena *arena, char *src_dir, char *dst_dir, char *src_folder){
Temp_Dir temp = fm_pushdir(src_dir);
fm_make_folder_if_missing(arena, fm_str(arena, dst_dir, "/", src_folder));
char *copy_name = fm_str(arena, dst_dir, "/", src_folder);
fm_copy_all(src_folder, copy_name);
fm_popdir(temp);
}
// List Helpers
internal i32
listsize(void *p, umem item_size){
u64 zero = 0;
u8 *ptr = (u8*)p;
for (;memcmp(ptr, &zero, (size_t)item_size) != 0; ptr += item_size);
i32 size = (i32)(ptr - (u8*)p);
return(size);
}
internal void*
fm__prepare(Arena *arena, i32 item_size, void *i1, va_list list){
List_String_Const_char out_list = {};
i32 size = listsize(i1, item_size);
string_list_push(arena, &out_list, SCchar((char*)i1, size));
void *ln = va_arg(list, void*);
for (;ln != 0;){
size = listsize(ln, item_size);
string_list_push(arena, &out_list, SCchar((char*)ln, size));
ln = va_arg(list, void*);
}
void *terminator = push_array_zero(arena, char, item_size);
string_list_push(arena, &out_list, SCchar((char*)terminator, item_size));
String_Const_char result = string_list_flatten(arena, out_list);
return(result.str);
}
internal char*
fm_basic_string_internal(Arena *arena, char *s1, ...){
i32 item_size = sizeof(*s1);
va_list list;
va_start(list, s1);
char *result = (char*)fm__prepare(arena, item_size, s1, list);
va_end(list);
return(result);
}
internal char*
fm_prepare_string_internal(Arena *arena, char *s1, ...){
i32 item_size = sizeof(*s1);
va_list list;
va_start(list, s1);
char *result = (char*)fm__prepare(arena, item_size, s1, list);
va_end(list);
fm_slash_fix(result);
return(result);
}
internal char**
fm_prepare_list_internal(Arena *arena, char **p1, ...){
i32 item_size = sizeof(*p1);
va_list list;
va_start(list, p1);
char **result = (char**)fm__prepare(arena, item_size, p1, list);
va_end(list);
return(result);
}
internal char**
fm_list_one_item(Arena *arena, char *item){
char **result = push_array(arena, char*, 2);
result[0] = item;
result[1] = 0;
return(result);
}
// Build Line
internal void
fm_init_build_line(Build_Line *line){
line->build_options = line->build_optionsA;
line->build_options_prev = line->build_optionsB;
line->build_optionsA[0] = 0;
line->build_optionsB[0] = 0;
line->build_max = BUILD_LINE_MAX;
}
internal void
fm_finish_build_line(Build_Line *line){
fm__swap_ptr(&line->build_options, &line->build_options_prev);
}
internal void
fm__swap_ptr(char **A, char **B){
char *a = *A;
char *b = *B;
*A = b;
*B = a;
}
#endif
// BOTTOM