Enough compatibility work to make figlet build and run!
I ran out of steam writing library routines and imported two BSD-licensed libc routines: sscanf() and getopt(). I will most likely rewrite them sooner or later. For now I just wanted to see figlet running.
This commit is contained in:
parent
69c7a59e6f
commit
819ce91395
Notes:
sideshowbarker
2024-07-19 18:35:47 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/819ce913958
22 changed files with 714 additions and 36 deletions
|
@ -41,7 +41,6 @@ void MemoryManager::initializePaging()
|
|||
|
||||
identityMap(LinearAddress(4096), 4 * MB);
|
||||
|
||||
// Put pages between 4MB and 8MB in the page freelist.
|
||||
for (size_t i = (4 * MB) + PAGE_SIZE; i < (8 * MB); i += PAGE_SIZE) {
|
||||
m_freePages.append(PhysicalAddress(i));
|
||||
}
|
||||
|
@ -170,7 +169,7 @@ RetainPtr<Zone> MemoryManager::createZone(size_t size)
|
|||
InterruptDisabler disabler;
|
||||
auto pages = allocatePhysicalPages(ceilDiv(size, PAGE_SIZE));
|
||||
if (pages.isEmpty()) {
|
||||
kprintf("[MM] createZone: no physical pages for size %u", size);
|
||||
kprintf("[MM] createZone: no physical pages for size %u\n", size);
|
||||
return nullptr;
|
||||
}
|
||||
return adopt(*new Zone(move(pages)));
|
||||
|
|
|
@ -77,10 +77,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
|||
case Syscall::PosixRead:
|
||||
//kprintf("syscall: read(%d, %p, %u)\n", arg1, arg2, arg3);
|
||||
return current->sys$read((int)arg1, (void*)arg2, (size_t)arg3);
|
||||
case Syscall::PosixSeek:
|
||||
// FIXME: This has the wrong signature, should be like lseek()
|
||||
kprintf("syscall: seek(%d, %d)\n", arg1, arg2);
|
||||
return current->sys$seek((int)arg1, (int)arg2);
|
||||
case Syscall::PosixLseek:
|
||||
return current->sys$lseek((int)arg1, (off_t)arg2, (int)arg3);
|
||||
case Syscall::PosixKill:
|
||||
return current->sys$kill((pid_t)arg1, (int)arg2);
|
||||
case Syscall::PosixGetuid:
|
||||
|
@ -104,6 +102,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
|||
return 0;
|
||||
case Syscall::GetArguments:
|
||||
return current->sys$get_arguments((int*)arg1, (char***)arg2);
|
||||
case Syscall::GetEnvironment:
|
||||
return current->sys$get_environment((char***)arg1);
|
||||
case Syscall::PosixChdir:
|
||||
return current->sys$chdir((const char*)arg1);
|
||||
case Syscall::PosixUname:
|
||||
|
|
|
@ -17,7 +17,7 @@ enum Function {
|
|||
PosixOpen = 0x1985,
|
||||
PosixClose = 0x1986,
|
||||
PosixRead = 0x1987,
|
||||
PosixSeek = 0x1988,
|
||||
PosixLseek = 0x1988,
|
||||
PosixKill = 0x1989,
|
||||
PosixGetuid = 0x1990,
|
||||
PosixExit = 0x1991,
|
||||
|
@ -39,6 +39,7 @@ enum Function {
|
|||
PosixWrite = 0x2007,
|
||||
PosixTtynameR = 0x2008,
|
||||
PosixStat = 0x2009,
|
||||
GetEnvironment = 0x2010,
|
||||
};
|
||||
|
||||
void initialize();
|
||||
|
|
|
@ -182,6 +182,7 @@ int Task::sys$set_mmap_name(void* addr, size_t size, const char* name)
|
|||
|
||||
void* Task::sys$mmap(void* addr, size_t size)
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
// FIXME: Implement mapping at a client-preferred address.
|
||||
ASSERT(addr == nullptr);
|
||||
auto* region = allocateRegion(size, "mmap");
|
||||
|
@ -193,6 +194,7 @@ void* Task::sys$mmap(void* addr, size_t size)
|
|||
|
||||
int Task::sys$munmap(void* addr, size_t size)
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
auto* region = regionFromRange(LinearAddress((dword)addr), size);
|
||||
if (!region)
|
||||
return -1;
|
||||
|
@ -213,6 +215,12 @@ int Task::sys$gethostname(char* buffer, size_t size)
|
|||
|
||||
int Task::sys$spawn(const char* path, const char** args)
|
||||
{
|
||||
if (args) {
|
||||
for (size_t i = 0; args[i]; ++i) {
|
||||
VALIDATE_USER_BUFFER(args[i], strlen(args[i]));
|
||||
}
|
||||
}
|
||||
|
||||
int error = 0;
|
||||
auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error, args, m_tty);
|
||||
if (child)
|
||||
|
@ -261,10 +269,17 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren
|
|||
taskArguments.append(parts.last());
|
||||
}
|
||||
|
||||
Vector<String> taskEnvironment;
|
||||
taskEnvironment.append("PATH=/bin");
|
||||
taskEnvironment.append("SHELL=/bin/sh");
|
||||
taskEnvironment.append("TERM=console");
|
||||
taskEnvironment.append("HOME=/");
|
||||
|
||||
InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE.
|
||||
Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3, move(cwd), handle->vnode(), tty);
|
||||
|
||||
t->m_arguments = move(taskArguments);
|
||||
t->m_initialEnvironment = move(taskEnvironment);
|
||||
|
||||
ExecSpace space;
|
||||
Region* region = nullptr;
|
||||
|
@ -322,11 +337,29 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren
|
|||
#ifdef TASK_DEBUG
|
||||
kprintf("Task %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip);
|
||||
#endif
|
||||
|
||||
error = 0;
|
||||
return t;
|
||||
}
|
||||
|
||||
int Task::sys$get_environment(char*** environ)
|
||||
{
|
||||
auto* region = allocateRegion(4096, "environ");
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
MM.mapRegion(*this, *region);
|
||||
char* envpage = (char*)region->linearAddress.get();
|
||||
*environ = (char**)envpage;
|
||||
char* bufptr = envpage + (sizeof(char*) * (m_initialEnvironment.size() + 1));
|
||||
for (size_t i = 0; i < m_initialEnvironment.size(); ++i) {
|
||||
(*environ)[i] = bufptr;
|
||||
memcpy(bufptr, m_initialEnvironment[i].characters(), m_initialEnvironment[i].length());
|
||||
bufptr += m_initialEnvironment[i].length();
|
||||
*(bufptr++) = '\0';
|
||||
}
|
||||
(*environ)[m_initialEnvironment.size()] = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Task::sys$get_arguments(int* argc, char*** argv)
|
||||
{
|
||||
auto* region = allocateRegion(4096, "argv");
|
||||
|
@ -763,12 +796,12 @@ ssize_t Task::sys$get_dir_entries(int fd, void* buffer, size_t size)
|
|||
return handle->get_dir_entries((byte*)buffer, size);
|
||||
}
|
||||
|
||||
int Task::sys$seek(int fd, int offset)
|
||||
int Task::sys$lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
auto* handle = fileHandleIfExists(fd);
|
||||
if (!handle)
|
||||
return -1;
|
||||
return handle->seek(offset, SEEK_SET);
|
||||
return -EBADF;
|
||||
return handle->seek(offset, whence);
|
||||
}
|
||||
|
||||
int Task::sys$ttyname_r(int fd, char* buffer, size_t size)
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
ssize_t sys$write(int fd, const void*, size_t);
|
||||
int sys$lstat(const char*, Unix::stat*);
|
||||
int sys$stat(const char*, Unix::stat*);
|
||||
int sys$seek(int fd, int offset);
|
||||
int sys$lseek(int fd, off_t, int whence);
|
||||
int sys$kill(pid_t pid, int sig);
|
||||
int sys$geterror() { return m_error; }
|
||||
void sys$exit(int status);
|
||||
|
@ -110,6 +110,7 @@ public:
|
|||
int sys$gettimeofday(timeval*);
|
||||
int sys$gethostname(char* name, size_t length);
|
||||
int sys$get_arguments(int* argc, char*** argv);
|
||||
int sys$get_environment(char*** environ);
|
||||
int sys$uname(utsname*);
|
||||
int sys$readlink(const char*, char*, size_t);
|
||||
int sys$ttyname_r(int fd, char*, size_t);
|
||||
|
@ -220,6 +221,7 @@ private:
|
|||
void murder();
|
||||
|
||||
Vector<String> m_arguments;
|
||||
Vector<String> m_initialEnvironment;
|
||||
};
|
||||
|
||||
extern void task_init();
|
||||
|
|
7
Kernel/sync-local.sh
Executable file
7
Kernel/sync-local.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
cp ../../figlet-2.2.5/figlet mnt/bin/
|
||||
mkdir -p mnt/usr/local/share/figlet
|
||||
FIGLET_FONTDIR=/
|
||||
cp ../../figlet-2.2.5/fonts/standard.flf mnt/$FIGLET_FONTDIR
|
||||
cp ../../figlet-2.2.5/fonts/big.flf mnt/$FIGLET_FONTDIR
|
||||
cp ../../figlet-2.2.5/fonts/slant.flf mnt/$FIGLET_FONTDIR
|
||||
cp ../../figlet-2.2.5/fonts/lean.flf mnt/$FIGLET_FONTDIR
|
|
@ -17,6 +17,7 @@ cp ../Userland/clear mnt/bin/clear
|
|||
cp ../Userland/tst mnt/bin/tst
|
||||
cp ../Userland/mm mnt/bin/mm
|
||||
cp ../Userland/kill mnt/bin/kill
|
||||
sh sync-local.sh
|
||||
cp kernel.map mnt/
|
||||
umount mnt
|
||||
sync
|
||||
|
|
|
@ -17,6 +17,8 @@ LIBC_OBJS = \
|
|||
utsname.o \
|
||||
assert.o \
|
||||
signal.o \
|
||||
getopt.o \
|
||||
scanf.o \
|
||||
entry.o
|
||||
|
||||
OBJS = $(AK_OBJS) $(LIBC_OBJS)
|
||||
|
|
|
@ -6,7 +6,7 @@ __BEGIN_DECLS
|
|||
|
||||
void __assertion_failed(const char* msg, const char* file, unsigned line, const char* func);
|
||||
|
||||
#define assert(expr) (static_cast<bool>(expr) ? (void)0 : __assertion_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__))
|
||||
#define assert(expr) ((expr) ? (void)0 : __assertion_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__))
|
||||
#define CRASH() do { asm volatile("ud2"); } while(0)
|
||||
#define ASSERT assert
|
||||
#define RELEASE_ASSERT assert
|
||||
|
|
|
@ -10,9 +10,14 @@ int errno;
|
|||
FILE* stdin;
|
||||
FILE* stdout;
|
||||
FILE* stderr;
|
||||
char** environ;
|
||||
|
||||
extern "C" void __malloc_init();
|
||||
|
||||
extern "C" int _start()
|
||||
{
|
||||
__malloc_init();
|
||||
|
||||
errno = 0;
|
||||
|
||||
__default_streams[0].fd = 0;
|
||||
|
@ -26,12 +31,18 @@ extern "C" int _start()
|
|||
|
||||
StringImpl::initializeGlobals();
|
||||
|
||||
int status = 254;
|
||||
int argc;
|
||||
char** argv;
|
||||
int rc = Syscall::invoke(Syscall::GetArguments, (dword)&argc, (dword)&argv);
|
||||
int status = 254;
|
||||
if (rc == 0)
|
||||
status = main(argc, argv);
|
||||
if (rc < 0)
|
||||
goto epilogue;
|
||||
rc = Syscall::invoke(Syscall::GetEnvironment, (dword)&environ);
|
||||
if (rc < 0)
|
||||
goto epilogue;
|
||||
status = main(argc, argv);
|
||||
|
||||
epilogue:
|
||||
Syscall::invoke(Syscall::PosixExit, status);
|
||||
|
||||
// Birger's birthday <3
|
||||
|
|
109
LibC/getopt.cpp
Normal file
109
LibC/getopt.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 1987, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int opterr = 1; /* if error message should be printed */
|
||||
int optind = 1; /* index into parent argv vector */
|
||||
int optopt; /* character checked for validity */
|
||||
int optreset; /* reset getopt */
|
||||
char *optarg; /* argument associated with option */
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG (int)':'
|
||||
#define EMSG ""
|
||||
|
||||
int getopt(int nargc, char* const nargv[], const char* ostr)
|
||||
{
|
||||
static const char* place = EMSG; /* option letter processing */
|
||||
char *oli; /* option letter list index */
|
||||
|
||||
ASSERT(nargv != NULL);
|
||||
ASSERT(ostr != NULL);
|
||||
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc || *(place = nargv[optind]) != '-') {
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
if (place[1] && *++place == '-' /* found "--" */
|
||||
&& place[1] == '\0') {
|
||||
++optind;
|
||||
place = EMSG;
|
||||
return -1;
|
||||
}
|
||||
} /* option letter okay? */
|
||||
if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) {
|
||||
/*
|
||||
* if the user didn't specify '-' as an option,
|
||||
* assume it means -1.
|
||||
*/
|
||||
if (optopt == (int)'-')
|
||||
return -1;
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (opterr && *ostr != ':')
|
||||
fprintf(stderr, "unknown option -- %c\n", optopt);
|
||||
return BADCH;
|
||||
}
|
||||
if (*++oli != ':') { /* don't need argument */
|
||||
optarg = NULL;
|
||||
if (!*place)
|
||||
++optind;
|
||||
}
|
||||
else { /* need an argument */
|
||||
if (*place) /* no white space */
|
||||
optarg = (char*)place;
|
||||
else if (nargc <= ++optind) { /* no arg */
|
||||
place = EMSG;
|
||||
if (*ostr == ':')
|
||||
return BADARG;
|
||||
if (opterr)
|
||||
fprintf(stderr, "option requires an argument -- %c\n", optopt);
|
||||
return BADCH;
|
||||
}
|
||||
else /* white space */
|
||||
optarg = nargv[optind];
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return optopt; /* dump back option letter */
|
||||
}
|
13
LibC/getopt.h
Normal file
13
LibC/getopt.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
int getopt(int argc, char* const argv[], const char* optstring);
|
||||
extern char* optarg;
|
||||
extern int optind;
|
||||
extern int opterr;
|
||||
extern int optopt;
|
||||
|
||||
__END_DECLS
|
255
LibC/scanf.cpp
Normal file
255
LibC/scanf.cpp
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Opsycon AB.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define MAXLN 512
|
||||
|
||||
static const char* determineBase(const char* p, int& base)
|
||||
{
|
||||
if (p[0] == '0') {
|
||||
switch (p[1]) {
|
||||
case 'x':
|
||||
base = 16;
|
||||
break;
|
||||
case 't':
|
||||
case 'n':
|
||||
base = 10;
|
||||
break;
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
default:
|
||||
base = 10;
|
||||
return p;
|
||||
}
|
||||
return p + 2;
|
||||
}
|
||||
base = 10;
|
||||
return p;
|
||||
}
|
||||
|
||||
static int _atob(unsigned long* vp, const char* p, int base)
|
||||
{
|
||||
unsigned long value, v1, v2;
|
||||
char *q, tmp[20];
|
||||
int digit;
|
||||
|
||||
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
|
||||
base = 16;
|
||||
p += 2;
|
||||
}
|
||||
|
||||
if (base == 16 && (q = strchr(p, '.')) != 0) {
|
||||
if (q - p > sizeof(tmp) - 1)
|
||||
return 0;
|
||||
strncpy(tmp, p, q - p);
|
||||
tmp[q - p] = '\0';
|
||||
if (!_atob(&v1, tmp, 16))
|
||||
return 0;
|
||||
++q;
|
||||
if (strchr(q, '.'))
|
||||
return 0;
|
||||
if (!_atob(&v2, q, 16))
|
||||
return 0;
|
||||
*vp = (v1 << 16) + v2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = *vp = 0;
|
||||
for (; *p; p++) {
|
||||
if (*p >= '0' && *p <= '9')
|
||||
digit = *p - '0';
|
||||
else if (*p >= 'a' && *p <= 'f')
|
||||
digit = *p - 'a' + 10;
|
||||
else if (*p >= 'A' && *p <= 'F')
|
||||
digit = *p - 'A' + 10;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (digit >= base)
|
||||
return 0;
|
||||
value *= base;
|
||||
value += digit;
|
||||
}
|
||||
*vp = value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int atob(unsigned int* vp, const char* p, int base)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
if (base == 0)
|
||||
p = determineBase(p, base);
|
||||
if (_atob(&v, p, base)) {
|
||||
*vp = v;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfscanf(FILE*, const char*, va_list);
|
||||
static int vsscanf(const char*, const char*, va_list);
|
||||
|
||||
#define ISSPACE " \t\n\r\f\v"
|
||||
|
||||
int scanf(const char* fmt, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
count = vfscanf(stdin, fmt, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
|
||||
int fscanf(FILE *fp, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int count = vfscanf(fp, fmt, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
|
||||
int sscanf(const char *buf, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int count = vsscanf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int vfscanf(FILE *fp, const char* fmt, va_list ap)
|
||||
{
|
||||
char buf[MAXLN + 1];
|
||||
if (!fgets(buf, MAXLN, fp))
|
||||
return -1;
|
||||
int count = vsscanf(buf, fmt, ap);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int vsscanf(const char *buf, const char *s, va_list ap)
|
||||
{
|
||||
int base;
|
||||
char *t;
|
||||
char tmp[MAXLN];
|
||||
bool noassign = false;
|
||||
bool lflag = false;
|
||||
int count = 0;
|
||||
int width = 0;
|
||||
|
||||
while (*s && *buf) {
|
||||
while (isspace (*s))
|
||||
s++;
|
||||
if (*s == '%') {
|
||||
s++;
|
||||
for (; *s; s++) {
|
||||
if (strchr ("dibouxcsefg%", *s))
|
||||
break;
|
||||
if (*s == '*')
|
||||
noassign = true;
|
||||
else if (*s == 'l' || *s == 'L')
|
||||
lflag = true;
|
||||
else if (*s >= '1' && *s <= '9') {
|
||||
const char* tc;
|
||||
for (tc = s; isdigit(*s); s++);
|
||||
strncpy (tmp, tc, s - tc);
|
||||
tmp[s - tc] = '\0';
|
||||
atob ((dword*)&width, tmp, 10);
|
||||
s--;
|
||||
}
|
||||
}
|
||||
if (*s == 's') {
|
||||
while (isspace(*buf))
|
||||
buf++;
|
||||
if (!width)
|
||||
width = strcspn(buf, ISSPACE);
|
||||
if (!noassign) {
|
||||
strncpy(t = va_arg(ap, char*), buf, width);
|
||||
t[width] = '\0';
|
||||
}
|
||||
buf += width;
|
||||
} else if (*s == 'c') {
|
||||
if (!width)
|
||||
width = 1;
|
||||
if (!noassign) {
|
||||
strncpy(t = va_arg(ap, char*), buf, width);
|
||||
t[width] = '\0';
|
||||
}
|
||||
buf += width;
|
||||
} else if (strchr("dobxu", *s)) {
|
||||
while (isspace(*buf))
|
||||
buf++;
|
||||
if (*s == 'd' || *s == 'u')
|
||||
base = 10;
|
||||
else if (*s == 'x')
|
||||
base = 16;
|
||||
else if (*s == 'o')
|
||||
base = 8;
|
||||
else if (*s == 'b')
|
||||
base = 2;
|
||||
if (!width) {
|
||||
if (isspace(*(s + 1)) || *(s + 1) == 0)
|
||||
width = strcspn(buf, ISSPACE);
|
||||
else
|
||||
width = strchr(buf, *(s + 1)) - buf;
|
||||
}
|
||||
strncpy(tmp, buf, width);
|
||||
tmp[width] = '\0';
|
||||
buf += width;
|
||||
if (!noassign)
|
||||
atob(va_arg(ap, dword*), tmp, base);
|
||||
}
|
||||
if (!noassign)
|
||||
++count;
|
||||
width = 0;
|
||||
noassign = false;
|
||||
lflag = false;
|
||||
++s;
|
||||
} else {
|
||||
while (isspace(*buf))
|
||||
buf++;
|
||||
if (*s != *buf)
|
||||
break;
|
||||
else {
|
||||
++s;
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
121
LibC/stdio.cpp
121
LibC/stdio.cpp
|
@ -4,15 +4,113 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <Kernel/Syscall.h>
|
||||
#include <AK/printf.cpp>
|
||||
|
||||
extern "C" {
|
||||
|
||||
int fileno(FILE* stream)
|
||||
{
|
||||
return stream->fd;
|
||||
}
|
||||
|
||||
int feof(FILE* stream)
|
||||
{
|
||||
return stream->eof;
|
||||
}
|
||||
|
||||
char* fgets(char* buffer, int size, FILE* stream)
|
||||
{
|
||||
ssize_t nread = 0;
|
||||
for (;;) {
|
||||
if (nread >= size)
|
||||
break;
|
||||
char ch = fgetc(stream);
|
||||
if (feof(stream))
|
||||
break;
|
||||
buffer[nread++] = ch;
|
||||
if (!ch || ch == '\n')
|
||||
break;
|
||||
}
|
||||
if (nread < size)
|
||||
buffer[nread] = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int fgetc(FILE* stream)
|
||||
{
|
||||
char ch;
|
||||
read(stream->fd, &ch, 1);
|
||||
return ch;
|
||||
}
|
||||
|
||||
int getc(FILE* stream)
|
||||
{
|
||||
return fgetc(stream);
|
||||
}
|
||||
|
||||
int getchar()
|
||||
{
|
||||
return getc(stdin);
|
||||
}
|
||||
|
||||
int fputc(int ch, FILE* stream)
|
||||
{
|
||||
write(stream->fd, &ch, 1);
|
||||
return (byte)ch;
|
||||
}
|
||||
|
||||
int putc(int ch, FILE* stream)
|
||||
{
|
||||
return fputc(ch, stream);
|
||||
}
|
||||
|
||||
int putchar(int ch)
|
||||
{
|
||||
write(0, &ch, 1);
|
||||
return (byte)ch;
|
||||
return putc(ch, stdout);
|
||||
}
|
||||
|
||||
void clearerr(FILE* stream)
|
||||
{
|
||||
stream->eof = false;
|
||||
}
|
||||
|
||||
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
|
||||
{
|
||||
ssize_t nread = read(stream->fd, ptr, nmemb * size);
|
||||
if (nread < 0)
|
||||
return 0;
|
||||
if (nread == 0)
|
||||
stream->eof = true;
|
||||
return nread;
|
||||
}
|
||||
|
||||
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
|
||||
{
|
||||
ssize_t nwritten = write(stream->fd, ptr, nmemb * size);
|
||||
if (nwritten < 0)
|
||||
return 0;
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
int fseek(FILE* stream, long offset, int whence)
|
||||
{
|
||||
off_t off = lseek(stream->fd, offset, whence);
|
||||
if (off < 0)
|
||||
return off;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long ftell(FILE* stream)
|
||||
{
|
||||
return lseek(stream->fd, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
void rewind(FILE* stream)
|
||||
{
|
||||
fseek(stream, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
static void sys_putch(char*&, char ch)
|
||||
|
@ -65,5 +163,24 @@ void perror(const char* s)
|
|||
printf("%s: %s\n", s, strerror(errno));
|
||||
}
|
||||
|
||||
FILE* fopen(const char* pathname, const char* mode)
|
||||
{
|
||||
assert(!strcmp(mode, "r") || !strcmp(mode, "rb"));
|
||||
int fd = open(pathname, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return nullptr;
|
||||
auto* fp = (FILE*)malloc(sizeof(FILE));
|
||||
fp->fd = fd;
|
||||
fp->eof = false;
|
||||
return fp;
|
||||
}
|
||||
|
||||
int fclose(FILE* stream)
|
||||
{
|
||||
int rc = close(stream->fd);
|
||||
free(stream);
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
16
LibC/stdio.h
16
LibC/stdio.h
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
@ -8,8 +9,13 @@ __BEGIN_DECLS
|
|||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
struct __STDIO_FILE {
|
||||
int fd;
|
||||
int eof;
|
||||
};
|
||||
|
||||
typedef struct __STDIO_FILE FILE;
|
||||
|
@ -18,11 +24,21 @@ extern FILE* stdin;
|
|||
extern FILE* stdout;
|
||||
extern FILE* stderr;
|
||||
|
||||
char* fgets(char* buffer, int size, FILE*);
|
||||
int fileno(FILE*);
|
||||
int fgetc(FILE*);
|
||||
int getc(FILE*);
|
||||
int getchar();
|
||||
FILE* fopen(const char* pathname, const char* mode);
|
||||
int fclose(FILE*);
|
||||
size_t fread(void* ptr, size_t size, size_t nmemb, FILE*);
|
||||
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE*);
|
||||
int fprintf(FILE*, const char* fmt, ...);
|
||||
int printf(const char* fmt, ...);
|
||||
int sprintf(char* buffer, const char* fmt, ...);
|
||||
int putchar(int ch);
|
||||
void perror(const char*);
|
||||
int sscanf (const char* buf, const char* fmt, ...);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -1,32 +1,50 @@
|
|||
#include "stdlib.h"
|
||||
#include "mman.h"
|
||||
#include "stdio.h"
|
||||
#include <stdlib.h>
|
||||
#include <mman.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <alloca.h>
|
||||
#include <Kernel/Syscall.h>
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
// FIXME: This is a temporary malloc() implementation. It never frees anything,
|
||||
// and you can't allocate more than 128 kB total.
|
||||
static const size_t mallocBudget = 131072;
|
||||
|
||||
static byte* nextptr = nullptr;
|
||||
static byte* endptr = nullptr;
|
||||
|
||||
void __malloc_init()
|
||||
{
|
||||
nextptr = (byte*)mmap(nullptr, mallocBudget);
|
||||
endptr = nextptr + mallocBudget;
|
||||
int rc = set_mmap_name(nextptr, mallocBudget, "malloc");
|
||||
if (rc < 0)
|
||||
perror("set_mmap_name failed");
|
||||
}
|
||||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
if (size > 4096) {
|
||||
if ((nextptr + size) > endptr) {
|
||||
volatile char* crashme = (char*)0xc007d00d;
|
||||
*crashme = 0;
|
||||
}
|
||||
void* ptr = mmap(nullptr, 4096);
|
||||
if (ptr) {
|
||||
int rc = set_mmap_name(ptr, 4096, "malloc");
|
||||
if (rc < 0) {
|
||||
perror("set_mmap_name failed");
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
byte* ret = nextptr;
|
||||
nextptr += size;
|
||||
nextptr += 16;
|
||||
nextptr = (byte*)((dword)nextptr & 0xfffffff0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void free(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
#if 0
|
||||
munmap(ptr, 4096);
|
||||
#endif
|
||||
}
|
||||
|
||||
void* calloc(size_t nmemb, size_t)
|
||||
|
@ -52,5 +70,41 @@ void abort()
|
|||
exit(253);
|
||||
}
|
||||
|
||||
char* getenv(const char* name)
|
||||
{
|
||||
for (size_t i = 0; environ[i]; ++i) {
|
||||
const char* decl = environ[i];
|
||||
char* eq = strchr(decl, '=');
|
||||
if (!eq)
|
||||
continue;
|
||||
size_t varLength = eq - decl;
|
||||
char* var = (char*)alloca(varLength + 1);
|
||||
memcpy(var, decl, varLength);
|
||||
var[varLength] = '\0';
|
||||
if (!strcmp(var, name)) {
|
||||
char* value = eq + 1;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int atoi(const char* str)
|
||||
{
|
||||
ssize_t len = strlen(str);
|
||||
int value = 0;
|
||||
bool isNegative = false;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (i == 0 && str[0] == '-') {
|
||||
isNegative = true;
|
||||
continue;
|
||||
}
|
||||
if (str[i] < '0' || str[i] > '9')
|
||||
return 0;
|
||||
value = value * 10;
|
||||
value += str[i] - '0';
|
||||
}
|
||||
return isNegative ? -value : value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ void* malloc(size_t);
|
|||
void free(void*);
|
||||
void* calloc(size_t nmemb, size_t);
|
||||
void* realloc(void *ptr, size_t);
|
||||
|
||||
char* getenv(const char* name);
|
||||
int atoi(const char*);
|
||||
|
||||
void exit(int status);
|
||||
void abort();
|
||||
|
|
|
@ -4,6 +4,40 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
void* memset(void* dest, int c, size_t n)
|
||||
{
|
||||
byte* bdest = (byte*)dest;
|
||||
for (; n; --n)
|
||||
*(bdest++) = c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
size_t strspn(const char* s, const char* accept)
|
||||
{
|
||||
const char* p = s;
|
||||
cont:
|
||||
char ch = *p++;
|
||||
char ac;
|
||||
for (const char* ap = accept; (ac = *ap++) != '\0';) {
|
||||
if (ac == ch)
|
||||
goto cont;
|
||||
}
|
||||
return p - 1 - s;
|
||||
}
|
||||
|
||||
size_t strcspn(const char* s, const char* reject)
|
||||
{
|
||||
for (auto* p = s;;) {
|
||||
char c = *p++;
|
||||
auto* rp = reject;
|
||||
char rc;
|
||||
do {
|
||||
if ((rc = *rp++) == c)
|
||||
return p - 1 - s;
|
||||
} while(rc);
|
||||
}
|
||||
}
|
||||
|
||||
size_t strlen(const char* str)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
@ -62,11 +96,22 @@ char* strchr(const char* str, int c)
|
|||
if (!str)
|
||||
return nullptr;
|
||||
char* ptr = (char*)str;
|
||||
while (*ptr != c)
|
||||
while (*ptr && *ptr != c)
|
||||
++ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char* strrchr(const char* str, int ch)
|
||||
{
|
||||
char *last = nullptr;
|
||||
char c;
|
||||
for (; (c = *str); ++str) {
|
||||
if (c == ch)
|
||||
last = (char*)str;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
char* strcat(char *dest, const char *src)
|
||||
{
|
||||
size_t destLength = strlen(dest);
|
||||
|
|
|
@ -9,11 +9,15 @@ size_t strlen(const char*);
|
|||
int strcmp(const char*, const char*);
|
||||
int memcmp(const void*, const void*, size_t);
|
||||
void memcpy(void*, const void*, size_t);
|
||||
void* memset(void*, int, size_t);
|
||||
char* strcpy(char* dest, const char* src);
|
||||
char* strncpy(char* dest, const char* src, size_t);
|
||||
char* strchr(const char*, int c);
|
||||
char* strrchr(const char*, int c);
|
||||
char* strcat(char *dest, const char *src);
|
||||
char* strncat(char *dest, const char *src, size_t);
|
||||
size_t strspn(const char*, const char* accept);
|
||||
size_t strcspn(const char*, const char* reject);
|
||||
const char* strerror(int errnum);
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -105,5 +105,11 @@ ssize_t readlink(const char* path, char* buffer, size_t size)
|
|||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
int rc = Syscall::invoke(Syscall::PosixLseek, (dword)fd, (dword)offset, (dword)whence);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern char** environ;
|
||||
|
||||
uid_t getuid();
|
||||
gid_t getgid();
|
||||
pid_t getpid();
|
||||
|
@ -22,6 +24,7 @@ int gethostname(char*, size_t);
|
|||
ssize_t readlink(const char* path, char* buffer, size_t);
|
||||
char* ttyname(int fd);
|
||||
int ttyname_r(int fd, char* buffer, size_t);
|
||||
off_t lseek(int fd, off_t, int whence);
|
||||
|
||||
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
|
||||
#define WTERMSIG(status) ((status) & 0x7f)
|
||||
|
|
|
@ -79,9 +79,8 @@ Unix::off_t FileHandle::seek(Unix::off_t offset, int whence)
|
|||
return -EINVAL;
|
||||
break;
|
||||
case SEEK_END:
|
||||
// FIXME: Implement!
|
||||
notImplemented();
|
||||
newOffset = 0;
|
||||
ASSERT(metadata.size); // FIXME: What do I do?
|
||||
newOffset = metadata.size;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -148,7 +147,7 @@ ssize_t FileHandle::get_dir_entries(byte* buffer, Unix::size_t size)
|
|||
// FIXME: Compute the actual size needed.
|
||||
auto tempBuffer = ByteBuffer::createUninitialized(2048);
|
||||
BufferStream stream(tempBuffer);
|
||||
m_vnode->vfs()->enumerateDirectoryInode(m_vnode->inode, [&stream] (const FileSystem::DirectoryEntry& entry) {
|
||||
m_vnode->vfs()->enumerateDirectoryInode(m_vnode->inode, [&stream] (auto& entry) {
|
||||
stream << (dword)entry.inode.index();
|
||||
stream << (byte)entry.fileType;
|
||||
stream << (dword)entry.name.length();
|
||||
|
|
Loading…
Add table
Reference in a new issue