| /* 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. |
| */ |
| |
| #include "vim.h" |
| |
| /* |
| * os_riscos.c |
| * |
| * Thomas Leonard <tal197@ecs.soton.ac.uk> |
| */ |
| |
| const char *__dynamic_da_name = "Vim heap"; /* Enable and name our dynamic area */ |
| int ro_line_mode = TRUE; /* For Ex mode we much echo chars to the screen ourselves */ |
| int windowed; /* Flag - are we running inside a text window? */ |
| int WinLeft, WinTop; /* We might be started inside a text window */ |
| int ScrollTop; /* Make cursor movements relative to ScrollTop. */ |
| |
| int old_escape_state = -1; |
| int old_cursor_state = -1; |
| |
| #define rgb(r,g,b) ((b<<24) + (g<<16) + (r<<8)) |
| #define NORMAL_FG 0x00000000 |
| #define NORMAL_BG 0xffffffff |
| |
| /* Convert a DOS colour number to an RGB palette entry. |
| * Mappings from X11 rgb/txt file. |
| */ |
| static int |
| map_colour(dos) |
| int dos; /* Standard DOS colour number. */ |
| { |
| switch (dos) |
| { |
| case 0: return 0; /* Black */ |
| case 1: return rgb(0,0,139); /* DarkBlue */ |
| case 2: return rgb(0,100,0); /* DarkGreen */ |
| case 3: return rgb(0,139,139); /* DarkCyan */ |
| case 4: return rgb(139,0,0); /* DarkRed */ |
| case 5: return rgb(139,0,139); /* DarkMagenta */ |
| case 6: return rgb(165,42,42); /* Brown, DarkYellow */ |
| case 7: return rgb(211,211,211); /* LightGray, LightGrey, Gray, Grey */ |
| case 8: return rgb(169,169,169); /* DarkGray, DarkGrey */ |
| case 9: return rgb(173,216,230); /* Blue, LightBlue */ |
| case 10: return rgb(144,238,144); /* Green, LightGreen */ |
| case 11: return rgb(224,255,255); /* Cyan, LightCyan */ |
| case 12: return rgb(255,0,0); /* Red, LightRed */ |
| case 13: return rgb(255,0,255); /* Magenta, LightMagenta */ |
| case 14: return rgb(255,255,0); /* Yellow, LightYellow */ |
| case 15: return rgb(255,255,255); /* White */ |
| } |
| return rgb(100,100,100); |
| } |
| |
| static void |
| text_fg(fg) |
| int fg; /* Foregound colour in the form &BBGGRR00 */ |
| { |
| xswi(ColourTrans_SetTextColour, fg, 0, 0, 0); |
| } |
| |
| static void |
| text_bg(bg) |
| int bg; /* Backgound colour in the form &BBGGRR00 */ |
| { |
| xswi(ColourTrans_SetTextColour, bg, 0, 0, 1 << 7); |
| } |
| |
| #define OUT_NORMAL 0 |
| #define OUT_NUMBER 1 /* Reading in a number */ |
| |
| void |
| mch_write(s, len) |
| char_u *s; |
| int len; |
| { |
| static int mode = OUT_NORMAL; |
| static int x, y; /* For reading numbers in. */ |
| |
| if (!term_console) |
| { |
| /* Maybe we are running Vim remotely - don't interpret chars */ |
| while (len--) |
| { |
| char_u c = *s++; |
| swi(OS_WriteC, c); |
| /* We might need to send a CR too. This shouldn't |
| * hurt if we don't need it, should it? |
| */ |
| if (c == 10) |
| swi(OS_WriteI + 13); |
| } |
| return; |
| } |
| |
| while (len--) |
| { |
| char_u c = *s++; |
| switch (mode) |
| { |
| case OUT_NUMBER: |
| if (c < '0' || c > '9') |
| { |
| mode = OUT_NORMAL; |
| } |
| else |
| { |
| x = (x * 10) + c - '0'; |
| continue; |
| } |
| /* note: no break here! */ |
| |
| case OUT_NORMAL: |
| switch (c) |
| { |
| case 1: |
| /* Number (in decimal) follows. */ |
| mode = OUT_NUMBER; |
| y = x; |
| x = 0; |
| break; |
| case 2: |
| /* Position cursor. */ |
| swi(OS_WriteI + 31); |
| swi(OS_WriteC, x); |
| swi(OS_WriteC, y - ScrollTop); |
| break; |
| case 3: |
| /* Set scroll region. */ |
| if (x == Rows -1 && y == 0 && !windowed) |
| { |
| /* Whole screen - remove text window. |
| * This is MUCH faster. |
| */ |
| swi(OS_WriteI + 26); |
| } |
| else |
| { |
| /* Create a text window. */ |
| swi(OS_WriteI + 28); |
| swi(OS_WriteC, WinLeft); |
| swi(OS_WriteC, WinTop + x); |
| swi(OS_WriteC, WinLeft + Columns - 1); |
| swi(OS_WriteC, WinTop + y); |
| } |
| ScrollTop = y; |
| break; |
| case 4: |
| /* Normal mode. */ |
| text_fg(NORMAL_FG); |
| text_bg(NORMAL_BG); |
| break; |
| case 5: |
| /* Reverse mode. */ |
| text_fg(NORMAL_BG); |
| text_bg(NORMAL_FG); |
| break; |
| case 10: |
| swi(OS_NewLine); |
| break; |
| case 14: |
| /* Cursor invisible. */ |
| swi(OS_WriteN, |
| "\027\001\000\000\000\000\000\000\000\000", |
| 10); |
| break; |
| case 15: |
| /* Cursor visible. */ |
| swi(OS_WriteN, |
| "\027\001\002\000\000\000\000\000\000\000", |
| 10); |
| break; |
| case 16: |
| /* Cursor very visible (flash) */ |
| swi(OS_WriteN, |
| "\027\001\003\000\000\000\000\000\000\000", |
| 10); |
| case 17: |
| /* Set foreground colour. */ |
| text_fg(map_colour(x)); |
| break; |
| case 18: |
| /* Set background colour. */ |
| text_bg(map_colour(x)); |
| break; |
| case 19: |
| /* Scroll text down. */ |
| swi(OS_WriteN, |
| "\027\007\000\002\000\000\000\000\000\000", |
| 10); |
| break; |
| default: |
| swi(OS_WriteC, c); |
| } |
| continue; |
| |
| default: |
| printf("[output error]"); |
| mode = OUT_NORMAL; |
| } |
| } |
| } |
| |
| /* |
| * mch_inchar(): low level input funcion. |
| * Get a characters from the keyboard. |
| * Return the number of characters that are available. |
| * If wtime == 0 do not wait for characters. |
| * If wtime == n wait n msecs for characters. |
| * If wtime == -1 wait forever for characters. |
| * |
| * TODO: call convert_input() for 'fileencoding' to 'encoding' conversion. |
| */ |
| int |
| mch_inchar(buf, maxlen, wtime, tb_change_cnt) |
| char_u *buf; |
| int maxlen; |
| long wtime; |
| int tb_change_cnt; |
| { |
| int got=0; |
| unsigned int start_time = clock(); |
| |
| if (ro_line_mode) |
| { |
| /* We're probably in Ex mode - get whole lines at a time. */ |
| |
| static char_u line_buffer[256]; |
| static int remaining_chars = 0; |
| static int buf_pos = 0; |
| |
| /* Do we need to fetch another line? */ |
| if (remaining_chars == 0) |
| { |
| int old_esc_state; |
| swi(OS_Byte, 200, 1, 0xfe); |
| old_esc_state = r1; |
| |
| buf_pos = 0; |
| if (xswi(OS_ReadLine, line_buffer, 255, 0, 255) & (c_flag | v_flag)) |
| { |
| got_int = TRUE; /* ESC pressed */ |
| r1 = 0; |
| } |
| line_buffer[r1] = 13; |
| remaining_chars = r1 + 1; /* Count CR as part of input */ |
| |
| swi(OS_Byte, 200, old_esc_state, 0); |
| } |
| |
| /* Can we send the rest of the buffer back in one go? */ |
| if (remaining_chars <= maxlen) |
| { |
| int got = remaining_chars; |
| |
| memcpy(buf, line_buffer + buf_pos, got); |
| remaining_chars = 0; |
| return got; |
| } |
| |
| /* Send as much as we can */ |
| memcpy(buf, line_buffer + buf_pos, maxlen); |
| buf_pos += maxlen; |
| remaining_chars -= maxlen; |
| |
| return maxlen; |
| } |
| |
| if (!term_console) |
| { |
| /* Use OS_ReadC for all input. |
| * Avoids problems with remote access getting interference from |
| * the keyboard. |
| */ |
| if (wtime == 0) |
| return 0; /* Ignore quick key checks */ |
| |
| if (xswi(OS_ReadC) & c_flag) |
| { |
| got_int = TRUE; /* ESC pressed - can this happen? */ |
| swi(OS_Byte, 124); /* Clear Escape state */ |
| r0 = 0x1b; /* It *might* not have been Escape! */ |
| } |
| buf[0] = r0; |
| return 1; |
| } |
| |
| /* |
| * OK, here's the plan: |
| * |
| * 1) Wait until wtime expires or we get a key |
| * 2) Get keys until the keyboard buffer is empty or buf is full |
| */ |
| |
| while (xswi(OS_Byte,145,0) & c_flag) |
| { |
| /* Nothing at all in the keyboard buffer. |
| * Has our time expired yet? |
| */ |
| if ( (wtime != -1) && (clock() - start_time) >= wtime ) |
| return 0; /* Nothing read - giving up */ |
| } |
| |
| /* We've got one char (in r2) - are there any more? */ |
| |
| while (got < maxlen) |
| { |
| buf[got++] = r2; |
| |
| if (xswi(OS_Byte,145,0) & c_flag) |
| return got; /* Keyboard buffer empty */ |
| } |
| return got; /* buf is full */ |
| } |
| |
| /* |
| * return non-zero if a character is available |
| */ |
| int |
| mch_char_avail() |
| { |
| if (!term_console) |
| return 0; /* Can't tell */ |
| if (xswi(OS_Byte, 152, 0) & c_flag) |
| return 0; |
| return 1; |
| } |
| |
| /* Find out how much free memory we have. |
| * I don't know how to work this out exactly but, since we can claim |
| * more memory from the OS, let's just report the free pool size. |
| * Dynamic area 6 doesn't exist pre 3.6 according to StrongHelp, so |
| * we'll use Wimp_SlotSize. If that fails (outside the desktop?) |
| * then just return a big number and hope. |
| */ |
| long_u |
| mch_avail_mem(special) |
| int special; |
| { |
| if (xswi(Wimp_SlotSize, -1, -1) & v_flag) |
| return 0x7fffffff; |
| return r2; |
| } |
| |
| void |
| mch_delay(msec, ignoreinput) |
| long msec; |
| int ignoreinput; |
| { |
| int start_time, time_now; |
| int csec = msec / 10; |
| |
| swi(OS_ReadMonotonicTime); |
| start_time = r0; |
| |
| for (;;) |
| { |
| swi(OS_ReadMonotonicTime); |
| time_now = r0; |
| if (time_now - start_time > csec) |
| return; |
| #ifdef FEAT_GUI |
| /* In the GUI, allow other programs to run while waiting. */ |
| if (gui.in_use) |
| gui_mch_wait_for_chars(start_time + csec); |
| #endif |
| } |
| } |
| |
| /* |
| * If the machine has job control, use it to suspend the program, |
| * otherwise fake it by starting a new shell. |
| */ |
| void |
| mch_suspend() |
| { |
| suspend_shell(); |
| } |
| |
| void |
| mch_init() |
| { |
| /* |
| * Read window size first. Calls to mch_get_shellsize() will |
| * simply return these values in future so that setting the |
| * text window (used for scrolling) won't give strange results. |
| */ |
| |
| int buf[7] = {132, 135, 256, 257, 1, 2, -1}; |
| |
| /* Command windows are no longer forced open, since if we are |
| * in the desktop then we'll use the GUI version. |
| * Opening a command window here messes up the GUI version startup |
| */ |
| #ifndef FEAT_GUI |
| swi(OS_WriteI); |
| #endif |
| swi(OS_ReadVduVariables, buf, buf); |
| WinLeft = buf[0]; |
| WinTop = buf[1]; |
| Columns = buf[2]; |
| Rows = buf[3] + 1; /* Seems to be one off (VduVars wrong?) */ |
| ScrollTop = 0; |
| |
| /* Are we running in a textwindow? */ |
| if (Rows == buf[5] + 1 && Columns == buf[4] + 1) |
| windowed = 0; |
| else |
| windowed = 1; |
| |
| /* Choose a nice colour scheme. */ |
| text_fg(NORMAL_FG); |
| text_bg(NORMAL_BG); |
| } |
| |
| /* |
| * Check_win checks whether we have an interactive stdout. |
| */ |
| /* ARGSUSED */ |
| int |
| mch_check_win(argc, argv) |
| int argc; |
| char **argv; |
| { |
| return OK; |
| } |
| |
| /* |
| * Return TRUE if the input comes from a terminal, FALSE otherwise. |
| */ |
| int |
| mch_input_isatty() |
| { |
| if (xswi(OS_ChangeRedirection, -1, -1) & v_flag) |
| return TRUE; /* Error - TRUE is probably correct though */ |
| if (r0 == 0) |
| return TRUE; |
| return FALSE; |
| } |
| |
| #ifdef FEAT_TITLE |
| int |
| mch_can_restore_title() |
| { |
| return FALSE; |
| } |
| |
| int |
| mch_can_restore_icon() |
| { |
| return FALSE; |
| } |
| |
| |
| /* |
| * Set the window title and icon. |
| */ |
| void |
| mch_settitle(title, icon) |
| char_u *title; |
| char_u *icon; |
| { |
| if (title == NULL) |
| title = (char_u *) "<untitled>"; |
| #ifdef FEAT_GUI |
| if (gui.in_use && strcmp(title, gui.window_title)) |
| { |
| int length; |
| length = strlen(title); |
| if (length >= gui.window_title_size) |
| length = gui.window_title_size - 1; |
| strncpy(gui.window_title, title, length); |
| gui.window_title[length] = 0; |
| ro_redraw_title(gui.window_handle); |
| } |
| #endif |
| return; |
| } |
| |
| /* |
| * Restore the window/icon title. |
| * "which" is one of: |
| * 1 only restore title |
| * 2 only restore icon |
| * 3 restore title and icon |
| */ |
| void |
| mch_restore_title(which) |
| int which; |
| { |
| return; |
| } |
| #endif |
| |
| /* |
| * Insert user name in s[len]. |
| * Return OK if a name found. |
| */ |
| int |
| mch_get_user_name(s, len) |
| char_u *s; |
| int len; |
| { |
| /* RISC OS doesn't support user names. */ |
| *s = NUL; |
| return FAIL; |
| } |
| |
| /* |
| * Insert host name in s[len]. |
| */ |
| |
| void |
| mch_get_host_name(s, len) |
| char_u *s; |
| int len; |
| { |
| if (xswi(OS_ReadVarVal, "Machine$Name", s, len, 0, 3) & v_flag) |
| { |
| /* Variable does not exist (normal operation) */ |
| vim_strncpy(s, "(unknown)", len - 1); |
| } |
| } |
| |
| /* |
| * return process ID |
| */ |
| long |
| mch_get_pid() |
| { |
| if (xswi(Wimp_ReadSysInfo, 5) & v_flag) |
| return 0; |
| return r0; |
| } |
| |
| /* |
| * Get name of current directory into buffer 'buf' of length 'len' bytes. |
| * Return OK for success, FAIL for failure. |
| */ |
| int |
| mch_dirname(buf, len) |
| char_u *buf; |
| int len; |
| { |
| if (xswi(OS_FSControl, 37, "@", buf, 0, 0, len) & v_flag) |
| return FAIL; |
| return OK; |
| } |
| |
| /* |
| * Get absolute file name into buffer 'buf' of length 'len' bytes. |
| * |
| * return FAIL for failure, OK for success |
| */ |
| int |
| mch_FullName(fname, buf, len, force) |
| char_u *fname, *buf; |
| int len; |
| int force; /* Also expand when already absolute path name. |
| * Not used under RISC OS. |
| */ |
| { |
| if (xswi(OS_FSControl, 37, fname, buf, 0, 0, len) & v_flag) |
| return FAIL; |
| return OK; |
| } |
| |
| /* |
| * Return TRUE if "fname" does not depend on the current directory. |
| */ |
| int |
| mch_isFullName(fname) |
| char_u *fname; |
| { |
| if (strstr(fname, "::") && strstr(fname,".$.")) |
| return TRUE; |
| return FALSE; |
| } |
| |
| /* |
| * Get file permissions for 'name'. |
| * Returns -1 when it doesn't exist. |
| */ |
| long |
| mch_getperm(name) |
| char_u *name; |
| { |
| struct stat statb; |
| |
| if (stat((char *)name, &statb)) |
| return -1; |
| return statb.st_mode; |
| } |
| |
| /* |
| * set file permission for 'name' to 'perm' |
| * |
| * return FAIL for failure, OK otherwise |
| */ |
| int |
| mch_setperm(name, perm) |
| char_u *name; |
| long perm; |
| { |
| return (chmod((char *)name, (mode_t)perm) == 0 ? OK : FAIL); |
| } |
| |
| /* |
| * Set hidden flag for "name". |
| */ |
| /* ARGSUSED */ |
| void |
| mch_hide(name) |
| char_u *name; |
| { |
| /* can't hide a file */ |
| } |
| |
| /* |
| * return TRUE if "name" is a directory |
| * return FALSE if "name" is not a directory |
| * return FALSE for error |
| */ |
| int |
| mch_isdir(name) |
| char_u *name; |
| { |
| if (xswi(OS_File, 17, name) & v_flag) |
| return FALSE; |
| if (r0 == 2 || r0 == 3) |
| return TRUE; /* Count image files as directories. */ |
| return FALSE; |
| } |
| |
| /* |
| * Return 1 if "name" can be executed, 0 if not. |
| * Return -1 if unknown. Requires which to work. |
| */ |
| int |
| mch_can_exe(name) |
| char_u *name; |
| { |
| char_u *buf; |
| char_u *p; |
| int retval; |
| |
| buf = alloc((unsigned)STRLEN(name) + 7); |
| if (buf == NULL) |
| return -1; |
| sprintf((char *)buf, "which %s", name); |
| p = get_cmd_output(buf, NULL, SHELL_SILENT); |
| vim_free(buf); |
| if (p == NULL) |
| return -1; |
| /* result can be: "name: Command not found" */ |
| retval = (*p != NUL && strstr((char *)p, "not found") == NULL); |
| vim_free(p); |
| return retval; |
| } |
| |
| /* |
| * Check what "name" is: |
| * NODE_NORMAL: file or directory (or doesn't exist) |
| * NODE_WRITABLE: writable device, socket, fifo, etc. |
| * NODE_OTHER: non-writable things |
| */ |
| int |
| mch_nodetype(name) |
| char_u *name; |
| { |
| /* TODO */ |
| return NODE_NORMAL; |
| } |
| |
| void |
| mch_early_init() |
| { |
| /* Turn off all the horrible filename munging in UnixLib. */ |
| int __riscosify_control = __RISCOSIFY_NO_PROCESS; |
| } |
| |
| void |
| mch_exit(r) |
| int r; |
| { |
| settmode(TMODE_COOK); |
| exiting = TRUE; |
| out_flush(); |
| ml_close_all(TRUE); /* remove all memfiles */ |
| |
| #ifdef FEAT_GUI |
| if (gui.in_use) |
| gui_exit(r); |
| #endif |
| swi(OS_NewLine); |
| if (old_escape_state != -1) |
| swi(OS_Byte, 229, old_escape_state, 0); |
| if (old_cursor_state != -1) |
| swi(OS_Byte, 4, old_cursor_state); |
| exit(r); |
| } |
| |
| void |
| mch_settmode(tmode) |
| int tmode; /* TMODE_RAW or TMODE_COOK */ |
| { |
| if (tmode == TMODE_COOK) |
| { |
| ro_line_mode = TRUE; |
| return; |
| } |
| |
| ro_line_mode = FALSE; |
| |
| if (term_console) |
| { |
| /* Block cursor. */ |
| swi(OS_WriteN, |
| "\027\000\012\000\000\000\000\000\000\000", |
| 10); |
| |
| /* Disable the standard cursor key actions. */ |
| swi(OS_Byte, 4, 1); |
| if (old_cursor_state == -1) |
| old_cursor_state = r1; |
| } |
| |
| /* Stop Escape from quitting Vim! */ |
| swi(OS_Byte, 229, 1, 0); |
| if (old_escape_state == -1) |
| old_escape_state = r1; |
| } |
| |
| /* |
| * set mouse clicks on or off (only works for xterms) |
| */ |
| void |
| mch_setmouse(on) |
| int on; |
| { |
| } |
| |
| /* |
| * set screen mode, always fails. |
| */ |
| /* ARGSUSED */ |
| int |
| mch_screenmode(arg) |
| char_u *arg; |
| { |
| EMSG(_(e_screenmode)); |
| return FAIL; |
| } |
| |
| /* |
| * Try to get the current window size. |
| * Return OK when size could be determined, FAIL otherwise. |
| * Simply return results stored by mch_init() if we are the |
| * machine's console. If not, we don't know how big the screen is. |
| */ |
| int |
| mch_get_shellsize() |
| { |
| /* if size changed: screenalloc will allocate new screen buffers */ |
| return term_console ? OK : FAIL; |
| } |
| |
| /* |
| * Can't change the size. |
| * Assume the user knows what he's doing and use the new values. |
| */ |
| void |
| mch_set_shellsize() |
| { |
| /* Assume the user knows what he's doing and use the new values. */ |
| } |
| |
| /* |
| * Rows and/or Columns has changed. |
| */ |
| void |
| mch_new_shellsize() |
| { |
| /* Nothing to do. */ |
| } |
| |
| int |
| mch_call_shell(cmd, options) |
| char_u *cmd; |
| int options; /* SHELL_*, see vim.h */ |
| { |
| int retval; |
| int tmode = cur_tmode; |
| |
| if (cmd == NULL) |
| cmd = (char_u *) "GOS"; |
| |
| #ifdef FEAT_GUI |
| if (gui.in_use) |
| return gui_mch_call_shell(cmd, options); |
| #endif |
| if (options & SHELL_COOKED) |
| settmode(TMODE_COOK); /* set to normal mode */ |
| MSG_PUTS("\n"); |
| |
| /* I don't even want to think about what UnixLib must |
| * be doing to allow this to work... |
| */ |
| retval = system(cmd); |
| if (retval && !(options & SHELL_SILENT)) |
| EMSG(strerror(EOPSYS)); /* Doesn't seem to set errno? */ |
| |
| swi(OS_Byte, 229, 1, 0); /* Re-disable escape */ |
| if (tmode == TMODE_RAW) |
| settmode(TMODE_RAW); /* set to raw mode */ |
| return retval ? FAIL : OK; |
| } |
| |
| /* |
| * Check for Escape being pressed right now. |
| * [ different if !term_console? ] |
| */ |
| void |
| mch_breakcheck() |
| { |
| if (xswi(OS_Byte, 121, 0xf0) & v_flag) |
| return; |
| if (r1 == 0xff) |
| { |
| got_int = TRUE; |
| swi(OS_Byte, 15, 1); /* Flush input buffer */ |
| } |
| } |
| |
| /* |
| * Recursively expand one path component into all matching files and/or |
| * directories. |
| * "path" has backslashes before chars that are not to be expanded. |
| * Return the number of matches found. |
| */ |
| int |
| mch_expandpath(gap, path, flags) |
| garray_T *gap; /* Grow array for results. */ |
| char_u *path; |
| int flags; /* EW_* flags */ |
| { |
| int got; /* Number of matches. */ |
| char_u *pattern; |
| |
| /* Plan: |
| * |
| * 1) Get first part of path - no wildcards |
| * 2) Get next path element (wildcarded) |
| * 3) Get rest of path |
| * |
| * If (3) is nothing then only the leaf is wildcarded - add to gap |
| * Otherwise call recursively for each path in (2), passing (3) |
| * |
| * This is just the header function. |
| */ |
| |
| /* We must be able to modifiy path, so make a copy */ |
| pattern = vim_strsave(path); |
| if (pattern == NULL) |
| return 0; |
| got = expand_section(gap, (char_u *)"", pattern, flags); |
| vim_free(pattern); |
| return got; |
| } |
| |
| /* |
| * expand_section(gap, "$.Dir1.Dir2", "ABBA*.myleaf##") |
| * |
| * calls expand_section(gap, "$.Dir1.Dir2.ABBA_Gold", "myleaf##") |
| * and expand_section(gap, "$.Dir1.Dir2.ABBA_Live", "myleaf##") |
| * |
| * If rest is just a leaf then all matches are added to gap. |
| * |
| * Returns number of items added to gap. |
| */ |
| int |
| expand_section(gap, root, rest, flags) |
| garray_T *gap; |
| char_u *root; /* Non-wildcarded path to search */ |
| char_u *rest; /* Wildcarded remainder of path */ |
| int flags; /* Add dirs/files/missing objects. */ |
| { |
| static char_u buf[MAXPATHL]; /* Temporary buffer. */ |
| char_u dir[MAXPATHL]; |
| int start_element = -1; /* Start of wildcarded element */ |
| char_u c; |
| int i; |
| int got, dir_pos; |
| int buflen; /* Chars used in buf[] */ |
| int colon = 0; /* Dir ends in ':' */ |
| |
| buflen = strlen(root); |
| STRNCPY(buf, root, buflen); /* Copy root into buffer. */ |
| |
| /* |
| * Find end of nonwildcarded section. |
| * Count ':' as a path sep since Vim:Bug* is a valid pathname. |
| */ |
| |
| for (i = 0; c = rest[i]; i++) |
| { |
| if (c == PATHSEP) |
| { |
| start_element = i; |
| colon = 0; |
| } |
| if (c == ':') |
| { |
| start_element = i + 1; |
| colon = 1; |
| } |
| if (c == '#' || c == '*') |
| break; |
| } |
| if (c == 0) |
| start_element = i; |
| |
| /* |
| * start_element +> terminator for non-wildcarded section. |
| * Transfer this bit into buf. |
| */ |
| if (buflen + start_element + 4 >= MAXPATHL) |
| return 0; /* Buffer full */ |
| if (start_element >= 0) |
| { |
| if (*root && !colon) |
| buf[buflen++] = PATHSEP; |
| strncpy(buf + buflen, rest, start_element); |
| buflen += start_element; |
| } |
| buf[buflen] = 0; |
| |
| /* |
| * Did we reach the end of the string without hitting any wildcards? |
| */ |
| if (c == 0) |
| { |
| /* Yes - add combined path to grow array and return. */ |
| addfile(gap, buf, flags); |
| return 1; |
| } |
| |
| if (start_element < 0 || !colon) |
| start_element++; |
| rest += start_element; |
| |
| /* |
| * rest does contain wildcards if we get here. |
| * |
| * Now : have we reached the leaf names part yet? |
| * If so, add all matches (files and dirs) to gap. |
| * If not, get next path element and scan all matching directories. |
| */ |
| |
| start_element = -1; |
| for (i = 0; rest[i]; i++) |
| { |
| if (rest[i] == '.') |
| { |
| start_element = i; |
| rest[i] = 0; /* Break string here. */ |
| break; |
| } |
| } |
| |
| /* If start_element is -1 then we are matching leaf names */ |
| |
| r3 = 0; /* Number of objs read. */ |
| dir_pos = 0; /* Position through directory. */ |
| got = 0; /* Files added so far. */ |
| while (dir_pos != -1) |
| { |
| buf[buflen] = 0; |
| if (xswi(OS_GBPB, 9, |
| buf, /* Directory to scan. */ |
| buf + buflen + (1 - colon), /* Buffer for result. */ |
| 1, /* Number of objects to read. */ |
| dir_pos, /* Search position. */ |
| MAXPATHL - 2 - buflen, /* Size of result buffer. */ |
| rest) /* Wildcarded leafname. */ |
| & v_flag) |
| { |
| EMSG(r0 + 4); |
| r4 = -1; |
| } |
| dir_pos = r4; /* r4 corrupted by addfile() */ |
| if (r3 > 0) |
| { |
| char_u *path = buf; |
| if (buflen == 0) |
| path++; /* Don't do '.File' */ |
| else if (!colon) |
| buf[buflen] = '.'; /* Join path and leaf */ |
| |
| /* Path -> full path of object found */ |
| if (start_element == -1) |
| { |
| addfile(gap, path, flags); |
| got++; |
| } |
| else |
| { |
| /* Scan into subdirectories and images; ignore files */ |
| swi(OS_File, 17, path); |
| if (r0 == 2 || r0 == 3) |
| got += expand_section(gap, |
| path, |
| rest + start_element + 1, |
| flags); |
| } |
| } |
| } |
| |
| /* Restore the dot if we removed it. */ |
| if (start_element >= 0) |
| rest[start_element] = '.'; |
| return got; |
| } |
| |
| /* |
| * mch_expand_wildcards() - this code does wild-card pattern matching using |
| * the shell. It isn't used under RISC OS. |
| * |
| * return OK for success, FAIL for error (you may lose some memory) and put |
| * an error message in *file. |
| * |
| * num_pat is number of input patterns |
| * pat is array of pointers to input patterns |
| * num_file is pointer to number of matched file names |
| * file is pointer to array of pointers to matched file names |
| */ |
| int |
| mch_expand_wildcards(num_pat, pat, num_file, file, flags) |
| int num_pat; |
| char_u **pat; |
| int *num_file; |
| char_u ***file; |
| int flags; /* EW_* flags */ |
| { |
| /* This doesn't get called unless SPECIAL_WILDCHAR is defined. */ |
| return FAIL; |
| } |
| |
| /* |
| * Return TRUE if "p" contains wildcards which can be expanded by |
| * mch_expandpath(). |
| */ |
| int |
| mch_has_exp_wildcard(p) |
| char_u *p; |
| { |
| if (vim_strpbrk((char_u *)"*#", p)) |
| return TRUE; |
| return FALSE; |
| } |
| |
| /* Return TRUE if "p" contains wildcards. */ |
| int |
| mch_has_wildcard(p) |
| char_u *p; |
| { |
| if (vim_strpbrk((char_u *)"*#`", p)) |
| return TRUE; |
| return FALSE; |
| } |
| |
| int /* see Unix unlink(2) */ |
| mch_remove(file) |
| char_u *file; /* Name of file to delete. */ |
| { |
| if (xswi(OS_FSControl, 27, file, 0, 0) & v_flag) |
| return EXIT_FAILURE; |
| return EXIT_SUCCESS; |
| } |
| |
| /* Try to make existing scripts work without modification. |
| * Return a pointer to the new string (freed by caller), or NULL |
| * |
| * Two main cases: |
| * - Absolute : $VIM/syntax/help.vim |
| * - Relative : Adfs::4.$.!Vim.Resources.Syntax/help.vim |
| */ |
| char_u * |
| mch_munge_fname(fname) |
| char_u *fname; |
| { |
| char_u c; |
| int len; |
| char_u *retval; |
| |
| retval = fname = vim_strsave(fname); |
| if (fname == NULL) |
| return NULL; |
| |
| if (strncmp(fname, "$VIM/", 5) == 0) |
| { |
| strncpy(fname, "Vim:", 4); |
| for (fname += 5; c = *fname; fname++) |
| { |
| if (c == '.') |
| break; |
| if (c == '/') |
| fname[-1] = '.'; |
| else |
| fname[-1] = c; |
| } |
| fname[-1] = '\0'; |
| } |
| else |
| { |
| /* Check to see if the file exists without modification. */ |
| if (xswi(OS_File, 17, fname) & v_flag) |
| r0 == 0; /* Invalid filename? */ |
| if (r0) |
| return retval; |
| |
| len = strlen(fname); |
| if (strcmp(fname + len - 4, ".vim") == 0) |
| { |
| fname[len - 4] = '\0'; |
| for (; c = *fname; fname++) |
| { |
| if (c == '/') |
| *fname = '.'; |
| } |
| } |
| } |
| return retval; |
| } |
| |
| /* QuickFix reads munged names from the error file. |
| * Correct them. |
| */ |
| int |
| ro_buflist_add(old_name) |
| char_u *old_name; /* Name of file found by quickfix */ |
| { |
| char_u *fname; |
| char_u *leaf; /* Pointer to start of leaf in old_name */ |
| char_u *ptr; |
| char_u c; |
| int retval; |
| |
| if (old_name == NULL) |
| return buflist_add(NULL, 0); |
| |
| /* Copy the name so we can mess around with it. */ |
| fname = vim_strsave(old_name); |
| if (fname == NULL) |
| /* Out of memory - can't modify name */ |
| return buflist_add(old_name, 0); |
| |
| /* Change `dir/main.c' into `dir.c.main' */ |
| leaf = fname; |
| for (ptr = fname; c = *ptr; ptr++) |
| { |
| if (c == '/') |
| { |
| leaf = ptr + 1; |
| *ptr = '.'; |
| } |
| else if (c == '.') |
| break; |
| } |
| if (c == '.') |
| { |
| /* Change `main.c' into `c.main' |
| * | | |
| * leaf ptr |
| */ |
| ptr += old_name - fname; |
| *ptr = '\0'; |
| sprintf(leaf, |
| "%s.%s", |
| ptr + 1, |
| leaf - fname + old_name); |
| } |
| |
| retval = buflist_add(fname, 0); |
| free(fname); |
| return retval; |
| } |
| |
| /* Change the current directory. |
| * Strip trailing dots to make it easier to use with filename completion. |
| * Return 0 for success, -1 for failure. |
| */ |
| int |
| mch_chdir(dir) |
| char_u *dir; |
| { |
| int length; |
| int retval; |
| char_u *new_dir; |
| |
| length = strlen(dir); |
| if (dir[length - 1] != '.') |
| return chdir(dir); /* No trailing dots - nothing to do. */ |
| new_dir = vim_strsave(dir); |
| if (new_dir == NULL) |
| return chdir(dir); /* Can't allocate memory. */ |
| |
| while (new_dir[--length] == '.') |
| new_dir[length] = '\0'; |
| |
| retval = chdir(new_dir); |
| vim_free(new_dir); |
| return retval; |
| } |
| |
| /* Examine the named file, and set the 'osfiletype' option |
| * (in curbuf) to the file's type. |
| */ |
| void |
| mch_read_filetype(file) |
| char_u *file; |
| { |
| int type; |
| char_u type_string[9]; |
| int i; |
| |
| if (xswi(OS_File, 23, file) & v_flag) |
| type = 0xfff; /* Default to Text */ |
| else |
| type = r6; |
| |
| /* Type is the numerical value - see if we have a textual equivalent */ |
| swi(OS_FSControl, 18, 0, type); |
| ((int *) type_string)[0] = r2; |
| ((int *) type_string)[1] = r3; |
| type_string[8] = 0; |
| for (i = 0; type_string[i] > ' '; i++) |
| ; |
| type_string[i] = 0; |
| |
| set_string_option_direct("osfiletype", -1, type_string, OPT_FREE, 0); |
| return; |
| } |
| |
| void |
| mch_set_filetype(file, type) |
| char_u *file; |
| char_u *type; |
| { |
| if (xswi(OS_FSControl, 31, type) & v_flag) |
| { |
| EMSG(_("E366: Invalid 'osfiletype' option - using Text")); |
| r2 = 0xfff; |
| } |
| |
| swi(OS_File, 18, file, r2); |
| } |
| |
| /* Return TRUE if the file's type matches 'type' |
| * RISC OS types always start with '&' |
| */ |
| int |
| mch_check_filetype(fname, type) |
| char_u *fname; |
| char_u *type; |
| { |
| int value; |
| char *end; |
| |
| if (*type != '&') |
| return FALSE; |
| |
| value = strtol(type + 1, &end, 16); |
| if (*end) |
| return FALSE; /* Invalid type (report error?) */ |
| |
| if (xswi(OS_File, 23, fname) & v_flag) |
| return FALSE; /* Invalid filename? */ |
| |
| return (r0 && r6 == value); |
| } |