/* 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. Load more
/* 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;