diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2022-01-14 13:39:15 -0500 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2022-01-14 13:43:04 -0500 |
commit | 3df5fac04835ccd8557c12442c4c7a3301d834f2 (patch) | |
tree | bd3e709ddec7f12e1fa8755da4685754abda64ca /main.c | |
parent | 53869ee640b69803699c55faa98cf0f5bbf99455 (diff) | |
download | weekly-3df5fac04835ccd8557c12442c4c7a3301d834f2.tar.gz |
Add MSVC and MINGW support
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 269 |
1 files changed, 226 insertions, 43 deletions
@@ -2,19 +2,75 @@ #include <stdlib.h> #include <string.h> #include <time.h> -#include <unistd.h> -#include <dirent.h> -#include <sys/stat.h> -#include <pwd.h> + +#if defined(_WIN32) || defined(_WIN64) + #define HAVE_WINDOWS 1 +#else + #define HAVE_WINDOWS 0 +#endif + +#if HAVE_WINDOWS && (defined(_MSC_BUILD) || defined(_MSC_VER) || defined(_MSC_EXTENSIONS)) + #define HAVE_MSVC 1 +#else + #define HAVE_MSVC 0 +#endif + +#if HAVE_WINDOWS && (defined(__MINGW32__) || defined(__MINGW64__)) + #define HAVE_MINGW 1 +#else + #define HAVE_MINGW 0 +#endif + +#if HAVE_WINDOWS + #if HAVE_MSVC + #include <io.h> + #if !defined(F_OK) + #define F_OK 0 + #endif + typedef long long ssize_t; + typedef unsigned long long size_t; + #endif + + #if HAVE_MINGW + #include <dirent.h> + #endif + + #include <direct.h> + #include <windows.h> + #define DIRSEP_C '\\' + #define DIRSEP_S "\\" + #define PATHSEP_C ';' + #define PATHSEP_S ";" + #define PATHVAR "path" + #define mkdir(X, Y) mkdir(X) + #define mkstemp _mktemp +#else + #include <limits.h> + #include <dirent.h> + #include <sys/stat.h> + #include <unistd.h> + #include <pwd.h> + #define DIRSEP_C '/' + #define DIRSEP_S "/" + #define PATHSEP_C ':' + #define PATHSEP_S ":" + #define PATHVAR "PATH" +#endif + +#if !defined(PATH_MAX) +#define PATH_MAX 1024 +#endif #define ARG(X) strcmp(argv[i], X) == 0 #define ARG_VERIFY_NEXT() (argv[i+1] != NULL) char *program_name; -char journalroot[1024] = {0}; -char intermediates[1024] = {0}; +char *homedir; +char journalroot[PATH_MAX] = {0}; +char intermediates[PATH_MAX] = {0}; const char *VERSION = "1.0.0"; const char *FMT_HEADER = "## date: %s\n" + "## time: %s\n" "## author: %s\n" "## host: %s\n"; const char *USAGE_STATEMENT = \ @@ -32,30 +88,99 @@ void usage() { unsigned is_base; is_base = 0; - name = strrchr(program_name, '/'); + name = strrchr(program_name, DIRSEP_C); if (name != NULL) { is_base = 1; } printf(USAGE_STATEMENT, is_base ? name + 1 : program_name, VERSION); } +int find_program(const char *name) { + char *token; + int found; + int found_extension; + char *pathvar; + + pathvar = getenv(PATHVAR); + if (!pathvar) { + return -1; + } + + found = 0; + token = strtok(pathvar, PATHSEP_S); + while (token != NULL) { + char filename[PATH_MAX] = {0}; + sprintf(filename, "%s%c%s", token, DIRSEP_C, name); +#if HAVE_WINDOWS + // I am aware of PATHEXT. Let's stick to binary executables and shell scripts + char *ext[] = {".bat", ".cmd", ".com", ".exe"}; + char filename_orig[PATH_MAX] = {0}; + + found_extension = 0; + for (size_t i = 0; i < sizeof(ext) / sizeof(char *); i++) { + if (strstr(filename, ext[i]) != NULL) { + found_extension = 1; + break; + } + } + if (!found_extension) { + for (size_t i = 0; i < sizeof(ext) / sizeof(char *); i++) { + strcpy(filename_orig, filename); + strcat(filename, ext[i]); + if (access(filename, F_OK) == 0) { + found = 1; + break; + } + strcpy(filename, filename_orig); + } + } else { + if (access(filename, F_OK) == 0) { + found = 1; + break; + } + } + if (found) + break; +#else + if (access(filename, F_OK) == 0) { + found = 1; + break; + } +#endif + token = strtok(NULL, PATHSEP_S); + } + return found; +} + int edit_file(const char *filename) { - char editor[255]; - char editor_cmd[1024]; + char editor[255] = {0}; + char editor_cmd[PATH_MAX] = {0}; int result; const char *user_editor; - // Allow the user to override the default editor (vi) + // Allow the user to override the default editor (vi/notepad) user_editor = getenv("EDITOR"); if (user_editor != NULL) { strcpy(editor, user_editor); } else { - strcpy(editor, "vi"); + if (find_program("vim")) { + strcpy(editor, "vim"); + } +#if HAVE_WINDOWS + else { + strcpy(editor, "notepad"); + } +#endif + } + + if (!find_program(editor)) { + fprintf(stderr, "Unable to find editor: %s\n", editor); + exit(1); } // When using vi, set editor cursor to the end of the file if(strstr(editor, "vim") || strstr(editor, "vi")) { - strcat(editor, " +99999"); + strcat(editor, " + -c \"set nobackup\" "); } sprintf(editor_cmd, "%s %s", editor, filename); @@ -70,16 +195,16 @@ int make_path(char *basepath) { char *make_output_path(char *basepath, char *path, int year, int week, int day_of_week) { strcpy(path, basepath); // Add trailing slash if it's not there - if (strlen(basepath) > 0 && strlen(basepath) - 1 != '/') { - strcat(path, "/"); + if (strlen(basepath) > 0 && strlen(basepath) - 1 != DIRSEP_C) { + strcat(path, DIRSEP_S); } make_path(path); // year - sprintf(path + strlen(path), "%d/", year); + sprintf(path + strlen(path), "%d%c", year, DIRSEP_C); make_path(path); // week of year - sprintf(path + strlen(path), "%d/", week); + sprintf(path + strlen(path), "%d%c", week, DIRSEP_C); make_path(path); // day of that week sprintf(path + strlen(path), "%d", day_of_week); @@ -102,8 +227,8 @@ ssize_t get_file_size(const char *filename) { char *init_tempfile(const char *basepath, char *data) { FILE *fp; - static char tempfile[1024]; - sprintf(tempfile, "%s/weekly.XXXXXX", basepath); + static char tempfile[PATH_MAX]; + sprintf(tempfile, "%s%cweekly.XXXXXX", basepath, DIRSEP_C); if ((mkstemp(tempfile)) < 0) { return NULL; } @@ -126,7 +251,8 @@ int append_stdin(const char *filename) { size_t bufsz; char *buf; - buf = malloc(BUFSIZ); + bufsz = BUFSIZ; + buf = malloc(bufsz); if (!buf) { return -1; } @@ -137,9 +263,15 @@ int append_stdin(const char *filename) { return -1; } +#if HAVE_WINDOWS + while (fgets(buf, (int) bufsz, stdin) != NULL) { + fprintf(fp, "%s", buf); + } +#else while (getline(&buf, &bufsz, stdin) >= 0) { fprintf(fp, "%s", buf); } +#endif free(buf); fclose(fp); return 0; @@ -186,6 +318,26 @@ int dump_file(const char *filename) { return 0; } +#if HAVE_MSVC +int dir_empty (const char *path) { + HANDLE hd; + WIN32_FIND_DATA data; + size_t i; + char winpath[PATH_MAX] = {0}; + + i = 0; + sprintf(winpath, "%s%c*.*", path, DIRSEP_C); + if ((hd = FindFirstFile(path, &data)) != INVALID_HANDLE_VALUE) { + do { + i++; + } while (FindNextFile(hd, &data) != 0); + FindClose(hd); + } else { + return -1; + } + return i != 0; +} +#else int dir_empty(const char *path) { DIR *dir; struct dirent *dp; @@ -206,22 +358,23 @@ int dir_empty(const char *path) { closedir(dir); return i != 0; } +#endif int dump_week(const char *root, int year, int week) { - char path_week[1024] = {0}; - char path_year[1024] = {0}; + char path_week[PATH_MAX] = {0}; + char path_year[PATH_MAX] = {0}; const int max_days = 7; - sprintf(path_year, "%s/%d", root, year); - sprintf(path_week, "%s/%d/%d", root, year, week); + sprintf(path_year, "%s%c%d", root, DIRSEP_C, year); + sprintf(path_week, "%s%c%d%c%d", root, DIRSEP_C, year, DIRSEP_C, week); - if (dir_empty(path_year)) { + if (!dir_empty(path_year)) { return -1; } for (int i = 0; i < max_days; i++) { - char tmp[1024]; - sprintf(tmp, "%s/%d", path_week, i); + char tmp[PATH_MAX]; + sprintf(tmp, "%s%c%d", path_week, DIRSEP_C, i); dump_file(tmp); } return 0; @@ -229,20 +382,30 @@ int dump_week(const char *root, int year, int week) { int main(int argc, char *argv[]) { // System info - struct passwd *user; char sysname[255] = {0}; char username[255] = {0}; +#if HAVE_WINDOWS + DWORD usernamesz; + usernamesz = sizeof(username); + DWORD sysnamesz; + sysnamesz = sizeof(sysname); + homedir = getenv("USERPROFILE"); +#else + struct passwd *user; + homedir = getenv("HOME"); +#endif - // Time and date + // Time and datestamp time_t t; struct tm *tm_; int year, week, day_of_week; - char date[255] = {0}; + char datestamp[255] = {0}; + char timestamp[255] = {0}; // Path and data buffers char *tempfile; - char journalfile[1024] = {0}; - char output[255]; + char journalfile[PATH_MAX] = {0}; + char header[255]; // Argument triggers int do_stdin; @@ -264,6 +427,18 @@ int main(int argc, char *argv[]) { week = (tm_->tm_yday + 7 - (tm_->tm_wday ? (tm_->tm_wday - 1) : 6)) / 7; day_of_week = tm_->tm_wday; +#if HAVE_WINDOWS + // Get system name + if(!GetComputerName(sysname, &sysnamesz)) { + perror("Unable to get system host name"); + strcpy(sysname, "unknown"); + } + // Get user information + if(!GetUserName(username, &usernamesz)) { + perror("Unable to read account information"); + strcpy(username, "unknown"); + } +#else // Get system name if (gethostname(sysname, sizeof(sysname) - 1) < 0) { perror("Unable to get system host name"); @@ -278,13 +453,20 @@ int main(int argc, char *argv[]) { } else { strcpy(username, user->pw_name); } - - strftime(date, sizeof(date) - 1, "%c", tm_); +#endif + // Get data; + strftime(datestamp, sizeof(datestamp) - 1, "%m/%d/%Y", tm_); + strftime(timestamp, sizeof(timestamp) - 1, "%H:%M:%S", tm_); // Populate header string - sprintf(output, FMT_HEADER, date, user->pw_name, sysname); - sprintf(journalroot, "%s/.weekly", getenv("HOME")); - sprintf(intermediates, "%s/tmp", journalroot); +#if HAVE_WINDOWS + sprintf(header, FMT_HEADER, datestamp, timestamp, username, sysname); + sprintf(journalroot, "%s%c.weekly", homedir, DIRSEP_C); +#else + sprintf(header, FMT_HEADER, datestamp, timestamp, user->pw_name, sysname); + sprintf(journalroot, "%s%c.weekly", homedir, DIRSEP_C); +#endif + sprintf(intermediates, "%s%ctmp", journalroot, DIRSEP_C); // Prime argument triggers do_stdin = 0; @@ -359,15 +541,19 @@ int main(int argc, char *argv[]) { exit(0); } + // Create weekly root directory + make_path(journalroot); + // Write header string to temporary file make_path(intermediates); - if ((tempfile = init_tempfile(intermediates, output)) == NULL) { + if ((tempfile = init_tempfile(intermediates, header)) == NULL) { perror("Unable to create temporary file"); exit(1); } // Create new weekly journalfile path if (make_output_path(journalroot, journalfile, year, week, day_of_week) < 0) { + fprintf(stderr, "Unable to create output path: %s (%s)\n", journalfile, strerror(errno)); perror(journalfile); unlink(tempfile); exit(1); @@ -395,25 +581,22 @@ int main(int argc, char *argv[]) { ssize_t tempfile_newsize; tempfile_newsize = get_file_size(tempfile); if (tempfile_newsize <= tempfile_size) { - fprintf(stderr, "Intermediate file unchanged, or smaller:\nOriginal size: %zi\nNew size: %zi\n", - tempfile_size, tempfile_newsize); + fprintf(stderr, "Empty message, aborting.\n"); unlink(tempfile); exit(1); } // Copy data from the temporary file to the weekly journal path if (append_contents(journalfile, tempfile) < 0) { - perror(journalfile); + fprintf(stderr, "Unable to append contents of '%s' to '%s' (%s)\n", tempfile, journalfile, strerror(errno)); exit(1); } // Nuke the temporary file if (unlink(tempfile) < 0) { - perror(tempfile); + fprintf(stderr, "Unable to remove temporary file: %s (%s)\n", tempfile, strerror(errno)); exit(1); } - // Inform the user - printf("Wrote: %s\n", journalfile); return 0; } |