ports: qbe, cproc :^)
This commit is contained in:
parent
1f938c20b4
commit
e43939bcc6
|
@ -0,0 +1,26 @@
|
|||
static const char target[] = "x86_64-camellia";
|
||||
static const char *const startfiles[] = {"-l", ":crt0.o"};
|
||||
static const char *const endfiles[] = {"-l", "c"};
|
||||
static const char *const preprocesscmd[] = {
|
||||
"cpp",
|
||||
|
||||
/* clear preprocessor GNU C version */
|
||||
"-U", "__GNUC__",
|
||||
"-U", "__GNUC_MINOR__",
|
||||
|
||||
/* we don't yet support these optional features */
|
||||
"-D", "__STDC_NO_ATOMICS__",
|
||||
"-D", "__STDC_NO_COMPLEX__",
|
||||
"-D", "__STDC_NO_VLA__",
|
||||
"-U", "__SIZEOF_INT128__",
|
||||
|
||||
/* we don't generate position-independent code */
|
||||
"-U", "__PIC__",
|
||||
|
||||
/* ignore attributes and extension markers */
|
||||
"-D", "__attribute__(x)=",
|
||||
"-D", "__extension__=",
|
||||
};
|
||||
static const char *const codegencmd[] = {"qbe"};
|
||||
static const char *const assemblecmd[] = {"as"};
|
||||
static const char *const linkcmd[] = {"ld", "-no-dynamic-linker", "-pie"};
|
|
@ -0,0 +1,5 @@
|
|||
PREFIX=/usr/
|
||||
BINDIR=$(PREFIX)/bin
|
||||
CC=cc
|
||||
CFLAGS=-std=c99 -Wall -Wpedantic -Wno-parentheses -Wno-switch -g -pipe
|
||||
LDFLAGS=
|
|
@ -0,0 +1,17 @@
|
|||
--- driver.c.orig
|
||||
+++ driver.c
|
||||
@@ -165,12 +165,10 @@ spawnphase(struct stageinfo *phase, int *fd, char *input, char *output, bool las
|
||||
goto err1;
|
||||
}
|
||||
if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) < 0) {
|
||||
- ret = errno;
|
||||
- goto err2;
|
||||
+ warn("fcntl(..., F_SETFD, FD_CLOEXEC):");
|
||||
}
|
||||
if (fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) < 0) {
|
||||
- ret = errno;
|
||||
- goto err2;
|
||||
+ warn("fcntl(..., F_SETFD, FD_CLOEXEC):");
|
||||
}
|
||||
ret = posix_spawn_file_actions_adddup2(&actions, pipefd[1], 1);
|
||||
if (ret)
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
. ports/pre
|
||||
|
||||
pkg=cproc
|
||||
tarball=michaelforney-cproc-0985a78.tar.gz
|
||||
tarball_dir=michaelforney-cproc-0985a78
|
||||
url=https://github.com/michaelforney/cproc/tarball/0985a7893a4b5de63a67ebab445892d9fffe275b
|
||||
|
||||
relink() {
|
||||
rm $tarball_dir/cproc
|
||||
}
|
||||
|
||||
. ports/post
|
|
@ -0,0 +1 @@
|
|||
cf9a4de550303eedcc8b8ee22f11b085a9387b911fa16a6fa7551382a3d7a1ea michaelforney-cproc-0985a78.tar.gz
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
. ports/pre
|
||||
|
||||
pkg=qbe
|
||||
tarball=qbe-1.1.tar.xz
|
||||
tarball_dir=qbe-1.1
|
||||
url=https://c9x.me/compile/release/$tarball
|
||||
|
||||
relink() {
|
||||
rm $tarball_dir/qbe
|
||||
}
|
||||
|
||||
. ports/post
|
|
@ -0,0 +1 @@
|
|||
7d0a53dd40df48072aae317e11ddde15d1a980673160e514e235b9ecaa1db12c qbe-1.1.tar.xz
|
|
@ -1,3 +1,4 @@
|
|||
#include <camellia/errno.h>
|
||||
#include <kernel/panic.h>
|
||||
#include <kernel/pipe.h>
|
||||
#include <kernel/util.h>
|
||||
|
@ -8,7 +9,7 @@ void pipe_joinqueue(Handle *h, Proc *proc, void __user *pbuf, size_t pbuflen) {
|
|||
assert(h && h->type == HANDLE_PIPE);
|
||||
assert(h->readable ^ h->writeable);
|
||||
if (!h->pipe.sister) {
|
||||
regs_savereturn(&proc->regs, -1);
|
||||
regs_savereturn(&proc->regs, h->readable ? 0 : -EPIPE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -349,10 +349,14 @@ void proc_tryreap(Proc *dead) {
|
|||
if (parent->state != PS_WAITS4CHILDDEATH) {
|
||||
return; /* don't reap yet */
|
||||
}
|
||||
uint32_t pid = proc_ns_id(parent->pns, dead);
|
||||
if (parent->awaited_death.pid && parent->awaited_death.pid != pid) {
|
||||
return; /* we're not The One */
|
||||
}
|
||||
if (parent->awaited_death.legacy) {
|
||||
regs_savereturn(&parent->regs, dead->death_msg);
|
||||
} else {
|
||||
regs_savereturn(&parent->regs, proc_ns_id(parent->pns, dead));
|
||||
regs_savereturn(&parent->regs, pid);
|
||||
if (parent->awaited_death.out) {
|
||||
struct sys_wait2 __user *out = parent->awaited_death.out;
|
||||
struct sys_wait2 data;
|
||||
|
|
|
@ -46,6 +46,7 @@ struct Proc {
|
|||
int death_msg; // PS_DEAD
|
||||
struct {
|
||||
bool legacy; /* false = wait2, true = await */
|
||||
uint32_t pid; /* valid if nonzero */
|
||||
struct sys_wait2 __user *out;
|
||||
} awaited_death;
|
||||
struct {
|
||||
|
|
|
@ -26,6 +26,7 @@ long _sys_await(void) {
|
|||
bool has_children = false;
|
||||
proc_setstate(proc_cur, PS_WAITS4CHILDDEATH);
|
||||
proc_cur->awaited_death.legacy = true;
|
||||
proc_cur->awaited_death.pid = 0;
|
||||
|
||||
for (Proc *iter = proc_cur->child;
|
||||
iter; iter = iter->sibling)
|
||||
|
@ -403,7 +404,7 @@ uint32_t _sys_getppid(void) {
|
|||
}
|
||||
|
||||
int _sys_wait2(int pid, int flags, struct sys_wait2 __user *out) {
|
||||
if (pid != -1 || flags != 0) {
|
||||
if (flags != 0) {
|
||||
SYSCALL_RETURN(-ENOSYS);
|
||||
}
|
||||
|
||||
|
@ -411,13 +412,13 @@ int _sys_wait2(int pid, int flags, struct sys_wait2 __user *out) {
|
|||
proc_setstate(proc_cur, PS_WAITS4CHILDDEATH);
|
||||
proc_cur->awaited_death.legacy = false;
|
||||
proc_cur->awaited_death.out = out;
|
||||
proc_cur->awaited_death.pid = (0 < pid) ? pid : 0;
|
||||
|
||||
for (Proc *iter = proc_cur->child; iter; iter = iter->sibling) {
|
||||
if (iter->noreap) continue;
|
||||
has_children = true;
|
||||
if (iter->state == PS_TOREAP) {
|
||||
proc_tryreap(iter);
|
||||
return 0; // dummy
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,10 @@ int isalpha(int c) {
|
|||
return islower(c) || isupper(c);
|
||||
}
|
||||
|
||||
int isblank(int c) {
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
int iscntrl(int c) {
|
||||
return c <= 0x1f || c == 0x7f;
|
||||
}
|
||||
|
|
|
@ -42,19 +42,22 @@ static bool valid_ehdr(const struct Elf64_Ehdr *h) {
|
|||
static bool load_phdr(const void *elf, void *exebase, size_t idx) {
|
||||
const struct Elf64_Ehdr *ehdr = elf;
|
||||
const struct Elf64_Phdr *phdr = elf + ehdr->e_phoff + idx * ehdr->e_phentsize;
|
||||
|
||||
if (phdr->p_type == PT_DYNAMIC) return true;
|
||||
|
||||
if (phdr->p_type != PT_LOAD) {
|
||||
printf("unknown type %x\n", phdr->p_type);
|
||||
|
||||
switch (phdr->p_type) {
|
||||
case PT_DYNAMIC:
|
||||
case 0x6474e551: /* GNU_STACK */
|
||||
return true;
|
||||
case PT_LOAD:
|
||||
// TODO overlap check
|
||||
// TODO don't ignore flags
|
||||
_sys_memflag(exebase + phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT);
|
||||
// TODO check that filesz <= memsz
|
||||
memcpy(exebase + phdr->p_vaddr, elf + phdr->p_offset, phdr->p_filesz);
|
||||
return true;
|
||||
default:
|
||||
printf("unknown elf phdr %x\n", phdr->p_type);
|
||||
return false;
|
||||
}
|
||||
// TODO overlap check
|
||||
// TODO don't ignore flags
|
||||
_sys_memflag(exebase + phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT);
|
||||
// TODO check that filesz <= memsz
|
||||
memcpy(exebase + phdr->p_vaddr, elf + phdr->p_offset, phdr->p_filesz);
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t elf_spread(const void *elf) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
int isalnum(int c);
|
||||
int isalpha(int c);
|
||||
int isblank(int c);
|
||||
int iscntrl(int c);
|
||||
int isdigit(int c);
|
||||
int isgraph(int c);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#define PRId64 "ld"
|
||||
#define PRIi64 "li"
|
||||
#define PRIo64 "lo"
|
||||
#define PRIu64 "lu"
|
||||
#define PRIx64 "lx"
|
||||
|
@ -9,11 +10,13 @@
|
|||
#define PRId32 "d"
|
||||
#define PRIo32 "o"
|
||||
#define PRIu32 "u"
|
||||
#define PRIuLEAST32 "u"
|
||||
#define PRIx32 "x"
|
||||
#define SCNu32 "u"
|
||||
|
||||
#define PRId16 "d"
|
||||
#define PRIo16 "o"
|
||||
#define PRIu16 "u"
|
||||
#define PRIuLEAST16 "u"
|
||||
#define PRIx16 "x"
|
||||
#define SCNu16 "u"
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct {
|
||||
struct file_action *f;
|
||||
} posix_spawn_file_actions_t;
|
||||
|
||||
typedef struct {} posix_spawnattr_t;
|
||||
|
||||
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *facts, int from, int to);
|
||||
int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *facts);
|
||||
int posix_spawn_file_actions_init(posix_spawn_file_actions_t *facts);
|
||||
|
||||
int posix_spawnp(
|
||||
pid_t *restrict pid,
|
||||
const char *restrict file,
|
||||
const posix_spawn_file_actions_t *restrict file_actions,
|
||||
const posix_spawnattr_t *restrict attrp,
|
||||
char *const argv[restrict],
|
||||
char *const envp[restrict]
|
||||
);
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <bits/file.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
@ -27,6 +28,7 @@ int printf(const char *restrict fmt, ...);
|
|||
int fprintf(FILE *restrict f, const char *restrict fmt, ...);
|
||||
|
||||
int sprintf(char *restrict s, const char *restrict fmt, ...);
|
||||
int snprintf(char *restrict str, size_t len, const char *restrict fmt, ...);
|
||||
|
||||
int vprintf(const char *restrict fmt, va_list ap);
|
||||
int vsprintf(char *restrict s, const char *restrict fmt, va_list ap);
|
||||
|
@ -86,4 +88,6 @@ char *tmpnam(char *s);
|
|||
|
||||
int sscanf(const char *restrict s, const char *restrict format, ...);
|
||||
int vsscanf(const char* str, const char* format, va_list ap);
|
||||
int fscanf(FILE* fp, const char* format, ...);
|
||||
int vfscanf(FILE* fp, const char* format, va_list ap);
|
||||
int vcbscanf(void* fp, int (*fgetc)(void*), int (*ungetc)(int, void*), const char* restrict format, va_list ap);
|
||||
|
|
|
@ -27,3 +27,4 @@ char *strdup(const char *s);
|
|||
size_t strnlen(const char *s, size_t len);
|
||||
|
||||
char *strerror(int errnum);
|
||||
char *strsignal(int sig);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#define WIFSTOPPED(x) 0
|
||||
#define WEXITSTATUS(x) ((x)&0xFF)
|
||||
#define WIFEXITED(x) 1
|
||||
#define WIFSIGNALED(x) 0
|
||||
#define WSTOPSIG(x) 0
|
||||
#define WTERMSIG(x) 0
|
||||
|
||||
|
@ -12,3 +13,4 @@
|
|||
|
||||
pid_t wait(int *wstatus);
|
||||
pid_t wait3(int *wstatus, int opts, struct rusage *rusage);
|
||||
pid_t waitpid(pid_t pid, int *wstatus, int opts);
|
||||
|
|
|
@ -22,6 +22,7 @@ int isatty(int fd);
|
|||
|
||||
int execv(const char *path, char *const argv[]);
|
||||
int execvp(const char *path, char *const argv[]);
|
||||
int execvpe(const char *path, char *const argv[], char *const envp[]);
|
||||
int execve(const char *path, char *const argv[], char *const envp[]);
|
||||
|
||||
int chdir(const char *path);
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
#include <camellia/syscalls.h>
|
||||
#include <errno.h>
|
||||
#include <spawn.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum act {
|
||||
ACT_DUP2 = 1,
|
||||
};
|
||||
|
||||
struct file_action {
|
||||
struct file_action *next;
|
||||
enum act type;
|
||||
int a, b;
|
||||
};
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *facts, int from, int to)
|
||||
{
|
||||
struct file_action *fact, **tail;
|
||||
fact = calloc(1, sizeof(*fact));
|
||||
if (!fact) return ENOMEM;
|
||||
|
||||
fact->type = ACT_DUP2;
|
||||
fact->a = from;
|
||||
fact->b = to;
|
||||
|
||||
tail = &facts->f;
|
||||
while (*tail) {
|
||||
tail = &(*tail)->next;
|
||||
}
|
||||
*tail = fact;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *facts)
|
||||
{
|
||||
while (facts->f) {
|
||||
struct file_action *cur = facts->f;
|
||||
facts->f = cur->next;
|
||||
free(cur);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawn_file_actions_init(posix_spawn_file_actions_t *facts)
|
||||
{
|
||||
facts->f = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
posix_spawnp(
|
||||
pid_t *restrict pidp,
|
||||
const char *restrict file,
|
||||
const posix_spawn_file_actions_t *restrict facts,
|
||||
const posix_spawnattr_t *restrict attrp,
|
||||
char *const argv[restrict],
|
||||
char *const envp[restrict]
|
||||
) {
|
||||
if (attrp) return ENOSYS;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) return errno;
|
||||
if (pid == 0) {
|
||||
struct file_action *fact = facts ? facts->f : NULL;
|
||||
while (fact) {
|
||||
switch (fact->type) {
|
||||
case ACT_DUP2:
|
||||
dup2(fact->a, fact->b);
|
||||
break;
|
||||
}
|
||||
fact = fact->next;
|
||||
}
|
||||
execvpe(file, argv, envp);
|
||||
_sys_exit(127);
|
||||
}
|
||||
if (pidp) *pidp = pid;
|
||||
return 0;
|
||||
}
|
|
@ -248,7 +248,7 @@ size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restri
|
|||
}
|
||||
|
||||
int fputs(const char *s, FILE *f) {
|
||||
return fprintf(f, "%s\n", s);
|
||||
return fprintf(f, "%s", s);
|
||||
}
|
||||
|
||||
char *fgets(char *buf, int size, FILE *f) {
|
||||
|
|
|
@ -124,6 +124,12 @@ size_t strnlen(const char *s, size_t len) {
|
|||
return len;
|
||||
}
|
||||
|
||||
char *strsignal(int sig) {
|
||||
static char buf[32];
|
||||
snprintf(buf, sizeof(buf), "signal %d", sig);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* strings.h */
|
||||
int strcasecmp(const char *s1, const char *s2) {
|
||||
return strncasecmp(s1, s2, ~0);
|
||||
|
|
|
@ -10,11 +10,18 @@ pid_t wait(int *wstatus) {
|
|||
}
|
||||
|
||||
pid_t wait3(int *wstatus, int opts, struct rusage *rusage) {
|
||||
struct sys_wait2 res;
|
||||
if (opts || rusage) {
|
||||
if (rusage) {
|
||||
__libc_panic("unimplemented");
|
||||
}
|
||||
pid_t ret = _sys_wait2(-1, 0, &res);
|
||||
return waitpid(-1, wstatus, opts);
|
||||
}
|
||||
|
||||
pid_t waitpid(pid_t pid, int *wstatus, int opts) {
|
||||
struct sys_wait2 res;
|
||||
if (opts) {
|
||||
__libc_panic("unimplemented");
|
||||
}
|
||||
pid_t ret = _sys_wait2(pid, 0, &res);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
return -1;
|
||||
|
|
|
@ -77,6 +77,19 @@ int execvp(const char *path, char *const argv[]) {
|
|||
return execve(path, argv, NULL);
|
||||
}
|
||||
|
||||
int execvpe(const char *path, char *const argv[], char *const envp[]) {
|
||||
if (path[0] != '/') {
|
||||
char *exp = malloc(strlen(path) + 6);
|
||||
int ret;
|
||||
strcpy(exp, "/bin/");
|
||||
strcat(exp, path);
|
||||
ret = execve(exp, argv, envp);
|
||||
free(exp);
|
||||
return ret;
|
||||
}
|
||||
return execve(path, argv, envp);
|
||||
}
|
||||
|
||||
int execve(const char *path, char *const argv[], char *const envp[]) {
|
||||
FILE *file = fopen(path, "e");
|
||||
char hdr[4] = {0};
|
||||
|
@ -225,8 +238,13 @@ ssize_t write(int fd, const void *buf, size_t count) {
|
|||
}
|
||||
|
||||
int pipe(int pipefd[2]) {
|
||||
(void)pipefd;
|
||||
__libc_panic("unimplemented");
|
||||
// TODO pipe buffering
|
||||
int ret = _sys_pipe(pipefd, 0);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dup(int oldfd) {
|
||||
|
@ -235,8 +253,12 @@ int dup(int oldfd) {
|
|||
}
|
||||
|
||||
int dup2(int oldfd, int newfd) {
|
||||
(void)oldfd; (void)newfd;
|
||||
__libc_panic("unimplemented");
|
||||
int ret = _sys_dup(oldfd, newfd, 0);
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned int sleep(unsigned int seconds) {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* stdio/fscanf.c
|
||||
* Input format conversion.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int fscanf(FILE* fp, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int ret = vfscanf(fp, format, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013, 2014 Jonas 'Sortie' Termansen.
|
||||
* Modified by dzwdz.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* stdio/vfscanf.c
|
||||
* Input format conversion.
|
||||
*
|
||||
* stdio/vfscanf_unlocked.c
|
||||
* Input format conversion.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int wrap_fgetc(void* fp)
|
||||
{
|
||||
return fgetc((FILE*) fp);
|
||||
}
|
||||
|
||||
static int wrap_ungetc(int c, void* fp)
|
||||
{
|
||||
return ungetc(c, (FILE*) fp);
|
||||
}
|
||||
|
||||
int vfscanf(FILE* fp, const char* format, va_list ap)
|
||||
{
|
||||
// if ( !(fp->flags & _FILE_READABLE) )
|
||||
// return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF;
|
||||
|
||||
return vcbscanf(fp, wrap_fgetc, wrap_ungetc, format, ap);
|
||||
}
|
|
@ -96,6 +96,22 @@ static void output_uint16(struct out_state *os, struct mods *m, unsigned long lo
|
|||
}
|
||||
}
|
||||
|
||||
static void output_octal(struct out_state *os, struct mods *m, unsigned long long n) {
|
||||
char buf[sizeof(unsigned long long) * 3];
|
||||
size_t pos = sizeof(buf);
|
||||
|
||||
if (!n) {
|
||||
buf[--pos] = '0';
|
||||
} else while (n) {
|
||||
unsigned long long q = n / 8, r = n % 8;
|
||||
buf[--pos] = r + '0';
|
||||
n = q;
|
||||
}
|
||||
size_t len = sizeof(buf) - pos;
|
||||
padnum(os, m, len, '\0');
|
||||
output(os, buf + pos, len);
|
||||
}
|
||||
|
||||
|
||||
int __printf_internal(const char *fmt, va_list argp,
|
||||
void (*back)(void*, const char*, size_t), void *backarg)
|
||||
|
@ -170,6 +186,10 @@ int __printf_internal(const char *fmt, va_list argp,
|
|||
lm = LM_size;
|
||||
c = *fmt++;
|
||||
break;
|
||||
case 'j':
|
||||
lm = LM_longlong;
|
||||
c = *fmt++;
|
||||
break;
|
||||
default:
|
||||
lm = LM_int;
|
||||
break;
|
||||
|
@ -201,19 +221,15 @@ int __printf_internal(const char *fmt, va_list argp,
|
|||
break;
|
||||
|
||||
case 'x':
|
||||
if (lm == LM_int) n = va_arg(argp, unsigned int);
|
||||
else if (lm == LM_long) n = va_arg(argp, unsigned long);
|
||||
else if (lm == LM_longlong) n = va_arg(argp, unsigned long long);
|
||||
else if (lm == LM_size) n = va_arg(argp, size_t);
|
||||
output_uint16(&os, &m, n);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'o':
|
||||
if (lm == LM_int) n = va_arg(argp, unsigned int);
|
||||
else if (lm == LM_long) n = va_arg(argp, unsigned long);
|
||||
else if (lm == LM_longlong) n = va_arg(argp, unsigned long long);
|
||||
else if (lm == LM_size) n = va_arg(argp, size_t);
|
||||
output_uint(&os, &m, n, '\0');
|
||||
if (c == 'x') output_uint16(&os, &m, n);
|
||||
if (c == 'u') output_uint(&os, &m, n, '\0');
|
||||
if (c == 'o') output_octal(&os, &m, n);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
|
|
Loading…
Reference in New Issue