updated for version 7.0001
diff --git a/src/os_riscos.c b/src/os_riscos.c
new file mode 100644
index 0000000..a1cdab4
--- /dev/null
+++ b/src/os_riscos.c
@@ -0,0 +1,1288 @@
+/* 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) */
+	STRNCPY(s, "(unknown)", len);
+    }
+}
+
+/*
+ * 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;
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * 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, 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;
+}
+#endif
+
+/*
+ * 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. */
+    __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_screnmode));
+    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);
+    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);
+}