/* vsprintf.c
*I don't mean to write the whole OS kernel.I just want to put what I have
*already learned into practice.But what will it be end up looking like.
*I don't know.ALA I have some free time,I will write something.Just like
*linus once said,"Just for fun".I don't care what this small ugly codes
*will be capable of,or does it worth something.I just write it for fun,
*and for practice.
* 10 / 3 / 2010 liangtao
* E-mail:liangtao90s@gmail.com
*/
/*
* it's been a little busy recently.yesterday i spent the whole evening
* debugging all the code.and finally got it working properly.
* the memory-maped video memory is fixed, so it's not that flexible.
* i don't know much info about the video adapter. if anyone
* knows.CC me. many THANKS...
* i hope it won't be buggy anymore.i'm tired of debugging.
* 10 / 12 / 2010 liangtao
*/
/*
* this whole codes are totally bullshit.
* need to be completely rewriten
*/
#include
#include
#include
#include
#include
#define DEFAULT_COLOR 0x07
#define MAX_LINES 24
#define MAX_COLS 80
/*
* this value should be probed. but in bochs, seems that the defualt display mode
* is absolutely not the 7th display mode. add probing codes if you want to make sure
*/
#define VIDEO_START ((char *)0xb8000)
#define VIDEO_PORT 0x3d4
#define ORIG_X (*(unsigned char *)0x90000)
#define ORIG_Y (*(unsigned char *)0x90001)
#define VIDEO_MODE (*(unsigned char *)0x90002)
static char *video_mem;
static char *cur_video_mem;
static unsigned short original_x;
static unsigned short original_y;
static unsigned char video_mode;
static int lines;
static int cols;
void putstr_init(void)
{
video_mem = VIDEO_START;
original_x = ORIG_X;
original_y = ORIG_Y;
lines = MAX_LINES;
cols = MAX_COLS;
video_mode = VIDEO_MODE;
cur_video_mem = video_mem + original_x * 2 + original_y * 80 * 2;
}
/* to make this much faster, directly handle the registers. don't need to get that far */
static void scroll_down(void)
{
int i = cols;
memncpy(video_mem, video_mem + cols * 2, (lines - 1) * cols * 2);
i = cur_video_mem - video_mem - (lines - 1) * cols * 2;
i >>= 1;
while(i-- > 0) {
cur_video_mem -= 2;
*cur_video_mem = 0;
}
}
void __putstr(const char *str)
{
int x = original_x;
int y = original_y;
int pos;
char c;
while((c = *str++) != '\0')
{
if(c == '\n')
{
if(++y >= lines) {
scroll_down();
y--;
//cur_video_mem -= cols * 2;
} else {
cur_video_mem += (cols - x) * 2;
}
x = 0;
}
else
{
if(++x >= cols)
{
x = 0;
if(++y >= lines)
{
scroll_down();
y--;
//cur_video_mem -= cols * 2;
}
}
*cur_video_mem++ = c;
cur_video_mem++ ;//= x & 0xff ; //= DEFAULT_COLOR;
}
}
if(cur_video_mem > 0xa0000 + 64000)
cur_video_mem = 0xa0000;
pos = (x + cols * y) * 2;
outb_p(14, VIDEO_PORT);
outb_p(0xff & (pos >> 9), VIDEO_PORT + 1);
outb_p(15, VIDEO_PORT);
outb_p(0xff & (pos >> 1), VIDEO_PORT + 1);
/*
original_x = x;
original_y = y;
*/
}
/*
* it's a stupid way. But i don't want to work on the other alternative right now
* this mean if we call putstr from user mode, Then we have trap into kernel mode to do this.
* because the call scroll_down is rather time consuming.when doing
*/
void putstr(const char *str)
{
cli();
__putstr(str);
sti();
}
__syscall1(void, stupid_putstr, const char *, str)
/* you can tell by the name */
void sys_stupid_putstr(const char *str)
{
cli();
__putstr(str);
sti();
}
#define SIGN 1
#define SMALL 2
#define PREFIX 4
/* cause we're totally on our own, we can't use "%" */
#define do_div(n,base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res; })
static inline char *num2str(char *str, long num, int base, int fildwidth, \
int precision, int flags)
{
static const char digit[] = "0123456789abcdef";
char tmp[64];
int i=0;
if(flags & SIGN)
*str++ = '-';
if(flags & PREFIX) {
*str++ = '0';
if(base == 16)
*str++ = 'x';
}
if(num == 0)
tmp[i++] = '0';
else
while(num != 0)
tmp[i++] = digit[do_div(num, base)];
while(--i >= 0)
*str++ = tmp[i];
return str;
}
/* much more work should be done on this */
int vsprintf(char *buf, const char *fmt, va_list args)
{
char *str, *s;
int base;
int flags = 0;
int fildwidth = -1;
int precision = -1;
int qualifier;
unsigned long num;
for(str = buf; *fmt != '\0'; fmt++) {
if(*fmt == '\t') {
int k = 8;
while(k--)
*str++ = ' ';
fmt++;
}
if(*fmt != '%') {
*str++ = *fmt;
continue;
}
handle_flags:
fmt++;
switch (*fmt) {
case '#':
flags |= PREFIX;
goto handle_flags;
}
/* handle_fldwidth: */
/* don't need this now */
/* handle_precision: */
/* don't need this now */
/* handle_lenmodifier: */
/* don't need this now */
/* handle_qualifier: */
qualifier = -1;
if(*fmt == 'l' || *fmt == 'L' || *fmt == 'h') {
qualifier = *fmt;
fmt++;
}
/* handle_convtype: */
base = 10;
switch(*fmt) {
case 'c':
/* processing alignment */
*str = (unsigned char)va_arg(args, int);
/* processing alignment */
continue;
case 's':
s = va_arg(args, char *);
str = strcpy(str, s); /* is it safe? */
str--;
continue;
case 'd':
break;
case 'o':
base = 8;
break;
case 'x':
flags |= SMALL;
case 'X':
base = 16;
break;
default:
*str++ = '%';
if(*fmt)
*str++ = *fmt;
else
fmt--;
continue;
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
else if (qualifier == 'h')
num = (unsigned short)va_arg(args, int);
else {
num = va_arg(args, int);
}
str = num2str(str, num, base, fildwidth, precision, flags);
}
*str = '\0';
return str - buf;
}
/* to versions, one can be called in kernel mode, the other one from user mode */
int printf(const char *fmt, ...)
{
char buf[1024];
va_list args;
int cnt;
va_start(args, fmt);
cnt = vsprintf(buf, fmt, args);
va_end(args);
putstr(buf);
return cnt;
}
printf_user(const char *fmt, ...)
{
char buf[1024];
va_list args;
int cnt;
va_start(args, fmt);
cnt = vsprintf(buf, fmt, args);
va_end(args);
stupid_putstr(buf);
return cnt;
}
阅读(4255) | 评论(2) | 转发(0) |