/* 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 #include #include #include #include #include #include #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); enum { /* Text modes are in sync with term.c */ TMODE_NORMAL = 0, TMODE_REVERSE = 1, TMODE_BOLD = 2, NCOLORS = 16 }; 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 */ /* 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); } 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)); border(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), 2, colortab[cterm_normal_fg_color - 1], ZP); } } 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"); exit(1); } 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; default: /* TODO */ fprintf(stderr, "scr_escape_sequence: unimplemented (p=%c)\n", *p); exit(1); } break; case 'K': /* clear to end of line */ draw(screen, Rect(screen->clipr.min.x + curcol * fontsize.x, screen->clipr.min.y + currow * fontsize.y, screen->clipr.max.x, screen->clipr.min.y + (currow + 1) * fontsize.y), bgcolor, nil, ZP); break; case 'L': /* add new blank line */ p++; nlines = 1; while (len >= 3 && p[0] == '\x1b' && p[1] == '[' && p[2] == 'L') { nlines++; len -= 3; p += 3; chlen += 3; } /* TODO what if nlines >= scroll region size */ scr_scroll_up(nlines); break; default: /* TODO */ fprintf(stderr, "scr_escape_sequence: unhandled sequence (p=%c)\n", *p); exit(1); } return chlen; } /* Handle special characters. */ static int write_special(char *p, int len) { int n; int nbytes; if (len == 0) { return 0; } nbytes = 0; while (len > 0) { switch (*p) { case '\a': /* Bell */ /* There is no bell on Plan 9. */ break; case '\b': /* Backspace */ if (curcol > scrollregion.min.x) { scr_pos(currow, curcol - 1); } else if (currow > scrollregion.min.y) { scr_pos(currow - 1, scrollregion.max.x - 1); } break; case '\n': /* New line */ for (n = 0; n < len && *p == '\n'; n++) { p++; } if (currow + n >= scrollregion.max.y) { scr_scroll_down(currow + n - scrollregion.max.y + 1); scr_pos(scrollregion.max.y - 1, scrollregion.min.x); } else { scr_pos(currow + n, scrollregion.min.x); } len -= n; nbytes += n; continue; /* process next character */ case '\r': /* Carriage return */ curcol = scrollregion.min.x; break; case '\x1b': /* Escape sequences */ if (len > 1 && p[1] == '[') { n = 2; n += scr_escape_sequence(p + 2, len - 2); p += n; len -= n; nbytes += n; continue; /* process next character */ } break; default: /* Normal character */ return nbytes; } p++; len--; nbytes++; } return nbytes; } /* Draw normal characters. */ static int write_str(char *p, int len) { int nbytes; int n; int m; if (len == 0) { return 0; } for (nbytes = 0; nbytes < len && p[nbytes] != '\a' && p[nbytes] != '\b' && p[nbytes] != '\n' && p[nbytes] != '\r' && p[nbytes] != '\x1b'; len--, nbytes++) ; n = nbytes; while (n > 0) { m = (curcol + n >= scrollregion.max.x) ? scrollregion.max.x - curcol : n; if (m == 0) { break; } stringnbg(screen, Pt(screen->clipr.min.x + curcol * fontsize.x, screen->clipr.min.y + currow * fontsize.y), fgcolor, ZP, curfont, p, m, bgcolor, ZP); curcol += m; if (curcol == scrollregion.max.x) { curcol = scrollregion.min.x; if (currow == scrollregion.max.y - 1) { scr_scroll_down(1); } else { currow++; } } p += m; n -= m; } return nbytes; } void mch_write(char_u *p, int len) { int slen; scr_unstamp_cursor(); while (len > 0) { /* Handle special characters. */ slen = write_special((char*)p, len); p += slen; len -= slen; /* Write as many normal characters as possible. */ slen = write_str((char*)p, len); p += slen; len -= slen; } scr_stamp_cursor(); flushimage(display, 1); } static void sigalrm(int, char*, void*) { /* Do nothing */ } /* Don't allow mouse events to accumulate. */ static void drain_mouse_events(void) { while (ecanmouse()) { emouse(); } } int RealWaitForChar(int, long msec, int*) { Rune rune; char utf[UTFmax]; int len; drain_mouse_events(); if (msec == 0 && !ecankbd()) { return 0; } if (msec > 0) { if (setjmp(timeoutjmpbuf)) { /* We arrive here if the alarm occurred and a library * function called drawerror() due to an interrupted * syscall. */ _ALARM(0); interruptable = 0; return 0; } interruptable = 1; _ALARM((unsigned long)msec); } /* TODO garbage collect */ rune = ekbd(); if (msec > 0) { _ALARM(0); interruptable = 0; } if (rune == Ctrl_C && ctrl_c_interrupts) { got_int = TRUE; return 0; } len = runetochar(utf, &rune); add_to_input_buf_csi((char_u*)utf, len); /* TODO escape K_SPECIAL? */ return len > 0; } int mch_inchar(char_u *buf, int maxlen, long msec, int) { if (vim_is_input_buf_empty() && RealWaitForChar(0, msec, NULL) == 0) { return 0; } return read_from_input_buf(buf, maxlen); } int mch_char_avail(void) { return ecankbd(); } void mch_delay(long msec, int ignoreinput) { if (ignoreinput) { sleep(msec / 1000); } else { RealWaitForChar(0, msec, NULL); } } int mch_nodetype(char_u *name) { struct stat st; if (stat((char*)name, &st) < 0) { return NODE_NORMAL; } if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { return NODE_NORMAL; } return NODE_WRITABLE; } int mch_FullName(char_u *fname, char_u *buf, int len, int force) { int l; char_u olddir[MAXPATHL]; char_u *p; int retval = OK; /* expand it if forced or not an absolute path */ if (force || !mch_isFullName(fname)) { /* * If the file name has a path, change to that directory for a moment, * and then do the getwd() (and get back to where we were). * This will get the correct path name with "../" things. */ if ((p = vim_strrchr(fname, '/')) != NULL) { /* Only change directory when we are sure we can return to where * we are now. After doing "su" chdir(".") might not work. */ if ( (mch_dirname(olddir, MAXPATHL) == FAIL || mch_chdir((char *)olddir) != 0)) { p = NULL; /* can't get current dir: don't chdir */ retval = FAIL; } else { /* The directory is copied into buf[], to be able to remove * the file name without changing it (could be a string in * read-only memory) */ if (p - fname >= len) retval = FAIL; else { vim_strncpy(buf, fname, p - fname); if (mch_chdir((char *)buf)) retval = FAIL; else fname = p + 1; *buf = NUL; } } } if (mch_dirname(buf, len) == FAIL) { retval = FAIL; *buf = NUL; } if (p != NULL) { l = mch_chdir((char *)olddir); if (l != 0) EMSG(_(e_prev_dir)); } l = STRLEN(buf); if (l >= len) retval = FAIL; else { if (l > 0 && buf[l - 1] != '/' && *fname != NUL && STRCMP(fname, ".") != 0) STRCAT(buf, "/"); } } /* Catch file names which are too long. */ if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len) return FAIL; /* Do not append ".", "/dir/." is equal to "/dir". */ if (STRCMP(fname, ".") != 0) STRCAT(buf, fname); return OK; } long mch_get_pid(void) { return (long)getpid(); } int mch_input_isatty(void) { return isatty(0) ? TRUE : FALSE; } int mch_setenv(char *var, char *value, int x) { char buf[100]; int fd; int len; snprintf(buf, sizeof buf, "/env/%s", var); /* Check for overwrite */ if (!x) { struct stat st; if (stat(buf, &st) == 0) { return -1; } } /* Write the value */ fd = creat(buf, 0666); if (fd < 0) { return -1; } len = strlen(value); if (write(fd, value, len) != len) { close(fd); return -1; } close(fd); return 0; } void mch_suspend(void) { suspend_shell(); } static void update_shellsize(void) { shellsize = Pt((screen->clipr.max.x - screen->clipr.min.x) / fontsize.x, (screen->clipr.max.y - screen->clipr.min.y) / fontsize.y); } int mch_get_shellsize(void) { update_shellsize(); Rows = shellsize.y; Columns = shellsize.x; scrollregion.min.x = 0; scrollregion.min.y = 0; scrollregion.max.x = shellsize.x; scrollregion.max.y = shellsize.y; return OK; } void mch_set_shellsize(void) { /* Do nothing */ } void mch_new_shellsize(void) { /* Do nothing */ } void mch_breakcheck(void) { if (scr_inited) { /* Read into input buffer and check for Ctrl-C. */ RealWaitForChar(0, 0, NULL); } } /* Called by libevent whenever a resize event occurs. */ void eresized(int renew) { if (renew) { if (getwindow(display, Refnone) < 0) { err9("resize failed"); } } shell_resized(); } static void init_colors(void) { int i; int colors[NCOLORS] = { /* Copied from hardcopy.c and adjusted for libdraw. */ 0x000000ff, 0x0000c0ff, 0x008000ff, 0x004080ff, 0xc00000ff, 0xc000c0ff, 0x808000ff, 0xc0c0c0ff, 0x808080ff, 0x6060ffff, 0x00ff00ff, 0x00ffffff, 0xff8080ff, 0xff40ffff, 0xffff00ff, 0xffffffff }; for (i = 0; i < NCOLORS; i++) { colortab[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, colors[i]); if (colortab[i] == nil) { err9("allocimage failed"); } } mch_set_normal_colors(); } static void free_colors(void) { int i; bgcolor = nil; fgcolor = nil; for (i = 0; i < NCOLORS; i++) { freeimage(colortab[i]); colortab[i] = nil; } } static void init_fonts(void) { normalfont = openfont(display, "/lib/font/bit/fixed/unicode.9x18.font"); if (normalfont == nil) { err9("openfont normal failed"); } boldfont = openfont(display, "/lib/font/bit/fixed/unicode.9x18B.font"); if (boldfont == nil) { err9("openfont bold failed"); } curfont = normalfont; } static void free_fonts(void) { freefont(normalfont); freefont(boldfont); curfont = nil; } void mch_early_init(void) { rfork(RFENVG | RFNOTEG); } int mch_check_win(int, char**) { return OK; } static void scr_init(void) { if (initdraw(derr, nil, "Vim") == -1) { err9("initdraw failed"); } init_colors(); init_fonts(); fontsize = stringsize(curfont, "A"); cursorsave = allocimage(display, Rect(0, 0, fontsize.x, fontsize.y), screen->chan, 0, DBlack); mch_get_shellsize(); scr_clear(); scr_stamp_cursor(); flushimage(display, 1); /* Mouse events must be enabled to receive window resizes. */ einit(Emouse | Ekeyboard); scr_inited = TRUE; } void mch_init(void) { signal(SIGALRM, sigalrm); scr_init(); /* * Force UTF-8 output no matter what the value of 'encoding' is. * did_set_string_option() in option.c prohibits changing 'termencoding' * to something else than UTF-8. */ set_option_value((char_u *)"termencoding", 0L, (char_u *)"utf-8", 0); #if defined(FEAT_CLIPBOARD) clip_init(TRUE); #endif } void mch_exit(int r) { ml_close_all(TRUE); /* remove all memfiles */ /* libdraw shuts down automatically on exit */ exit(r); } #if defined(FEAT_TITLE) void mch_settitle(char_u *title, char_u *) { int fd; fd = open("/dev/label", O_WRONLY); if (fd < 0) { /* Not running under rio. */ return; } write(fd, (char*)title, strlen((char*)title)); close(fd); } void mch_restore_title(int) { /* No need to restore - libdraw does this automatically. */ } int mch_can_restore_title(void) { return TRUE; } int mch_can_restore_icon(void) { return FALSE; } #endif #if defined(FEAT_CLIPBOARD) int clip_mch_own_selection(VimClipboard*) { /* We never own the clipboard. */ return FAIL; } void clip_mch_lose_selection(VimClipboard*) { /* Do nothing */ } void clip_mch_request_selection(VimClipboard *cbd) { int fd; char_u *data; char_u *newdata; long_u len; /* used length */ long_u mlen; /* max allocated length */ ssize_t n; int type; fd = open("/dev/snarf", O_RDONLY); if (fd < 0) { /* Not running under rio. */ return; } n = 0; len = 0; mlen = 0; data = NULL; do { len += n; mlen += 4096; newdata = vim_realloc(data, mlen); if (!newdata) { n = -1; break; } data = newdata; n = read(fd, data, 4096); /* TODO breakcheck? */ } while (n == 4096); if (n >= 0) { len += n; type = memchr(data, '\n', len) ? MLINE : MCHAR; clip_yank_selection(type, data, len, cbd); } vim_free(data); close(fd); } void clip_mch_set_selection(VimClipboard *cbd) { char_u *data; long_u len; int type; int fd; /* If the '*' register isn't already filled in, fill it in now. */ cbd->owned = TRUE; clip_get_selection(cbd); cbd->owned = FALSE; type = clip_convert_selection(&data, &len, cbd); if (type < 0) { return; } fd = open("/dev/snarf", O_WRONLY); if (fd >= 0) { write(fd, data, len); close(fd); } vim_free(data); } #endif #if defined(FEAT_MOUSE) void mch_setmouse(int) { /* Do nothing. Mouse needed for clipboard. */ } #endif static pid_t forkwin(int hide){ char spec[256]; char *wsys; int wfd; pid_t pid; /* Fork child. */ pid = fork(); if(pid != 0) return pid; /* We need a separate namespace from parent process. */ rfork(RFNAMEG); /* Mounting the window system creates a new window. */ wsys = getenv("wsys"); if(!wsys){ fprintf(stderr, "wsys not set\n"); exit(1); } wfd = open(wsys, O_RDWR); if(wfd < 0){ fprintf(stderr, "unable to open \"%s\"\n", wsys); exit(1); } snprintf(spec, sizeof spec, "new -pid %d -scroll %s", getpid(), hide ? "-hide" : ""); if(mount(wfd, -1, "/mnt/wsys", MREPL, spec) < 0){ fprintf(stderr, "unable to mount\n"); exit(1); } if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){ fprintf(stderr, "unable to bind\n"); exit(1); } /* Now reopen standard input, output, and error. */ freopen("/dev/cons", "r", stdin); setbuf(stdin, NULL); freopen("/dev/cons", "w", stdout); setbuf(stdout, NULL); freopen("/dev/cons", "w", stderr); setbuf(stderr, NULL); return pid; } int mch_call_shell(char_u *cmd, int options) { char ch; pid_t pid; int status; int hide; /* Non-interactive commands run in a hidden window. */ hide = options & SHELL_FILTER || options & SHELL_DOOUT; pid = forkwin(hide); if (pid == -1) { MSG_PUTS(_("\nCannot fork\n")); return -1; } if (pid == 0) { /* Fork again so that we can prompt the user to * press a key before the window closes. */ pid = fork(); if (pid == -1) { exit(255); } if (pid == 0) { if (cmd) { execl("/bin/rc", "rc", "-c", cmd, NULL); } else { execl("/bin/rc", "rc", NULL); } exit(122); /* same as on UNIX Vim */ } else { waitpid(pid, &status, 0); if (!hide) { printf("\nPress RETURN to close this window..."); read(0, &ch, 1); } exit(status); } } waitpid(pid, &status, 0); return status; }