diff --git a/boot/Makefile b/boot/Makefile index fc930db..9c506df 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -5,7 +5,7 @@ PROG = boot SRCS = srt0.S gdt.S boot.c OBJS = srt0.o gdt.o boot.o -ESRCS = pccon.c sricon.c print.c a20.c time.c mem.c +ESRCS = pccon.c sricon.c print.c fmt.c a20.c time.c mem.c OBJS += $(ESRCS:.c=.o) include $(SDIR)/Makefile.inc diff --git a/boot/dat.h b/boot/dat.h index d71c07e..dedfe79 100644 --- a/boot/dat.h +++ b/boot/dat.h @@ -2,6 +2,7 @@ // 0x60 Read/Write Data Port // 0x64 Read Status Register // 0x64 Write Command Register +#define TABWIDTH 8 enum{ CON_PC, @@ -42,6 +43,16 @@ typedef struct{ u32 type; /* Type of block */ } __attribute__((packed)) BIOSmmap; +// fmt.c +typedef struct{ + int ucase; + int padch; + char *p; + char *ep; + int f1, f2, f3; + va_list ap; +}Op; + // gdt.S extern volatile struct BIOSreg BIOSreg; diff --git a/boot/fmt.c b/boot/fmt.c new file mode 100644 index 0000000..6d1ca01 --- /dev/null +++ b/boot/fmt.c @@ -0,0 +1,304 @@ +#include +#include "dat.h" +#include "fn.h" + +#define MAXCON 30 +#define IDIGIT 30 + +enum{ + FLONG = (1<<0), + FSHORT = (1<<2), + FUNSIGN = (1<<3), +}; + +static Op put(Op, int); +static Op noconv(Op); +static Op cconv(Op); +static Op dconv(Op); +static Op hconv(Op); +static Op lconv(Op); +static Op sconv(Op); +static Op uconv(Op); +static Op xconv(Op); +static Op Xconv(Op); +static Op percent(Op); + +static Op (*fmtconv[MAXCON])(Op) = { + noconv, + cconv, dconv, hconv, lconv, + sconv, uconv, xconv, Xconv, + percent, +}; + +int fmtindex[128] = { + ['c'] = 1, + ['d'] = 2, + ['h'] = 3, + ['l'] = 4, + ['s'] = 5, + ['u'] = 6, + ['x'] = 7, + ['X'] = 8, + ['%'] = 9, +}; +int convcnt = 11; + +int +strlen(char *s) +{ + char *p = s; + + while(*p) + ++p; + return p-s; +} + +int +fmtinstall(int c, Op (*f)(Op)) +{ + c &= 0177; + if(fmtindex[c] == 0){ + if(convcnt + 1 >= MAXCON) + return -1; + fmtindex[c] = convcnt++; + } + fmtconv[fmtindex[c]] = f; + return 0; +} + +char* +doprint(char *p, char *ep, char *fmt, va_list ap) +{ + int sf1, c; + Op o = { .p = p, .ep = ep, .ap = ap }; + + while(1){ + c = *fmt++; + if(c != '%'){ + if(c == 0){ + if(o.p < o.ep) + *o.p = 0; + return o.p; + } + o = put(o, c); + continue; + } + o.f2 = -1; + o.f1 = o.f3 = 0; + o.padch = sf1 = 0; + c = *fmt++; + if(c == '-'){ + sf1 = 1; + c = *fmt++; + }else if(c == '0' || c == ' '){ + o.padch = c; + c = *fmt++; + } + while(c >= '0' && c <= '9'){ + o.f1 = o.f1*10 + c-'0'; + c = *fmt++; + } + if(sf1) + o.f1 = -o.f1; + if(c != '.') + goto conv; + c = *fmt++; + while(c >= '0' && c <= '9'){ + if(o.f2 < 0) + o.f2 = 0; + o.f2 = o.f2*10 + c-'0'; + c = *fmt++; + } +conv: + if(c == 0) + fmt -= 1; + o = (*fmtconv[fmtindex[c&0177]])(o); + if(o.f3){ + c = *fmt++; + goto conv; + } + } +} + +static Op +strconv(char *o, Op op, int f1, int f2) +{ + int n, c; + char *p; + + n = strlen(o); + if(f1 >= 0) + while(n < f1){ + op = put(op, op.padch); + n += 1; + } + for(p=o; (c = *p++);) + if(f2){ + op = put(op, c); + f2 -= 1; + } + if(f1 < 0){ + f1 = -f1; + while(n < f1){ + op = put(op, ' '); + n += 1; + } + } + return op; +} + +static Op +numconv(Op op, int base) +{ + char b[IDIGIT]; + int i,f,n; + long v; + short h; + + i = IDIGIT-1; + f = 0; + b[i] = 0; + switch(op.f3 & (FLONG|FSHORT|FUNSIGN)){ + case FLONG: + v = va_arg(op.ap, long); + break; + case FUNSIGN|FLONG: + v = va_arg(op.ap, ulong); + break; + case FSHORT: + v = h = va_arg(op.ap, short); + break; + case FUNSIGN|FSHORT: + h = va_arg(op.ap, ushort); + v = (ushort)h; + break; + case FUNSIGN: + v = va_arg(op.ap, unsigned); + break; + default: + v = va_arg(op.ap, long); + break; + } + if((op.f3 & FUNSIGN) && v < 0){ + v = -v; + f = 1; + } + while(--i){ + n = v % base; + n += '0'; + if(n > '9'){ + n += 'a' - ('9'+1); + if(op.ucase) + n += 'A'-'a'; + } + b[i] = n; + v = (ulong)v / base; + if(i < 2) + break; + if(op.f2 >= 0 && i >= IDIGIT - op.f2) + continue; + if(v <= 0) + break; + } + if(f) + b[--i] = '-'; + op.f3 = 0; + return strconv(b+i, op, op.f1, -1); +} + +static Op +noconv(Op op) +{ + return strconv("***ERROR: noconv***", op, 0, -1); +} + +static Op +cconv(Op op) +{ + char b[2]; + + b[0] = va_arg(op.ap, char); + b[1] = 0; + return strconv(b, op, op.f1, -1); +} + +static Op +dconv(Op op) +{ + return numconv(op, 10); +} + +static Op +hconv(Op op) +{ + op.f3 |= FSHORT; + return op; +} + +static Op +lconv(Op op) +{ + op.f3 |= FLONG; + return op; +} + +static Op +uconv(Op op) +{ + op.f3 |= FUNSIGN; + return op; +} + +static Op +sconv(Op op) +{ + char *p; + + p = va_arg(op.ap, char*); + return strconv(p?p:"", op, op.f1, op.f2); +} + +static Op +xconv(Op op) +{ + return numconv(op, 16); +} + +static Op +Xconv(Op op) +{ + op.ucase = 1; + op = numconv(op, 16); + op.ucase = 0; + return op; +} + +static Op +percent(Op op) +{ + return put(op, '%'); +} + +static Op +put(Op o, int c) +{ + static int pos; + int opos; + + if(c == 0) + return o; + if(c == '\t'){ + opos = pos; + pos = (opos+TABWIDTH) & (~(TABWIDTH-1)); + while(opos++ < pos && o.p < o.ep) + *o.p++ = ' '; + return o; + } + if(o.p < o.ep){ + *o.p++ = c; + pos++; + } + if(c == '\n') + pos = 0; + return o; +} \ No newline at end of file diff --git a/boot/fn.h b/boot/fn.h index 1231d2a..faa32d0 100644 --- a/boot/fn.h +++ b/boot/fn.h @@ -11,10 +11,17 @@ int comprobe(ConDev *d); int comgetc(int dev); void computc(int dev, int c); +// fmt.c +int fmtinstall(int c, Op (*f)(Op)); +char *doprint(char *p, char *ep, char *fmt, va_list ap); +int strlen(char *s); + // print.c void putchar(int c); +void putstr(char *s, int l); int getchar(void); -void print(const char *fmt, ...); +int print(char *fmt, ...); +int snprint(char *buf, int len, char *fmt, ...); // a20.c void a20up(void); diff --git a/boot/mem.c b/boot/mem.c index e0a23fe..7d2170f 100644 --- a/boot/mem.c +++ b/boot/mem.c @@ -42,13 +42,13 @@ dumpmem(BIOSmmap *m) ulong tot = 0; for(BIOSmmap *p=m; p->type != MAP_END; ++p){ - print("MEM %u type %u size %lldKB at 0x%llx\n", - p-m, p->type, p->size/1024, p->addr); + print("MEM % 2ud type %ud size % 10udKB at %08x:%08x\n", + p-m, p->type, (uint)(p->size/1024), (uint)(p->addr>>32), (uint)p->addr); if(p->type == MAP_FREE) tot += p->size/1024; } - print("RAM low:%dKB high:%dKB\n", cnvmem, extmem); - print("Total free memory: %dKB\n", tot); + print("RAM low:%udKB high:%udKB\n", cnvmem, extmem); + print("Total free memory: %udKB\n", tot); } static int @@ -70,13 +70,12 @@ memprobe(void) m->type = MAP_END; for(m = biosmmap; m->type != MAP_END; ++m){ if(m->type != MAP_FREE || m->size <= 0) - continue; + continue; if(m->addr < IOMEM_BEGIN) cnvmem = MAX(cnvmem, m->addr + m->size)/1024; if(m->addr >= IOMEM_END) extmem += m->size/1024; } dumpmem(biosmmap); - print("A20:%d", isa20done()); -} - + print("A20:%s\n", isa20done() ? "ok" : "no"); +} \ No newline at end of file diff --git a/boot/print.c b/boot/print.c index 647e82d..4ef3644 100644 --- a/boot/print.c +++ b/boot/print.c @@ -2,61 +2,42 @@ #include "dat.h" #include "fn.h" -#define TABWIDTH 4 +#define BUFSIZE 1024 -static void conputc(int c); +static void conputc(int); static int congetc(void); -static void doprint(void (*put)(int), const char *fmt, va_list ap); -static void putint(void (*put)(int), int n, const char *sym, int base); -static int pos = 0; -void -print(const char *fmt, ...) +int +print(char *fmt, ...) { + char buf[BUFSIZE], *p; va_list args; va_start(args, fmt); - doprint(putchar, fmt, args); + p = doprint(buf, buf+sizeof(buf), fmt, args); va_end(args); + putstr(buf, p-buf); + return p-buf; } -static void -doprint(void (*put)(int), const char *s, va_list ap) +int +snprint(char *buf, int len, char *fmt, ...) { - while(*s){ - if(*s != '%'){ - put(*s++); - continue; - } - ++s; - switch(*s){ - case 'd': - putint(put, va_arg(ap,int), "0123456789", 10); - break; - case 'x': - putint(put, va_arg(ap,int), "0123456789abcdef", 16); - break; - case 'X': - putint(put, va_arg(ap,int), "0123456789ABCDEF", 16); - break; - case 's': - for(char *p=va_arg(ap,char*); *p; ++p) - put(*p); - break; - default: - return; - } - ++s; - } -} + char *p; + va_list args; + va_start(args, fmt); + p = doprint(buf, buf+len, fmt, args); + va_end(args); + return p-buf; +} int getchar(void) { int c; - c = congetc(); + c = congetc(); if(c == '\r') c = '\n'; if((c < ' ' && c != '\n') || c == '\177') @@ -65,6 +46,13 @@ getchar(void) return c; } +void +putstr(char *s, int l) +{ + while(l--) + putchar(*s++); +} + void putchar(int c) { @@ -72,24 +60,20 @@ putchar(int c) case '\177': conputc('\b'); conputc(' '); + break; case '\b': conputc('\b'); - if(pos > 0) - --pos; break; case '\t': - do{ + for(int i = 0; i < TABWIDTH; ++i) conputc(' '); - }while(++pos % TABWIDTH); break; case '\n': case '\r': conputc(c); - pos = 0; break; default: conputc(c); - ++pos; break; } } @@ -108,20 +92,4 @@ static int congetc(void) { return con->getc(con->dev); -} - -static void -putint(void (*put)(int), int n, const char *sym, int base) -{ - int i; - char buf[16]; - - i = 0; - do{ - buf[i++] = n%base; - n /= base; - }while(n); - do{ - put((int)sym[(int)buf[--i]]); - }while(i); } \ No newline at end of file