shithub: scc

ref: 2b05b5d52482e818baf747bc8b0619fd0d26ca02
dir: /src/libc/stdio/_fpopen.c/

View raw version
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#include <sys.h>

#include "../syscall.h"
#include "../libc.h"

FILE *
_fpopen(const char *restrict fname,
        const char *restrict mode,
        FILE * restrict fp)
{
	int i, flags, fd, rw, bin;

	flags = rw = bin = 0;

	if (mode[0] == '\0')
		goto einval;

	for (i = 1; mode[i]; ++i) {
		switch (mode[i]) {
		case '+':
			if (rw)
				goto einval;
			rw = 1;
			break;
		case 'b':
			if (bin)
				goto einval;
			bin = 1;
			break;
		default:
			goto einval;
		}
	}

	switch (mode[0]) {
	case 'a':
		flags |= O_APPEND | O_CREAT;
		goto wrflags;
	case 'w':
		flags |= O_TRUNC | O_CREAT;
	wrflags:
		flags |= (rw) ? O_RDWR : O_WRONLY;
		break;
	case 'r':
		flags = (rw) ? O_RDWR : O_RDONLY;
		break;
	default:
	einval:
		errno = EINVAL;
		return NULL;
	}

	if ((fd = _open(fname, flags, 0666)) < 0)
		return NULL;

	fp->buf = NULL;
	fp->fd = fd;

	if (!bin)
		fp->flags |= _IOTXT;

	switch (flags & O_ACCMODE) {
	case O_RDWR:
		fp->flags |= _IORW;
		break;
	case O_RDONLY:
		fp->flags |= _IOREAD;
		break;
	case O_WRONLY:
		fp->flags |= _IOWRITE;
		break;
	}

	fp->lp = fp->rp = fp->wp = NULL;

	return fp;
}