#include "shared.h" #include #include #include #include #include #include #include void* xcalloc(size_t nmemb, size_t size) { void *mem = calloc(nmemb, size); if(!mem) { #if defined ___VXGG___XALLOC_EXIT_ON_ERROR___ && ___VXGG___XALLOC_EXIT_ON_ERROR___ > 0 #if defined ___VXGG___VERBOSE_ERRORS___ && ___VXGG___VERBOSE_ERRORS___ > 0 error(1, errno, " Could not allocate memory"); #else exit(EXIT_FAILURE); #endif #endif abort(); } return mem; } void* xreallocarray(void *ptr, size_t nmemb, size_t size) { void *mem = reallocarray(ptr, nmemb, size); if(mem == NULL) { #if defined ___VXGG___XALLOC_EXIT_ON_ERROR___ && ___VXGG___XALLOC_EXIT_ON_ERROR___ > 0 #if defined ___VXGG___VERBOSE_ERRORS___ && ___VXGG___VERBOSE_ERRORS___ > 0 error(1, errno, " Could not allocate memory"); #else exit(EXIT_FAILURE); #endif #endif abort(); } return mem; } int readwholebuffer(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 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 defined ___VXGG___VERBOSE_ERRORS___ && ___VXGG___VERBOSE_ERRORS___ > 0 error(0, errno, "Could not reallocate enough space for lstr"); #endif free(lstr); lstr = NULL; // Need to set this because of the break bytesread = -100; break; } lstr = tmp; } } if(bytesread < 0 && bytesread != -100) { #if defined ___VXGG___VERBOSE_ERRORS___ && ___VXGG___VERBOSE_ERRORS___ > 0 error(0, errno, "Ran into a read() error"); #endif free(lstr); lstr = NULL; } if(lstr) { tmp = realloc(lstr, csize - ccap + 1); if(!tmp) { #if defined ___VXGG___VERBOSE_ERRORS___ && ___VXGG___VERBOSE_ERRORS___ > 0 error(0, errno, "Could not shrink lstr after reading buffer"); #endif free(lstr); bytesread = -100; } 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 writewholebuffer(int fd, const unsigned char *buf, int len) { int total = 0; int left = len; int n; 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) abort(); 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) abort(); 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) abort(); // 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) abort(); return tmp; } if(count == 1) { free(tmp); tmp = strdup("/"); if(!tmp) abort(); 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) abort(); free(tmp); return actual; }