1215 lines · 31.4 KB · C
RawDownload
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved	by Bram Moolenaar * * Do ":help uganda"  in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * os_plan9.c * * Plan 9 system-dependent routines. */ #include <signal.h>#include <setjmp.h>#include <fcntl.h>#include <lib9.h>#include <draw.h>#include <keyboard.h>#include <event.h>#include <plumb.h>#include "vim.h" /* Vim defines Display.  We need it for libdraw. */#undef Display /* We need to access the native Plan 9 alarm() since * it takes milliseconds rather than seconds. */extern int _ALARM(unsigned long);extern int _SLEEP(long); enum {    /* Text modes are in sync with term.c */    TMODE_NORMAL  = 0,    TMODE_REVERSE = 1,    TMODE_BOLD    = 2,     NCOLORS       = 256}; static int scr_inited;static Point fontsize;static Point shellsize;static Rectangle scrollregion;static int currow; /* TODO use a Point */static int curcol;static Image *cursorsave;static Image *colortab[NCOLORS];static Image *fgcolor;static Image *bgcolor;static Font *normalfont;static Font *boldfont;static Font *curfont;static int curmode; /* TODO remove this, use cterm_normal_fg_color instead for comparing */static int plumbkey;static int done; /* Timeouts are handled using alarm() and a signal handler. * When an alarm happens during a syscall, the syscall is * interrupted.  We use setjmp() to handle control flow from * interrupted library functions. */static int interruptable;static jmp_buf timeoutjmpbuf; static void err9(char *msg) {    char errs[256];    /* TODO */    errstr(errs, sizeof errs);    fprintf(stderr, "%s: %s\n", msg, errs);    exit(1);} /* Error handler for libdraw */static void derr(Display*, char *msg) {    if (interruptable && strcmp(msg, "eof on event pipe") == 0) {        longjmp(timeoutjmpbuf, 1);    }    err9(msg);} static void drain_plumb_events(void) {    Event e;    Plumbmsg *m;    char *addr;    int l = ECMD_ONE;     while(ecanread(plumbkey)){	eread(plumbkey, &e);	m = e.v;	if(m == nil)		return;	addr = plumblookup(m->attr, "addr");	if(addr)		l = atoi(addr);	do_ecmd(0, (char_u*)m->data, NULL, NULL, (linenr_T)l, ECMD_HIDE);	shell_resized();    }} static void start_plumber_thread(void){	switch (rfork(RFPROC|RFMEM)){	case -1:		fprintf(stderr, "rfork failed\n");		return;	case 0:		while(!done){			drain_plumb_events();			_SLEEP(100);		}		exit(0);	default:		break;	}} int mch_has_wildcard(char_u *p) {    for (; *p; mb_ptr_adv(p)) {        if (*p == '\\' && p[1] != NUL) {            ++p;        } else if (vim_strchr((char_u *)"*?[{`'$", *p) != NULL ||                (*p == '~' && p[1] != NUL)) {            return TRUE;        }    }    return FALSE;} int mch_has_exp_wildcard(char_u *p) {    for (; *p; mb_ptr_adv(p))    {        if (*p == '\\' && p[1] != NUL)            ++p;        else            if (vim_strchr((char_u *) "*?[{'", *p) != NULL)                return TRUE;    }    return FALSE;} int mch_expandpath(garray_T *gap, char_u *pat, int flags) {    return unix_expandpath(gap, pat, 0, flags, FALSE);} int mch_isdir(char_u *name) {    struct stat st;    if (stat((char*)name, &st) != 0) {        return FALSE;    }    return S_ISDIR(st.st_mode) ? TRUE : FALSE;} static int executable_file(char_u *name){    struct stat	st;     if (stat((char *)name, &st))        return 0;    return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;} int mch_isFullName(char_u *fname) {    return fname[0] == '/' || fname[0] == '#';} int mch_can_exe(char_u *name) {    char_u	*buf;    char_u	*p, *e;    int		retval;     /* If it's an absolute or relative path don't need to use $path. */    if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'				      || (name[1] == '.' && name[2] == '/'))))        return executable_file(name);     p = (char_u *)getenv("path");    if (p == NULL || *p == NUL)        return -1;    buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));    if (buf == NULL)        return -1;     /*     * Walk through all entries in $PATH to check if "name" exists there and     * is an executable file.     */    for (;;)    {        e = (char_u *)strchr((char *)p, '\01');        if (e == NULL)            e = p + STRLEN(p);        if (e - p <= 1)		/* empty entry means current dir */            STRCPY(buf, "./");        else        {            vim_strncpy(buf, p, e - p);            add_pathsep(buf);        }        STRCAT(buf, name);        retval = executable_file(buf);        if (retval == 1)            break;         if (*e != '\01')            break;        p = e + 1;    }     vim_free(buf);    return retval;} int mch_dirname(char_u *buf, int len) {    return (getcwd((char*)buf, len) ? OK : FAIL);} long mch_getperm(char_u *name) {    struct stat st;    if (stat((char*)name, &st) < 0) {        return -1;    }    return st.st_mode;} int mch_setperm(char_u *name, long perm) {    return chmod((char*)name, (mode_t)perm) == 0 ? OK : FAIL;} int mch_remove(char_u *name) {    return remove((char*)name);} void mch_hide(char_u*) {    /* Do nothing */} /* getuser() and sysname() can be implemented using this. */static int read_value_from_file(char *fname, char_u *s, int len) {    int fd;    int n;    fd = open(fname, O_RDONLY);    if (fd < 0) {        vim_strncpy(s, (char_u*)"none", len - 1);        return FAIL;    }    n = read(fd, s, len - 1);    if (n <= 0) {        vim_strncpy(s, (char_u*)"none", len - 1);    } else {        s[n] = '\0';    }    close(fd);    return (n > 0) ? OK : FAIL;} int mch_get_user_name(char_u *s, int len) {    return read_value_from_file("/dev/user", s, len);} void mch_get_host_name(char_u *s, int len) {    read_value_from_file("/dev/sysname", s, len);} void mch_settmode(int) {    /* Do nothing */} int mch_screenmode(char_u*) {    /* Always fail */    EMSG(_(e_screenmode));    return FAIL;} static void scr_stamp_cursor(void) {    if (cursorsave) {        draw(cursorsave, Rect(0, 0, fontsize.x, fontsize.y),                screen, nil, Pt(screen->clipr.min.x + curcol * fontsize.x,                    screen->clipr.min.y + currow * fontsize.y));        drawop(screen, Rect(screen->clipr.min.x + curcol * fontsize.x,                    screen->clipr.min.y + currow * fontsize.y,                    screen->clipr.min.x + (curcol + 1) * fontsize.x,                    screen->clipr.min.y + (currow + 1) * fontsize.y),                colortab[cterm_normal_fg_color - 1], cursorsave, ZP, SoverD);    }} static void scr_unstamp_cursor(void) {    if (cursorsave) {        Rectangle r;        r = Rect(screen->clipr.min.x + curcol * fontsize.x,                screen->clipr.min.y + currow * fontsize.y,                screen->clipr.min.x + (curcol + 1) * fontsize.x,                screen->clipr.min.y + (currow + 1) * fontsize.y);        draw(screen, r, cursorsave, nil, ZP);    }} static void scr_pos(int row, int col) {    currow = row;    curcol = col;} static void scr_clear(void) {    scr_pos(0, 0);    draw(screen, screen->clipr, bgcolor, nil, ZP);    draw(cursorsave, Rect(0, 0, fontsize.x, fontsize.y), bgcolor, nil, ZP);} static void scr_scroll_down(int nlines) {    Rectangle r;    Point pt;     /* Copy up visible part of scroll region */    r = Rect(screen->clipr.min.x + scrollregion.min.x * fontsize.x,            screen->clipr.min.y + scrollregion.min.y * fontsize.y,            screen->clipr.min.x + scrollregion.max.x * fontsize.x,            screen->clipr.min.y + (scrollregion.max.y - nlines) * fontsize.y);    pt = Pt(screen->clipr.min.x + scrollregion.min.x * fontsize.x,            screen->clipr.min.y + (scrollregion.min.y + nlines) * fontsize.y);    draw(screen, r, screen, nil, pt);     /* Clear newly exposed part of scroll region */    r.min.y = r.max.y;    r.max.y = screen->clipr.min.y + scrollregion.max.y * fontsize.y;    draw(screen, r, bgcolor, nil, ZP);} static void scr_scroll_up(int nlines) {    Rectangle r;    Point pt;     /* Copy down visible part of scroll region */    r = Rect(screen->clipr.min.x + scrollregion.min.x * fontsize.x,            screen->clipr.min.y + (scrollregion.min.y + nlines) * fontsize.y,            screen->clipr.min.x + scrollregion.max.x * fontsize.x,            screen->clipr.min.y + scrollregion.max.y * fontsize.y);    pt = Pt(screen->clipr.min.x + scrollregion.min.x * fontsize.x,            screen->clipr.min.y + scrollregion.min.y * fontsize.y);    draw(screen, r, screen, nil, pt);     /* Clear newly exposed part of scroll region */    r.max.y = r.min.y;    r.min.y = screen->clipr.min.y + scrollregion.min.y * fontsize.y;    draw(screen, r, bgcolor, nil, ZP);} static void scr_set_color(Image **cp, int c) {    if (c >= 0 && c < NCOLORS) {        *cp = colortab[c];    }} void mch_set_normal_colors(void) {    char_u	*p;    int		n;     if (cterm_normal_fg_color == 0) {	cterm_normal_fg_color = 1;    }    if (cterm_normal_bg_color == 0) {	cterm_normal_bg_color = 16;    }    if (T_ME[0] == ESC && T_ME[1] == '|')    {	p = T_ME + 2;	n = getdigits(&p);	if (*p == 'm' && n > 0)	{	    cterm_normal_fg_color = (n & 0xf) + 1;	    cterm_normal_bg_color = ((n >> 4) & 0xf) + 1;	}    }     scr_set_color(&bgcolor, cterm_normal_bg_color - 1);    scr_set_color(&fgcolor, cterm_normal_fg_color - 1);} static void scr_tmode(int mode) {    Image *tmp;    if ((curmode & TMODE_REVERSE) != (mode & TMODE_REVERSE)) {        tmp = fgcolor;        fgcolor = bgcolor;        bgcolor = tmp;    }    if (mode & TMODE_BOLD) {        curfont = boldfont;    } else {        curfont = normalfont;    }    if (mode == TMODE_NORMAL) {	scr_set_color(&bgcolor, cterm_normal_bg_color - 1);	scr_set_color(&fgcolor, cterm_normal_fg_color - 1);    }    curmode = mode;} /* Read a number and return bytes consumed. */static int scr_escape_number(char *p, int len, int *n) {    int num;    int chlen;    if (len == 0) {        return -1;    }    num = 0;    chlen = 0;    while (len && isdigit(*p)) {        num = num * 10 + (*p - '0');        p++;        len--;        chlen++;    }    *n = num;    return chlen;} /* Handle escape sequence and return number of bytes consumed. */static int scr_escape_sequence(char *p, int len) {    int nlines;    int n1;    int n2;    int i;    int chlen;     if (len == 0) {        return 0;    }     chlen = 1;    switch (*p) {        case 'J': /* clear screen */            scr_clear();            break;         case '0': case '1': case '2': case '3': case '4':        case '5': case '6': case '7': case '8': case '9':            n1 = -1;            n2 = -1;             /* First number */            i = scr_escape_number(p, len, &n1);            if (i == -1) {                /* TODO */                fprintf(stderr, "scr_escape_sequence: escape at end of string\n");                exit(1);            }            p += i;            len -= i;            chlen += i;             /* Optional second number */            if (len && *p == ';') {                p += 1;                len -= 1;                chlen += 1;                i = scr_escape_number(p, len, &n2);                if (i == -1) {                    /* TODO */                    fprintf(stderr, "scr_escape_sequence: missing second number\n");                    exit(1);                }                p += i;                len -= i;                chlen += i;            }             if (len == 0) {                /* TODO */                fprintf(stderr, "scr_escape_sequence: early end of escape sequence\n");		trash_input_buf();		return 0;            }             switch (*p) {                case 'b': /* background color */                    scr_set_color(&bgcolor, n1);                    break;                 case 'f': /* foreground color */                    scr_set_color(&fgcolor, n1);                    break;                 case 'H': /* cursor motion */                    scr_pos(n1, n2);                    break;                 case 'm': /* mode */                    scr_tmode(n1);                    break;                 case 'R': /* scroll region */                    scrollregion.min.y = n1;                    scrollregion.max.y = n2 + 1;                    break;                 case 'V': /* scroll region vertical */                    scrollregion.min.x = n1;                    scrollregion.max.x = n2 + 1;                    break;

Lines 1–500 of 1215.