Add popen(3)/pclose(3), add missing signatures to headers
This commit is contained in:
@@ -12,6 +12,8 @@ SHARED_LIBS=
|
||||
|
||||
# Build
|
||||
CFLAGS=-I include \
|
||||
-ggdb \
|
||||
-Og \
|
||||
-ffreestanding \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
|
||||
@@ -3,4 +3,23 @@
|
||||
#define HUGE_VAL (__builtin_huge_val())
|
||||
|
||||
double log10(double f);
|
||||
double log2(double f);
|
||||
double log(double f);
|
||||
double sqrt(double f);
|
||||
double floor(double f);
|
||||
double ceil(double f);
|
||||
double fmod(double x, double y);
|
||||
double atan2(double x, double y);
|
||||
double asin(double x);
|
||||
double acos(double x);
|
||||
double fabs(double x);
|
||||
double pow(double x, double y);
|
||||
double tanh(double f);
|
||||
double cosh(double f);
|
||||
double sinh(double f);
|
||||
double sin(double f);
|
||||
double cos(double f);
|
||||
double tan(double f);
|
||||
double frexp(double x, int *exp);
|
||||
double ldexp(double x, int exp);
|
||||
double exp(double f);
|
||||
|
||||
@@ -4,5 +4,7 @@ typedef struct {
|
||||
unsigned long _v[8];
|
||||
} jmp_buf[1];
|
||||
|
||||
int _setjmp(jmp_buf env);
|
||||
int setjmp(jmp_buf env);
|
||||
void _longjmp(jmp_buf env, int val);
|
||||
void longjmp(jmp_buf env, int val);
|
||||
|
||||
@@ -34,6 +34,12 @@ int renameat(int olddfd, const char *oldpath, int newdfd, const char *newpath
|
||||
char *ctermid(char *s);
|
||||
int setvbuf(FILE *fp, char *buf, int mode, size_t size);
|
||||
void setbuf(FILE *fp, char *buf);
|
||||
int ungetc(int ch, FILE *fp);
|
||||
|
||||
FILE *tmpfile(void);
|
||||
|
||||
FILE *popen(const char *command, const char *type);
|
||||
int pclose(FILE *fp);
|
||||
|
||||
void flockfile(FILE *fp);
|
||||
void funlockfile(FILE *fp);
|
||||
|
||||
+6
-3
@@ -11,12 +11,15 @@ __Malloc void *calloc(size_t size, size_t nmemb);
|
||||
__Malloc void *malloc(size_t size);
|
||||
void *realloc(void *p, size_t newsz);
|
||||
void free(void *ptr);
|
||||
_Noreturn void abort(void);
|
||||
int abs(int d);
|
||||
|
||||
int system(const char *command);
|
||||
|
||||
int atoi(const char *str);
|
||||
|
||||
char *getenv(const char *name);
|
||||
int setenv(const char *name, const char *value, int overwrite);
|
||||
|
||||
// XXX: POSIX doesn't define _Noreturn attribute on those?
|
||||
void _Exit(int status);
|
||||
void exit(int status);
|
||||
_Noreturn void _Exit(int status);
|
||||
_Noreturn void exit(int status);
|
||||
|
||||
@@ -23,4 +23,6 @@ time_t time(time_t *t);
|
||||
double difftime(time_t t1, time_t t0);
|
||||
|
||||
struct tm *gmtime_r(const time_t *restrict timep, struct tm *restrict res);
|
||||
struct tm *localtime_r(const time_t *restrict timep, struct tm *restrict res);
|
||||
time_t mktime(struct tm *tm);
|
||||
size_t strftime(char *restrict buf, size_t lim, const char *restrict fmt, const struct tm *restrict tm);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void *calloc(size_t size, size_t nmemb) {
|
||||
void *blk = malloc(size * nmemb);
|
||||
if (blk) {
|
||||
memset(blk, 0, size * nmemb);
|
||||
}
|
||||
return blk;
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int fflush(FILE *fp) {
|
||||
if (!fp) {
|
||||
// TODO: flush all open files
|
||||
return 0;
|
||||
}
|
||||
if (fp->buf_mode != _IONBF) {
|
||||
if (__libc_file_flush_read(fp) != 0) {
|
||||
return -1;
|
||||
|
||||
@@ -20,6 +20,7 @@ FILE *__libc_file_create(void) {
|
||||
|
||||
res->free = file_default_free;
|
||||
res->buf = ((void *) res) + sizeof(FILE);
|
||||
res->buf_mode = _IOLBF;
|
||||
res->ungetc = -1;
|
||||
|
||||
return res;
|
||||
|
||||
@@ -23,6 +23,7 @@ ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *fp) {
|
||||
}
|
||||
|
||||
p = *lineptr;
|
||||
rem = *n;
|
||||
|
||||
while (1) {
|
||||
if (!rem) {
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int pclose(FILE *fp) {
|
||||
(void) fp;
|
||||
return 0;
|
||||
return fclose(fp);
|
||||
}
|
||||
|
||||
+107
-3
@@ -1,9 +1,113 @@
|
||||
#include <_libc/stdio.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Internal pipe state
|
||||
struct pipe {
|
||||
int fd;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
static ssize_t pipe_read(void *ctx, void *buf, size_t lim) {
|
||||
return read(((struct pipe *) ctx)->fd, buf, lim);
|
||||
}
|
||||
|
||||
static ssize_t pipe_write(void *ctx, const void *buf, size_t lim) {
|
||||
return write(((struct pipe *) ctx)->fd, buf, lim);
|
||||
}
|
||||
|
||||
static off_t pipe_seek(void *ctx, off_t offset, int whence) {
|
||||
(void) ctx;
|
||||
(void) offset;
|
||||
(void) whence;
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pipe_close(void *_ctx) {
|
||||
struct pipe *ctx = _ctx;
|
||||
close(ctx->fd);
|
||||
int r;
|
||||
if (waitpid(ctx->pid, &r, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
free(ctx);
|
||||
return r;
|
||||
}
|
||||
|
||||
FILE *popen(const char *command, const char *mode) {
|
||||
(void) command;
|
||||
(void) mode;
|
||||
errno = EINVAL;
|
||||
int fds[2];
|
||||
struct pipe *ctx;
|
||||
FILE *fp = NULL;
|
||||
int flags = __libc_file_mode(mode);
|
||||
if (flags < 0) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if ((flags & (FILE_MODE_WRITE | FILE_MODE_READ)) == (FILE_MODE_READ | FILE_MODE_WRITE)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(ctx = calloc(1, sizeof(struct pipe)))) {
|
||||
goto err;
|
||||
}
|
||||
if (!(fp = __libc_file_create())) {
|
||||
goto err_ctx;
|
||||
}
|
||||
if (pipe(fds) != 0) {
|
||||
goto err_file;
|
||||
}
|
||||
if ((ctx->pid = fork()) == -1) {
|
||||
goto err_pipe;
|
||||
}
|
||||
|
||||
if (ctx->pid == 0) {
|
||||
// In child
|
||||
if (flags & FILE_MODE_WRITE) {
|
||||
if (dup2(fds[0], STDIN_FILENO) < 0) {
|
||||
_exit(-1);
|
||||
}
|
||||
} else {
|
||||
if (dup2(fds[1], STDOUT_FILENO) < 0) {
|
||||
_exit(-1);
|
||||
}
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
|
||||
_exit(execl("/bin/sh", "sh", "-c", command, NULL));
|
||||
}
|
||||
|
||||
if (flags & FILE_MODE_WRITE) {
|
||||
close(fds[0]);
|
||||
ctx->fd = fds[1];
|
||||
fp->flags = FILE_MODE_WRITE;
|
||||
} else {
|
||||
close(fds[1]);
|
||||
ctx->fd = fds[0];
|
||||
fp->flags = FILE_MODE_READ;
|
||||
}
|
||||
|
||||
fp->ctx = ctx;
|
||||
fp->read = pipe_read;
|
||||
fp->write = pipe_write;
|
||||
fp->seek = pipe_seek;
|
||||
fp->close = pipe_close;
|
||||
|
||||
return fp;
|
||||
|
||||
// TODO: preserve errno here
|
||||
err_pipe:
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
err_file:
|
||||
fclose(fp);
|
||||
err_ctx:
|
||||
free(ctx);
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ time_t time(time_t *t) {
|
||||
if (gettimeofday(&now, NULL) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return t ? *t = now.tv_sec : now.tv_sec;
|
||||
return t ? *t = (time_t) now.tv_sec : (time_t) now.tv_sec;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user