shithub: psxe

ref: 0ba99d05a4e514da5a78ef2bf7a339548c4c7bb5
dir: /psx/p9.h/

View raw version
#ifndef PSX_P9_H
#define PSX_P9_H

#include <u.h>
#include <libc.h>

/* C99 integer aliases mapped to native 9front integer types. */
typedef u8int uint8_t;
typedef u16int uint16_t;
typedef u32int uint32_t;
typedef u64int uint64_t;
typedef s8int int8_t;
typedef s16int int16_t;
typedef s32int int32_t;
typedef s64int int64_t;
typedef intptr intptr_t;
typedef uintptr uintptr_t;

/* stddef-like aliases used across the core. */
#ifndef _SIZE_T
typedef uintptr size_t;
#define _SIZE_T
#endif
#ifndef _SSIZE_T
typedef intptr ssize_t;
#define _SSIZE_T
#endif

/* stdbool compatibility for native toolchains without <stdbool.h>. */
#ifndef __bool_true_false_are_defined
typedef int bool;
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#endif

/* Plan 9 uses `nil`; keep NULL-compatible call sites building. */
#ifndef NULL
#define NULL 0
#endif

/* Minimal libc naming shims for native Plan 9 builds. */
#ifndef printf
#define printf print
#endif
#ifndef putchar
static inline int
p9_putchar(int c)
{
	return print("%c", c);
}
#define putchar(c) p9_putchar((c))
#endif
#ifndef exit
static inline void
p9_exit(int status)
{
	exits(status ? "error" : nil);
}
#define exit(status) p9_exit((status))
#endif

/* Minimal stdio compatibility for code still using FILE*. */
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef EOF
#define EOF (-1)
#endif

#ifndef _P9_FILE_COMPAT
#define _P9_FILE_COMPAT
typedef struct p9_file {
	int fd;
} FILE;

static inline FILE*
fopen(const char *path, const char *mode)
{
	int fd;
	int omode;
	FILE *fp;

	if (!path || !mode)
		return nil;

	omode = -1;

	switch (mode[0]) {
	case 'r':
		omode = OREAD;
		break;
	case 'w':
		omode = OWRITE | OTRUNC;
		break;
	case 'a':
		omode = OWRITE;
		break;
	}

	if (omode < 0)
		return nil;

	if (mode[0] == 'r') {
		fd = open(path, omode);
	} else {
		fd = create(path, omode, 0666);
		if (fd < 0)
			fd = open(path, omode);
	}

	if (fd < 0)
		return nil;

	fp = malloc(sizeof(*fp));
	if (!fp) {
		close(fd);
		return nil;
	}

	fp->fd = fd;

	if (mode[0] == 'a')
		(void)seek(fp->fd, 0, SEEK_END);

	return fp;
}

static inline int
fclose(FILE *fp)
{
	int r;

	if (!fp)
		return -1;

	r = close(fp->fd);
	free(fp);
	return r;
}

static inline int
fseek(FILE *fp, long offset, int whence)
{
	if (!fp)
		return -1;

	return seek(fp->fd, offset, whence) < 0 ? -1 : 0;
}

static inline long
ftell(FILE *fp)
{
	vlong pos;

	if (!fp)
		return -1;

	pos = seek(fp->fd, 0, SEEK_CUR);
	if (pos < 0)
		return -1;

	return (long)pos;
}

static inline size_t
fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
{
	size_t total;
	size_t done;
	uchar *p;

	if (!fp || !ptr || size == 0 || nmemb == 0)
		return 0;

	total = size * nmemb;
	done = 0;
	p = (uchar*)ptr;

	while (done < total) {
		long r = read(fp->fd, p + done, total - done);

		if (r <= 0)
			break;

		done += r;
	}

	return done / size;
}

static inline size_t
fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
{
	size_t total;
	size_t done;
	const uchar *p;

	if (!fp || !ptr || size == 0 || nmemb == 0)
		return 0;

	total = size * nmemb;
	done = 0;
	p = (const uchar*)ptr;

	while (done < total) {
		long w = write(fp->fd, (void*)(p + done), total - done);

		if (w <= 0)
			break;

		done += w;
	}

	return done / size;
}

static inline int
fgetc(FILE *fp)
{
	uchar c;
	long r;

	if (!fp)
		return EOF;

	r = read(fp->fd, &c, 1);
	if (r != 1)
		return EOF;

	return (int)c;
}
#endif

#ifndef isdigit
static inline int
p9_isdigit(int c)
{
	return c >= '0' && c <= '9';
}
#define isdigit(c) p9_isdigit((c))
#endif

#ifndef isalpha
static inline int
p9_isalpha(int c)
{
	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
#define isalpha(c) p9_isalpha((c))
#endif

#ifndef isspace
static inline int
p9_isspace(int c)
{
	return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
}
#define isspace(c) p9_isspace((c))
#endif

/* GCC attributes are ignored by native 9front compilers. */
#ifndef __attribute__
#define __attribute__(x)
#endif

/* 6c may provide __FILE/__LINE (without trailing underscores). */
#ifndef __FILE__
#ifdef __FILE
#define __FILE__ __FILE
#else
#define __FILE__ "unknown"
#endif
#endif
#ifndef __LINE__
#ifdef __LINE
#define __LINE__ __LINE
#else
#define __LINE__ 0
#endif
#endif

/* Some toolchains do not accept the C99 inline keyword. */
#ifndef __GNUC__
#ifndef inline
#define inline
#endif
#endif

/* Minimal assert replacement for native headers. */
#ifndef assert
#define assert(x) do { \
  if (!(x)) sysfatal("assert failed: %s:%d: %s", __FILE__, __LINE__, #x); \
} while (0)
#endif

/* Helpers for codepaths that expect C99 float math helpers. */
#ifndef floorf
#define floorf(x) ((float)floor((double)(x)))
#endif
#ifndef ceilf
#define ceilf(x) ((float)ceil((double)(x)))
#endif
#ifndef roundf
#define roundf(x) ((float)(((x) >= 0) ? floor((double)(x) + 0.5) : ceil((double)(x) - 0.5)))
#endif

/* GCC builtin compatibility shims used by the CPU core. */
#ifndef __GNUC__
static inline int
p9_builtin_ssub_overflow(int a, int b, int *r)
{
  vlong v = (vlong)a - (vlong)b;
  *r = (int)v;
  return (v > 2147483647LL) || (v < -2147483648LL);
}

static inline int
p9_builtin_clz(unsigned int x)
{
  int n = 0;

  if (x == 0)
    return 32;

  while ((x & 0x80000000U) == 0) {
    n++;
    x <<= 1;
  }

  return n;
}

#define __builtin_ssub_overflow(a, b, r) p9_builtin_ssub_overflow((a), (b), (r))
#define __builtin_clz(x) p9_builtin_clz((unsigned int)(x))
#endif

/* stdint limit macros used in the codebase. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT8_MAX
#define INT8_MAX 127
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32768)
#endif
#ifndef INT16_MAX
#define INT16_MAX 32767
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647 - 1)
#endif
#ifndef INT32_MAX
#define INT32_MAX 2147483647
#endif

#endif