Newer
Older
vvd / src / os.c
@dd86k dd86k on 16 Aug 2020 5 KB Interface changes
#include <stdio.h>
#include "os.h"
#ifndef _WIN32
#include <string.h>	// memset
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#endif

//
// os_fopen
//

__OSFILE os_fopen(const oschar *path) {
#ifdef _WIN32
	__OSFILE fd = CreateFileW(
		path,	// lpFileName
		GENERIC_READ | GENERIC_WRITE,	// dwDesiredAccess
		0,	// dwShareMode
		NULL,	// lpSecurityAttributes
		OPEN_EXISTING,	// dwCreationDisposition
		0,	// dwFlagsAndAttributes
		NULL	// hTemplateFile
	);
	if (fd == INVALID_HANDLE_VALUE)
		return 0;
#else
	__OSFILE fd = open(path, O_RDWR);
	if (fd == -1)
		return 0;
#endif
	return fd;
}

//
// os_fcreate
//

__OSFILE os_fcreate(const oschar *path) {
#ifdef _WIN32
	__OSFILE fd = CreateFileW(
		path,	// lpFileName
		GENERIC_READ | GENERIC_WRITE,	// dwDesiredAccess
		0,	// dwShareMode
		NULL,	// lpSecurityAttributes
		CREATE_ALWAYS,	// dwCreationDisposition
		0,	// dwFlagsAndAttributes
		NULL	// hTemplateFile
	);
	if (fd == INVALID_HANDLE_VALUE)
		return 0;
#else
	__OSFILE fd = open(path, O_RDWR | O_CREAT | O_TRUNC);
	if (fd == -1)
		return 0;
#endif
	return fd;
}

//
// os_fseek
//

int os_fseek(__OSFILE fd, int64_t pos, int flags) {
#ifdef _WIN32
	LARGE_INTEGER a;
	a.QuadPart = pos;
	if (SetFilePointerEx(fd, a, NULL, flags) == 0)
		return -1;
#else
	if (lseek(fd, (off_t)pos, flags) == -1)
		return -1;
#endif
	return 0;
}

//
// os_fread
//

int os_fread(__OSFILE fd, void *buffer, size_t size) {
#ifdef _WIN32
	DWORD r;
	if (ReadFile(fd, buffer, size, &r, NULL) == 0)
		return -1;
	/*if (r != size) {
		fprintf(stderr, "os_fread: Failed to read %u/%u bytes",
			(uint32_t)r, (uint32_t)size);
		return -2;
	}*/
#else
	ssize_t r;
	if ((r = read(fd, buffer, size)) == -1)
		return -1;
	/*if (r != size) {
		fprintf(stderr, "os_fread: Failed to read %d/%u bytes",
			(int32_t)r, (uint32_t)size);
		return -2;
	}*/
#endif
	return 0;
}

//
// os_fwrite
//

int os_fwrite(__OSFILE fd, void *buffer, size_t size) {
#ifdef _WIN32
	DWORD r;
	if (WriteFile(fd, buffer, size, &r, NULL) == 0)
		return -1;
	/*if (r != size)
		return -2;*/
#else
	ssize_t r;
	if ((r = write(fd, buffer, size)) == -1)
		return -1;
	/*if (r != size)
		return -2;*/
#endif
	return 0;
}

//
// os_fsize
//

int os_fsize(__OSFILE fd, uint64_t *size) {
#if _WIN32
	LARGE_INTEGER li;
	// NOTE: Doc says 0 (FALSE) on failure which apparently doesn't.
	// NOTE: Not supported in Windows Store Apps (use GetFileInformationByHandleEx)
	if (GetFileSizeEx(fd, &li))
		return -1;
	*size = li.QuadPart;
	return 0;
#else
	// fstat(2) sets st_size to 0 on block devices
	struct stat s;
	if (fstat(fd, &s) == -1)
		return 1;
	switch (s.st_mode & __S_IFMT) {
	case __S_IFREG:
	case __S_IFLNK:
		*size = s.st_size;
		return 0;
	case __S_IFBLK:
		//TODO: Non-linux variant
		ioctl(fd, BLKGETSIZE64, size);
		return 0;
	default: return -1;
	}
#endif
}

//
// os_falloc
//

int os_falloc(__OSFILE fd, uint64_t fsize) {
	const int bsize = 1024 * 1024; // 1 MiB
	uint8_t *buf = calloc(1, bsize); // zeroed
	if (fsize >= bsize) {
		if (buf == NULL)
			return 1;
		while (fsize > bsize) {
			if (os_fwrite(fd, buf, bsize))
				return -1;
			fsize -= bsize;
		}
	}
	if (fsize > 0) {
		if (os_fwrite(fd, buf, bsize - fsize))
			return -1;
	}
	free(buf);
	return 0;
}

//
// os_pinit
//

int os_pinit(struct progress_t *p, uint32_t flags, uint32_t max) {
#if _WIN32
	p->fd = GetStdHandle(STD_OUTPUT_HANDLE);

	CONSOLE_SCREEN_BUFFER_INFO csbi;
	GetConsoleScreenBufferInfo(p->fd, &csbi);
	p->leny = (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
	p->lenx = (csbi.srWindow.Right - csbi.srWindow.Left + 1);
	p->inity = csbi.dwCursorPosition.Y;
	p->initx = csbi.dwCursorPosition.X;
#else
	struct winsize ws;
	ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
	p->leny = ws.ws_row;
	p->lenx = ws.ws_col;
#endif
	p->bfill = malloc(1024);
	p->bspace = malloc(1024);
	memset(p->bfill, '=', 1024);
	memset(p->bspace, ' ', 1024);
	p->maximum = max;
	p->flags = flags;

	return 0;
}

//
// os_pupdate
//

int os_pupdate(struct progress_t *p, uint32_t val) {
#if _WIN32
	COORD c;
	c.X = 0;
	c.Y = p->inity;
	SetConsoleCursorPosition(p->fd, c);
#else
	//printf("\033[%d;%dH", p->inity, 0);
	fputs("\r", stdout); // "CSI2n" clears line
#endif
	float cc = (float)val / p->maximum; // current
	int pc; // characters printed
	uint32_t ph;	// placeholder
	switch (p->flags & 0xF) {
	case PROG_MODE_CUR_MAX:
		pc = printf("%u/%u [", val, p->maximum);
		break;
	case PROG_MODE_CUR_ONLY:
		pc = printf("%u [", val);
		break;
	case PROG_MODE_POURCENT:
		ph = (uint32_t)(cc * 100.0f);
		/*if (ph == ((float)p->current / p->maximum) * 100.0f) { // same %
			p->current = val;
			return 0; // NOP
		}*/
		pc = printf("%u%% [", ph);
		break;
	default:
		pc = printf("[");
		break;
	}
	if (pc < 0)
		return -11;

	uint32_t total = p->lenx - pc - 2;
	uint32_t occup = cc * total;	// filled
	uint32_t space = total - occup;	// what's left
	printf("%.*s%.*s]", occup, p->bfill, space, p->bspace);

	p->current = val;
	return 0;
}

//
// os_pfinish
//

int os_pfinish(struct progress_t *p) {
	if (p->flags & PROG_FLAG_REMOVE) {
#if _WIN32
		COORD c;
		c.X = 0;
		c.Y = p->inity;
		SetConsoleCursorPosition(p->fd, c);
#else
		fputs("\r", stdout);
#endif
		printf("%.*s", p->lenx, p->bspace);
	}
	free(p->bfill);
	free(p->bspace);
	putchar('\n');
	return 0;
}