Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2793709
  • 博文数量: 154
  • 博客积分: 7136
  • 博客等级: 准将
  • 技术积分: 1428
  • 用 户 组: 管理员
  • 注册时间: 2010-02-21 11:26
文章分类

全部博文(154)

文章存档

2016年(2)

2014年(2)

2013年(4)

2012年(16)

2011年(51)

2010年(68)

2009年(3)

2006年(3)

2005年(5)

分类:

2010-10-21 18:36:40

/*  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;
}

阅读(4262) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

anders09132012-10-16 09:16:20

send_linux2010-10-21 18:37:31