lexlib 2.0.1

library with miscellaneous stuff
Documentation
// Copyright 2023 alexevier <alexevier@proton.me>
// licensed under the zlib license <https://www.zlib.net/zlib_license.html>

#ifdef __unix__
#	define _POSIX_SOURCE
#	include<unistd.h>
#	include<fcntl.h>
#	include<sys/stat.h>
#endif

#include<lexlib/str.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>

#ifdef _WIN32
#	define SEP '\\'
#else
#	define SEP '/'
#endif

#if __GNUC__
	__attribute__((alias("lexlibStrCopy"))) char *lexlibStrNew(const char *str);
#else
	char *lexlibStrNew(const char *str){return lexlibStrCopy(str);}
#endif

char *lexlibStrCat(const char *str1, const char *str2){
	/* meow
	      /\_/\
	     ( o.o )
	      > ^ <
	*/
	char *str = NULL;
	if(!str1 || !str2)
		return NULL;

	size_t len = strlen(str1) + strlen(str2) + 1;
	str = calloc(len, sizeof(char));
	if(!str)
		return NULL;

	strcat(str, str1);
	strcat(str, str2);
	str[len-1] = '\0';

	return str;
}

char *lexlibStrCopy(const char *str){
	char *new = NULL;
	size_t len = strlen(str) + 1; // will include the null char

	new = malloc(len * sizeof(char));
	if(!new)
		return NULL;

	memcpy(new, str, len);

	return new;
}

char *lexlibStrFile(const char *filename){
	char *buffer = NULL;
	unsigned long length = 0;

	FILE *file = fopen(filename, "r");
	if(!file){
		return NULL;
	}

#ifdef __unix__
	struct stat info;
	if(fstat(fileno(file), &info) != 0){
		fclose(file);
		return NULL;
	}
	length = info.st_size;
#else
	if(fseek(file, 0, SEEK_END) != 0){
		fclose(file);
		return NULL;
	};
	length = ftell(file);
	if(fseek(file, 0, SEEK_SET) != 0){
		fclose(file);
		return NULL;
	};
#endif

	buffer = malloc(length+1);
	if(!buffer){
		fclose(file);
		return NULL;
	}
	buffer[length] = '\0';

	if(fread(buffer, sizeof(char), length, file) != length){
		free(buffer);
		fclose(file);
		return NULL;
	}

	fclose(file);
	return buffer;
}

char *lexlibStrPathNew(const char *str){
	size_t len = strlen(str);
	char *path = calloc(len+1, sizeof(char));

	if(!path)
		return NULL;

	for(size_t i = 0; i < len; i++){
		char chr = str[i];
		if(chr == '/' || chr == '\\')
			chr = SEP;
		path[i] = chr;
	}

	return path;
}

uint8_t lexlibStrPathPush(char **str, const char *add){
	size_t strLen = strlen(*str);
	size_t addLen = strlen(add);
	size_t len = strLen + addLen;

	if(strLen == 0 || addLen == 0)
		return LEXLIB_INVALID_VALUE;

	char *path = realloc(*str, (len+2) * sizeof(char));
	char *offPath = path+strLen;

	if(!path)
		return LEXLIB_OUT_OF_MEMORY;

	if(path[strLen-1] != '/' && path[strLen-1] != '\\'){
		offPath++;
		path[strLen] = SEP;
	}

	for(size_t i = 0; i < addLen; i++){
		char chr = add[i];
		if(chr == '/' || chr == '\\'){
			if(i == 0){
				offPath--;
			}
			chr = SEP;
		}
		offPath[i] = chr;
	}

	offPath[addLen] = '\0';

	// switch the string and return.
	*str = path;
	return LEXLIB_OK;
}

uint8_t lexlibStrPathPop(char **str){
	size_t len = 0;
	char *fst;
	char *lst;

	// get dividers pos
	fst = strchr(*str, '/');
	if(!fst)
		fst = strchr(*str, '\\');
	lst = strrchr(*str, '/');
	if(!lst)
		lst = strrchr(*str, '\\');
	if(!fst || !lst)
		return LEXLIB_INVALID_OPERATION;
	if(fst == lst)
		return LEXLIB_INVALID_OPERATION;

	len = strlen(lst);
	memset(lst, 0, len);

	return LEXLIB_OK;
}

uint8_t lexlibStrPathAsDir(char **str){
	size_t len = strlen(*str);

	if(len == 0)
		return LEXLIB_INVALID_VALUE;

	if((*str)[len-1] == '/' || (*str)[len-1] == '\\')
		return LEXLIB_OK;

	char *new = realloc(*str, (len+2) * sizeof(char));
	if(!new)
		return LEXLIB_OUT_OF_MEMORY;
	new[len+1] = '\0';

	new[len] = SEP;

	*str = new;
	return LEXLIB_OK;
}

uint8_t lexlibStrPathAsFile(char **str){
	size_t len = strlen(*str);

	if(len == 0)
		return LEXLIB_INVALID_VALUE;

	len--;

	if((*str)[len] == '/' || (*str)[len] == '\\')
		(*str)[len] = '\0';
	else
		return LEXLIB_OK;

	return LEXLIB_OK;
}

/* https://ascii.co.uk/art/cats */