added stdio functionality
This commit is contained in:
parent
990391144c
commit
78f56d916c
2
limine
2
limine
@ -1 +1 @@
|
||||
Subproject commit e0e61c946933696453f591da525ab1f8a66a553d
|
||||
Subproject commit eecf8d682a749701691e31b89f66f330f525c611
|
||||
BIN
obj/src/int.c.o
BIN
obj/src/int.c.o
Binary file not shown.
@ -1,6 +1,7 @@
|
||||
obj/src/main.c.o: src/main.c src/../include/limine.h src/prompt/lex.h \
|
||||
src/prompt/file.h src/acpi.h src/common.h src/alloc.h src/apic.h \
|
||||
src/map.h src/print.h
|
||||
src/kbd.h src/map.h src/print.h src/lib/stdio.h src/lib/malloc.h \
|
||||
src/lib/../common.h src/lib/../kbd.h src/lib/../print.h
|
||||
src/../include/limine.h:
|
||||
src/prompt/lex.h:
|
||||
src/prompt/file.h:
|
||||
@ -8,5 +9,11 @@ src/acpi.h:
|
||||
src/common.h:
|
||||
src/alloc.h:
|
||||
src/apic.h:
|
||||
src/kbd.h:
|
||||
src/map.h:
|
||||
src/print.h:
|
||||
src/lib/stdio.h:
|
||||
src/lib/malloc.h:
|
||||
src/lib/../common.h:
|
||||
src/lib/../kbd.h:
|
||||
src/lib/../print.h:
|
||||
|
||||
BIN
obj/src/main.c.o
BIN
obj/src/main.c.o
Binary file not shown.
2
run.sh
2
run.sh
@ -1 +1 @@
|
||||
qemu-system-x86_64 image.hdd
|
||||
/mnt/c/'Program Files'/qemu/qemu-system-x86_64.exe image.hdd
|
||||
|
||||
29
src/alloc.c
29
src/alloc.c
@ -3,6 +3,19 @@
|
||||
#include "common.h"
|
||||
#include "print.h"
|
||||
|
||||
#ifdef DBG
|
||||
#define dprint(x) print(x)
|
||||
#define dprint8(x) print8(x)
|
||||
#define dprint16(x) print16(x)
|
||||
#define dprint32(x) print32(x)
|
||||
#define dprint64(x) print64(x)
|
||||
#else
|
||||
#define dprint(x)
|
||||
#define dprint8(x)
|
||||
#define dprint16(x)
|
||||
#define dprint32(x)
|
||||
#define dprint64(x)
|
||||
#endif
|
||||
__attribute__((
|
||||
used,
|
||||
section(".limine_requests"))) static volatile struct limine_memmap_request
|
||||
@ -106,7 +119,7 @@ static void usepage(size_t page) {
|
||||
}
|
||||
|
||||
static void usepagerange(size_t page, size_t len) {
|
||||
for (size_t i = 0; i < len; len++) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
usepage(i + page);
|
||||
}
|
||||
}
|
||||
@ -118,7 +131,7 @@ static void unusepage(size_t page) {
|
||||
}
|
||||
|
||||
static void unusepagerange(size_t page, size_t len) {
|
||||
for (size_t i = 0; i < len; len++) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
unusepage(i + page);
|
||||
}
|
||||
}
|
||||
@ -144,9 +157,10 @@ void *alloc(size_t size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
print("Attempting to find ");
|
||||
print64(pages);
|
||||
print(" consecutive pages\n");
|
||||
|
||||
dprint("Attempting to find ");
|
||||
dprint64(pages);
|
||||
dprint(" consecutive pages.....");
|
||||
size_t consecutive = 0;
|
||||
|
||||
for (size_t i = 0; i < total_pages / 64; i++) {
|
||||
@ -157,6 +171,7 @@ void *alloc(size_t size) {
|
||||
consecutive += 64;
|
||||
if (consecutive >= pages) {
|
||||
usepagerange(page, pages);
|
||||
dprint("succeeded!\n");
|
||||
return addr(page);
|
||||
}
|
||||
continue;
|
||||
@ -174,6 +189,7 @@ void *alloc(size_t size) {
|
||||
|
||||
if (++consecutive >= pages) {
|
||||
usepagerange(page, pages);
|
||||
dprint("succeeded!\n");
|
||||
return addr(page);
|
||||
}
|
||||
} else {
|
||||
@ -183,5 +199,8 @@ void *alloc(size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
dprint("failed :(!\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -11,3 +11,4 @@ static inline u64 virt_to_phys(void *virt) { return (u64)virt - hhdm_offset; }
|
||||
static inline void *phys_to_virt(u64 phys) {
|
||||
return (void *)(phys + hhdm_offset);
|
||||
}
|
||||
|
||||
|
||||
37
src/kbd.c
37
src/kbd.c
@ -72,6 +72,25 @@ char kbd_buffer_getc() {
|
||||
return c;
|
||||
}
|
||||
|
||||
static u8 held_map[0x100/16];
|
||||
static void hold_key(u8 key) {
|
||||
key &= (0x100/2)-1;
|
||||
|
||||
held_map[key>>3] |= (1 << (key & 7));
|
||||
}
|
||||
|
||||
static void release_key(u8 key) {
|
||||
key &= (0x100/2)-1;
|
||||
|
||||
held_map[key>>3] &= ~(1 << (key & 7));
|
||||
}
|
||||
|
||||
static bool key_held(u8 key) {
|
||||
key &= (0x100/2)-1;
|
||||
|
||||
return (held_map[key>>3] & (1 << (key & 7)));
|
||||
}
|
||||
|
||||
void kbd_handler() {
|
||||
u8 scancode = inb(PS2_DATA_PORT);
|
||||
bool released = (scancode & 0x80);
|
||||
@ -91,6 +110,7 @@ void kbd_handler() {
|
||||
if(!released) {
|
||||
kbd_state.caps = !kbd_state.caps;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -106,18 +126,29 @@ void kbd_handler() {
|
||||
|
||||
|
||||
if(kbd_state.caps && c >= 'a' && c <= 'z') {
|
||||
|
||||
c = c - 'a' + 'A';
|
||||
} else if(kbd_state.caps && c >= 'A' && c <= 'Z') {
|
||||
c = c - 'A' + 'a';
|
||||
}
|
||||
|
||||
if(c != 0) {
|
||||
if(c != 0 && !key_held(scancode)) {
|
||||
kbd_buffer_putc(c);
|
||||
}
|
||||
printn(&c, 1);
|
||||
|
||||
hold_key(scancode);
|
||||
} else {
|
||||
release_key(scancode);
|
||||
}
|
||||
|
||||
|
||||
send_eoi();
|
||||
}
|
||||
|
||||
int kbd_getc_blocking() {
|
||||
int ch;
|
||||
|
||||
while(!(ch =kbd_buffer_getc()))
|
||||
;
|
||||
|
||||
return ch;
|
||||
}
|
||||
@ -1,2 +1,4 @@
|
||||
#pragma once
|
||||
void kbd_handler();
|
||||
int kbd_getc_blocking();
|
||||
char kbd_buffer_getc();
|
||||
33
src/lib/malloc.c
Normal file
33
src/lib/malloc.c
Normal file
@ -0,0 +1,33 @@
|
||||
#include <stddef.h>
|
||||
#include "../alloc.h"
|
||||
|
||||
struct malloc_header {
|
||||
size_t size;
|
||||
};
|
||||
|
||||
void* malloc(size_t sz) {
|
||||
size_t total = sz + sizeof(struct malloc_header);
|
||||
|
||||
struct malloc_header* mh = alloc(total);
|
||||
if(!mh)
|
||||
return mh;
|
||||
mh->size = total;
|
||||
return (void*)(&mh[1]);
|
||||
}
|
||||
|
||||
void* calloc(size_t sz, size_t n) {
|
||||
// for now ignore the case of sz * n > 1 << 64
|
||||
size_t N = sz * n;
|
||||
u8* ptr = malloc(N);
|
||||
for(size_t i = 0; i < N; i++)
|
||||
ptr[i] = 0;
|
||||
}
|
||||
|
||||
void free(void* ptr) {
|
||||
if(!ptr) {
|
||||
return;
|
||||
}
|
||||
size_t sz = ((struct malloc_header*)ptr)[-1].size;
|
||||
|
||||
dealloc(ptr, sz);
|
||||
}
|
||||
5
src/lib/malloc.h
Normal file
5
src/lib/malloc.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void* malloc(size_t sz);
|
||||
void* calloc(size_t sz, size_t n);
|
||||
void* free(void* ptr);
|
||||
475
src/lib/stdio.h
Normal file
475
src/lib/stdio.h
Normal file
@ -0,0 +1,475 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "malloc.h"
|
||||
#include "../common.h"
|
||||
#include "../kbd.h"
|
||||
#include "../print.h"
|
||||
|
||||
#define MAX_LINE_LEN 256
|
||||
|
||||
static inline int puts(const char *s) {
|
||||
print(s);
|
||||
put('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define _STDIO_PEEK_BUFF_EMPTY -1
|
||||
static int _stdio_peek_buf = _STDIO_PEEK_BUFF_EMPTY;
|
||||
/* getc – blocking, consumes one character */
|
||||
static inline int getc(void) {
|
||||
if (_stdio_peek_buf >= 0) {
|
||||
int c = _stdio_peek_buf;
|
||||
_stdio_peek_buf = -1;
|
||||
return c;
|
||||
}
|
||||
return kbd_getc_blocking();
|
||||
}
|
||||
|
||||
/* peek – blocking, returns next char WITHOUT consuming it */
|
||||
static inline int peek(void) {
|
||||
if (_stdio_peek_buf < 0)
|
||||
_stdio_peek_buf = kbd_getc_blocking();
|
||||
return _stdio_peek_buf;
|
||||
}
|
||||
|
||||
/* getc_nb – non-blocking version; returns -1 if no char ready */
|
||||
static inline int getc_nb(void) {
|
||||
if (_stdio_peek_buf >= 0) {
|
||||
int c = _stdio_peek_buf;
|
||||
_stdio_peek_buf = _STDIO_PEEK_BUFF_EMPTY;
|
||||
return c;
|
||||
}
|
||||
int c = kbd_buffer_getc();
|
||||
return c ? c : _STDIO_PEEK_BUFF_EMPTY;
|
||||
}
|
||||
|
||||
/* peek_nb – non-blocking peek; returns -1 if no char ready */
|
||||
static inline int peek_nb(void) {
|
||||
if (_stdio_peek_buf < 0) {
|
||||
int c = kbd_buffer_getc();
|
||||
if (!c) return -1;
|
||||
_stdio_peek_buf = c;
|
||||
}
|
||||
return _stdio_peek_buf;
|
||||
}
|
||||
|
||||
static inline char *getline_alloc(size_t max_hint) {
|
||||
size_t cap = max_hint > 0 ? max_hint : 128;
|
||||
char *buf = (char *)malloc(cap);
|
||||
if (!buf) {
|
||||
print("getline_alloc failed to alloc! :(\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
|
||||
for (;;) {
|
||||
int c = getc();
|
||||
|
||||
|
||||
|
||||
if (c == '\b') { /* backspace */
|
||||
if (len > 0) {
|
||||
len--;
|
||||
unput();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* grow buffer if needed (leave room for NUL) */
|
||||
if (len + 1 >= cap) {
|
||||
size_t new_cap = cap * 2;
|
||||
char *new_buf = (char *)malloc(new_cap);
|
||||
if (!new_buf) { free(buf); print("getline_alloc failed to alloc! :(\n"); return NULL; }
|
||||
for (size_t i = 0; i < len; i++) new_buf[i] = buf[i];
|
||||
free(buf);
|
||||
buf = new_buf;
|
||||
cap = new_cap;
|
||||
}
|
||||
|
||||
buf[len++] = (char)c;
|
||||
if (c == '\n' || c == '\r') {
|
||||
put('\n');
|
||||
break;
|
||||
} else {
|
||||
put(c); /* echo */
|
||||
}
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline int getline_buf(char *buf, size_t n) {
|
||||
if (!buf || n == 0) return -1;
|
||||
size_t len = 0;
|
||||
|
||||
for (;;) {
|
||||
int c = getc();
|
||||
|
||||
if (c == '\n' || c == '\r') {
|
||||
put('\n');
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\b') {
|
||||
if (len > 0) { len--; unput(); }
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len < n - 1) {
|
||||
buf[len++] = (char)c;
|
||||
put(c);
|
||||
}
|
||||
/* else: buffer full – keep echoing but discard */
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
|
||||
static inline char *_fmt_uint(char *end, u64 val, int base, bool upper) {
|
||||
static const char lo[] = "0123456789abcdef";
|
||||
static const char up[] = "0123456789ABCDEF";
|
||||
const char *digs = upper ? up : lo;
|
||||
*--end = '\0';
|
||||
if (val == 0) { *--end = '0'; return end; }
|
||||
while (val) { *--end = digs[val % (u64)base]; val /= (u64)base; }
|
||||
return end;
|
||||
}
|
||||
|
||||
static inline int vprintf(const char *fmt, va_list ap) {
|
||||
int written = 0;
|
||||
|
||||
#define _EMIT(c) do { put(c); written++; } while(0)
|
||||
#define _EMITS(s) do { const char *_p=(s); while(*_p){_EMIT(*_p);_p++;} } while(0)
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt != '%') { _EMIT(*fmt++); continue; }
|
||||
fmt++; /* skip '%' */
|
||||
|
||||
/* flags */
|
||||
bool left_align = false;
|
||||
bool zero_pad = false;
|
||||
if (*fmt == '-') { left_align = true; fmt++; }
|
||||
if (*fmt == '0') { zero_pad = true; fmt++; }
|
||||
|
||||
/* width */
|
||||
int width = 0;
|
||||
while (*fmt >= '0' && *fmt <= '9') width = width*10 + (*fmt++ - '0');
|
||||
|
||||
/* length modifier */
|
||||
int lng = 0; /* 0=int, 1=long, 2=long long */
|
||||
if (*fmt == 'l') { lng=1; fmt++; }
|
||||
if (*fmt == 'l') { lng=2; fmt++; }
|
||||
|
||||
char tmp[66];
|
||||
char *s = NULL;
|
||||
char cbuf[2] = {0,0};
|
||||
bool neg = false;
|
||||
|
||||
switch (*fmt++) {
|
||||
case '%':
|
||||
_EMIT('%');
|
||||
continue;
|
||||
|
||||
case 'c':
|
||||
cbuf[0] = (char)va_arg(ap, int);
|
||||
s = cbuf;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
s = va_arg(ap, char *);
|
||||
if (!s) s = "(null)";
|
||||
break;
|
||||
|
||||
case 'd': case 'i': {
|
||||
i64 v = (lng==2) ? va_arg(ap,long long) :
|
||||
(lng==1) ? va_arg(ap,long) :
|
||||
va_arg(ap,int);
|
||||
if (v < 0) { neg = true; v = -v; }
|
||||
s = _fmt_uint(tmp+65, (u64)v, 10, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'u': {
|
||||
u64 v = (lng==2) ? va_arg(ap,unsigned long long) :
|
||||
(lng==1) ? va_arg(ap,unsigned long) :
|
||||
va_arg(ap,unsigned int);
|
||||
s = _fmt_uint(tmp+65, v, 10, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'o': {
|
||||
u64 v = (lng==2) ? va_arg(ap,unsigned long long) :
|
||||
(lng==1) ? va_arg(ap,unsigned long) :
|
||||
va_arg(ap,unsigned int);
|
||||
s = _fmt_uint(tmp+65, v, 8, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'x': {
|
||||
u64 v = (lng==2) ? va_arg(ap,unsigned long long) :
|
||||
(lng==1) ? va_arg(ap,unsigned long) :
|
||||
va_arg(ap,unsigned int);
|
||||
s = _fmt_uint(tmp+65, v, 16, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'X': {
|
||||
u64 v = (lng==2) ? va_arg(ap,unsigned long long) :
|
||||
(lng==1) ? va_arg(ap,unsigned long) :
|
||||
va_arg(ap,unsigned int);
|
||||
s = _fmt_uint(tmp+65, v, 16, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
u64 v = (u64)(uintptr_t)va_arg(ap, void *);
|
||||
print("0x");
|
||||
written += 2;
|
||||
s = _fmt_uint(tmp+65, v, 16, false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
_EMIT('?');
|
||||
continue;
|
||||
}
|
||||
|
||||
/* padding / output */
|
||||
int slen = 0;
|
||||
for (const char *p = s; *p; p++) slen++;
|
||||
if (neg) slen++; /* for '-' */
|
||||
|
||||
int pad = width - slen;
|
||||
|
||||
if (!left_align && pad > 0) {
|
||||
char pc = zero_pad ? '0' : ' ';
|
||||
if (neg && zero_pad) { _EMIT('-'); neg=false; written++; }
|
||||
while (pad-- > 0) { _EMIT(pc); written++; }
|
||||
}
|
||||
if (neg) { _EMIT('-'); written++; }
|
||||
while (*s) { _EMIT(*s++); written++; }
|
||||
if (left_align && pad > 0)
|
||||
while (pad-- > 0) { _EMIT(' '); written++; }
|
||||
}
|
||||
|
||||
#undef _EMIT
|
||||
#undef _EMITS
|
||||
return written;
|
||||
}
|
||||
|
||||
static inline int printf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int r = vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
typedef struct { char *p; size_t rem; } _sbuf;
|
||||
|
||||
/* We re-implement the inner loop targeting a string buffer instead of the
|
||||
* screen. Factoring out a shared back-end with a function pointer would be
|
||||
* cleaner but adds complexity; this keeps it self-contained. */
|
||||
static inline int vsnprintf(char *out, size_t size, const char *fmt, va_list ap) {
|
||||
if (!out || !size) return 0;
|
||||
char *cur = out;
|
||||
char *end = out + size - 1; /* leave room for NUL */
|
||||
int written = 0;
|
||||
|
||||
#define _SEMIT(c) do { if(cur<end){*cur++=(char)(c);} written++; } while(0)
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt != '%') { _SEMIT(*fmt++); continue; }
|
||||
fmt++;
|
||||
|
||||
bool left_align=false, zero_pad=false;
|
||||
if (*fmt=='-'){left_align=true;fmt++;}
|
||||
if (*fmt=='0'){zero_pad=true;fmt++;}
|
||||
int width=0;
|
||||
while(*fmt>='0'&&*fmt<='9') width=width*10+(*fmt++-'0');
|
||||
int lng=0;
|
||||
if(*fmt=='l'){lng=1;fmt++;}
|
||||
if(*fmt=='l'){lng=2;fmt++;}
|
||||
|
||||
char tmp[66];
|
||||
char *s=NULL;
|
||||
char cbuf[2]={0,0};
|
||||
bool neg=false;
|
||||
|
||||
switch(*fmt++) {
|
||||
case '%': _SEMIT('%'); continue;
|
||||
case 'c': cbuf[0]=(char)va_arg(ap,int); s=cbuf; break;
|
||||
case 's': s=va_arg(ap,char*); if(!s)s="(null)"; break;
|
||||
case 'd': case 'i': {
|
||||
i64 v=(lng==2)?va_arg(ap,long long):(lng==1)?va_arg(ap,long):va_arg(ap,int);
|
||||
if(v<0){neg=true;v=-v;}
|
||||
s=_fmt_uint(tmp+65,(u64)v,10,false); break;
|
||||
}
|
||||
case 'u': {
|
||||
u64 v=(lng==2)?va_arg(ap,unsigned long long):(lng==1)?va_arg(ap,unsigned long):va_arg(ap,unsigned int);
|
||||
s=_fmt_uint(tmp+65,v,10,false); break;
|
||||
}
|
||||
case 'o': {
|
||||
u64 v=(lng==2)?va_arg(ap,unsigned long long):(lng==1)?va_arg(ap,unsigned long):va_arg(ap,unsigned int);
|
||||
s=_fmt_uint(tmp+65,v,8,false); break;
|
||||
}
|
||||
case 'x': {
|
||||
u64 v=(lng==2)?va_arg(ap,unsigned long long):(lng==1)?va_arg(ap,unsigned long):va_arg(ap,unsigned int);
|
||||
s=_fmt_uint(tmp+65,v,16,false); break;
|
||||
}
|
||||
case 'X': {
|
||||
u64 v=(lng==2)?va_arg(ap,unsigned long long):(lng==1)?va_arg(ap,unsigned long):va_arg(ap,unsigned int);
|
||||
s=_fmt_uint(tmp+65,v,16,true); break;
|
||||
}
|
||||
case 'p': {
|
||||
u64 v=(u64)(uintptr_t)va_arg(ap,void*);
|
||||
_SEMIT('0'); _SEMIT('x'); written+=2;
|
||||
s=_fmt_uint(tmp+65,v,16,false); break;
|
||||
}
|
||||
default: _SEMIT('?'); continue;
|
||||
}
|
||||
|
||||
int slen=0; for(const char*p=s;*p;p++) slen++; if(neg) slen++;
|
||||
int pad=width-slen;
|
||||
if(!left_align&&pad>0){char pc=zero_pad?'0':' '; if(neg&&zero_pad){_SEMIT('-');neg=false;} while(pad-->0){_SEMIT(pc);}}
|
||||
if(neg){_SEMIT('-');}
|
||||
while(*s){_SEMIT(*s++);}
|
||||
if(left_align&&pad>0) while(pad-->0){_SEMIT(' ');}
|
||||
}
|
||||
#undef _SEMIT
|
||||
*cur = '\0';
|
||||
return written;
|
||||
}
|
||||
|
||||
static inline int snprintf(char *out, size_t size, const char *fmt, ...) {
|
||||
va_list ap; va_start(ap, fmt);
|
||||
int r = vsnprintf(out, size, fmt, ap);
|
||||
va_end(ap); return r;
|
||||
}
|
||||
|
||||
static inline int sprintf(char *out, const char *fmt, ...) {
|
||||
va_list ap; va_start(ap, fmt);
|
||||
/* pass a huge size – caller's responsibility to have enough room */
|
||||
int r = vsnprintf(out, (size_t)-1, fmt, ap);
|
||||
va_end(ap); return r;
|
||||
}
|
||||
|
||||
static inline int _skip_ws(const char **p) {
|
||||
while (**p==' '||**p=='\t'||**p=='\n'||**p=='\r') (*p)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int vsscanf(const char *str, const char *fmt, va_list ap) {
|
||||
const char *s = str;
|
||||
int matched = 0;
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt == ' ') { _skip_ws(&s); fmt++; continue; }
|
||||
if (*fmt != '%') {
|
||||
if (*s != *fmt) return matched;
|
||||
s++; fmt++; continue;
|
||||
}
|
||||
fmt++; /* skip '%' */
|
||||
if (*fmt == '%') { if (*s=='%') s++; fmt++; continue; }
|
||||
|
||||
int lng = 0;
|
||||
if (*fmt=='l'){lng=1;fmt++;}
|
||||
if (*fmt=='l'){lng=2;fmt++;}
|
||||
|
||||
_skip_ws(&s);
|
||||
|
||||
switch (*fmt++) {
|
||||
case 'c': {
|
||||
char *out = va_arg(ap, char*);
|
||||
if (!*s) return matched;
|
||||
*out = *s++;
|
||||
matched++;
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
char *out = va_arg(ap, char*);
|
||||
if (!*s) return matched;
|
||||
while (*s && *s!=' '&&*s!='\t'&&*s!='\n'&&*s!='\r')
|
||||
*out++ = *s++;
|
||||
*out = '\0';
|
||||
matched++;
|
||||
break;
|
||||
}
|
||||
case 'd': case 'i': {
|
||||
bool neg2 = false;
|
||||
if (*s=='-'){neg2=true;s++;}
|
||||
else if(*s=='+') s++;
|
||||
if (*s<'0'||*s>'9') return matched;
|
||||
i64 v=0;
|
||||
while(*s>='0'&&*s<='9') v=v*10+(*s++-'0');
|
||||
if(neg2) v=-v;
|
||||
if(lng==2) *va_arg(ap,long long*)=(long long)v;
|
||||
else if(lng==1) *va_arg(ap,long*)=(long)v;
|
||||
else *va_arg(ap,int*)=(int)v;
|
||||
matched++;
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
if(*s<'0'||*s>'9') return matched;
|
||||
u64 v=0;
|
||||
while(*s>='0'&&*s<='9') v=v*10+(*s++-'0');
|
||||
if(lng==2) *va_arg(ap,unsigned long long*)=(unsigned long long)v;
|
||||
else if(lng==1) *va_arg(ap,unsigned long*)=(unsigned long)v;
|
||||
else *va_arg(ap,unsigned int*)=(unsigned int)v;
|
||||
matched++;
|
||||
break;
|
||||
}
|
||||
case 'x': case 'X': {
|
||||
if(*s=='0'&&(*(s+1)=='x'||*(s+1)=='X')) s+=2;
|
||||
u64 v=0; bool any=false;
|
||||
while((*s>='0'&&*s<='9')||(*s>='a'&&*s<='f')||(*s>='A'&&*s<='F')){
|
||||
u8 d=(*s>='a')?*s-'a'+10:(*s>='A')?*s-'A'+10:*s-'0';
|
||||
v=v*16+d; s++; any=true;
|
||||
}
|
||||
if(!any) return matched;
|
||||
if(lng==2) *va_arg(ap,unsigned long long*)=(unsigned long long)v;
|
||||
else if(lng==1) *va_arg(ap,unsigned long*)=(unsigned long)v;
|
||||
else *va_arg(ap,unsigned int*)=(unsigned int)v;
|
||||
matched++;
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
if(*s<'0'||*s>'7') return matched;
|
||||
u64 v=0;
|
||||
while(*s>='0'&&*s<='7') v=v*8+(*s++-'0');
|
||||
if(lng==2) *va_arg(ap,unsigned long long*)=(unsigned long long)v;
|
||||
else if(lng==1) *va_arg(ap,unsigned long*)=(unsigned long)v;
|
||||
else *va_arg(ap,unsigned int*)=(unsigned int)v;
|
||||
matched++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
static inline int sscanf(const char *str, const char *fmt, ...) {
|
||||
va_list ap; va_start(ap, fmt);
|
||||
int r = vsscanf(str, fmt, ap);
|
||||
va_end(ap); return r;
|
||||
}
|
||||
|
||||
|
||||
static inline int scanf(const char *fmt, ...) {
|
||||
char *line = getline_alloc(MAX_LINE_LEN);
|
||||
if (!line) return -1;
|
||||
va_list ap; va_start(ap, fmt);
|
||||
int r = vsscanf(line, fmt, ap);
|
||||
va_end(ap);
|
||||
free(line);
|
||||
return r;
|
||||
}
|
||||
48
src/main.c
48
src/main.c
@ -12,8 +12,10 @@ void print_tok(struct token* tok);
|
||||
#include "alloc.h"
|
||||
#include "apic.h"
|
||||
#include "common.h"
|
||||
#include "kbd.h"
|
||||
#include "map.h"
|
||||
#include "print.h"
|
||||
#include "lib/stdio.h"
|
||||
|
||||
// credit owed to https://wiki.osdev.org/Limine_Bare_Bones for the limine setup
|
||||
// code
|
||||
@ -110,7 +112,8 @@ void draw(u8 vect) {
|
||||
for (size_t y = 0; y < fb->height; y++) {
|
||||
for (size_t x = 0; x < fb->width; x++) {
|
||||
volatile u32 *fb_ptr = fb->address;
|
||||
fb_ptr[y * fb->width + x] = (((x ^ y) & 0xff) * 0x0F0003) * vect;
|
||||
int tone = ((x ^ y) & 0xFF) >> 6;
|
||||
fb_ptr[y * fb->width + x] = (tone << 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -153,8 +156,8 @@ void kmain() {
|
||||
draw(1);
|
||||
print_init(fb);
|
||||
init_idt();
|
||||
bg = 0xFFFFFF;
|
||||
fg = 0x000000;
|
||||
fg = 0xFFFFFF;
|
||||
bg = 0x000000;
|
||||
|
||||
if (!hhdm_req.response) {
|
||||
print("Failed to get higher half direct mapping\n.");
|
||||
@ -197,19 +200,30 @@ void kmain() {
|
||||
apic_enable();
|
||||
print("APIC Enabled\n");
|
||||
ioapic_init();
|
||||
const char* src[] = {
|
||||
"u8 main(u32 x) {\n",
|
||||
" u16 y = x + 16;\n",
|
||||
" u8 z = x * y;\n",
|
||||
" return z; }\n"
|
||||
};
|
||||
|
||||
const char* name = "prompt> ";
|
||||
asm volatile("sti");
|
||||
|
||||
#define LINES 40
|
||||
size_t max_len = MAX_LINE_LEN;
|
||||
char* line = getline_alloc(max_len);
|
||||
char* lines[LINES];
|
||||
|
||||
size_t n_lines = 0;
|
||||
for(n_lines = 0; n_lines < LINES; n_lines++) {
|
||||
line = getline_alloc(max_len);
|
||||
if(!line)
|
||||
break;
|
||||
if(line[0] == 'F' && line[1] == 'I' && line[2] == '\n')
|
||||
break;
|
||||
lines[n_lines] = line;
|
||||
}
|
||||
|
||||
const char* name = "stdin";
|
||||
struct file input = {
|
||||
.row = 0,
|
||||
.col = 0,
|
||||
.rows = 4,
|
||||
.lines = (char**)src,
|
||||
.rows = n_lines,
|
||||
.lines = (char**)lines,
|
||||
.name = name,
|
||||
.tokens = NULL,
|
||||
.tail = &input.tokens,
|
||||
@ -217,21 +231,15 @@ void kmain() {
|
||||
|
||||
int res = lex(&input);
|
||||
|
||||
print("Result from lexing: ");
|
||||
print("Number of Errors: ");
|
||||
print8(res);
|
||||
|
||||
if(res != 0) {
|
||||
hang();
|
||||
}
|
||||
|
||||
printf("\n# of Tokens: %d\n", input.tokens->len);
|
||||
struct token* token = input.tokens;
|
||||
|
||||
for(;token; token = token->next) {
|
||||
print_tok(token);
|
||||
}
|
||||
|
||||
|
||||
|
||||
asm volatile("sti");
|
||||
hang();
|
||||
}
|
||||
|
||||
43
src/print.c
43
src/print.c
@ -14,20 +14,24 @@ static volatile u32 *fb_scr;
|
||||
#define TAB_STOP 4
|
||||
|
||||
// buffer at each edge for readability
|
||||
#define TERM_WIDTH (FONT_WIDTH + 2)
|
||||
#define TERM_HEIGHT (FONT_HEIGHT + 2)
|
||||
#define GLYPH_WIDTH (FONT_WIDTH + 2)
|
||||
#define GLYPH_HEIGHT (FONT_HEIGHT + 2)
|
||||
|
||||
void print_init(struct limine_framebuffer *fb) {
|
||||
term_width = fb->width / TERM_WIDTH;
|
||||
term_height = fb->height / TERM_HEIGHT;
|
||||
term_width = fb->width / GLYPH_WIDTH;
|
||||
term_height = fb->height / GLYPH_HEIGHT;
|
||||
fb_width = fb->width;
|
||||
fb_height = fb->height;
|
||||
fb_scr = fb->address;
|
||||
}
|
||||
|
||||
static void scrollback() {
|
||||
memmove((void *)fb_scr, (void *)(fb_scr + fb_width * TERM_HEIGHT),
|
||||
fb_width * (fb_height - TERM_HEIGHT) * sizeof(u32));
|
||||
memmove((void *)fb_scr, (void *)(fb_scr + fb_width * GLYPH_HEIGHT),
|
||||
fb_width * (fb_height - GLYPH_HEIGHT) * sizeof(u32));
|
||||
size_t last_row_start = (term_height - 1) * fb_width;
|
||||
for (size_t i = 0; i < fb_width; i++) {
|
||||
fb_scr[last_row_start + i] = bg;
|
||||
}
|
||||
}
|
||||
|
||||
void put(int ch) {
|
||||
@ -63,14 +67,14 @@ void put(int ch) {
|
||||
size_t idx = ch - ' ';
|
||||
u32 glyph = font[idx];
|
||||
|
||||
size_t px = col * TERM_WIDTH;
|
||||
size_t py = row * TERM_HEIGHT;
|
||||
size_t px = col * GLYPH_WIDTH;
|
||||
size_t py = row * GLYPH_HEIGHT;
|
||||
|
||||
for (size_t y = 0; y < TERM_HEIGHT; y++) {
|
||||
for (size_t x = 0; x < TERM_WIDTH; x++) {
|
||||
for (size_t y = 0; y < GLYPH_HEIGHT; y++) {
|
||||
for (size_t x = 0; x < GLYPH_WIDTH; x++) {
|
||||
size_t off = (py + y) * fb_width + (px + x);
|
||||
bool padding =
|
||||
(y == 0 || y == TERM_HEIGHT - 1 || x == 0 || x == TERM_WIDTH - 1);
|
||||
(y == 0 || y == GLYPH_HEIGHT - 1 || x == 0 || x == GLYPH_WIDTH - 1);
|
||||
fb_scr[off] = ((~glyph & 1) | padding) ? bg : fg;
|
||||
glyph >>= !padding;
|
||||
}
|
||||
@ -112,3 +116,20 @@ void print64(u64 n) {
|
||||
print32(n >> 32);
|
||||
print32(n & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void unput(void) {
|
||||
if (col > 0) {
|
||||
col--;
|
||||
} else if (row > 0) {
|
||||
row--;
|
||||
col = term_width - 1;
|
||||
} else {
|
||||
return; /* already at (0,0), nothing to erase */
|
||||
}
|
||||
|
||||
size_t px = col * GLYPH_WIDTH;
|
||||
size_t py = row * GLYPH_HEIGHT;
|
||||
for (size_t y = 0; y < GLYPH_HEIGHT; y++)
|
||||
for (size_t x = 0; x < GLYPH_WIDTH; x++)
|
||||
fb_scr[(py + y) * fb_width + (px + x)] = bg;
|
||||
}
|
||||
@ -13,3 +13,4 @@ void print32(u32 n);
|
||||
void print16(u16 n);
|
||||
void print8(u8 n);
|
||||
void print_init(struct limine_framebuffer *fb);
|
||||
void unput(void);
|
||||
|
||||
@ -6,8 +6,11 @@
|
||||
|
||||
static int lex_error(struct file* state, const char* err) {
|
||||
print(state->name);
|
||||
print("[");
|
||||
print16(state->row+1);
|
||||
print(":");
|
||||
print16(state->col+1);
|
||||
print("] ");
|
||||
print(err);
|
||||
print("\n");
|
||||
return 1;
|
||||
@ -74,14 +77,12 @@ static struct token* tok(enum tokentype type, struct file* state, int col, void*
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool isdigit(int ch) {
|
||||
return (ch <= '9' && ch >= '0');
|
||||
}
|
||||
|
||||
static bool isxdigit(int ch) {
|
||||
return ((ch <= '9' && ch >= '0') || (ch <= 'F' && ch >= 'A') || (ch <= 'F' && ch >= 'A'));
|
||||
}
|
||||
|
||||
static bool isalpha(int ch) {
|
||||
return (ch <= 'z' && ch >= 'a')
|
||||
|| (ch <= 'Z' && ch >= 'A');
|
||||
@ -103,6 +104,10 @@ static int tolower(int ch) {
|
||||
return ch;
|
||||
}
|
||||
|
||||
static bool isxdigit(int ch) {
|
||||
return isdigit(ch) || (isalpha(ch) && tolower(ch) <= 'f');
|
||||
}
|
||||
|
||||
// cribbed from musl
|
||||
static bool isspace(int ch) {
|
||||
return ch == ' ' || (unsigned)ch-'\t' < 5;
|
||||
@ -113,7 +118,10 @@ static int parse_num(struct file* state, int save, int sign) {
|
||||
int ch = state->lines[state->row][state->col];
|
||||
if(ch == '0' && state->lines[state->row][state->col+1] == 'x') {
|
||||
state->col+=2;
|
||||
if(!isdigit(state->lines[state->row][state->col])) {
|
||||
if(!isxdigit(state->lines[state->row][state->col])) {
|
||||
print("On input: '");
|
||||
printn(&state->lines[state->row][state->col], 1);
|
||||
print("'\n");
|
||||
lex_error(state, "expected hexadecimal digits in hex literal");
|
||||
return 1;
|
||||
}
|
||||
@ -155,7 +163,7 @@ int lex(struct file* state) {
|
||||
if(state->row >= state->rows)
|
||||
return 0;
|
||||
while(isspace(state->lines[state->row][state->col])) {
|
||||
if(state->lines[state->row][state->col] == '\n') {
|
||||
if(state->lines[state->row][state->col] == '\n' || !state->lines[state->row][state->col]) {
|
||||
state->col = 0;
|
||||
state->row++;
|
||||
if(state->row >= state->rows)
|
||||
@ -168,7 +176,7 @@ int lex(struct file* state) {
|
||||
if(state->lines[state->row][state->col] == '/' && state->lines[state->row][state->col+1] == '*') {
|
||||
state->col += 2;
|
||||
while(!(state->lines[state->row][state->col] == '*' && state->lines[state->row][state->col+1] == '/')) {
|
||||
if(state->lines[state->row][state->col] == '\n') {
|
||||
if(state->lines[state->row][state->col] == '\n' || !state->lines[state->row][state->col]) {
|
||||
state->col = -1;
|
||||
state->row++;
|
||||
if(state->row >= state->rows)
|
||||
@ -177,7 +185,7 @@ int lex(struct file* state) {
|
||||
state->col++;
|
||||
}
|
||||
state->col += 2;
|
||||
if(state->lines[state->row][state->col] == '\n') {
|
||||
if(state->lines[state->row][state->col] == '\n' || !state->lines[state->row][state->col]) {
|
||||
state->row++;
|
||||
state->col = 0;
|
||||
}
|
||||
@ -240,7 +248,7 @@ int lex(struct file* state) {
|
||||
print8(ch);
|
||||
print(") '");
|
||||
printn(&ch,1);
|
||||
print("\n");
|
||||
print("'\n");
|
||||
state->col++;
|
||||
return 1 + lex(state);
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ static size_t strlen(const char* str) {
|
||||
extern u32 fg, bg;
|
||||
|
||||
void print_tok(struct token* tok) {
|
||||
u32 savebg = bg, savefg = fg;
|
||||
/* header: [file:row:col] */
|
||||
print("[");
|
||||
print(tok->file->name);
|
||||
@ -29,24 +30,28 @@ void print_tok(struct token* tok) {
|
||||
}
|
||||
print("] ");
|
||||
|
||||
u32 color = fg;
|
||||
switch (tok->type) {
|
||||
case TOK_KEYWORD:
|
||||
color = 0xFF3322;
|
||||
print("keyword: ");
|
||||
print(keywords[tok->keyword]);
|
||||
print("\n");
|
||||
break;
|
||||
case TOK_NUM:
|
||||
color = 0x3322FF;
|
||||
print("number: ");
|
||||
print(" (");
|
||||
print64((unsigned long)tok->num);
|
||||
print("):\n");
|
||||
break;
|
||||
case TOK_IDEN: {
|
||||
color = 0x137FFF;
|
||||
struct iden* id = &identbl[tok->iden];
|
||||
print("iden: { .hash = 0x");
|
||||
print32(id->hash);
|
||||
print(", .data = \"");
|
||||
print(*id->data);
|
||||
print(id->data);
|
||||
print("\" (");
|
||||
/* print pointer value as hex */
|
||||
print("ptr"); /* pointer printing omitted; add if needed */
|
||||
@ -56,6 +61,7 @@ void print_tok(struct token* tok) {
|
||||
break;
|
||||
}
|
||||
case TOK_OP: {
|
||||
color = 0xBEDEAD;
|
||||
print("operator: ");
|
||||
print(ops[tok->op]);
|
||||
print(" (#");
|
||||
@ -64,6 +70,7 @@ void print_tok(struct token* tok) {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
color = 0x00FF00;
|
||||
/* print single char and hex */
|
||||
char c[2] = { (char)tok->type, 0 };
|
||||
print(c);
|
||||
@ -108,13 +115,15 @@ void print_tok(struct token* tok) {
|
||||
printn(tok->file->lines[tok->row], tok->col);
|
||||
|
||||
/* print token text */
|
||||
fg = color;
|
||||
if (tok->len > 0)
|
||||
printn(tok->file->lines[tok->row] + tok->col, tok->len);
|
||||
fg = savefg;
|
||||
bg = savebg;
|
||||
|
||||
/* print rest of line after token */
|
||||
printn(tok->file->lines[tok->row] + tok->col + tok->len,
|
||||
strlen(tok->file->lines[tok->row] + tok->col + tok->len));
|
||||
print("\n");
|
||||
|
||||
/* caret line */
|
||||
print("\t | ");
|
||||
@ -125,7 +134,7 @@ void print_tok(struct token* tok) {
|
||||
print(" ");
|
||||
}
|
||||
}
|
||||
u32 savebg = bg, savefg = fg;
|
||||
|
||||
fg = bg;
|
||||
bg = ~fg;
|
||||
print("^");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user