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>

#if defined(__unix__)
#	define _POSIX_SOURCE
#	include<unistd.h>
#	include<fcntl.h>
#	include<sys/stat.h>
#	include<sys/mman.h>
#elif defined(_WIN32)
#	include<windows.h>
#	include<io.h>
#endif

#include<lexlib/defines.h>
#include<internal/misc.h>
#include<lexlib/cfile.h>
#include<stdio.h>

void *lexlibCFileMap(FILE *file){
#if defined(__unix__)
	int fd = fileno(file);
	if(fd == -1)
		return NULL;

	uint64_t filesize = lexlibCFileSize(file);

	int prot;
	int flag;

	int mode = fcntl(fd, F_GETFL) & O_ACCMODE;
	switch(mode){
		case O_RDONLY:
			prot = PROT_READ;
			flag = MAP_PRIVATE;
			break;
		case O_WRONLY:
			prot = PROT_WRITE;
			flag = MAP_SHARED;
			break;
		case O_RDWR:
			prot = PROT_READ | PROT_WRITE;
			flag = MAP_SHARED;
			break;
		default:
			return NULL;
	}

	void* mem = mmap(NULL, filesize, prot, flag, fd, 0);
	if(mem == MAP_FAILED)
		return NULL;

	return mem;
#elif defined(_WIN32)
	HANDLE handle = (HANDLE)_get_osfhandle(_fileno(file));
	if(handle == INVALID_HANDLE_VALUE)
		return NULL;

	DWORD flagPage;
	DWORD flagMap;

	switch(lexlibCFileMode(file) & LEXLIB_RDWR){
		case LEXLIB_RD:
			flagPage = PAGE_READONLY;
			flagMap = FILE_MAP_READ;
			break;
		case LEXLIB_WR:
			flagPage = PAGE_WRITECOPY;
			flagMap = FILE_MAP_WRITE;
			break;
		case LEXLIB_RDWR:
			flagPage = PAGE_READWRITE;
			flagMap = FILE_MAP_ALL_ACCESS;
			break;
		default:
			return NULL;
	}

	HANDLE map = CreateFileMapping(handle, NULL, flagPage, 0, 0, NULL);

	void* mem = MapViewOfFile(map, flagMap, 0, 0, 0);
	CloseHandle(map);

	return mem;
#endif
}

uint8_t lexlibCFileMode(FILE *file){
#if defined(__unix__)
	int fmode = fcntl(fileno(file), F_GETFL);
	uint8_t mode = LEXLIB_NONE;
	switch(fmode & O_ACCMODE){
		case O_RDONLY:
			mode |= LEXLIB_RD;
			break;
		case O_WRONLY:
			mode |= LEXLIB_WR;
			break;
		case O_RDWR:
			mode |= LEXLIB_RDWR;
			break;
	}

	if(!mode)
		return LEXLIB_NONE;

	if(fmode & O_CREAT)
		mode |= LEXLIB_CREATE;

	if(fmode & O_APPEND)
		mode |= LEXLIB_APPEND;

	return mode;
#elif defined(_WIN32)
	// this might not work with all libc
	if(file->_flag & 0x01)
		return LEXLIB_RD;
	if(file->_flag & 0x02)
		return LEXLIB_WR;
	if(file->_flag & 0x80)
		return LEXLIB_RDWR;
	return LEXLIB_NONE;
#endif
}

int64_t lexlibCFileSize(FILE *file){
#if defined(__unix__)
	struct stat info;
	int state = fstat(fileno(file), &info);
	if(state != 0)
		return -1;

	return (int64_t)info.st_size;
#elif defined(__WIN32)
	HANDLE handle = (HANDLE)_get_osfhandle(_fileno(file));
	if(handle == INVALID_HANDLE_VALUE)
		return -1;

	LARGE_INTEGER size;
	DWORD state = GetFileSizeEx(handle, &size);
	if(state == 0)
		return -1;

	return (int64_t)size.QuadPart;
#endif
}

uint16_t lexlibCFileType(FILE *file){
	#define RETURN(X) { fsetpos(file, &fileOffset); return X; }

	fpos_t fileOffset;
	if(fgetpos(file, &fileOffset) != 0)
		RETURN(LEXLIB_FILETYPE_UNKNOWN);
	rewind(file);

	uint8_t mem[16];
	uint16_t type = LEXLIB_FILETYPE_UNKNOWN;
	if(fread(mem, 2, 1, file) != 1)
		RETURN(LEXLIB_FILETYPE_UNKNOWN);
	type = lexlibInternalFileTypeSig(mem, 2);
	if(type){RETURN(type);}

	if(fread(mem+2, 6, 1, file) != 1)
		RETURN(LEXLIB_FILETYPE_UNKNOWN);
	type = lexlibInternalFileTypeSig(mem, 8);
	if(type){RETURN(type);}

	RETURN(LEXLIB_FILETYPE_UNKNOWN);
	#undef RETURN
}