#include "shared.h" #include #include #include #include #include enum XALLOC_TYPE { XALLOC_INVAL, // Default when unset XALLOC_MALLOC, XALLOC_CALLOC, XALLOC_REALLOC, XALLOC_2BIG // Out of range }; void * xalloc(size_t nmemb, size_t size, enum XALLOC_TYPE actype, void *ptr) { if(actype <= XALLOC_INVAL || actype >= XALLOC_2BIG) RETURNWERR(EINVAL, NULL); void *mem = NULL; switch(actype) { case XALLOC_MALLOC: mem = malloc(nmemb * size); break; case XALLOC_CALLOC: mem = calloc(nmemb, size); break; case XALLOC_REALLOC: mem = realloc(ptr, nmemb * size); break; default: XALLOC_EXIT(" An unknown alloc type was passed, which shouldn't be possible", ); } if(!mem) XALLOC_EXIT(" Could not allocate memory", ); return mem; } void * xmalloc(size_t size) { return xalloc(size, 1, XALLOC_MALLOC, NULL); } void * xcalloc(size_t nmemb, size_t size) { return xalloc(nmemb, size, XALLOC_CALLOC, NULL); } void * xreallocarray(void *ptr, size_t nmemb, size_t size) { return xalloc(nmemb, size, XALLOC_REALLOC, ptr); } 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 const int ECODE = -100; char *lstr = NULL, *tmp = NULL; ssize_t bytesread = -1; int csize = initsize, ccap = initsize; lstr = xcalloc(initsize, sizeof(char)); 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) { 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 * xdirname(const char * const path) { char *tmp = NULL; if(!path) { // Path being null is a special case which should return super early, before anything else tmp = strdup("."); if(!tmp) XALLOC_EXIT(" could not strdup \".\" for set path result \"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) XALLOC_EXIT(" could not strdup a set path result", ); 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) XALLOC_EXIT(" could not strdup the given path \"%s\" for internal manipulation", , path); // 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) { free(tmp); tmp = strdup("."); if(!tmp) XALLOC_EXIT(" could not strdup \".\" for set path result", ); return tmp; } if(count == 1) { free(tmp); tmp = strdup("/"); if(!tmp) XALLOC_EXIT(" could not strdup \"/\" for set path result", ); return tmp; } 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); if(!actual) XALLOC_EXIT(" could not strdup tmp string to make a shorter end string", ); free(tmp); return actual; } int cleanup_init(cleanup *loc, fcallback callbacks[], void *arguments[], int size) { if(!loc || !callbacks || !arguments || size <= 0) {errno = EINVAL; return -1;} loc->callbacks = callbacks; loc->arguments = arguments; loc->size = size; loc->used = 0; return 0; } // registers if flag is NOT set int cleanup_register(cleanup *loc, fcallback cb, void *arg) { if(!loc || !cb) {errno = EINVAL; return -1;} if(loc->used >= loc->size || loc->used < 0) {errno = ENOMEM; return -1;} loc->callbacks[loc->used] = cb; loc->arguments[loc->used] = arg; loc->used++; return 0; } 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) {errno = EINVAL; return -1;} loc->used = 0; return 0; } int cleanup_fire(cleanup *loc) { if(!loc) {errno = EINVAL; return -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; }