Created
January 26, 2026 20:46
-
-
Save nyteshade/433be496907ed34075d1ed61463fa5c0 to your computer and use it in GitHub Desktop.
Edit scriptsort scripts shell command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/stat.h> | |
| #include <unistd.h> | |
| /* SGR Color Constants */ | |
| #define SGR_BOLD "\033[1m" | |
| #define SGR_RED "\033[31m" | |
| #define SGR_GREEN "\033[32m" | |
| #define SGR_CYAN "\033[36m" | |
| #define SGR_RESET "\033[0m" | |
| /* Program Constants */ | |
| #define SUB_SHARED "shared" | |
| #define SUB_BASH "bash" | |
| #define SUB_ZSH "zsh" | |
| typedef enum { CMD_NONE, CMD_WRITE, CMD_APPEND, CMD_REMOVE } Command; | |
| /* Function Prototypes */ | |
| void print_usage(const char *progname); | |
| int file_exists(const char *path); | |
| char *build_path(const char *sub_dir, const char *filename); | |
| char *read_stdin_to_buffer(void); | |
| int scriptsort_main(int argc, char **argv); | |
| int main(int argc, char **argv) { | |
| return scriptsort_main(argc, argv); | |
| } | |
| void print_usage(const char *progname) { | |
| printf(SGR_BOLD "Usage:" SGR_RESET " %s [options] <command> [args]\n\n", progname); | |
| printf(SGR_BOLD "Options:\n" SGR_RESET); | |
| printf(" --shared Operate in 'shared' directory (default)\n"); | |
| printf(" --bash Operate in 'bash' directory\n"); | |
| printf(" --zsh Operate in 'zsh' directory\n\n"); | |
| printf(SGR_BOLD "Commands:\n" SGR_RESET); | |
| printf(" " SGR_CYAN "write" SGR_RESET " [-f|--force] [-q|--quiet] <file> [text]\n"); | |
| printf(" " SGR_CYAN "append" SGR_RESET " [-q|--quiet] <file> [text]\n"); | |
| printf(" " SGR_CYAN "remove" SGR_RESET " <file>\n\n"); | |
| printf(SGR_BOLD "Note:" SGR_RESET " If [text] is omitted, program reads from STDIN (Heredocs).\n"); | |
| } | |
| int file_exists(const char *path) { | |
| struct stat st; | |
| return (stat(path, &st) == 0); | |
| } | |
| char *read_stdin_to_buffer(void) { | |
| size_t capacity = 1024; | |
| size_t size = 0; | |
| char *buffer = (char *)malloc(capacity); | |
| int ch; | |
| if (!buffer) return NULL; | |
| while ((ch = getchar()) != EOF) { | |
| if (size + 1 >= capacity) { | |
| capacity *= 2; | |
| buffer = (char *)realloc(buffer, capacity); | |
| if (!buffer) return NULL; | |
| } | |
| buffer[size++] = (char)ch; | |
| } | |
| buffer[size] = '\0'; | |
| return buffer; | |
| } | |
| char *build_path(const char *sub_dir, const char *filename) { | |
| const char *base = getenv("SCRIPTSORT_DIR"); | |
| char *home = getenv("HOME"); | |
| char *full_path; | |
| size_t len; | |
| if (!base) { | |
| if (!home) { | |
| fprintf(stderr, SGR_RED "Error:" SGR_RESET " SCRIPTSORT_DIR and HOME are unset.\n"); | |
| return NULL; | |
| } | |
| len = strlen(home) + strlen("/.local/scripts/") + strlen(sub_dir) + strlen("/") + strlen(filename) + 1; | |
| full_path = (char *)calloc(len, sizeof(char)); | |
| if (full_path) sprintf(full_path, "%s/.local/scripts/%s/%s", home, sub_dir, filename); | |
| } else { | |
| len = strlen(base) + strlen("/") + strlen(sub_dir) + strlen("/") + strlen(filename) + 1; | |
| full_path = (char *)calloc(len, sizeof(char)); | |
| if (full_path) sprintf(full_path, "%s/%s/%s", base, sub_dir, filename); | |
| } | |
| return full_path; | |
| } | |
| int scriptsort_main(int argc, char **argv) { | |
| const char *sub_dir = SUB_SHARED; | |
| const char *filename = NULL; | |
| char *input_content = NULL; | |
| char *full_path = NULL; | |
| Command cmd = CMD_NONE; | |
| int force = 0, quiet = 0, i = 1, alloc_content = 0; | |
| FILE *fp; | |
| if (argc < 2) { print_usage(argv[0]); return 1; } | |
| /* 1. Global Flags */ | |
| for (; i < argc; i++) { | |
| if (strcmp(argv[i], "--bash") == 0) sub_dir = SUB_BASH; | |
| else if (strcmp(argv[i], "--zsh") == 0) sub_dir = SUB_ZSH; | |
| else if (strcmp(argv[i], "--shared") == 0) sub_dir = SUB_SHARED; | |
| else break; | |
| } | |
| /* 2. Subcommand */ | |
| if (i >= argc) { print_usage(argv[0]); return 1; } | |
| if (strcmp(argv[i], "write") == 0) cmd = CMD_WRITE; | |
| else if (strcmp(argv[i], "append") == 0) cmd = CMD_APPEND; | |
| else if (strcmp(argv[i], "remove") == 0) cmd = CMD_REMOVE; | |
| else { fprintf(stderr, SGR_RED "Unknown command: %s\n" SGR_RESET, argv[i]); return 1; } | |
| i++; | |
| /* 3. Subcommand Flags & Args */ | |
| for (; i < argc; i++) { | |
| if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--force") == 0) force = 1; | |
| else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0) quiet = 1; | |
| else if (!filename) filename = argv[i]; | |
| else if (!input_content) input_content = argv[i]; | |
| } | |
| if (!filename) { fprintf(stderr, SGR_RED "Error:" SGR_RESET " Filename required.\n"); return 1; } | |
| full_path = build_path(sub_dir, filename); | |
| if (!full_path) return 1; | |
| /* 4. Handle STDIN if content argument is missing */ | |
| if (cmd != CMD_REMOVE && !input_content) { | |
| input_content = read_stdin_to_buffer(); | |
| alloc_content = 1; | |
| if (!input_content) { free(full_path); return 1; } | |
| } | |
| /* 5. Execution */ | |
| if (cmd == CMD_WRITE) { | |
| if (file_exists(full_path) && !force) { | |
| fprintf(stderr, SGR_RED "Error:" SGR_RESET " File exists. Use -f to overwrite.\n"); | |
| if (alloc_content) free(input_content); | |
| free(full_path); | |
| return 1; | |
| } | |
| fp = fopen(full_path, "w"); | |
| if (!fp) { perror("fopen"); } | |
| else { | |
| fputs(input_content, fp); | |
| fclose(fp); | |
| if (!quiet) printf("%s\n", filename); | |
| } | |
| } | |
| else if (cmd == CMD_APPEND) { | |
| fp = fopen(full_path, "a"); | |
| if (!fp) { perror("fopen"); } | |
| else { | |
| fprintf(fp, "\n%s", input_content); | |
| fclose(fp); | |
| if (!quiet) printf("%s\n", filename); | |
| } | |
| } | |
| else if (cmd == CMD_REMOVE) { | |
| if (unlink(full_path) != 0) { | |
| free(full_path); | |
| return 1; | |
| } | |
| } | |
| if (alloc_content) free(input_content); | |
| free(full_path); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment