/** * @file shared.c * @author syxhe (https://t.me/syxhe) * @brief *Implementing `shared.h`* * @version 0.1 * @date 2025-06-09 * * @copyright Copyright (c) 2025 * */ #include "shared.h" #include #include #include #include #include int rwbuf(char **str, unsigned long int initsize, int fd) { // Try to read bytes from fd into str // Bytes read == 0, return 0 // Bytes read < 0, free string, return -1; // When string hits capacity, double the capacity, and reallocate the string if(!str || initsize < 1) ERRRET(EINVAL, -1); const int ECODE = -100; char *lstr = NULL, *tmp = NULL; ssize_t bytesread = -1; int csize = initsize, ccap = initsize; lstr = calloc(initsize, sizeof(char)); if(!lstr) return -1; while((bytesread = read(fd, lstr + (csize - ccap), ccap)) > 0) { ccap -= bytesread; if(ccap <= 0) { csize *= 2; ccap = csize / 2; tmp = realloc(lstr, csize * sizeof(char)); if(!tmp) { if(___VXGG___VERBOSE_ERRORS___) error(0, errno, "Could not reallocate enough space for lstr"); free(lstr); lstr = NULL; // Need to set this because of the break bytesread = ECODE; break; } lstr = tmp; } } if(bytesread < 0 && bytesread != ECODE) { if(___VXGG___VERBOSE_ERRORS___) error(0, errno, "Ran into a read() error"); free(lstr); lstr = NULL; } if(lstr) { tmp = realloc(lstr, csize - ccap + 1); if(!tmp) { if(___VXGG___VERBOSE_ERRORS___) error(0, errno, "Could not shrink lstr after reading buffer"); free(lstr); bytesread = ECODE; } lstr = tmp; } if(lstr && fd == STDIN_FILENO) { lstr[csize - ccap - 1] = '\0'; // Don't include the newline } *str = lstr; return ((bytesread == 0) ? (csize - ccap) : -1); } int wwbuf(int fd, const unsigned char *buf, int len) { if(!buf || len <= 0) ERRRET(EINVAL, -1); int total = 0; int left = len; int n = -1; while(total < len) { if((n = write(fd, buf + total, left)) < 0) break; total += n; left -= n; } return (n < 0) ? -1 : 0; } // Adapted from Beej's `sendall()` function // https://beej.us/guide/bgnet/html/split/slightly-advanced-techniques.html#sendall // Thanks Beej! // dirname but less retarded hopefully char * vxdirname(const char * const path) { char *tmp = NULL; if(!path) { // Path being null is a special case which should return early, before anything else (as to avoid null dereference) tmp = strdup("."); if(!tmp) { WARN(errno, " could not strdup \".\" for set path result \"NULL\"", ); return NULL; } return tmp; } unsigned char flag = 0; if(strcmp(path, ".") == 0) {tmp = strdup("."); flag++;} if(strcmp(path, "/") == 0 && !flag) {tmp = strdup("/"); flag++;} if(strcmp(path, "..") == 0 && !flag) {tmp = strdup("."); flag++;} if(flag) { if(!tmp) { WARN(errno, " could not strdup a set path result", ); return NULL; } return tmp; } /* From the manpages: (man 3 dirname) // +=======================================+ // | path dirname basename | // +=======================================+ // | /usr/lib /usr lib | // | /usr/ / usr | // | usr . usr | // +=======================================+ */ // Get a temp copy of the path for manipulation purposes tmp = strdup(path); if(!tmp) { WARN(errno, " could not strdup the given path \"%s\" for internal manipulation", , path); return NULL; } // If there's a trailing '/', delete it size_t pathlen = strlen(path); if(tmp[pathlen - 1] == '/') { tmp[pathlen - 1] = '\0'; pathlen--; } // Ok, I think the easiest way to do this (if maybe a bit slow) is to count the number of '/'s in the string // If there's only one, return '/' // If there are 2 or more, find the last one in the list and set it to '\0' size_t count = 0; for(size_t i = 0; i < pathlen; i++) { if(tmp[i] == '/') count++; } if(count == 0 || count == 1) free(tmp); if(count == 0) { tmp = strdup("."); if(!tmp) { WARN(errno, " could not strdup \".\" for set path result", ); return NULL; } return tmp; } else if(count == 1) { tmp = strdup("/"); if(!tmp) { WARN(errno, " could not strdup \"/\" for set path result", ); return NULL; } return tmp; } // This is retarded, fix it for(size_t i = 0, c2 = 0; i < pathlen; i++) { if(tmp[i] == '/') c2++; if(c2 == count) tmp[i] = '\0'; } char * const actual = strdup(tmp); free(tmp); if(!actual) { WARN(errno, " could not strdup tmp string to make a shorter end string", ); return NULL; } return actual; } int cleanup_init(cleanup *loc, fcallback callbacks[], void *arguments[], int size) { if(!loc || !callbacks || !arguments || size <= 0) ERRRET(EINVAL, -1); loc->callbacks = callbacks; loc->arguments = arguments; loc->size = size; loc->used = 0; return 0; } int cleanup_register(cleanup *loc, fcallback cb, void *arg) { if(!loc || !cb) ERRRET(EINVAL, -1); if(loc->used >= loc->size || loc->used < 0) ERRRET(ENOMEM, -1); loc->callbacks[loc->used] = cb; loc->arguments[loc->used] = arg; loc->used++; return 0; } // registers if flag is NOT set int cleanup_cndregister(cleanup *loc, fcallback cb, void *arg, unsigned char flag) { if(flag) return 0; return cleanup_register(loc, cb, arg); } int cleanup_clear(cleanup *loc) { if(!loc) ERRRET(EINVAL, -1); loc->used = 0; return 0; } int cleanup_fire(cleanup *loc) { if(!loc) ERRRET(EINVAL, -1); for(int i = (loc->used - 1); i >= 0; i--) { if(loc->callbacks[i] == NULL) { error(0, EINVAL, "cleanup_fire: refusing to run null callback..."); continue; } loc->callbacks[i](loc->arguments[i]); } cleanup_clear(loc); return 0; } // Fires if flag is set int cleanup_cndfire(cleanup *loc, unsigned char flag) { if(flag) return cleanup_fire(loc); return 0; }