#include "shared.h" #include #include #include #include #include void* xcalloc(size_t nmemb, size_t size) { void *mem = calloc(nmemb, size); if(!mem) XALLOC_EXIT(" Could not allocate memory"); return mem; } void* xreallocarray(void *ptr, size_t nmemb, size_t size) { void *mem = reallocarray(ptr, nmemb, size); if(mem == NULL) XALLOC_EXIT(" Could not allocate memory"); 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(___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 = -100; break; } lstr = tmp; } } if(bytesread < 0 && bytesread != -100) { 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 = -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) 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; }