1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
15 * Thomas Leonard <tal197@ecs.soton.ac.uk>
18 const char *__dynamic_da_name
= "Vim heap"; /* Enable and name our dynamic area */
19 int ro_line_mode
= TRUE
; /* For Ex mode we much echo chars to the screen ourselves */
20 int windowed
; /* Flag - are we running inside a text window? */
21 int WinLeft
, WinTop
; /* We might be started inside a text window */
22 int ScrollTop
; /* Make cursor movements relative to ScrollTop. */
24 int old_escape_state
= -1;
25 int old_cursor_state
= -1;
27 #define rgb(r,g,b) ((b<<24) + (g<<16) + (r<<8))
28 #define NORMAL_FG 0x00000000
29 #define NORMAL_BG 0xffffffff
31 /* Convert a DOS colour number to an RGB palette entry.
32 * Mappings from X11 rgb/txt file.
36 int dos
; /* Standard DOS colour number. */
40 case 0: return 0; /* Black */
41 case 1: return rgb(0,0,139); /* DarkBlue */
42 case 2: return rgb(0,100,0); /* DarkGreen */
43 case 3: return rgb(0,139,139); /* DarkCyan */
44 case 4: return rgb(139,0,0); /* DarkRed */
45 case 5: return rgb(139,0,139); /* DarkMagenta */
46 case 6: return rgb(165,42,42); /* Brown, DarkYellow */
47 case 7: return rgb(211,211,211); /* LightGray, LightGrey, Gray, Grey */
48 case 8: return rgb(169,169,169); /* DarkGray, DarkGrey */
49 case 9: return rgb(173,216,230); /* Blue, LightBlue */
50 case 10: return rgb(144,238,144); /* Green, LightGreen */
51 case 11: return rgb(224,255,255); /* Cyan, LightCyan */
52 case 12: return rgb(255,0,0); /* Red, LightRed */
53 case 13: return rgb(255,0,255); /* Magenta, LightMagenta */
54 case 14: return rgb(255,255,0); /* Yellow, LightYellow */
55 case 15: return rgb(255,255,255); /* White */
57 return rgb(100,100,100);
62 int fg
; /* Foregound colour in the form &BBGGRR00 */
64 xswi(ColourTrans_SetTextColour
, fg
, 0, 0, 0);
69 int bg
; /* Backgound colour in the form &BBGGRR00 */
71 xswi(ColourTrans_SetTextColour
, bg
, 0, 0, 1 << 7);
75 #define OUT_NUMBER 1 /* Reading in a number */
82 static int mode
= OUT_NORMAL
;
83 static int x
, y
; /* For reading numbers in. */
87 /* Maybe we are running Vim remotely - don't interpret chars */
92 /* We might need to send a CR too. This shouldn't
93 * hurt if we don't need it, should it?
107 if (c
< '0' || c
> '9')
113 x
= (x
* 10) + c
- '0';
116 /* note: no break here! */
122 /* Number (in decimal) follows. */
128 /* Position cursor. */
131 swi(OS_WriteC
, y
- ScrollTop
);
134 /* Set scroll region. */
135 if (x
== Rows
-1 && y
== 0 && !windowed
)
137 /* Whole screen - remove text window.
138 * This is MUCH faster.
144 /* Create a text window. */
146 swi(OS_WriteC
, WinLeft
);
147 swi(OS_WriteC
, WinTop
+ x
);
148 swi(OS_WriteC
, WinLeft
+ Columns
- 1);
149 swi(OS_WriteC
, WinTop
+ y
);
167 /* Cursor invisible. */
169 "\027\001\000\000\000\000\000\000\000\000",
173 /* Cursor visible. */
175 "\027\001\002\000\000\000\000\000\000\000",
179 /* Cursor very visible (flash) */
181 "\027\001\003\000\000\000\000\000\000\000",
184 /* Set foreground colour. */
185 text_fg(map_colour(x
));
188 /* Set background colour. */
189 text_bg(map_colour(x
));
192 /* Scroll text down. */
194 "\027\007\000\002\000\000\000\000\000\000",
203 printf("[output error]");
210 * mch_inchar(): low level input funcion.
211 * Get a characters from the keyboard.
212 * Return the number of characters that are available.
213 * If wtime == 0 do not wait for characters.
214 * If wtime == n wait n msecs for characters.
215 * If wtime == -1 wait forever for characters.
217 * TODO: call convert_input() for 'fileencoding' to 'encoding' conversion.
220 mch_inchar(buf
, maxlen
, wtime
, tb_change_cnt
)
227 unsigned int start_time
= clock();
231 /* We're probably in Ex mode - get whole lines at a time. */
233 static char_u line_buffer
[256];
234 static int remaining_chars
= 0;
235 static int buf_pos
= 0;
237 /* Do we need to fetch another line? */
238 if (remaining_chars
== 0)
241 swi(OS_Byte
, 200, 1, 0xfe);
245 if (xswi(OS_ReadLine
, line_buffer
, 255, 0, 255) & (c_flag
| v_flag
))
247 got_int
= TRUE
; /* ESC pressed */
250 line_buffer
[r1
] = 13;
251 remaining_chars
= r1
+ 1; /* Count CR as part of input */
253 swi(OS_Byte
, 200, old_esc_state
, 0);
256 /* Can we send the rest of the buffer back in one go? */
257 if (remaining_chars
<= maxlen
)
259 int got
= remaining_chars
;
261 memcpy(buf
, line_buffer
+ buf_pos
, got
);
266 /* Send as much as we can */
267 memcpy(buf
, line_buffer
+ buf_pos
, maxlen
);
269 remaining_chars
-= maxlen
;
276 /* Use OS_ReadC for all input.
277 * Avoids problems with remote access getting interference from
281 return 0; /* Ignore quick key checks */
283 if (xswi(OS_ReadC
) & c_flag
)
285 got_int
= TRUE
; /* ESC pressed - can this happen? */
286 swi(OS_Byte
, 124); /* Clear Escape state */
287 r0
= 0x1b; /* It *might* not have been Escape! */
294 * OK, here's the plan:
296 * 1) Wait until wtime expires or we get a key
297 * 2) Get keys until the keyboard buffer is empty or buf is full
300 while (xswi(OS_Byte
,145,0) & c_flag
)
302 /* Nothing at all in the keyboard buffer.
303 * Has our time expired yet?
305 if ( (wtime
!= -1) && (clock() - start_time
) >= wtime
)
306 return 0; /* Nothing read - giving up */
309 /* We've got one char (in r2) - are there any more? */
315 if (xswi(OS_Byte
,145,0) & c_flag
)
316 return got
; /* Keyboard buffer empty */
318 return got
; /* buf is full */
322 * return non-zero if a character is available
328 return 0; /* Can't tell */
329 if (xswi(OS_Byte
, 152, 0) & c_flag
)
334 /* Find out how much free memory we have.
335 * I don't know how to work this out exactly but, since we can claim
336 * more memory from the OS, let's just report the free pool size.
337 * Dynamic area 6 doesn't exist pre 3.6 according to StrongHelp, so
338 * we'll use Wimp_SlotSize. If that fails (outside the desktop?)
339 * then just return a big number and hope.
342 mch_avail_mem(special
)
345 if (xswi(Wimp_SlotSize
, -1, -1) & v_flag
)
351 mch_delay(msec
, ignoreinput
)
355 int start_time
, time_now
;
356 int csec
= msec
/ 10;
358 swi(OS_ReadMonotonicTime
);
363 swi(OS_ReadMonotonicTime
);
365 if (time_now
- start_time
> csec
)
368 /* In the GUI, allow other programs to run while waiting. */
370 gui_mch_wait_for_chars(start_time
+ csec
);
376 * If the machine has job control, use it to suspend the program,
377 * otherwise fake it by starting a new shell.
389 * Read window size first. Calls to mch_get_shellsize() will
390 * simply return these values in future so that setting the
391 * text window (used for scrolling) won't give strange results.
394 int buf
[7] = {132, 135, 256, 257, 1, 2, -1};
396 /* Command windows are no longer forced open, since if we are
397 * in the desktop then we'll use the GUI version.
398 * Opening a command window here messes up the GUI version startup
403 swi(OS_ReadVduVariables
, buf
, buf
);
407 Rows
= buf
[3] + 1; /* Seems to be one off (VduVars wrong?) */
410 /* Are we running in a textwindow? */
411 if (Rows
== buf
[5] + 1 && Columns
== buf
[4] + 1)
416 /* Choose a nice colour scheme. */
422 * Check_win checks whether we have an interactive stdout.
426 mch_check_win(argc
, argv
)
434 * Return TRUE if the input comes from a terminal, FALSE otherwise.
439 if (xswi(OS_ChangeRedirection
, -1, -1) & v_flag
)
440 return TRUE
; /* Error - TRUE is probably correct though */
448 mch_can_restore_title()
454 mch_can_restore_icon()
461 * Set the window title and icon.
464 mch_settitle(title
, icon
)
469 title
= (char_u
*) "<untitled>";
471 if (gui
.in_use
&& strcmp(title
, gui
.window_title
))
474 length
= strlen(title
);
475 if (length
>= gui
.window_title_size
)
476 length
= gui
.window_title_size
- 1;
477 strncpy(gui
.window_title
, title
, length
);
478 gui
.window_title
[length
] = 0;
479 ro_redraw_title(gui
.window_handle
);
486 * Restore the window/icon title.
488 * 1 only restore title
489 * 2 only restore icon
490 * 3 restore title and icon
493 mch_restore_title(which
)
501 * Insert user name in s[len].
502 * Return OK if a name found.
505 mch_get_user_name(s
, len
)
509 /* RISC OS doesn't support user names. */
515 * Insert host name in s[len].
519 mch_get_host_name(s
, len
)
523 if (xswi(OS_ReadVarVal
, "Machine$Name", s
, len
, 0, 3) & v_flag
)
525 /* Variable does not exist (normal operation) */
526 vim_strncpy(s
, "(unknown)", len
- 1);
536 if (xswi(Wimp_ReadSysInfo
, 5) & v_flag
)
542 * Get name of current directory into buffer 'buf' of length 'len' bytes.
543 * Return OK for success, FAIL for failure.
546 mch_dirname(buf
, len
)
550 if (xswi(OS_FSControl
, 37, "@", buf
, 0, 0, len
) & v_flag
)
556 * Get absolute file name into buffer 'buf' of length 'len' bytes.
558 * return FAIL for failure, OK for success
561 mch_FullName(fname
, buf
, len
, force
)
564 int force
; /* Also expand when already absolute path name.
565 * Not used under RISC OS.
568 if (xswi(OS_FSControl
, 37, fname
, buf
, 0, 0, len
) & v_flag
)
574 * Return TRUE if "fname" does not depend on the current directory.
577 mch_isFullName(fname
)
580 if (strstr(fname
, "::") && strstr(fname
,".$."))
586 * Get file permissions for 'name'.
587 * Returns -1 when it doesn't exist.
595 if (stat((char *)name
, &statb
))
597 return statb
.st_mode
;
601 * set file permission for 'name' to 'perm'
603 * return FAIL for failure, OK otherwise
606 mch_setperm(name
, perm
)
610 return (chmod((char *)name
, (mode_t
)perm
) == 0 ? OK
: FAIL
);
614 * Set hidden flag for "name".
621 /* can't hide a file */
625 * return TRUE if "name" is a directory
626 * return FALSE if "name" is not a directory
627 * return FALSE for error
633 if (xswi(OS_File
, 17, name
) & v_flag
)
635 if (r0
== 2 || r0
== 3)
636 return TRUE
; /* Count image files as directories. */
641 * Return 1 if "name" can be executed, 0 if not.
642 * Return -1 if unknown. Requires which to work.
652 buf
= alloc((unsigned)STRLEN(name
) + 7);
655 sprintf((char *)buf
, "which %s", name
);
656 p
= get_cmd_output(buf
, NULL
, SHELL_SILENT
);
660 /* result can be: "name: Command not found" */
661 retval
= (*p
!= NUL
&& strstr((char *)p
, "not found") == NULL
);
667 * Check what "name" is:
668 * NODE_NORMAL: file or directory (or doesn't exist)
669 * NODE_WRITABLE: writable device, socket, fifo, etc.
670 * NODE_OTHER: non-writable things
683 /* Turn off all the horrible filename munging in UnixLib. */
684 int __riscosify_control
= __RISCOSIFY_NO_PROCESS
;
691 settmode(TMODE_COOK
);
694 ml_close_all(TRUE
); /* remove all memfiles */
701 if (old_escape_state
!= -1)
702 swi(OS_Byte
, 229, old_escape_state
, 0);
703 if (old_cursor_state
!= -1)
704 swi(OS_Byte
, 4, old_cursor_state
);
710 int tmode
; /* TMODE_RAW or TMODE_COOK */
712 if (tmode
== TMODE_COOK
)
718 ro_line_mode
= FALSE
;
724 "\027\000\012\000\000\000\000\000\000\000",
727 /* Disable the standard cursor key actions. */
729 if (old_cursor_state
== -1)
730 old_cursor_state
= r1
;
733 /* Stop Escape from quitting Vim! */
734 swi(OS_Byte
, 229, 1, 0);
735 if (old_escape_state
== -1)
736 old_escape_state
= r1
;
740 * set mouse clicks on or off (only works for xterms)
749 * set screen mode, always fails.
756 EMSG(_(e_screenmode
));
761 * Try to get the current window size.
762 * Return OK when size could be determined, FAIL otherwise.
763 * Simply return results stored by mch_init() if we are the
764 * machine's console. If not, we don't know how big the screen is.
769 /* if size changed: screenalloc will allocate new screen buffers */
770 return term_console
? OK
: FAIL
;
774 * Can't change the size.
775 * Assume the user knows what he's doing and use the new values.
780 /* Assume the user knows what he's doing and use the new values. */
784 * Rows and/or Columns has changed.
793 mch_call_shell(cmd
, options
)
795 int options
; /* SHELL_*, see vim.h */
798 int tmode
= cur_tmode
;
801 cmd
= (char_u
*) "GOS";
805 return gui_mch_call_shell(cmd
, options
);
807 if (options
& SHELL_COOKED
)
808 settmode(TMODE_COOK
); /* set to normal mode */
811 /* I don't even want to think about what UnixLib must
812 * be doing to allow this to work...
814 retval
= system(cmd
);
815 if (retval
&& !(options
& SHELL_SILENT
))
816 EMSG(strerror(EOPSYS
)); /* Doesn't seem to set errno? */
818 swi(OS_Byte
, 229, 1, 0); /* Re-disable escape */
819 if (tmode
== TMODE_RAW
)
820 settmode(TMODE_RAW
); /* set to raw mode */
821 return retval
? FAIL
: OK
;
825 * Check for Escape being pressed right now.
826 * [ different if !term_console? ]
831 if (xswi(OS_Byte
, 121, 0xf0) & v_flag
)
836 swi(OS_Byte
, 15, 1); /* Flush input buffer */
841 * Recursively expand one path component into all matching files and/or
843 * "path" has backslashes before chars that are not to be expanded.
844 * Return the number of matches found.
847 mch_expandpath(gap
, path
, flags
)
848 garray_T
*gap
; /* Grow array for results. */
850 int flags
; /* EW_* flags */
852 int got
; /* Number of matches. */
857 * 1) Get first part of path - no wildcards
858 * 2) Get next path element (wildcarded)
859 * 3) Get rest of path
861 * If (3) is nothing then only the leaf is wildcarded - add to gap
862 * Otherwise call recursively for each path in (2), passing (3)
864 * This is just the header function.
867 /* We must be able to modifiy path, so make a copy */
868 pattern
= vim_strsave(path
);
871 got
= expand_section(gap
, (char_u
*)"", pattern
, flags
);
877 * expand_section(gap, "$.Dir1.Dir2", "ABBA*.myleaf##")
879 * calls expand_section(gap, "$.Dir1.Dir2.ABBA_Gold", "myleaf##")
880 * and expand_section(gap, "$.Dir1.Dir2.ABBA_Live", "myleaf##")
882 * If rest is just a leaf then all matches are added to gap.
884 * Returns number of items added to gap.
887 expand_section(gap
, root
, rest
, flags
)
889 char_u
*root
; /* Non-wildcarded path to search */
890 char_u
*rest
; /* Wildcarded remainder of path */
891 int flags
; /* Add dirs/files/missing objects. */
893 static char_u buf
[MAXPATHL
]; /* Temporary buffer. */
894 char_u dir
[MAXPATHL
];
895 int start_element
= -1; /* Start of wildcarded element */
899 int buflen
; /* Chars used in buf[] */
900 int colon
= 0; /* Dir ends in ':' */
902 buflen
= strlen(root
);
903 STRNCPY(buf
, root
, buflen
); /* Copy root into buffer. */
906 * Find end of nonwildcarded section.
907 * Count ':' as a path sep since Vim:Bug* is a valid pathname.
910 for (i
= 0; c
= rest
[i
]; i
++)
919 start_element
= i
+ 1;
922 if (c
== '#' || c
== '*')
929 * start_element +> terminator for non-wildcarded section.
930 * Transfer this bit into buf.
932 if (buflen
+ start_element
+ 4 >= MAXPATHL
)
933 return 0; /* Buffer full */
934 if (start_element
>= 0)
937 buf
[buflen
++] = PATHSEP
;
938 strncpy(buf
+ buflen
, rest
, start_element
);
939 buflen
+= start_element
;
944 * Did we reach the end of the string without hitting any wildcards?
948 /* Yes - add combined path to grow array and return. */
949 addfile(gap
, buf
, flags
);
953 if (start_element
< 0 || !colon
)
955 rest
+= start_element
;
958 * rest does contain wildcards if we get here.
960 * Now : have we reached the leaf names part yet?
961 * If so, add all matches (files and dirs) to gap.
962 * If not, get next path element and scan all matching directories.
966 for (i
= 0; rest
[i
]; i
++)
971 rest
[i
] = 0; /* Break string here. */
976 /* If start_element is -1 then we are matching leaf names */
978 r3
= 0; /* Number of objs read. */
979 dir_pos
= 0; /* Position through directory. */
980 got
= 0; /* Files added so far. */
981 while (dir_pos
!= -1)
985 buf
, /* Directory to scan. */
986 buf
+ buflen
+ (1 - colon
), /* Buffer for result. */
987 1, /* Number of objects to read. */
988 dir_pos
, /* Search position. */
989 MAXPATHL
- 2 - buflen
, /* Size of result buffer. */
990 rest
) /* Wildcarded leafname. */
996 dir_pos
= r4
; /* r4 corrupted by addfile() */
1001 path
++; /* Don't do '.File' */
1003 buf
[buflen
] = '.'; /* Join path and leaf */
1005 /* Path -> full path of object found */
1006 if (start_element
== -1)
1008 addfile(gap
, path
, flags
);
1013 /* Scan into subdirectories and images; ignore files */
1014 swi(OS_File
, 17, path
);
1015 if (r0
== 2 || r0
== 3)
1016 got
+= expand_section(gap
,
1018 rest
+ start_element
+ 1,
1024 /* Restore the dot if we removed it. */
1025 if (start_element
>= 0)
1026 rest
[start_element
] = '.';
1031 * mch_expand_wildcards() - this code does wild-card pattern matching using
1032 * the shell. It isn't used under RISC OS.
1034 * return OK for success, FAIL for error (you may lose some memory) and put
1035 * an error message in *file.
1037 * num_pat is number of input patterns
1038 * pat is array of pointers to input patterns
1039 * num_file is pointer to number of matched file names
1040 * file is pointer to array of pointers to matched file names
1043 mch_expand_wildcards(num_pat
, pat
, num_file
, file
, flags
)
1048 int flags
; /* EW_* flags */
1050 /* This doesn't get called unless SPECIAL_WILDCHAR is defined. */
1055 * Return TRUE if "p" contains wildcards which can be expanded by
1059 mch_has_exp_wildcard(p
)
1062 if (vim_strpbrk((char_u
*)"*#", p
))
1067 /* Return TRUE if "p" contains wildcards. */
1072 if (vim_strpbrk((char_u
*)"*#`", p
))
1077 int /* see Unix unlink(2) */
1079 char_u
*file
; /* Name of file to delete. */
1081 if (xswi(OS_FSControl
, 27, file
, 0, 0) & v_flag
)
1082 return EXIT_FAILURE
;
1083 return EXIT_SUCCESS
;
1086 /* Try to make existing scripts work without modification.
1087 * Return a pointer to the new string (freed by caller), or NULL
1090 * - Absolute : $VIM/syntax/help.vim
1091 * - Relative : Adfs::4.$.!Vim.Resources.Syntax/help.vim
1094 mch_munge_fname(fname
)
1101 retval
= fname
= vim_strsave(fname
);
1105 if (strncmp(fname
, "$VIM/", 5) == 0)
1107 strncpy(fname
, "Vim:", 4);
1108 for (fname
+= 5; c
= *fname
; fname
++)
1121 /* Check to see if the file exists without modification. */
1122 if (xswi(OS_File
, 17, fname
) & v_flag
)
1123 r0
== 0; /* Invalid filename? */
1127 len
= strlen(fname
);
1128 if (strcmp(fname
+ len
- 4, ".vim") == 0)
1130 fname
[len
- 4] = '\0';
1131 for (; c
= *fname
; fname
++)
1141 /* QuickFix reads munged names from the error file.
1145 ro_buflist_add(old_name
)
1146 char_u
*old_name
; /* Name of file found by quickfix */
1149 char_u
*leaf
; /* Pointer to start of leaf in old_name */
1154 if (old_name
== NULL
)
1155 return buflist_add(NULL
, 0);
1157 /* Copy the name so we can mess around with it. */
1158 fname
= vim_strsave(old_name
);
1160 /* Out of memory - can't modify name */
1161 return buflist_add(old_name
, 0);
1163 /* Change `dir/main.c' into `dir.c.main' */
1165 for (ptr
= fname
; c
= *ptr
; ptr
++)
1177 /* Change `main.c' into `c.main'
1181 ptr
+= old_name
- fname
;
1186 leaf
- fname
+ old_name
);
1189 retval
= buflist_add(fname
, 0);
1194 /* Change the current directory.
1195 * Strip trailing dots to make it easier to use with filename completion.
1196 * Return 0 for success, -1 for failure.
1206 length
= strlen(dir
);
1207 if (dir
[length
- 1] != '.')
1208 return chdir(dir
); /* No trailing dots - nothing to do. */
1209 new_dir
= vim_strsave(dir
);
1210 if (new_dir
== NULL
)
1211 return chdir(dir
); /* Can't allocate memory. */
1213 while (new_dir
[--length
] == '.')
1214 new_dir
[length
] = '\0';
1216 retval
= chdir(new_dir
);
1221 /* Examine the named file, and set the 'osfiletype' option
1222 * (in curbuf) to the file's type.
1225 mch_read_filetype(file
)
1229 char_u type_string
[9];
1232 if (xswi(OS_File
, 23, file
) & v_flag
)
1233 type
= 0xfff; /* Default to Text */
1237 /* Type is the numerical value - see if we have a textual equivalent */
1238 swi(OS_FSControl
, 18, 0, type
);
1239 ((int *) type_string
)[0] = r2
;
1240 ((int *) type_string
)[1] = r3
;
1242 for (i
= 0; type_string
[i
] > ' '; i
++)
1246 set_string_option_direct("osfiletype", -1, type_string
, OPT_FREE
, 0);
1251 mch_set_filetype(file
, type
)
1255 if (xswi(OS_FSControl
, 31, type
) & v_flag
)
1257 EMSG(_("E366: Invalid 'osfiletype' option - using Text"));
1261 swi(OS_File
, 18, file
, r2
);
1264 /* Return TRUE if the file's type matches 'type'
1265 * RISC OS types always start with '&'
1268 mch_check_filetype(fname
, type
)
1278 value
= strtol(type
+ 1, &end
, 16);
1280 return FALSE
; /* Invalid type (report error?) */
1282 if (xswi(OS_File
, 23, fname
) & v_flag
)
1283 return FALSE
; /* Invalid filename? */
1285 return (r0
&& r6
== value
);