Mercurial > vim
annotate src/os_msdos.c @ 7942:5d117679edcd
Added tag v7.4.1266 for changeset 98644de08f1513a4c99381bd0c5b685fe4c8ec2f
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 06 Feb 2016 15:30:05 +0100 |
parents | cf744110897d |
children | 563c923b1584 |
rev | line source |
---|---|
7 | 1 /* vi:set ts=8 sts=4 sw=4: |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * | |
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. | |
8 */ | |
9 | |
10 /* | |
11 * os_msdos.c | |
12 * | |
13 * MSDOS system-dependent routines. | |
14 * A cheap plastic imitation of the amiga dependent code. | |
15 * A lot in this file was made by Juergen Weigert (jw). | |
16 * | |
17 * DJGPP changes by Gert van Antwerpen | |
18 * Faster text screens by John Lange (jlange@zilker.net) | |
19 * Windows clipboard functionality added by David Kotchan (dk) | |
20 * | |
21 * Some functions are also used for Win16 (MS-Windows 3.1). | |
22 */ | |
23 | |
24 #include "vim.h" | |
25 | |
3927 | 26 /* cproto fails on missing include files */ |
27 #ifndef PROTO | |
28 # include <conio.h> | |
29 #endif | |
7 | 30 |
31 /* | |
32 * MS-DOS only code, not used for Win16. | |
33 */ | |
34 #ifndef WIN16 | |
35 | |
36 | |
3927 | 37 #ifndef PROTO |
38 # include <bios.h> | |
39 # ifdef DJGPP | |
40 # include <dpmi.h> | |
41 # include <signal.h> | |
42 # include <sys/movedata.h> | |
43 # include <crt0.h> | |
44 # ifdef FEAT_CLIPBOARD | |
45 # include <sys/segments.h> | |
46 # endif | |
47 # else | |
48 # include <alloc.h> | |
7 | 49 # endif |
50 #endif | |
51 | |
52 #if defined(DJGPP) || defined(PROTO) | |
53 # define _cdecl /* DJGPP doesn't have this */ | |
54 #endif | |
55 | |
56 static int cbrk_pressed = FALSE; /* set by ctrl-break interrupt */ | |
57 static int ctrlc_pressed = FALSE; /* set when ctrl-C or ctrl-break detected */ | |
58 static int delayed_redraw = FALSE; /* set when ctrl-C detected */ | |
59 | |
60 static int bioskey_read = _NKEYBRD_READ; /* bioskey() argument: read key */ | |
61 static int bioskey_ready = _NKEYBRD_READY; /* bioskey() argument: key ready? */ | |
62 | |
63 #ifdef FEAT_MOUSE | |
64 static int mouse_avail = FALSE; /* mouse present */ | |
65 static int mouse_active; /* mouse enabled */ | |
66 static int mouse_hidden; /* mouse not shown */ | |
67 static int mouse_click = -1; /* mouse status */ | |
68 static int mouse_last_click = -1; /* previous status at click */ | |
1210 | 69 static int mouse_x = -1; /* mouse x coordinate */ |
70 static int mouse_y = -1; /* mouse y coordinate */ | |
7 | 71 static long mouse_click_time = 0; /* biostime() of last click */ |
72 static int mouse_click_count = 0; /* count for multi-clicks */ | |
73 static int mouse_click_x = 0; /* x of previous mouse click */ | |
74 static int mouse_click_y = 0; /* y of previous mouse click */ | |
75 static linenr_T mouse_topline = 0; /* w_topline at previous mouse click */ | |
76 #ifdef FEAT_DIFF | |
77 static int mouse_topfill = 0; /* w_topfill at previous mouse click */ | |
78 #endif | |
79 static int mouse_x_div = 8; /* column = x coord / mouse_x_div */ | |
80 static int mouse_y_div = 8; /* line = y coord / mouse_y_div */ | |
81 #endif | |
82 | |
83 #define BIOSTICK 55 /* biostime() increases one tick about | |
84 every 55 msec */ | |
85 | |
86 static int orig_attr = 0x0700; /* video attributes when starting */ | |
87 | |
88 static int S_iLeft = 0; /* Scroll window; these are 1 offset */ | |
89 static int S_iTop = 0; | |
90 static int S_iRight = 0; | |
91 static int S_iBottom = 0; | |
92 | |
93 /* | |
94 * Need to remember the values, because we set horizontal and vertical | |
95 * edges separately. | |
96 */ | |
97 static void | |
98 mywindow(int iLeft, int iTop, int iRight, int iBottom) | |
99 { | |
100 S_iLeft = iLeft; | |
101 S_iTop = iTop; | |
102 S_iRight = iRight; | |
103 S_iBottom = iBottom; | |
104 window(iLeft, iTop, iRight, iBottom); | |
105 } | |
106 | |
107 #ifdef DJGPP | |
108 /* | |
109 * For DJGPP, use our own functions for fast text screens. JML 1/18/98 | |
110 */ | |
111 | |
112 unsigned long S_ulScreenBase = 0xb8000; | |
113 unsigned short S_uiAttribute = 0; | |
114 int S_iCurrentRow = 0; /* These are 0 offset */ | |
115 int S_iCurrentColumn = 0; | |
116 short S_selVideo; /* Selector for DJGPP direct video transfers */ | |
117 | |
118 /* | |
119 * Use burst writes to improve mch_write speed - VJN 01/10/99 | |
120 */ | |
121 unsigned short S_linebuffer[8000]; /* <VN> enough for 160x50 */ | |
122 unsigned short S_blankbuffer[256]; /* <VN> max length of console line */ | |
123 unsigned short *S_linebufferpos = S_linebuffer; | |
124 int S_iBufferRow; | |
125 int S_iBufferColumn; | |
126 | |
127 static void | |
128 myflush(void) | |
129 { | |
130 if (S_linebufferpos != S_linebuffer) | |
131 { | |
132 _dosmemputw(S_linebuffer, (S_linebufferpos - S_linebuffer), | |
133 S_ulScreenBase | |
134 + S_iBufferRow * (Columns << 1) + (S_iBufferColumn << 1)); | |
135 S_linebufferpos = S_linebuffer; | |
136 } | |
137 } | |
138 | |
139 static void | |
140 mygotoxy(int x, int y) | |
141 { | |
142 S_iCurrentRow = y - 1; | |
143 S_iCurrentColumn = x - 1; | |
144 } | |
145 | |
146 /* | |
147 * Set the system cursor to our cursor position. | |
148 */ | |
149 static void | |
150 set_sys_cursor(void) | |
151 { | |
152 if (term_console && full_screen) | |
153 { | |
154 myflush(); | |
155 gotoxy(S_iCurrentColumn + 1, S_iCurrentRow + 1); | |
156 } | |
157 } | |
158 | |
159 static void | |
160 setblankbuffer(unsigned short uiValue) | |
161 { | |
162 int i; | |
163 static unsigned short olduiValue = 0; | |
164 | |
165 if (olduiValue != uiValue) | |
166 { | |
167 /* Load blank line buffer with spaces */ | |
168 for (i = 0; i < Columns; ++i) | |
169 S_blankbuffer[i] = uiValue; | |
170 olduiValue = uiValue; | |
171 } | |
172 } | |
173 | |
174 static void | |
175 myclreol(void) | |
176 { | |
177 /* Clear to end of line */ | |
178 setblankbuffer(S_uiAttribute | ' '); | |
179 _dosmemputw(S_blankbuffer, S_iRight - S_iCurrentColumn, S_ulScreenBase | |
180 + (S_iCurrentRow) * (Columns << 1) | |
181 + (S_iCurrentColumn << 1)); | |
182 } | |
183 | |
184 static void | |
185 myclrscr(void) | |
186 { | |
187 /* Clear whole screen */ | |
188 short iColumn; | |
189 int endpoint = (Rows * Columns) << 1; | |
190 | |
191 setblankbuffer(S_uiAttribute | ' '); | |
192 | |
193 for (iColumn = 0; iColumn < endpoint; iColumn += (Columns << 1)) | |
194 _dosmemputw(S_blankbuffer, Columns, S_ulScreenBase + iColumn); | |
195 } | |
196 | |
197 static void | |
198 mydelline(void) | |
199 { | |
200 short iRow, iColumn; | |
201 | |
202 iColumn = (S_iLeft - 1) << 1; | |
203 | |
204 /* Copy the lines underneath */ | |
205 for (iRow = S_iCurrentRow; iRow < S_iBottom - 1; iRow++) | |
206 movedata(S_selVideo, (((iRow + 1) * Columns) << 1) + iColumn, | |
207 S_selVideo, ((iRow * Columns) << 1) + iColumn, | |
208 (S_iRight - S_iLeft + 1) << 1); | |
209 | |
210 /* Clear the new row */ | |
211 setblankbuffer(S_uiAttribute | ' '); | |
212 | |
213 _dosmemputw(S_blankbuffer, (S_iRight - S_iLeft) + 1, S_ulScreenBase | |
214 + (S_iBottom - 1) * (Columns << 1) + iColumn); | |
215 } | |
216 | |
217 static void | |
218 myinsline(void) | |
219 { | |
220 short iRow, iColumn; | |
221 | |
222 iColumn = (S_iLeft - 1) << 1; | |
223 | |
224 /* Copy the lines underneath */ | |
225 for (iRow = S_iBottom - 1; iRow >= S_iTop; iRow--) | |
226 movedata(S_selVideo, (((iRow - 1) * Columns) << 1) + iColumn, | |
227 S_selVideo, ((iRow * Columns) << 1) + iColumn, | |
228 (S_iRight - S_iLeft + 1) << 1); | |
229 | |
230 /* Clear the new row */ | |
231 setblankbuffer(S_uiAttribute | ' '); | |
232 | |
233 _dosmemputw(S_blankbuffer, (S_iRight - S_iLeft) + 1, S_ulScreenBase | |
234 + (S_iTop - 1) * (Columns << 1) + iColumn); | |
235 } | |
236 | |
237 /* | |
238 * Scroll the screen one line up, clear the last line. | |
239 */ | |
240 static void | |
241 myscroll(void) | |
242 { | |
243 short iRow, iColumn; | |
244 | |
245 iColumn = (S_iLeft - 1) << 1; | |
246 | |
247 /* Copy the screen */ | |
248 for (iRow = S_iTop; iRow < S_iBottom; iRow++) | |
249 movedata(S_selVideo, ((iRow * Columns) << 1) + iColumn, | |
250 S_selVideo, (((iRow - 1) * Columns) << 1) + iColumn, | |
251 (S_iRight - S_iLeft + 1) << 1); | |
252 | |
253 /* Clear the bottom row */ | |
254 setblankbuffer(S_uiAttribute | ' '); | |
255 | |
256 _dosmemputw(S_blankbuffer, (S_iRight - S_iLeft) + 1, S_ulScreenBase | |
257 + (S_iBottom - 1) * (Columns << 1) + iColumn); | |
258 } | |
259 | |
260 static int | |
261 myputch(int iChar) | |
262 { | |
263 unsigned short uiValue; | |
264 | |
265 if (iChar == '\n') | |
266 { | |
267 myflush(); | |
268 if (S_iCurrentRow >= S_iBottom - S_iTop) | |
269 myscroll(); | |
270 else | |
271 { | |
272 S_iCurrentColumn = S_iLeft - 1; | |
273 S_iCurrentRow++; | |
274 } | |
275 } | |
276 else if (iChar == '\r') | |
277 { | |
278 myflush(); | |
279 S_iCurrentColumn = S_iLeft - 1; | |
280 } | |
281 else if (iChar == '\b') | |
282 { | |
283 myflush(); | |
284 if (S_iCurrentColumn >= S_iLeft) | |
285 S_iCurrentColumn--; | |
286 } | |
287 else if (iChar == 7) | |
288 { | |
289 sound(440); /* short beep */ | |
290 delay(200); | |
291 nosound(); | |
292 } | |
293 else | |
294 { | |
295 uiValue = S_uiAttribute | (unsigned char)iChar; | |
296 | |
297 /* | |
298 * Normal char - are we starting to buffer? | |
299 */ | |
300 if (S_linebufferpos == S_linebuffer) | |
301 { | |
302 S_iBufferColumn = S_iCurrentColumn; | |
303 S_iBufferRow = S_iCurrentRow; | |
304 } | |
305 | |
306 *S_linebufferpos++ = uiValue; | |
307 | |
308 S_iCurrentColumn++; | |
309 if (S_iCurrentColumn >= S_iRight && S_iCurrentRow >= S_iBottom - S_iTop) | |
310 { | |
311 myflush(); | |
312 myscroll(); | |
313 S_iCurrentColumn = S_iLeft - 1; | |
314 S_iCurrentRow++; | |
315 } | |
316 } | |
317 | |
318 return 0; | |
319 } | |
320 | |
321 static void | |
322 mytextinit(struct text_info *pTextinfo) | |
323 { | |
324 S_selVideo = __dpmi_segment_to_descriptor(S_ulScreenBase >> 4); | |
325 S_uiAttribute = pTextinfo->normattr << 8; | |
326 } | |
327 | |
328 static void | |
329 get_screenbase(void) | |
330 { | |
331 static union REGS regs; | |
332 | |
333 /* old Hercules grafic card has different base address (Macewicz) */ | |
334 regs.h.ah = 0x0f; | |
335 (void)int86(0x10, ®s, ®s); /* int 10 0f */ | |
336 if (regs.h.al == 0x07) /* video mode 7 -- hercules mono */ | |
337 S_ulScreenBase = 0xb0000; | |
338 else | |
339 S_ulScreenBase = 0xb8000; | |
340 } | |
341 | |
342 static void | |
343 mytextattr(int iAttribute) | |
344 { | |
345 S_uiAttribute = (unsigned short)iAttribute << 8; | |
346 } | |
347 | |
348 static void | |
349 mynormvideo(void) | |
350 { | |
351 mytextattr(orig_attr); | |
352 } | |
353 | |
354 static void | |
355 mytextcolor(int iTextColor) | |
356 { | |
357 S_uiAttribute = (unsigned short)((S_uiAttribute & 0xf000) | |
358 | (unsigned short)iTextColor << 8); | |
359 } | |
360 | |
361 static void | |
362 mytextbackground(int iBkgColor) | |
363 { | |
364 S_uiAttribute = (unsigned short)((S_uiAttribute & 0x0f00) | |
365 | (unsigned short)(iBkgColor << 12)); | |
366 } | |
367 /* | |
368 * Getdigits: Get a number from a string and skip over it. | |
369 * Note: the argument is a pointer to a char_u pointer! | |
370 */ | |
371 | |
372 static long | |
7842
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
373 mygetdigits(char_u **pp) |
7 | 374 { |
375 char_u *p; | |
376 long retval = 0; | |
377 | |
378 p = *pp; | |
379 if (*p == '-') /* skip negative sign */ | |
380 ++p; | |
381 while (VIM_ISDIGIT(*p)) | |
382 { | |
383 retval = (retval * 10) + (*p - '0'); | |
384 ++p; | |
385 } | |
386 if (**pp == '-') /* process negative sign */ | |
387 retval = -retval; | |
388 | |
389 *pp = p; | |
390 return retval; | |
391 } | |
392 #else | |
393 # define mygotoxy gotoxy | |
394 # define myputch putch | |
395 # define myscroll scroll | |
396 # define mynormvideo normvideo | |
397 # define mytextattr textattr | |
398 # define mytextcolor textcolor | |
399 # define mytextbackground textbackground | |
400 # define mygetdigits getdigits | |
401 # define myclreol clreol | |
402 # define myclrscr clrscr | |
403 # define myinsline insline | |
404 # define mydelline delline | |
405 #endif | |
406 | |
407 static const struct | |
408 { | |
409 char_u scancode; | |
410 char_u metakey; | |
411 } altkey_table[] = | |
412 { | |
413 {0x1e, 0xe1}, /* a */ | |
414 {0x30, 0xe2}, /* b */ | |
415 {0x2e, 0xe3}, /* c */ | |
416 {0x20, 0xe4}, /* d */ | |
417 {0x12, 0xe5}, /* e */ | |
418 {0x21, 0xe6}, /* f */ | |
419 {0x22, 0xe7}, /* g */ | |
420 {0x23, 0xe8}, /* h */ | |
421 {0x17, 0xe9}, /* i */ | |
422 {0x24, 0xea}, /* j */ | |
423 {0x25, 0xeb}, /* k */ | |
424 {0x26, 0xec}, /* l */ | |
425 {0x32, 0xed}, /* m */ | |
426 {0x31, 0xee}, /* n */ | |
427 {0x18, 0xef}, /* o */ | |
428 {0x19, 0xf0}, /* p */ | |
429 {0x10, 0xf1}, /* q */ | |
430 {0x13, 0xf2}, /* r */ | |
431 {0x1f, 0xf3}, /* s */ | |
432 {0x14, 0xf4}, /* t */ | |
433 {0x16, 0xf5}, /* u */ | |
434 {0x2f, 0xf6}, /* v */ | |
435 {0x11, 0xf7}, /* w */ | |
436 {0x2d, 0xf8}, /* x */ | |
437 {0x15, 0xf9}, /* y */ | |
438 {0x2c, 0xfa}, /* z */ | |
439 {0x78, 0xb1}, /* 1 */ | |
440 {0x79, 0xb2}, /* 2 */ | |
441 {0x7a, 0xb3}, /* 3 */ | |
442 {0x7b, 0xb4}, /* 4 */ | |
443 {0x7c, 0xb5}, /* 5 */ | |
444 {0x7d, 0xb6}, /* 6 */ | |
445 {0x7e, 0xb7}, /* 7 */ | |
446 {0x7f, 0xb8}, /* 8 */ | |
447 {0x80, 0xb9}, /* 9 */ | |
448 {0x81, 0xb0}, /* 0 */ | |
449 }; | |
450 | |
451 /* | |
452 * Translate extended keycodes into meta-chars where applicable | |
453 */ | |
454 static int | |
455 translate_altkeys(int rawkey) | |
456 { | |
457 int i, c; | |
458 | |
459 if ((rawkey & 0xff) == 0) | |
460 { | |
461 c = (rawkey >> 8); | |
462 for (i = sizeof(altkey_table) / sizeof(altkey_table[0]); --i >= 0; ) | |
463 { | |
464 if (c == altkey_table[i].scancode) | |
465 return (int)altkey_table[i].metakey; | |
466 } | |
467 } | |
468 return rawkey; | |
469 } | |
470 | |
471 /* | |
1210 | 472 * Set normal fg/bg color, based on T_ME. Called when t_me has been set. |
7 | 473 */ |
474 void | |
7842
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
475 mch_set_normal_colors(void) |
7 | 476 { |
477 char_u *p; | |
478 int n; | |
479 | |
480 cterm_normal_fg_color = (orig_attr & 0xf) + 1; | |
481 cterm_normal_bg_color = ((orig_attr >> 4) & 0xf) + 1; | |
482 if (T_ME[0] == ESC && T_ME[1] == '|') | |
483 { | |
484 p = T_ME + 2; | |
485 n = getdigits(&p); | |
486 if (*p == 'm' && n > 0) | |
487 { | |
488 cterm_normal_fg_color = (n & 0xf) + 1; | |
489 cterm_normal_bg_color = ((n >> 4) & 0xf) + 1; | |
490 } | |
491 } | |
492 } | |
493 | |
494 #if defined(MCH_CURSOR_SHAPE) || defined(PROTO) | |
495 /* | |
496 * Save/restore the shape of the cursor. | |
497 * call with FALSE to save, TRUE to restore | |
498 */ | |
499 static void | |
500 mch_restore_cursor_shape(int restore) | |
501 { | |
502 static union REGS regs; | |
503 static int saved = FALSE; | |
504 | |
505 if (restore) | |
506 { | |
507 if (saved) | |
36 | 508 regs.h.ah = 0x01; /* Set Cursor */ |
7 | 509 else |
510 return; | |
511 } | |
512 else | |
513 { | |
36 | 514 regs.h.ah = 0x03; /* Get Cursor */ |
515 regs.h.bh = 0x00; /* Page */ | |
7 | 516 saved = TRUE; |
517 } | |
518 | |
519 (void)int86(0x10, ®s, ®s); | |
520 } | |
521 | |
522 /* | |
523 * Set the shape of the cursor. | |
524 * 'thickness' can be from 0 (thin) to 7 (block) | |
525 */ | |
526 static void | |
527 mch_set_cursor_shape(int thickness) | |
528 { | |
529 union REGS regs; | |
530 | |
36 | 531 regs.h.ch = 7 - thickness; /* Starting Line */ |
532 regs.h.cl = 7; /* Ending Line */ | |
533 regs.h.ah = 0x01; /* Set Cursor */ | |
7 | 534 (void)int86(0x10, ®s, ®s); |
535 } | |
536 | |
537 void | |
538 mch_update_cursor(void) | |
539 { | |
540 int idx; | |
541 int thickness; | |
542 | |
543 /* | |
544 * How the cursor is drawn depends on the current mode. | |
545 */ | |
546 idx = get_shape_idx(FALSE); | |
547 | |
548 if (shape_table[idx].shape == SHAPE_BLOCK) | |
549 thickness = 7; | |
550 else | |
551 thickness = (7 * shape_table[idx].percentage + 90) / 100; | |
552 mch_set_cursor_shape(thickness); | |
553 } | |
554 #endif | |
555 | |
556 /* | |
3634 | 557 * Return amount of memory currently available in Kbyte. |
7 | 558 */ |
559 long_u | |
560 mch_avail_mem(int special) | |
561 { | |
562 #ifdef DJGPP | |
3634 | 563 return _go32_dpmi_remaining_virtual_memory() >> 10; |
7 | 564 #else |
3634 | 565 return coreleft() >> 10; |
7 | 566 #endif |
567 } | |
568 | |
569 #ifdef FEAT_MOUSE | |
570 | |
571 /* | |
572 * Set area where mouse can be moved to: The whole screen. | |
573 * Rows and Columns must be valid when calling! | |
574 */ | |
575 static void | |
576 mouse_area(void) | |
577 { | |
578 union REGS regs; | |
579 | |
580 if (mouse_avail) | |
581 { | |
582 regs.x.cx = 0; /* mouse visible between cx and dx */ | |
583 regs.x.dx = Columns * mouse_x_div - 1; | |
584 regs.x.ax = 7; | |
585 (void)int86(0x33, ®s, ®s); | |
586 | |
587 regs.x.cx = 0; /* mouse visible between cx and dx */ | |
588 regs.x.dx = Rows * mouse_y_div - 1; | |
589 regs.x.ax = 8; | |
590 (void)int86(0x33, ®s, ®s); | |
591 } | |
592 } | |
593 | |
594 static void | |
595 show_mouse(int on) | |
596 { | |
597 static int was_on = FALSE; | |
598 union REGS regs; | |
599 | |
600 if (mouse_avail) | |
601 { | |
602 if (!mouse_active || mouse_hidden) | |
603 on = FALSE; | |
604 /* | |
605 * Careful: Each switch on must be compensated by exactly one switch | |
606 * off | |
607 */ | |
608 if ((on && !was_on) || (!on && was_on)) | |
609 { | |
610 was_on = on; | |
611 regs.x.ax = on ? 1 : 2; | |
612 int86(0x33, ®s, ®s); /* show mouse */ | |
613 if (on) | |
614 mouse_area(); | |
615 } | |
616 } | |
617 } | |
618 | |
619 #endif | |
620 | |
621 /* | |
622 * Version of kbhit() and getch() that use direct console I/O. | |
623 * This avoids trouble with CTRL-P and the like, and should work over a telnet | |
624 * connection (it works for Xvi). | |
625 */ | |
626 | |
627 static int cons_key = -1; | |
628 | |
629 /* | |
630 * Try to get one character directly from the console. | |
631 * If there is a key, it is stored in cons_key. | |
632 * Only call when cons_key is -1! | |
633 */ | |
634 static void | |
635 cons_getkey(void) | |
636 { | |
637 union REGS regs; | |
638 | |
639 /* call DOS function 6: Direct console I/O */ | |
640 regs.h.ah = 0x06; | |
641 regs.h.dl = 0xff; | |
642 (void)intdos(®s, ®s); | |
643 if ((regs.x.flags & 0x40) == 0) /* zero flag not set? */ | |
644 cons_key = (regs.h.al & 0xff); | |
645 } | |
646 | |
647 /* | |
648 * Return TRUE if a character is available. | |
649 */ | |
650 static int | |
651 cons_kbhit(void) | |
652 { | |
653 if (cons_key < 0) | |
654 cons_getkey(); | |
655 return (cons_key >= 0); | |
656 } | |
657 | |
658 /* | |
659 * Return a character from the console. | |
660 * Should only be called when vim_kbhit() returns TRUE. | |
661 */ | |
662 static int | |
663 cons_getch(void) | |
664 { | |
665 int c = -1; | |
666 | |
667 if (cons_key < 0) | |
668 cons_getkey(); | |
669 c = cons_key; | |
670 cons_key = -1; | |
671 return c; | |
672 } | |
673 | |
674 | |
675 #ifdef DJGPP | |
676 /* | |
677 * DJGPP provides a kbhit() function that goes to the BIOS instead of DOS. | |
678 * This doesn't work for terminals connected to a serial port. | |
679 * Redefine kbhit() here to make it work. | |
680 */ | |
681 static int | |
682 vim_kbhit(void) | |
683 { | |
684 union REGS regs; | |
685 | |
686 regs.h.ah = 0x0b; | |
687 (void)intdos(®s, ®s); | |
688 return regs.h.al; | |
689 } | |
690 | |
691 #ifdef kbhit | |
692 # undef kbhit /* might have been defined in conio.h */ | |
693 #endif | |
694 #define kbhit() vim_kbhit() | |
695 | |
696 #endif | |
697 | |
698 /* | |
699 * Simulate WaitForChar() by slowly polling with bioskey(1) or kbhit(). | |
700 * | |
701 * If Vim should work over the serial line after a 'ctty com1' we must use | |
702 * kbhit() and getch(). (jw) | |
703 * Usually kbhit() is not used, because then CTRL-C and CTRL-P | |
4352 | 704 * will be caught by DOS (mool). |
7 | 705 * |
706 * return TRUE if a character is available, FALSE otherwise | |
707 */ | |
708 | |
709 #define FOREVER 1999999999L | |
710 | |
711 static int | |
712 WaitForChar(long msec) | |
713 { | |
714 long starttime = 0; | |
715 | |
716 if (msec != 0) | |
717 starttime = biostime(0, 0L); | |
718 | |
719 for (;;) | |
720 { | |
721 #ifdef FEAT_MOUSE | |
722 long clicktime; | |
723 static int old_status = 0; | |
799 | 724 union REGS regs; |
725 int x, y; | |
7 | 726 |
727 if (mouse_avail && mouse_active && mouse_click < 0) | |
728 { | |
729 regs.x.ax = 3; | |
730 int86(0x33, ®s, ®s); /* check mouse status */ | |
731 /* only recognize button-down and button-up event */ | |
732 x = regs.x.cx / mouse_x_div; | |
733 y = regs.x.dx / mouse_y_div; | |
734 if ((old_status == 0) != (regs.x.bx == 0)) | |
735 { | |
736 if (old_status) /* button up */ | |
737 mouse_click = MOUSE_RELEASE; | |
738 else /* button down */ | |
739 { | |
740 /* | |
741 * Translate MSDOS mouse events to Vim mouse events. | |
742 * TODO: should handle middle mouse button, by pressing | |
743 * left and right at the same time. | |
744 */ | |
745 if (regs.x.bx & MSDOS_MOUSE_LEFT) | |
746 mouse_click = MOUSE_LEFT; | |
747 else if (regs.x.bx & MSDOS_MOUSE_RIGHT) | |
748 mouse_click = MOUSE_RIGHT; | |
749 else if (regs.x.bx & MSDOS_MOUSE_MIDDLE) | |
750 mouse_click = MOUSE_MIDDLE; | |
751 | |
752 /* | |
753 * Find out if this is a multi-click | |
754 */ | |
755 clicktime = biostime(0, 0L); | |
756 if (mouse_click_x == x && mouse_click_y == y | |
757 && mouse_topline == curwin->w_topline | |
758 #ifdef FEAT_DIFF | |
759 && mouse_topfill == curwin->w_topfill | |
760 #endif | |
761 && mouse_click_count != 4 | |
762 && mouse_click == mouse_last_click | |
763 && clicktime < mouse_click_time | |
764 + p_mouset / BIOSTICK) | |
765 ++mouse_click_count; | |
766 else | |
767 mouse_click_count = 1; | |
768 mouse_click_time = clicktime; | |
769 mouse_last_click = mouse_click; | |
770 mouse_click_x = x; | |
771 mouse_click_y = y; | |
772 mouse_topline = curwin->w_topline; | |
773 #ifdef FEAT_DIFF | |
774 mouse_topfill = curwin->w_topfill; | |
775 #endif | |
776 SET_NUM_MOUSE_CLICKS(mouse_click, mouse_click_count); | |
777 } | |
778 } | |
779 else if (old_status && (x != mouse_x || y != mouse_y)) | |
780 mouse_click = MOUSE_DRAG; | |
781 old_status = regs.x.bx; | |
782 if (mouse_hidden && mouse_x >= 0 && (mouse_x != x || mouse_y != y)) | |
783 { | |
784 mouse_hidden = FALSE; | |
785 show_mouse(TRUE); | |
786 } | |
787 mouse_x = x; | |
788 mouse_y = y; | |
789 } | |
790 #endif | |
791 | |
792 if ((p_consk ? cons_kbhit() | |
793 : p_biosk ? bioskey(bioskey_ready) : kbhit()) | |
794 || cbrk_pressed | |
795 #ifdef FEAT_MOUSE | |
796 || mouse_click >= 0 | |
797 #endif | |
798 ) | |
799 return TRUE; | |
800 /* | |
801 * Use biostime() to wait until our time is done. | |
802 * We busy-wait here. Unfortunately, delay() and usleep() have been | |
803 * reported to give problems with the original Windows 95. This is | |
804 * fixed in service pack 1, but not everybody installed that. | |
805 * The DJGPP implementation of usleep() uses a busy-wait loop too. | |
806 */ | |
807 if (msec == 0 || (msec != FOREVER | |
808 && biostime(0, 0L) > starttime + msec / BIOSTICK)) | |
809 break; | |
810 | |
811 #ifdef DJGPP | |
812 /* Yield the CPU to the next process. */ | |
813 __dpmi_yield(); | |
814 #endif | |
815 } | |
816 return FALSE; | |
817 } | |
818 | |
819 /* | |
820 * don't do anything for about "msec" msec | |
821 */ | |
822 void | |
823 mch_delay( | |
824 long msec, | |
825 int ignoreinput) | |
826 { | |
827 long starttime; | |
828 | |
829 if (ignoreinput) | |
830 { | |
831 /* | |
832 * We busy-wait here. Unfortunately, delay() and usleep() have been | |
833 * reported to give problems with the original Windows 95. This is | |
834 * fixed in service pack 1, but not everybody installed that. | |
835 */ | |
836 starttime = biostime(0, 0L); | |
837 while (biostime(0, 0L) < starttime + msec / BIOSTICK) | |
838 ; | |
839 } | |
840 else | |
841 WaitForChar(msec); | |
842 } | |
843 | |
844 /* | |
845 * mch_write(): write the output buffer to the screen | |
846 */ | |
847 void | |
848 mch_write( | |
849 char_u *s, | |
850 int len) | |
851 { | |
852 char_u *p; | |
853 int row, col; | |
854 | |
855 if (term_console && full_screen) | |
856 while (len--) | |
857 { | |
858 /* translate ESC | sequences into bios calls */ | |
859 if (p_wd) /* testing: wait a bit for each char */ | |
860 WaitForChar(p_wd); | |
861 | |
862 if (s[0] == '\n') | |
863 #ifdef DJGPP | |
864 { | |
865 myflush(); | |
866 S_iCurrentColumn = S_iLeft - 1; | |
867 } | |
868 #else | |
869 myputch('\r'); | |
870 #endif | |
871 else if (s[0] == ESC && len > 1 && s[1] == '|') | |
872 { | |
873 switch (s[2]) | |
874 { | |
875 #ifdef DJGPP | |
876 case 'B': ScreenVisualBell(); | |
877 goto got3; | |
878 #endif | |
879 case 'J': | |
880 #ifdef DJGPP | |
881 myflush(); | |
882 #endif | |
883 myclrscr(); | |
884 goto got3; | |
885 | |
886 case 'K': | |
887 #ifdef DJGPP | |
888 myflush(); | |
889 #endif | |
890 myclreol(); | |
891 goto got3; | |
892 | |
893 case 'L': | |
894 #ifdef DJGPP | |
895 myflush(); | |
896 #endif | |
897 myinsline(); | |
898 goto got3; | |
899 | |
900 case 'M': | |
901 #ifdef DJGPP | |
902 myflush(); | |
903 #endif | |
904 mydelline(); | |
905 got3: s += 3; | |
906 len -= 2; | |
907 continue; | |
908 | |
909 case '0': | |
910 case '1': | |
911 case '2': | |
912 case '3': | |
913 case '4': | |
914 case '5': | |
915 case '6': | |
916 case '7': | |
917 case '8': | |
918 case '9': p = s + 2; | |
919 row = mygetdigits(&p); /* no check for length! */ | |
920 if (p > s + len) | |
921 break; | |
922 if (*p == ';') | |
923 { | |
924 ++p; | |
925 col = mygetdigits(&p); /* no check for length! */ | |
926 if (p > s + len) | |
927 break; | |
928 if (*p == 'H' || *p == 'r' || *p == 'V') | |
929 { | |
930 #ifdef DJGPP | |
931 myflush(); | |
932 #endif | |
933 if (*p == 'H') /* set cursor position */ | |
934 mygotoxy(col, row); | |
935 else if (*p == 'V') | |
936 mywindow(row, S_iTop, col, S_iBottom); | |
937 else /* set scroll region */ | |
938 mywindow(S_iLeft, row, S_iRight, col); | |
939 len -= p - s; | |
940 s = p + 1; | |
941 continue; | |
942 } | |
943 } | |
944 else if (*p == 'm' || *p == 'f' || *p == 'b') | |
945 { | |
946 if (*p == 'm') /* set color */ | |
947 { | |
948 if (row == 0) | |
949 mynormvideo();/* reset color */ | |
950 else | |
951 mytextattr(row); | |
952 } | |
953 else if (*p == 'f') /* set foreground color */ | |
954 mytextcolor(row); | |
955 else /* set background color */ | |
956 mytextbackground(row); | |
957 | |
958 len -= p - s; | |
959 s = p + 1; | |
960 continue; | |
961 } | |
962 } | |
963 } | |
964 myputch(*s++); | |
965 } | |
966 else | |
967 { | |
968 write(1, s, (unsigned)len); | |
969 } | |
970 } | |
971 | |
972 /* | |
4352 | 973 * mch_inchar(): low level input function. |
7 | 974 * Get a characters from the keyboard. |
975 * If time == 0 do not wait for characters. | |
976 * If time == n wait a short time for characters. | |
977 * If time == -1 wait forever for characters. | |
978 * | |
979 * return the number of characters obtained | |
980 */ | |
981 int | |
982 mch_inchar( | |
983 char_u *buf, | |
984 int maxlen, | |
985 long time, | |
986 int tb_change_cnt) | |
987 { | |
988 int len = 0; | |
989 int c; | |
990 int tmp_c; | |
991 static int nextchar = 0; /* may keep character when maxlen == 1 */ | |
992 | |
993 /* | |
994 * if we got a ctrl-C when we were busy, there will be a "^C" somewhere | |
4352 | 995 * on the screen, so we need to redisplay it. |
7 | 996 */ |
997 if (delayed_redraw) | |
998 { | |
999 delayed_redraw = FALSE; | |
1000 update_screen(CLEAR); | |
1001 setcursor(); | |
1002 out_flush(); | |
1003 } | |
1004 | |
1005 /* return remaining character from last call */ | |
1006 if (nextchar) | |
1007 { | |
1008 *buf = nextchar; | |
1009 nextchar = 0; | |
1010 return 1; | |
1011 } | |
1012 | |
1013 #ifdef FEAT_MOUSE | |
1014 if (time != 0) | |
1015 show_mouse(TRUE); | |
1016 #endif | |
1017 #ifdef DJGPP | |
1018 set_sys_cursor(); | |
1019 #endif | |
1020 if (time >= 0) | |
1021 { | |
1022 if (WaitForChar(time) == 0) /* no character available */ | |
1023 { | |
1024 #ifdef FEAT_MOUSE | |
1025 show_mouse(FALSE); | |
1026 #endif | |
1027 return 0; | |
1028 } | |
1029 } | |
1030 else /* time == -1 */ | |
1031 { | |
1032 /* | |
1033 * If there is no character available within 2 seconds (default) | |
212 | 1034 * write the autoscript file to disk. Or cause the CursorHold event |
1035 * to be triggered. | |
7 | 1036 */ |
212 | 1037 if (WaitForChar(p_ut) == 0) |
7 | 1038 { |
1039 #ifdef FEAT_AUTOCMD | |
610 | 1040 if (trigger_cursorhold() && maxlen >= 3) |
7 | 1041 { |
212 | 1042 buf[0] = K_SPECIAL; |
1043 buf[1] = KS_EXTRA; | |
1044 buf[2] = (int)KE_CURSORHOLD; | |
1045 return 3; | |
7 | 1046 } |
1047 #endif | |
370 | 1048 before_blocking(); |
7 | 1049 } |
1050 } | |
1051 WaitForChar(FOREVER); /* wait for key or mouse click */ | |
1052 | |
1053 /* | |
1054 * Try to read as many characters as there are, until the buffer is full. | |
1055 */ | |
1056 /* | |
1057 * we will get at least one key. Get more if they are available | |
1058 * After a ctrl-break we have to read a 0 (!) from the buffer. | |
1059 * bioskey(1) will return 0 if no key is available and when a | |
1060 * ctrl-break was typed. When ctrl-break is hit, this does not always | |
1061 * implies a key hit. | |
1062 */ | |
1063 cbrk_pressed = FALSE; | |
1064 #ifdef FEAT_MOUSE | |
1065 if (mouse_click >= 0 && maxlen >= 5) | |
1066 { | |
1067 len = 5; | |
1068 *buf++ = ESC + 128; | |
1069 *buf++ = 'M'; | |
1070 *buf++ = mouse_click; | |
1071 *buf++ = mouse_x + '!'; | |
1072 *buf++ = mouse_y + '!'; | |
1073 mouse_click = -1; | |
1074 } | |
1075 else | |
1076 #endif | |
1077 { | |
1078 #ifdef FEAT_MOUSE | |
1079 mouse_hidden = TRUE; | |
1080 #endif | |
1081 if (p_biosk && !p_consk) | |
1082 { | |
1083 while ((len == 0 || bioskey(bioskey_ready)) && len < maxlen) | |
1084 { | |
1085 c = translate_altkeys(bioskey(bioskey_read)); /* get the key */ | |
1086 /* | |
1087 * translate a few things for inchar(): | |
1088 * 0x0000 == CTRL-break -> 3 (CTRL-C) | |
1089 * 0x0300 == CTRL-@ -> NUL | |
1090 * 0xnn00 == extended key code -> K_NUL, nn | |
1091 * 0xnne0 == enhanced keyboard -> K_NUL, nn | |
1092 * K_NUL -> K_NUL, 3 | |
1093 */ | |
1094 if (c == 0) | |
1095 c = 3; | |
1096 else if (c == 0x0300) | |
1097 c = NUL; | |
1098 else if ((c & 0xff) == 0 | |
1099 || c == K_NUL | |
1100 || c == 0x4e2b | |
1101 || c == 0x4a2d | |
1102 || c == 0x372a | |
1103 || ((c & 0xff) == 0xe0 && c != 0xe0)) | |
1104 { | |
1105 if (c == K_NUL) | |
1106 c = 3; | |
1107 else | |
1108 c >>= 8; | |
1109 *buf++ = K_NUL; | |
1110 ++len; | |
1111 } | |
1112 | |
1113 if (len < maxlen) | |
1114 { | |
1115 *buf++ = c; | |
1116 len++; | |
1117 #ifdef FEAT_MBYTE | |
1118 /* Convert from 'termencoding' to 'encoding'. Only | |
1119 * translate normal characters, not key codes. */ | |
1120 if (input_conv.vc_type != CONV_NONE | |
1121 && (len == 1 || buf[-2] != K_NUL)) | |
1122 len += convert_input(buf - 1, 1, maxlen - len + 1) - 1; | |
1123 #endif | |
1124 } | |
1125 else | |
1126 nextchar = c; | |
1127 } | |
1128 } | |
1129 else | |
1130 { | |
1131 while ((len == 0 || (p_consk ? cons_kbhit() : kbhit())) | |
1132 && len < maxlen) | |
1133 { | |
1134 switch (c = (p_consk ? cons_getch() : getch())) | |
1135 { | |
1136 case 0: | |
1137 /* NUL means that there is another character. | |
1138 * Get it immediately, because kbhit() doesn't always | |
1139 * return TRUE for the second character. | |
1140 */ | |
1141 if (p_consk) | |
1142 c = cons_getch(); | |
1143 else | |
1144 c = getch(); | |
1145 tmp_c = translate_altkeys(c << 8); | |
1146 if (tmp_c == (c << 8)) | |
1147 { | |
1148 *buf++ = K_NUL; | |
1149 ++len; | |
1150 } | |
1151 else | |
1152 c = tmp_c; | |
1153 break; | |
1154 case K_NUL: | |
1155 *buf++ = K_NUL; | |
1156 ++len; | |
1157 c = 3; | |
1158 break; | |
1159 case 3: | |
1160 cbrk_pressed = TRUE; | |
1161 /*FALLTHROUGH*/ | |
1162 default: | |
1163 break; | |
1164 } | |
1165 if (len < maxlen) | |
1166 { | |
1167 *buf++ = c; | |
1168 ++len; | |
1169 } | |
1170 else | |
1171 nextchar = c; | |
1172 } | |
1173 } | |
1174 } | |
1175 #ifdef FEAT_MOUSE | |
1176 show_mouse(FALSE); | |
1177 #endif | |
1178 | |
1179 beep_count = 0; /* may beep again now that we got some chars */ | |
1180 return len; | |
1181 } | |
1182 | |
1183 /* | |
1184 * return non-zero if a character is available | |
1185 */ | |
1186 int | |
1187 mch_char_avail(void) | |
1188 { | |
1189 return WaitForChar(0L); | |
1190 } | |
1191 | |
1192 #ifdef DJGPP | |
1193 # define INT_ARG int | |
1194 #else | |
1195 # define INT_ARG | |
1196 #endif | |
1197 | |
1198 /* | |
1199 * function for ctrl-break interrupt | |
1200 */ | |
1201 static void interrupt | |
1202 #ifdef DJGPP | |
1203 catch_cbrk(int a) | |
1204 #else | |
1205 catch_cbrk(void) | |
1206 #endif | |
1207 { | |
1208 cbrk_pressed = TRUE; | |
1209 ctrlc_pressed = TRUE; | |
1210 } | |
1211 | |
1212 #ifndef DJGPP | |
1213 /* | |
1214 * ctrl-break handler for DOS. Never called when a ctrl-break is typed, because | |
1215 * we catch interrupt 1b. If you type ctrl-C while Vim is waiting for a | |
1216 * character this function is not called. When a ctrl-C is typed while Vim is | |
1217 * busy this function may be called. By that time a ^C has been displayed on | |
1218 * the screen, so we have to redisplay the screen. We can't do that here, | |
1219 * because we may be called by DOS. The redraw is in mch_inchar(). | |
1220 */ | |
1221 static int _cdecl | |
1222 cbrk_handler(void) | |
1223 { | |
1224 delayed_redraw = TRUE; | |
1225 return 1; /* resume operation after ctrl-break */ | |
1226 } | |
1227 | |
1228 /* | |
1229 * function for critical error interrupt | |
1230 * For DOS 1 and 2 return 0 (Ignore). | |
1231 * For DOS 3 and later return 3 (Fail) | |
1232 */ | |
1233 static void interrupt | |
7842
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1234 catch_cint( |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1235 unsigned bp, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1236 unsigned di, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1237 unsigned si, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1238 unsigned ds, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1239 unsigned es, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1240 unsigned dx, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1241 unsigned cx, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1242 unsigned bx, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1243 unsigned ax) |
7 | 1244 { |
1245 ax = (ax & 0xff00); /* set AL to 0 */ | |
1246 if (_osmajor >= 3) | |
1247 ax |= 3; /* set AL to 3 */ | |
1248 } | |
1249 #endif | |
1250 | |
1251 /* | |
1252 * Set the interrupt vectors for use with Vim on or off. | |
1253 * on == TRUE means as used within Vim | |
1254 */ | |
1255 static void | |
1256 set_interrupts(int on) | |
1257 { | |
1258 static int saved_cbrk; | |
1259 #ifndef DJGPP | |
1260 static void interrupt (*old_cint)(); | |
1261 #endif | |
1262 static void interrupt (*old_cbrk)(INT_ARG); | |
1263 | |
1264 if (on) | |
1265 { | |
1266 saved_cbrk = getcbrk(); /* save old ctrl-break setting */ | |
1267 setcbrk(0); /* do not check for ctrl-break */ | |
1268 #ifdef DJGPP | |
1269 old_cbrk = signal(SIGINT, catch_cbrk); /* critical error interrupt */ | |
1270 #else | |
1271 old_cint = getvect(0x24); /* save old critical error interrupt */ | |
1272 setvect(0x24, catch_cint); /* install our critical error interrupt */ | |
1273 old_cbrk = getvect(0x1B); /* save old ctrl-break interrupt */ | |
1274 setvect(0x1B, catch_cbrk); /* install our ctrl-break interrupt */ | |
1275 ctrlbrk(cbrk_handler); /* vim's ctrl-break handler */ | |
1276 #endif | |
1277 if (term_console) | |
1278 out_str(T_ME); /* set colors */ | |
1279 } | |
1280 else | |
1281 { | |
1282 setcbrk(saved_cbrk); /* restore ctrl-break setting */ | |
1283 #ifdef DJGPP | |
1284 signal(SIGINT,old_cbrk); /* critical error interrupt */ | |
1285 #else | |
1286 setvect(0x24, old_cint); /* restore critical error interrupt */ | |
1287 setvect(0x1B, old_cbrk); /* restore ctrl-break interrupt */ | |
1288 #endif | |
1289 /* restore ctrl-break handler, how ??? */ | |
1290 if (term_console) | |
1291 mynormvideo(); /* restore screen colors */ | |
1292 } | |
1293 } | |
1294 | |
1295 /* | |
1296 * We have no job control, fake it by starting a new shell. | |
1297 */ | |
1298 void | |
1299 mch_suspend(void) | |
1300 { | |
1301 suspend_shell(); | |
1302 } | |
1303 | |
1304 extern int _fmode; | |
1305 | |
1306 /* | |
1307 * Prepare window for use by Vim. | |
1308 */ | |
1309 void | |
1310 mch_init(void) | |
1311 { | |
1312 union REGS regs; | |
1313 | |
1314 #if defined(DJGPP) && defined(FEAT_CLIPBOARD) | |
1315 __dpmi_regs dpmi_regs; | |
1316 #endif | |
1317 | |
1318 /* | |
1319 * Get the video attributes at the cursor. These will be used as the | |
1320 * default attributes. | |
1321 */ | |
1322 regs.h.ah = 0x08; | |
1323 regs.h.bh = 0x00; /* video page 0 */ | |
1324 int86(0x10, ®s, ®s); | |
1325 orig_attr = regs.h.ah; | |
1326 mynormvideo(); | |
1327 if (cterm_normal_fg_color == 0) | |
1328 cterm_normal_fg_color = (orig_attr & 0xf) + 1; | |
1329 if (cterm_normal_bg_color == 0) | |
1330 cterm_normal_bg_color = ((orig_attr >> 4) & 0xf) + 1; | |
1331 | |
1332 term_console = TRUE; /* assume using the console for the things here */ | |
1333 _fmode = O_BINARY; /* we do our own CR-LF translation */ | |
1334 out_flush(); | |
1335 set_interrupts(TRUE); /* catch interrupts */ | |
1336 | |
1337 #ifdef DJGPP | |
1338 /* | |
1339 * Use Long File Names by default, if $LFN not set. | |
1340 */ | |
1341 if (getenv("LFN") == NULL) | |
1342 putenv("LFN=y"); | |
1343 | |
1344 get_screenbase(); | |
1345 #endif | |
1346 | |
1347 #ifdef FEAT_MOUSE | |
1348 /* find out if a MS compatible mouse is available */ | |
1349 regs.x.ax = 0; | |
1350 (void)int86(0x33, ®s, ®s); | |
1351 mouse_avail = regs.x.ax; | |
1352 /* best guess for mouse coordinate computations */ | |
1353 mch_get_shellsize(); | |
1354 if (Columns <= 40) | |
1355 mouse_x_div = 16; | |
1356 if (Rows == 30) | |
1357 mouse_y_div = 16; | |
1358 #endif | |
1359 | |
1360 /* | |
1361 * Try switching to 16 colors for background, instead of 8 colors and | |
1362 * blinking. Does this always work? Can the old value be restored? | |
1363 */ | |
1364 regs.x.ax = 0x1003; | |
1365 regs.h.bl = 0x00; | |
1366 regs.h.bh = 0x00; | |
1367 int86(0x10, ®s, ®s); | |
1368 | |
1369 /* | |
1370 * Test if we have an enhanced AT keyboard. Write 0xFFFF to the keyboard | |
1371 * buffer and try to read it back. If we can't in 16 tries, it's an old | |
1372 * type XT keyboard. | |
1373 */ | |
1374 regs.h.ah = 0x05; | |
1375 regs.x.cx = 0xffff; | |
1376 int86(0x16, ®s, ®s); | |
1377 if (regs.h.al != 1) /* skip this when keyboard buffer is full */ | |
1378 { | |
1379 int i; | |
1380 | |
1381 for (i = 0; i < 16; ++i) | |
1382 { | |
1383 regs.h.ah = 0x10; | |
1384 int86(0x16, ®s, ®s); | |
1385 if (regs.x.ax == 0xffff) | |
1386 break; | |
1387 } | |
1388 if (i == 16) /* 0xffff not read, must be old keyboard */ | |
1389 { | |
1390 bioskey_read = 0; | |
1391 bioskey_ready = 1; | |
1392 } | |
1393 } | |
1394 | |
1395 #ifdef MCH_CURSOR_SHAPE | |
1396 /* Save the old cursor shape */ | |
1397 mch_restore_cursor_shape(FALSE); | |
1398 /* Initialise the cursor shape */ | |
1399 mch_update_cursor(); | |
1400 #endif | |
1401 | |
1402 #if defined(DJGPP) && defined(FEAT_CLIPBOARD) | |
1403 /* | |
1404 * Check to see if the Windows clipboard is available, ie. are we | |
1405 * running from a DOS session within Windows. Obviously, the Windows | |
1406 * clipboard will not be available if we're running under pure DOS. | |
1407 * | |
1408 * int 0x2f, AX = 0x1700 identifies the Windows version we're running | |
1409 * under. Upon return from the interrupt, if AX is unchanged, we're | |
1410 * running under pure DOS and no Windows clipboard is available. | |
1411 * | |
1412 * Remark: could use int86() here but __dpmi_int() is recommended in | |
1413 * the DJGPP docs, since int86() doesn't cover all available interrupts. | |
1414 */ | |
1415 dpmi_regs.x.ax = 0x1700; | |
1416 if (__dpmi_int(0x2f, &dpmi_regs) == -1) | |
1417 /* real-mode interrupt failed? */ | |
1418 dpmi_regs.x.ax = 0x1700; /* force failure */ | |
1419 | |
1420 if (dpmi_regs.x.ax == 0x1700) /* no change in AX? */ | |
1421 clip_init(FALSE); /* no clipboard available, too bad */ | |
1422 else /* else, running under Windows, OK */ | |
1423 clip_init(TRUE); /* clipboard is available */ | |
1424 #endif | |
1425 } | |
1426 | |
1427 int | |
1428 mch_check_win( | |
1429 int argc, | |
1430 char **argv) | |
1431 { | |
1432 /* store argv[0], may be used for $VIM */ | |
1433 if (*argv[0] != NUL) | |
1434 exe_name = FullName_save((char_u *)argv[0], FALSE); | |
1435 | |
1436 /* | |
1437 * Try the DOS search path. The executable may in | |
1438 * fact be called differently, so try this last. | |
1439 */ | |
1440 if (exe_name == NULL || *exe_name == NUL) | |
1441 exe_name = searchpath("vim.exe"); | |
1442 | |
1443 if (isatty(1)) | |
1444 return OK; | |
1445 return FAIL; | |
1446 } | |
1447 | |
1448 /* | |
1449 * Return TRUE if the input comes from a terminal, FALSE otherwise. | |
1450 */ | |
1451 int | |
1452 mch_input_isatty(void) | |
1453 { | |
1454 if (isatty(read_cmd_fd)) | |
1455 return TRUE; | |
1456 return FALSE; | |
1457 } | |
1458 | |
1459 #if defined(USE_FNAME_CASE) || defined(PROTO) | |
1460 /* | |
1461 * fname_case(): Set the case of the file name, if it already exists. | |
1462 * TODO: should expand short to long file names. Need to use DOS interrupts, | |
1463 * see DJGPP sources libc/dos/dir/findfirs.c. | |
1464 */ | |
1465 void | |
1466 fname_case(char_u *name, int len) | |
1467 { | |
1468 char_u *tail; | |
1469 struct ffblk fb; | |
1470 | |
1471 slash_adjust(name); | |
1472 if (findfirst(name, &fb, 0) == 0) | |
1473 { | |
1474 tail = gettail(name); | |
1475 if (len == 0 ? STRLEN(tail) == STRLEN(fb.ff_name) | |
1476 : (tail - name) + STRLEN(fb.ff_name) < len) | |
1477 STRCPY(tail, fb.ff_name); | |
1478 } | |
1479 } | |
1480 #endif | |
1481 | |
1482 /* | |
1483 * return process ID | |
1484 */ | |
1485 long | |
1486 mch_get_pid(void) | |
1487 { | |
1488 return (long)0; | |
1489 } | |
1490 | |
1491 /* | |
1492 * Change default drive (just like _chdrive of Borland C 3.1) | |
1493 */ | |
1494 static int | |
1495 change_drive(int drive) | |
1496 { | |
1497 union REGS regs; | |
1498 | |
1499 regs.h.ah = 0x0e; | |
1500 regs.h.dl = drive - 1; | |
1501 intdos(®s, ®s); /* set default drive */ | |
1502 regs.h.ah = 0x19; | |
1503 intdos(®s, ®s); /* get default drive */ | |
1504 if (regs.h.al == drive - 1) | |
1505 return 0; | |
1506 return -1; | |
1507 } | |
1508 | |
1509 /* | |
1510 * Get absolute file name into buffer 'buf' of length 'len' bytes. | |
1511 * All slashes are replaced with backslashes, to avoid trouble when comparing | |
1512 * file names. When 'shellslash' set do it the other way around. | |
1513 * | |
1514 * return FAIL for failure, OK otherwise | |
1515 */ | |
1516 int | |
1517 mch_FullName( | |
1518 char_u *fname, | |
1519 char_u *buf, | |
1520 int len, | |
1521 int force) | |
1522 { | |
1523 if (!force && mch_isFullName(fname)) /* already expanded */ | |
1524 { | |
418 | 1525 vim_strncpy(buf, fname, len - 1); |
7 | 1526 slash_adjust(buf); |
1527 return OK; | |
1528 } | |
1529 | |
1530 #ifdef __BORLANDC__ /* Only Borland C++ has this */ | |
1531 if (_fullpath((char *)buf, (char *)fname, len - 1) == NULL) | |
1532 return FAIL; | |
1533 return OK; | |
1534 #else /* almost the same as mch_FullName() in os_unix.c */ | |
1535 { | |
1536 # if 1 | |
1537 char_u fullpath[MAXPATHL]; | |
1538 | |
1539 if (!_truename(fname, fullpath)) | |
1540 return FAIL; | |
1541 slash_adjust(fullpath); /* Only needed when 'shellslash' set */ | |
418 | 1542 vim_strncpy(buf, fullpath, len - 1); |
7 | 1543 return OK; |
1544 | |
1545 # else /* Old code, to be deleted... */ | |
1546 int l; | |
1547 char_u olddir[MAXPATHL]; | |
1548 char_u *p, *q; | |
1549 int c; | |
1550 int retval = OK; | |
1551 | |
1552 *buf = 0; | |
1553 /* | |
1554 * change to the directory for a moment, | |
1555 * and then do the getwd() (and get back to where we were). | |
1556 * This will get the correct path name with "../" things. | |
1557 */ | |
1558 p = vim_strrchr(fname, '/'); | |
1559 q = vim_strrchr(fname, '\\'); | |
1560 if (q != NULL && (p == NULL || q > p)) | |
1561 p = q; | |
1562 q = vim_strrchr(fname, ':'); | |
1563 if (q != NULL && (p == NULL || q > p)) | |
1564 p = q; | |
1565 if (p != NULL) | |
1566 { | |
1567 if (getcwd(olddir, MAXPATHL) == NULL) | |
1568 { | |
1569 p = NULL; /* can't get current dir: don't chdir */ | |
1570 retval = FAIL; | |
1571 } | |
1572 else | |
1573 { | |
1574 if (p == fname) /* /fname */ | |
1575 q = p + 1; /* -> / */ | |
1576 else if (q + 1 == p) /* ... c:\foo */ | |
1577 q = p + 1; /* -> c:\ */ | |
1578 else /* but c:\foo\bar */ | |
1579 q = p; /* -> c:\foo */ | |
1580 | |
1581 c = *q; /* truncate at start of fname */ | |
1582 *q = NUL; | |
1583 # ifdef DJGPP | |
1584 STRCPY(buf, fname); | |
1585 slash_adjust(buf); /* needed when fname starts with \ */ | |
1586 if (mch_chdir(buf)) /* change to the directory */ | |
1587 # else | |
1588 if (mch_chdir(fname)) /* change to the directory */ | |
1589 # endif | |
1590 retval = FAIL; | |
1591 else | |
1592 { | |
1593 fname = q; | |
1594 if (c == psepc) /* if we cut the name at a */ | |
1595 fname++; /* '\', don't add it again */ | |
1596 } | |
1597 *q = c; | |
1598 } | |
1599 } | |
1600 if (getcwd(buf, len) == NULL) | |
1601 { | |
1602 retval = FAIL; | |
1603 *buf = NUL; | |
1604 } | |
1605 # ifdef USE_FNAME_CASE | |
1606 else | |
1607 { | |
1608 char_u *head; | |
1609 char_u *tail; | |
1610 struct ffblk fb; | |
1611 int c; | |
1612 int added; | |
1613 | |
1614 /* Apparently "longna~1" isn't expanded by getcwd(), at least not | |
1615 * for DJGPP. Expand it here. Have to do each dirname | |
1616 * separately. */ | |
1617 slash_adjust(buf); | |
1618 head = buf; | |
1619 if (isalpha(*head) && head[1] == ':') | |
1620 head += 2; /* skip "c:" */ | |
1621 while (*head != NUL) | |
1622 { | |
1623 /* Advance "head" to the start of a dirname and "tail" to just | |
1624 * after it. */ | |
1625 while (*head == '/' || *head == '\\') | |
1626 ++head; | |
1627 for (tail = head; *tail != NUL; ++tail) | |
1628 if (*tail == '/' || *tail == '\\') | |
1629 break; | |
1630 c = *tail; | |
1631 *tail = NUL; | |
1632 | |
1633 if (findfirst(buf, &fb, FA_DIREC) == 0) | |
1634 { | |
1635 added = STRLEN(fb.ff_name); | |
1636 if ((head - buf) + added + STRLEN(tail + 1) + 2 < len) | |
1637 { | |
1638 added -= (tail - head); | |
1639 if (added != 0) | |
1621 | 1640 STRMOVE(tail + 1 + added, tail + 1); |
7 | 1641 STRCPY(head, fb.ff_name); |
1642 tail += added; | |
1643 } | |
1644 } | |
1645 *tail = c; | |
1646 head = tail; | |
1647 } | |
1648 } | |
1649 # endif | |
1650 if (p != NULL) | |
1651 mch_chdir(olddir); | |
1652 /* | |
1653 * Concatenate the file name to the path. | |
1654 */ | |
1655 if (*fname != NUL) | |
1656 { | |
1657 l = STRLEN(buf); | |
1658 if (l > 0 && buf[l - 1] != '/' && buf[l - 1] != '\\') | |
1659 strcat(buf, pseps); | |
1660 strcat(buf, fname); | |
1661 } | |
1662 return retval; | |
1663 # endif | |
1664 } | |
1665 #endif | |
1666 } | |
1667 | |
1668 /* | |
1669 * Replace all slashes by backslashes. | |
1670 * This used to be the other way around, but MS-DOS sometimes has problems | |
1671 * with slashes (e.g. in a command name). We can't have mixed slashes and | |
1672 * backslashes, because comparing file names will not work correctly. The | |
1673 * commands that use a file name should try to avoid the need to type a | |
1674 * backslash twice. | |
1675 * When 'shellslash' set do it the other way around. | |
1676 */ | |
1677 void | |
1678 slash_adjust(char_u *p) | |
1679 { | |
1680 #ifdef OLD_DJGPP /* this seems to have been fixed in DJGPP 2.01 */ | |
1681 /* DJGPP can't handle a file name that starts with a backslash, and when it | |
1682 * starts with a slash there should be no backslashes */ | |
1683 if (*p == '\\' || *p == '/') | |
1684 while (*p) | |
1685 { | |
1686 if (*p == '\\') | |
1687 *p = '/'; | |
39 | 1688 mb_ptr_adv(p); |
7 | 1689 } |
1690 else | |
1691 #endif | |
1692 while (*p) | |
1693 { | |
1694 if (*p == psepcN) | |
1695 *p = psepc; | |
39 | 1696 mb_ptr_adv(p); |
7 | 1697 } |
1698 } | |
1699 | |
1700 /* | |
1701 * Return TRUE if "fname" does not depend on the current directory. | |
1702 */ | |
1703 int | |
1704 mch_isFullName(char_u *fname) | |
1705 { | |
1706 /* A name like "d:/foo" and "//server/share" is absolute */ | |
1707 return (fname[0] != NUL && fname[1] == ':' | |
1708 && (fname[2] == '/' || fname[2] == '\\')) | |
1709 || (fname[0] == fname[1] && (fname[0] == '/' || fname[0] == '\\')); | |
1710 } | |
1711 | |
1712 | |
1713 void | |
1714 mch_early_init(void) | |
1715 { | |
1716 } | |
1717 | |
1718 /* | |
1719 * Careful: mch_exit() may be called before mch_init()! | |
1720 */ | |
1721 void | |
1722 mch_exit(int r) | |
1723 { | |
1724 settmode(TMODE_COOK); | |
1725 stoptermcap(); | |
1726 set_interrupts(FALSE); /* restore interrupts */ | |
1727 #ifdef DJGPP | |
1728 set_sys_cursor(); | |
1729 #endif | |
1730 /* Somehow outputting CR-NL causes the original colors to be restored */ | |
1731 out_char('\r'); | |
1732 out_char('\n'); | |
1733 out_flush(); | |
1734 ml_close_all(TRUE); /* remove all memfiles */ | |
1735 #ifdef MCH_CURSOR_SHAPE | |
1736 mch_restore_cursor_shape(TRUE); | |
1737 #endif | |
1738 exit(r); | |
1739 } | |
1740 | |
1741 /* | |
1742 * set the tty in (raw) ? "raw" : "cooked" mode | |
1743 * Does not change the tty, as bioskey() and kbhit() work raw all the time. | |
1744 */ | |
1745 void | |
1746 mch_settmode(int tmode) | |
1747 { | |
1748 } | |
1749 | |
1750 #ifdef FEAT_MOUSE | |
1751 void | |
1752 mch_setmouse(int on) | |
1753 { | |
1754 mouse_active = on; | |
4352 | 1755 mouse_hidden = TRUE; /* don't show it until moved */ |
7 | 1756 } |
1757 #endif | |
1758 | |
1759 /* | |
1760 * set screen mode | |
1761 * return FAIL for failure, OK otherwise | |
1762 */ | |
1763 int | |
1764 mch_screenmode(char_u *arg) | |
1765 { | |
1766 int mode; | |
1767 int i; | |
1768 static char *(names[]) = {"BW40", "C40", "BW80", "C80", "MONO", "C4350"}; | |
1769 static int modes[] = { BW40, C40, BW80, C80, MONO, C4350}; | |
1770 | |
1771 mode = -1; | |
1772 if (VIM_ISDIGIT(*arg)) /* mode number given */ | |
1773 mode = atoi((char *)arg); | |
1774 else | |
1775 { | |
1776 for (i = 0; i < sizeof(names) / sizeof(char_u *); ++i) | |
1777 if (stricmp(names[i], (char *)arg) == 0) | |
1778 { | |
1779 mode = modes[i]; | |
1780 break; | |
1781 } | |
1782 } | |
1783 if (mode == -1) | |
1784 { | |
1785 EMSG("E362: Unsupported screen mode"); | |
1786 return FAIL; | |
1787 } | |
1788 textmode(mode); /* use Borland function */ | |
1789 #ifdef DJGPP | |
1790 /* base address may have changed */ | |
1791 get_screenbase(); | |
1792 #endif | |
1793 | |
1794 /* Screen colors may have changed. */ | |
1795 out_str(T_ME); | |
1796 | |
1797 #ifdef FEAT_MOUSE | |
1798 if (mode <= 1 || mode == 4 || mode == 5 || mode == 13 || mode == 0x13) | |
1799 mouse_x_div = 16; | |
1800 else | |
1801 mouse_x_div = 8; | |
1802 if (mode == 0x11 || mode == 0x12) | |
1803 mouse_y_div = 16; | |
1804 else if (mode == 0x10) | |
1805 mouse_y_div = 14; | |
1806 else | |
1807 mouse_y_div = 8; | |
1808 shell_resized(); | |
1809 #endif | |
1810 return OK; | |
1811 } | |
1812 | |
1813 /* | |
1814 * Structure used by Turbo-C/Borland-C to store video parameters. | |
1815 */ | |
1816 #ifndef DJGPP | |
1817 extern struct text_info _video; | |
1818 #endif | |
1819 | |
1820 /* | |
1821 * try to get the real window size | |
1822 * return FAIL for failure, OK otherwise | |
1823 */ | |
1824 int | |
1825 mch_get_shellsize(void) | |
1826 { | |
1827 struct text_info textinfo; | |
1828 | |
1829 /* | |
1830 * The screenwidth is returned by the BIOS OK. | |
1831 * The screenheight is in a location in the bios RAM, if the display is | |
1832 * EGA or VGA. | |
1833 */ | |
1834 if (!term_console) | |
1835 return FAIL; | |
1836 gettextinfo(&textinfo); | |
1837 Columns = textinfo.screenwidth; | |
1838 Rows = textinfo.screenheight; | |
1839 #ifndef DJGPP | |
1840 if (textinfo.currmode > 10) | |
1841 Rows = *(char far *)MK_FP(0x40, 0x84) + 1; | |
1842 #endif | |
1843 | |
1844 if (Columns < MIN_COLUMNS || Rows < MIN_LINES) | |
1845 { | |
1846 /* these values are overwritten by termcap size or default */ | |
1847 Columns = 80; | |
1848 Rows = 25; | |
1849 return FAIL; | |
1850 } | |
1851 #ifdef DJGPP | |
1852 mytextinit(&textinfo); /* Added by JML, 1/15/98 */ | |
1853 #endif | |
1854 | |
1855 return OK; | |
1856 } | |
1857 | |
1858 /* | |
1859 * Set the active window for delline/insline. | |
1860 */ | |
1861 static void | |
1862 set_window(void) | |
1863 { | |
1864 if (term_console) | |
1865 { | |
1866 #ifndef DJGPP | |
1867 _video.screenheight = Rows; | |
1868 #endif | |
1869 mywindow(1, 1, Columns, Rows); | |
1870 } | |
1871 screen_start(); | |
1872 } | |
1873 | |
1874 void | |
1875 mch_set_shellsize(void) | |
1876 { | |
1877 /* Should try to set the window size to Rows and Columns. | |
1878 * May involve switching display mode.... | |
1879 * We assume the user knows the size and just use it. */ | |
1880 } | |
1881 | |
1882 /* | |
1883 * Rows and/or Columns has changed. | |
1884 */ | |
1885 void | |
7842
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1886 mch_new_shellsize(void) |
7 | 1887 { |
1888 #ifdef FEAT_MOUSE | |
1889 /* best guess for mouse coordinate computations */ | |
1890 if (Columns <= 40) | |
1891 mouse_x_div = 16; | |
1892 if (Rows == 30) | |
1893 mouse_y_div = 16; | |
1894 #endif | |
1895 set_window(); | |
1896 #ifdef FEAT_MOUSE | |
1897 mouse_area(); /* set area where mouse can go */ | |
1898 #endif | |
1899 } | |
1900 | |
1901 #if defined(DJGPP) || defined(PROTO) | |
1902 /* | |
1903 * Check the number of Columns with a BIOS call. This avoids a crash of the | |
1904 * DOS console when 'columns' is set to a too large value. | |
1905 */ | |
1906 void | |
7842
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
1907 mch_check_columns(void) |
7 | 1908 { |
1909 static union REGS regs; | |
1910 | |
1911 regs.h.ah = 0x0f; | |
1912 (void)int86(0x10, ®s, ®s); | |
1913 if ((unsigned)Columns > (unsigned)regs.h.ah) | |
1914 Columns = (unsigned)regs.h.ah; | |
1915 } | |
1916 #endif | |
1917 | |
1918 /* | |
1919 * call shell, return FAIL for failure, OK otherwise | |
1920 * options: SHELL_*, see vim.h. | |
1921 */ | |
1922 int | |
1923 mch_call_shell( | |
1924 char_u *cmd, | |
1925 int options) | |
1926 { | |
1927 int x; | |
1928 int tmode = cur_tmode; | |
1929 #ifndef DJGPP | |
1930 char_u *newcmd; | |
1931 #endif | |
1932 | |
1933 out_flush(); | |
1934 #ifdef DJGPP | |
1935 set_sys_cursor(); | |
1936 #endif | |
1937 | |
1938 if (options & SHELL_COOKED) | |
1939 settmode(TMODE_COOK); /* set to normal mode */ | |
1940 set_interrupts(FALSE); /* restore interrupts */ | |
1941 | |
1942 #ifdef DJGPP | |
1943 /* ignore signals while external command is running */ | |
1944 signal(SIGINT, SIG_IGN); | |
1945 signal(SIGHUP, SIG_IGN); | |
1946 signal(SIGQUIT, SIG_IGN); | |
1947 signal(SIGTERM, SIG_IGN); | |
1948 #endif | |
1949 if (cmd == NULL) | |
1950 x = system((char *)p_sh); | |
1951 else | |
1952 { | |
1953 #ifdef DJGPP | |
1954 /* | |
1955 * Use 'shell' for system(). | |
1956 */ | |
1957 setenv("SHELL", (char *)p_sh, 1); | |
1958 x = system(cmd); | |
1959 #else | |
1960 /* we use "command" to start the shell, slow but easy */ | |
1961 newcmd = alloc(STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 3); | |
1962 if (newcmd == NULL) | |
1963 x = -1; | |
1964 else | |
1965 { | |
1966 sprintf((char *)newcmd, "%s %s %s", p_sh, p_shcf, cmd); | |
1967 x = system((char *)newcmd); | |
1968 vim_free(newcmd); | |
1969 } | |
1970 #endif | |
1971 } | |
1972 #ifdef DJGPP | |
1973 signal(SIGINT, SIG_DFL); | |
1974 signal(SIGHUP, SIG_DFL); | |
1975 signal(SIGQUIT, SIG_DFL); | |
1976 signal(SIGTERM, SIG_DFL); | |
1977 #endif | |
1978 if (tmode == TMODE_RAW) | |
1979 settmode(TMODE_RAW); /* set to raw mode */ | |
1980 set_interrupts(TRUE); /* catch interrupts */ | |
1981 | |
1982 if (x && !(options & SHELL_SILENT) && !emsg_silent) | |
1983 { | |
1984 MSG_PUTS("\nshell returned "); | |
1985 msg_outnum((long)x); | |
1986 msg_putchar('\n'); | |
1987 } | |
1988 | |
1989 return x; | |
1990 } | |
1991 | |
1992 /* | |
1993 * check for an "interrupt signal": CTRL-break or CTRL-C | |
1994 */ | |
1995 void | |
1996 mch_breakcheck(void) | |
1997 { | |
1998 if (ctrlc_pressed) | |
1999 { | |
2000 ctrlc_pressed = FALSE; | |
2001 got_int = TRUE; | |
2002 } | |
2003 } | |
2004 | |
2005 /* | |
2006 * Return TRUE if "p" contain a wildcard that can be expanded by | |
2007 * dos_expandpath(). | |
2008 */ | |
2009 int | |
2010 mch_has_exp_wildcard(char_u *p) | |
2011 { | |
39 | 2012 for ( ; *p; mb_ptr_adv(p)) |
7 | 2013 { |
2014 if (vim_strchr((char_u *)"?*[", *p) != NULL | |
2015 || (*p == '~' && p[1] != NUL)) | |
2016 return TRUE; | |
2017 } | |
2018 return FALSE; | |
2019 } | |
2020 | |
2021 /* | |
2022 * Return TRUE if "p" contain a wildcard or a "~1" kind of thing (could be a | |
2023 * shortened file name). | |
2024 */ | |
2025 int | |
2026 mch_has_wildcard(char_u *p) | |
2027 { | |
39 | 2028 for ( ; *p; mb_ptr_adv(p)) |
7 | 2029 { |
2030 if (vim_strchr((char_u *) | |
2031 # ifdef VIM_BACKTICK | |
2032 "?*$[`" | |
2033 # else | |
2034 "?*$[" | |
2035 # endif | |
2036 , *p) != NULL | |
2037 || (*p == '~' && p[1] != NUL)) | |
2038 return TRUE; | |
2039 } | |
2040 return FALSE; | |
2041 } | |
2042 | |
2043 /* | |
2044 * Change directory to "path". | |
2045 * The normal chdir() does not change the default drive. This one does. | |
2046 * Return 0 for success, -1 for failure. | |
2047 */ | |
2048 int | |
2049 mch_chdir(char *path) | |
2050 { | |
2051 if (path[0] == NUL) /* just checking... */ | |
2052 return 0; | |
1936 | 2053 if (p_verbose >= 5) |
2054 { | |
2055 verbose_enter(); | |
2056 smsg((char_u *)"chdir(%s)", path); | |
2057 verbose_leave(); | |
2058 } | |
7 | 2059 if (path[1] == ':') /* has a drive name */ |
2060 { | |
2061 if (change_drive(TOLOWER_ASC(path[0]) - 'a' + 1)) | |
2062 return -1; /* invalid drive name */ | |
2063 path += 2; | |
2064 } | |
2065 if (*path == NUL) /* drive name only */ | |
2066 return 0; | |
2067 return chdir(path); /* let the normal chdir() do the rest */ | |
2068 } | |
2069 | |
2070 #ifdef DJGPP | |
2071 /* | |
2072 * mch_rename() works around a bug in rename (aka MoveFile) in | |
2073 * Windows 95: rename("foo.bar", "foo.bar~") will generate a | |
2074 * file whose short file name is "FOO.BAR" (its long file name will | |
2075 * be correct: "foo.bar~"). Because a file can be accessed by | |
2076 * either its SFN or its LFN, "foo.bar" has effectively been | |
2077 * renamed to "foo.bar", which is not at all what was wanted. This | |
2078 * seems to happen only when renaming files with three-character | |
2079 * extensions by appending a suffix that does not include ".". | |
2080 * Windows NT gets it right, however, with an SFN of "FOO~1.BAR". | |
2081 * This works like mch_rename in os_win32.c, but is a bit simpler. | |
2082 * | |
2083 * Like rename(), returns 0 upon success, non-zero upon failure. | |
2084 * Should probably set errno appropriately when errors occur. | |
2085 */ | |
2086 | |
2087 int | |
2088 mch_rename(const char *OldFile, const char *NewFile) | |
2089 { | |
2090 char_u *TempFile; | |
2091 int retval; | |
2092 int fd; | |
2093 | |
2094 /* rename() works correctly without long file names, so use that */ | |
2095 if (!_USE_LFN) | |
2096 return rename(OldFile, NewFile); | |
2097 | |
2098 if ((TempFile = alloc((unsigned)(STRLEN(OldFile) + 13))) == NULL) | |
2099 return -1; | |
2100 | |
2101 STRCPY(TempFile, OldFile); | |
2102 STRCPY(gettail(TempFile), "axlqwqhy.ba~"); | |
2103 if (rename(OldFile, TempFile)) | |
2104 retval = -1; | |
2105 else | |
2106 { | |
2107 /* now create an empty file called OldFile; this prevents | |
2108 * the operating system using OldFile as an alias (SFN) | |
2109 * if we're renaming within the same directory. For example, | |
2110 * we're editing a file called filename.asc.txt by its SFN, | |
2111 * filena~1.txt. If we rename filena~1.txt to filena~1.txt~ | |
2112 * (i.e., we're making a backup while writing it), the SFN | |
2113 * for filena~1.txt~ will be filena~1.txt, by default, which | |
39 | 2114 * will cause all sorts of problems later in buf_write(). So, we |
7 | 2115 * create an empty file called filena~1.txt and the system will have |
2116 * to find some other SFN for filena~1.txt~, such as filena~2.txt | |
2117 */ | |
2118 if ((fd = open(OldFile, O_RDWR|O_CREAT|O_EXCL, 0444)) < 0) | |
2119 return -1; | |
2120 retval = rename(TempFile, NewFile); | |
2121 close(fd); | |
2122 mch_remove((char_u *)OldFile); | |
2123 | |
2124 /* If renaming to NewFile failed, rename TempFile back to OldFile, so | |
2125 * that it looks like nothing happened. */ | |
2126 if (retval) | |
2127 rename(TempFile, OldFile); | |
2128 } | |
2129 vim_free(TempFile); | |
2130 | |
2131 return retval; /* success */ | |
2132 } | |
2133 #endif | |
2134 | |
2135 #if defined(DJGPP) || defined(PROTO) | |
2136 /* | |
2137 * setlocale() for DJGPP with MS-DOS codepage support | |
2138 * Author: Cyril Slobin <slobin@fe.msk.ru> | |
2139 * | |
2140 * Scaled down a lot for use by Vim: Only support setlocale(LC_ALL, ""). | |
2141 */ | |
2142 | |
2143 #undef setlocale | |
2144 | |
3927 | 2145 #ifndef PROTO |
2146 # include <go32.h> | |
2147 # include <inlines/ctype.ha> | |
2148 #endif | |
7 | 2149 #include <locale.h> |
2150 | |
2151 #define UPCASE (__dj_ISALNUM | __dj_ISALPHA | __dj_ISGRAPH | __dj_ISPRINT | __dj_ISUPPER) | |
2152 #define LOCASE (__dj_ISALNUM | __dj_ISALPHA | __dj_ISGRAPH | __dj_ISPRINT | __dj_ISLOWER) | |
2153 | |
2154 char * | |
2155 djgpp_setlocale(void) | |
2156 { | |
2157 __dpmi_regs regs; | |
2158 struct { char id; unsigned short off, seg; } __attribute__ ((packed)) info; | |
2159 unsigned char buffer[0x82], lower, upper; | |
2160 int i; | |
2161 | |
2162 regs.x.ax = 0x6502; | |
2163 regs.x.bx = 0xffff; | |
2164 regs.x.dx = 0xffff; | |
2165 regs.x.cx = 5; | |
2166 regs.x.es = __tb >> 4; | |
2167 regs.x.di = __tb & 0xf; | |
2168 | |
2169 __dpmi_int(0x21, ®s); | |
2170 | |
2171 if (regs.x.flags & 1) | |
2172 return NULL; | |
2173 | |
2174 dosmemget(__tb, 5, &info); | |
2175 dosmemget((info.seg << 4) + info.off, 0x82, buffer); | |
2176 | |
2177 if (*(short *)buffer != 0x80) | |
2178 return NULL; | |
2179 | |
2180 /* Fix problem of underscores being replaced with y-umlaut. (Levin) */ | |
2181 if (buffer[26] == 0x5f) | |
2182 buffer[26] = 0x98; | |
2183 | |
2184 for (i = 0; i < 0x80; i++) | |
2185 { | |
2186 lower = i + 0x80; | |
2187 upper = (buffer+2)[i]; | |
2188 if (lower != upper) | |
2189 { | |
2190 __dj_ctype_flags[lower+1] = LOCASE; | |
2191 __dj_ctype_toupper[lower+1] = upper; | |
2192 if (__dj_ctype_flags[upper+1] == 0) | |
2193 __dj_ctype_flags[upper+1] = UPCASE; | |
2194 if (__dj_ctype_tolower[upper+1] == upper) | |
2195 __dj_ctype_tolower[upper+1] = lower; | |
2196 } | |
2197 } | |
2198 | |
2199 return "C"; | |
2200 } | |
2201 | |
2202 #if defined(FEAT_CLIPBOARD) || defined(PROTO) | |
2203 | |
2204 /* | |
2205 * Clipboard stuff, for cutting and pasting text to other windows. | |
2206 * | |
2207 * Implementation of DOS/Windows clipboard data transfer | |
2208 * by David Kotchan (dkotchan@sympatico.ca) | |
2209 */ | |
2210 | |
2211 #define CF_TEXT 0x01 /* Windows clipboard format: Windows (ANSI) text */ | |
2212 #define CF_OEMTEXT 0x07 /* Windows clipboard format: OEM (DOS) text */ | |
2213 #define CF_VIMCLIP 0x04 /* trick: SYLK clipboard format for VimClipboard */ | |
2214 | |
2215 static int Win16OpenClipboard(void); | |
2216 static int Win16CloseClipboard(void); | |
2217 static int Win16EmptyClipboard(void); | |
2218 static char_u *Win16GetClipboardData(int clip_data_format); | |
2219 static int Win16SetClipboardData(int clip_data_format, char_u *clip_data, int clip_data_size, int clip_data_type); | |
2220 | |
2221 /* | |
2222 * Make vim the owner of the current selection. Return OK upon success. | |
2223 */ | |
2224 int | |
2225 clip_mch_own_selection(VimClipboard *cbd) | |
2226 { | |
2227 /* | |
2228 * Never actually own the clipboard. If another application sets the | |
2229 * clipboard, we don't want to think that we still own it. | |
2230 */ | |
2231 return FAIL; | |
2232 } | |
2233 | |
2234 /* | |
2235 * Make vim NOT the owner of the current selection. | |
2236 */ | |
2237 void | |
2238 clip_mch_lose_selection(VimClipboard *cbd) | |
2239 { | |
2240 /* Nothing needs to be done here */ | |
2241 } | |
2242 | |
2243 /* | |
2244 * Read the Windows clipboard text and put it in Vim's clipboard register. | |
2245 */ | |
2246 void | |
2247 clip_mch_request_selection(VimClipboard *cbd) | |
2248 { | |
2896 | 2249 int type = MAUTO; |
7 | 2250 char_u *pAllocated = NULL; |
2251 char_u *pClipText = NULL; | |
2252 int clip_data_format = 0; | |
2253 | |
2254 if (Win16OpenClipboard()) | |
2255 { | |
2256 /* Check for Vim's own clipboard format first. The CF_VIMCLIP format | |
2257 * is just ordinary text (like CF_TEXT) except prepended by the | |
2258 * selection type (as a single character). Note that under DOS we | |
2259 * actually cannot define a custom CF_VIMCLIP clipboard format; we | |
2260 * use instead one of the existing Windows-defined formats, usually | |
2261 * "DIF" or "SYLK". See Win16GetClipboardData() for details. | |
2262 * | |
2263 * Note that Win16GetClipboardData() returns the address of the memory | |
2264 * block it allocated. This is not necessary the start of the | |
2265 * clipboard text data: there may be other bytes ahead of the | |
2266 * text (particularly for CF_VIMCLIP) which are used for data | |
2267 * management. So pClipText is not necessarily == pAllocated. | |
2268 */ | |
2269 | |
2270 if ((pAllocated = Win16GetClipboardData(CF_VIMCLIP)) != NULL) | |
2271 { | |
2272 clip_data_format = CF_VIMCLIP; | |
2273 pClipText = pAllocated; | |
2274 | |
2275 switch (*pClipText++) /* after ++, pClipText points to text */ | |
2276 { | |
2277 default: | |
2278 case 'L': type = MLINE; break; | |
2279 case 'C': type = MCHAR; break; | |
2280 case 'B': type = MBLOCK; break; | |
2281 } | |
2282 } | |
2283 | |
2284 /* Otherwise, check for the normal Windows text formats. There are | |
2285 * two of these: CF_TEXT (common) and CF_OEMTEXT (used for DOS | |
2286 * compatibility). Experiments show that, under the DOS/Windows | |
2287 * clipboard interface, writing CF_TEXT data to the clipboard | |
2288 * automatically creates a CF_OEMTEXT format as well. | |
2289 */ | |
2290 | |
2291 else if ((pAllocated = Win16GetClipboardData(CF_TEXT)) != NULL) | |
2292 { | |
2293 clip_data_format = CF_TEXT; | |
2294 pClipText = pAllocated; | |
2295 } | |
2296 | |
2297 else if ((pAllocated = Win16GetClipboardData(CF_OEMTEXT)) != NULL) | |
2298 { | |
2299 clip_data_format = CF_OEMTEXT; | |
2300 pClipText = pAllocated; | |
2301 } | |
2302 | |
2303 /* Did we get anything? */ | |
2304 | |
2305 if (pClipText != NULL) | |
2306 { | |
2307 char_u *pDest; | |
2308 char_u *pStart; | |
2309 char_u *pEnd; | |
2310 | |
2311 long_u clip_data_size = 0; | |
2312 | |
2313 /* The Windows clipboard normally stores its text lines terminated | |
2314 * by <CR><NL>. But Vim uses only <NL>, so translate the <CR><NL> | |
2315 * into <NL>. Also, watch for possible null bytes at the end of | |
2316 * pClipText. These are padding added by "get_clipboard_data" | |
2317 * (int 0x2f, AX= 0x1705) in order to round the data size up to the | |
2318 * next multiple of 32 bytes. See Win16GetClipboardData() for | |
2319 * details. | |
2320 */ | |
2321 | |
2322 pDest = strstr( pClipText, "\r\n" ); /* find first <CR><NL> */ | |
2323 | |
2324 if (pDest != NULL) /* found one? */ | |
2325 { | |
2326 pStart = pDest + 1; /* points to <NL> after <CR> */ | |
2327 pEnd = strstr( pStart, "\r\n" );/* find next <CR><NL> */ | |
2328 | |
2329 while (pEnd != NULL) /* found one? */ | |
2330 { | |
2331 memmove(pDest, pStart, (long)(pEnd - pStart)); | |
2332 /* exclude <CR> */ | |
2333 pDest += (long)(pEnd - pStart); /* new destination */ | |
2334 pStart = pEnd + 1; /* new starting point */ | |
2335 pEnd = strstr(pStart, "\r\n"); /* find next <CR><NL> */ | |
2336 } | |
2337 | |
2338 /* Fell out of while() loop: no more <CR><NL> pairs. Just copy | |
2339 * the rest of the data, up to the first null byte. */ | |
2340 pEnd = strchr(pStart, '\0'); /* find first null */ | |
2341 | |
2342 memmove(pDest, pStart, (long)(pEnd - pStart)); /* exclude nul */ | |
2343 pDest += (long)(pEnd - pStart); | |
2344 *pDest = '\0'; /* terminate */ | |
2345 | |
2346 /* Now that all <CR><NL> pairs have been "compressed" into just | |
2347 * <NL>'s, determine the true text length. */ | |
2348 clip_data_size = (long_u)(pDest - pClipText); | |
2349 } | |
2350 else | |
2351 { | |
2352 /* no <CR><NL> pairs at all */ | |
2353 /* Since the data may have been padded with trailing nulls, | |
2354 * determine the true string length. */ | |
2355 clip_data_size = STRLEN(pClipText); /* true data length */ | |
2356 } | |
2357 | |
2358 /* Copy the cleaned-up data over to Vim's clipboard "*" register. */ | |
2359 clip_yank_selection(type, pClipText, clip_data_size, cbd); | |
2360 | |
2361 /* Free the memory that Win16GetClipboardData() allocated. */ | |
2362 vim_free(pAllocated); | |
2363 } | |
2364 | |
2365 Win16CloseClipboard(); | |
2366 | |
2367 } // end if (Win16OpenClipboard()) | |
2368 } | |
2369 | |
2370 /* | |
2371 * Send the currently selected Vim text to the Windows clipboard. | |
2372 */ | |
2373 void | |
2374 clip_mch_set_selection( VimClipboard *cbd ) | |
2375 { | |
2376 char_u *pClipData = NULL; | |
2377 long_u clip_data_size; | |
2378 int clip_data_type; | |
2379 | |
2380 /* If the '*' register isn't already filled in, fill it in now. */ | |
2381 cbd->owned = TRUE; | |
2382 clip_get_selection(cbd); | |
2383 cbd->owned = FALSE; | |
2384 | |
2385 /* | |
2386 * clip_convert_selection() returns a pointer to a buffer containing | |
2387 * the text to send to the Windows clipboard, together with a count | |
2388 * of the number of characters (bytes) in the buffer. The function's | |
2389 * return value is the 'type' of selection: MLINE, MCHAR, or MBLOCK; | |
2390 * or -1 for failure. | |
2391 */ | |
2392 clip_data_type = clip_convert_selection(&pClipData, &clip_data_size, cbd); | |
2393 | |
2394 if (clip_data_type < 0) /* could not convert? */ | |
2395 return; /* early exit */ | |
2396 | |
2397 if (Win16OpenClipboard()) | |
2398 { | |
2399 if (Win16EmptyClipboard()) | |
2400 { | |
2401 int sentOK; | |
2402 | |
2403 sentOK = Win16SetClipboardData(CF_TEXT, pClipData, | |
2404 clip_data_size, clip_data_type); | |
2405 sentOK = Win16SetClipboardData(CF_VIMCLIP, | |
2406 pClipData, clip_data_size, clip_data_type) && sentOK; | |
2407 | |
2408 if (!sentOK) | |
2409 { | |
2410 /* one or both of Win16SetClipboardData() failed. */ | |
2411 /* Technically we don't know why Win16SetClipboardData() | |
2412 * failed, but almost always it will be because there wasn't | |
1210 | 2413 * enough DOS memory to buffer the data, so report that as the |
7 | 2414 * problem. |
2415 * | |
2416 * We report the error here (instead of in | |
2417 * Win16SetClipboardData()) because we don't want the error | |
2418 * reported twice. | |
2419 */ | |
2420 EMSG("E450: Selection too large, cannot allocate DOS buffer"); | |
2421 } | |
2422 } | |
2423 | |
2424 Win16CloseClipboard(); | |
2425 } | |
2426 | |
2427 /* release memory allocated by clip_convert_selection() */ | |
2428 vim_free(pClipData); | |
2429 | |
2430 return; | |
2431 } | |
2432 | |
2433 /* | |
2434 * Win16OpenClipboard: open the Windows clipboard. The clipboard must be open | |
2435 * before it can be communicated with at all. Return TRUE on success, | |
2436 * FALSE on failure. | |
2437 */ | |
2438 static int | |
2439 Win16OpenClipboard(void) | |
2440 { | |
2441 __dpmi_regs dpmi_regs; | |
2442 | |
2443 long start_time; | |
2444 int tick_count; | |
2445 | |
4352 | 2446 /* int 0x2f, AX = 0x1701 attempts to open the Windows clipboard. Upon |
7 | 2447 * return from the interrupt, if AX is non-zero, the clipboard was |
2448 * successfully opened. If AX is zero, the clipboard could not be opened | |
2449 * because it is currently in use by another process. | |
2450 * | |
2451 * Remark: other DOS programs I (dk) have written that use the Windows | |
2452 * clipboard sometimes encounter the problem that the clipboard cannot | |
2453 * be opened even though it is demonstrably not in use by any other | |
2454 * process. In all cases, repeated attempts to open the clipboard | |
2455 * eventually succeed, but the initial attempt occasionally fails. | |
2456 * | |
2457 * The problem is intermittent and appears to be related to DOS being | |
2458 * "busy" at certain unpredictable times. DOS maintains two internal | |
2459 * flags that indicate whether it's busy: InDOS and CritErr. The | |
2460 * location of InDOS can be found by calling int 0x21, AH = 0x34. The | |
2461 * location of CritErr can be found by calling int 0x21, AX = 0x5d06. | |
2462 * If either of these flags is set, DOS is "busy" and cannot be | |
2463 * interrupted. See "Undocumented DOS" by Schulman et al for details. | |
2464 * | |
2465 * However here I take the easier approach that if the first call to open | |
2466 * the clipboard does not succeed, just try again. In fact, try once per | |
2467 * biostime() clock tick, up to 18 times (about one second). | |
2468 */ | |
2469 | |
2470 tick_count = 0; | |
2471 | |
2472 dpmi_regs.x.ax = 0x1701; /* open Windows clipboard */ | |
2473 if (__dpmi_int(0x2f, &dpmi_regs) == -1) | |
2474 { | |
2475 /* real-mode interrupt failed? */ | |
2476 return FALSE; /* FALSE --> clipboard not open */ | |
2477 } | |
2478 | |
2479 /* wait up to one second */ | |
2480 while (dpmi_regs.x.ax == 0 && tick_count++ < 18) | |
2481 { | |
2482 /* Wait one clock tick (18.2 ticks/sec = 55 msec per tick). | |
2483 * | |
2484 * We busy-wait here. Unfortunately, delay() and usleep() have been | |
2485 * reported to give problems with the original Windows 95. This is | |
2486 * fixed in service pack 1, but not everybody installed that. | |
2487 */ | |
2488 start_time = biostime(0, 0L); | |
2489 while (biostime(0, 0L) == start_time) | |
2490 ; | |
2491 | |
2492 dpmi_regs.x.ax = 0x1701; /* open Windows clipboard */ | |
2493 if (__dpmi_int(0x2f, &dpmi_regs) == -1) | |
2494 { | |
2495 /* real-mode interrupt failed? */ | |
2496 return FALSE; /* FALSE --> clipboard not open */ | |
2497 } | |
2498 } | |
2499 | |
2500 /* Couldn't open the clipboard, even after 18 attempts? */ | |
2501 | |
2502 if (tick_count >= 18 && dpmi_regs.x.ax == 0) | |
2503 return FALSE; /* FALSE --> clipboard not open */ | |
2504 | |
2505 return TRUE; /* TRUE --> clipboard opened successfully, OK */ | |
2506 } | |
2507 | |
2508 /* | |
2509 * Win16CloseClipboard: close the Windows clipboard. Return TRUE on | |
2510 * success, FALSE on failure. This function can always be called, | |
2511 * whether the clipboard is open or not. | |
2512 */ | |
2513 static int | |
2514 Win16CloseClipboard(void) | |
2515 { | |
2516 __dpmi_regs dpmi_regs; | |
2517 | |
2518 /* Close the clipboard. This interrupt can always be called, even | |
2519 * if the clipboard is already closed. | |
2520 */ | |
2521 | |
2522 dpmi_regs.x.ax = 0x1708; /* close the clipboard */ | |
2523 if (__dpmi_int(0x2f, &dpmi_regs) == -1) | |
2524 { | |
2525 /* real-mode interrupt failed? */ | |
2526 return FALSE; /* FALSE --> clipboard could not be closed */ | |
2527 } | |
2528 | |
2529 return TRUE; /* TRUE --> clipboard closed successfully, OK */ | |
2530 } | |
2531 | |
2532 /* | |
2533 * Win16EmptyClipboard: empty the (previously opened) Windows clipboard. | |
2534 * Return TRUE on success, FALSE on failure. | |
2535 */ | |
2536 static int | |
2537 Win16EmptyClipboard(void) | |
2538 { | |
2539 __dpmi_regs dpmi_regs; | |
2540 | |
4352 | 2541 /* int 0x2f, AX = 0x1702 attempts to empty the Windows clipboard. Upon |
7 | 2542 * return from the interrupt, if AX == 0, the clipboard could not be |
2543 * emptied (for some reason). | |
2544 */ | |
2545 dpmi_regs.x.ax = 0x1702; /* empty the Windows clipboard */ | |
2546 if (__dpmi_int(0x2f, &dpmi_regs) == -1) | |
2547 { | |
2548 /* real-mode interrupt failed? */ | |
2549 return FALSE; /* FALSE --> clipboard could not be emptied */ | |
2550 } | |
2551 | |
2552 /* Did we succeed in clearing the clipboard? */ | |
2553 if (dpmi_regs.x.ax == 0) | |
2554 return FALSE; /* FALSE --> clipboard could not be emptied */ | |
2555 | |
2556 return TRUE; /* TRUE --> clipboard was emptied, OK */ | |
2557 } | |
2558 | |
2559 /* | |
2560 * FreeDOSMemory: a helper function to free memory previously | |
2561 * allocated by a call to __dpmi_allocate_dos_memory(). | |
2562 */ | |
2563 static void | |
2564 FreeDOSMemory(int protected_mode_selector) | |
2565 { | |
2566 /* Free the DOS buffer and release the DPMI prot-mode selector. | |
2567 * | |
2568 * It's important that DOS memory be properly released because | |
2569 * there's only a limited amount of it. Therefore, if the call | |
2570 * to __dpmi_free_dos_memory() fails, emit an error message | |
2571 * unconditionally. | |
2572 */ | |
2573 if (__dpmi_free_dos_memory(protected_mode_selector) == -1) | |
2574 EMSG("E451: could not free DOS memory buffer (DJGPP)"); | |
2575 } | |
2576 | |
2577 /* | |
2578 * Win16GetClipboardData: query the Windows clipboard as to whether data | |
2579 * is available in a particular clipboard format. If data is | |
2580 * available, allocate a buffer for it and read the data from the | |
2581 * clipboard into the buffer. Return a pointer to the buffer. If | |
2582 * no data is available in the requested format, return NULL. | |
2583 * | |
2584 * This routine allocates memory to hold the retrieved clipboard | |
2585 * data. It's the caller's responsibility to free this memory | |
2586 * once it's finished using it. The memory should be freed by | |
2587 * calling vim_free(). | |
2588 */ | |
2589 static char_u * | |
2590 Win16GetClipboardData(int clip_data_format) | |
2591 { | |
2592 __dpmi_regs dpmi_regs; | |
2593 | |
2594 int real_mode_segment_address; | |
2595 int protected_mode_selector; | |
2596 | |
2597 char_u *clip_data_buffer; | |
2598 long_u clip_data_size; | |
2599 | |
2600 /* We only handle clipboard formats we recognize, others are ignored. | |
2601 * | |
2602 * It's not possible to create a custom clipboard format for VimClipboard | |
2603 * data under DOS, so one of the predefined Windows formats had to be | |
2604 * used for CF_VIMCLIP. Two obscure formats, popular when Windows 3.0 | |
2605 * came out but no longer in much use today, are the DIF and SYLK formats. | |
2606 * DIF is the Data Interchange Format, SYLK is the Symbolic Link format. | |
2607 * They are both text formats and either one can be hijacked for use as | |
2608 * "the VimClipboard format". Of course, this conflicts with anyone who | |
2609 * still *is* using DIF or SYLK data formats, but that will be very few | |
2610 * people. | |
2611 * | |
2612 * I (dk) chose SYLK as the more obscure format because it was used | |
2613 * mostly for Microsoft Multiplan (the pre-cursor to Excel) and it's not | |
2614 * likely Multiplan is used anywhere much anymore. Mind you, Excel can | |
2615 * still export to both DIF and SYLK formats. | |
2616 */ | |
2617 | |
2618 switch (clip_data_format) | |
2619 { | |
2620 case CF_VIMCLIP: /* Vim's own special clipboard format */ | |
2621 case CF_TEXT: /* Windows text */ | |
2622 case CF_OEMTEXT: /* DOS (OEM) text */ | |
2623 | |
4352 | 2624 /* int 0x2f, AX = 0x1704 returns the number of bytes of data currently |
7 | 2625 * on the Windows clipboard, for the specified format. Upon return |
2626 * from the interrupt, DX:AX = the number of bytes, rounded up to the | |
2627 * nearest multiple of 32. | |
2628 */ | |
2629 | |
2630 dpmi_regs.x.ax = 0x1704; /* get size of clipbd data */ | |
2631 dpmi_regs.x.dx = clip_data_format; | |
2632 if (__dpmi_int(0x2f, &dpmi_regs) == -1) | |
2633 { | |
2634 /* real-mode interrupt failed? */ | |
2635 return NULL; /* early exit */ | |
2636 } | |
2637 | |
2638 /* Did we get anything? If not, this is not an error. */ | |
2639 if (dpmi_regs.x.dx == 0 && dpmi_regs.x.ax == 0) | |
2640 { | |
2641 /* no CF_VIMCLIP data? */ | |
2642 return NULL; /* early exit */ | |
2643 } | |
2644 | |
2645 /* There is data available in the requested clipboard format. | |
2646 * | |
2647 * Calculate data size. Remember this is rounded up to the nearest | |
2648 * multiple of 32, so clip_data_size is actually an upper limit. | |
2649 * The extra bytes, if any, are set to null (0x00) when the data is | |
2650 * read from the clipboard. (Later:) actually I'm no longer sure | |
2651 * this is strictly true: the end-of-data is marked by a null, but | |
2652 * the extra bytes appear to sometimes be null, sometimes not. | |
2653 * They may just be garbage. | |
2654 */ | |
2655 clip_data_size = dpmi_regs.x.ax + (dpmi_regs.x.dx << 16); | |
2656 | |
2657 /* Allocate memory to retrieve the data. The buffer has to lie in the | |
2658 * DOS memory region (in the first 1 MByte of address space) because | |
2659 * the Windows clipboard interface expects a 16-bit segment:offset | |
2660 * pointer to a buffer address within the DOS region. Must therefore | |
2661 * use __dpmi_allocate_dos_memory() instead of lalloc() or alloc(). | |
2662 */ | |
2663 real_mode_segment_address = __dpmi_allocate_dos_memory( | |
2664 (clip_data_size + 15) >> 4, /* buffer size, in 16-byte paragraphs */ | |
2665 &protected_mode_selector); /* prot-mode selector for the address */ | |
2666 | |
2667 if (real_mode_segment_address == -1) | |
2668 { | |
2669 /* memory allocation failed. */ | |
2670 | |
2671 /* Technically we don't know why the allocation failed, but | |
2672 * almost always it will be because there wasn't enough DOS | |
2673 * memory to satisfy the request, so report that as the problem. | |
2674 * On my system, DJGPP is able to satisfy a DOS allocation request | |
2675 * up to about 600K in size. This depends on your HIMEM.SYS and | |
2676 * EMM386.EXE settings however. | |
2677 */ | |
2678 EMSG("E452: Clipboard data too large, cannot allocate DOS buffer"); | |
2679 return NULL; /* early exit */ | |
2680 } | |
2681 | |
2682 /* Copy data from the clipboard into the buffer. Experiments show that | |
2683 * the Windows clipboard is smart enough to handle data transfers | |
2684 * larger than 64K properly, even though the buffer address is a 16-bit | |
2685 * segment:offset (which would normally limit the block size to 64K | |
2686 * unless ES gets incremented). | |
2687 */ | |
2688 dpmi_regs.x.ax = 0x1705; /* get clipboard data */ | |
2689 dpmi_regs.x.dx = clip_data_format; /* CF_VIMCLIP */ | |
2690 dpmi_regs.x.es = real_mode_segment_address; /* buffer ad: segment */ | |
2691 dpmi_regs.x.bx = 0; /* buffer ad: offset */ | |
2692 if (__dpmi_int( 0x2f, &dpmi_regs) == -1) | |
2693 { | |
2694 /* real-mode interrupt failed? */ | |
2695 EMSG("E453: could not copy clipboard data to DOS buffer"); | |
2696 FreeDOSMemory(protected_mode_selector); /* clean up DOS mem */ | |
2697 return NULL; /* early exit */ | |
2698 } | |
2699 | |
2700 /* Clipboard data is now in DOS memory in the buffer pointed to by | |
2701 * ES:BX. Copy this into ordinary memory that Vim can access (ie. | |
2702 * prot-mode memory). Allocate one extra byte to ensure the text | |
2703 * is terminated properly (in case it was somehow corrupted). | |
2704 */ | |
2705 clip_data_buffer = (char_u *)lalloc(clip_data_size + 1, TRUE); | |
2706 | |
2707 if (clip_data_buffer == NULL) | |
2708 { | |
2709 /* allocation failed? */ | |
2710 EMSG("E454: could not allocate clipboard memory buffer"); | |
2711 FreeDOSMemory(protected_mode_selector); /* clean up DOS mem */ | |
2712 return NULL; /* early exit */ | |
2713 } | |
2714 | |
2715 *(clip_data_buffer + clip_data_size) = '\0'; /* ensure terminated */ | |
2716 | |
2717 /* Copy the data from DOS memory to Vim-accessible memory. */ | |
2718 movedata( /* DJGPP version of memcpy() */ | |
2719 protected_mode_selector, 0, /* source: DOS ad (via selector) */ | |
2720 _my_ds(), (unsigned)clip_data_buffer, | |
2721 /* target: normal mem address */ | |
2722 clip_data_size); /* how many bytes */ | |
2723 | |
2724 /* Free the DOS buffer and release the DPMI prot-mode selector. */ | |
2725 FreeDOSMemory(protected_mode_selector); /* clean up DOS memory */ | |
2726 | |
2727 return clip_data_buffer; /* return pointer to allocated buffer */ | |
2728 | |
2729 default: /* unknown clipboard format */ | |
2730 return NULL; | |
2731 } | |
2732 } | |
2733 | |
2734 /* | |
2735 * Win16SetClipboardData: send 'clip_data_size' bytes of data from the buffer | |
2736 * pointed to by 'clip_data', to the Windows clipboard. The data is | |
2737 * registered with the clipboard as being in the 'clip_data_format' | |
2738 * format. | |
2739 */ | |
2740 static int | |
2741 Win16SetClipboardData( | |
2742 int clip_data_format, | |
2743 char_u *clip_data, | |
2744 int clip_data_size, | |
2745 int clip_data_type) | |
2746 { | |
2747 __dpmi_regs dpmi_regs; | |
2748 | |
2749 int real_mode_segment_address; | |
2750 int protected_mode_selector; | |
2751 long_u protected_mode_offset = 0L; | |
2752 int total_size = clip_data_size; | |
2753 | |
2754 char_u *clip_sel_type; | |
2755 | |
2756 /* If we're using the CF_VIMCLIP custom format, allocate an extra | |
2757 * byte for clip_sel_type, which is a character indicating the type | |
2758 * of text selection: MLINE, MCHAR, or MBLOCK. | |
2759 */ | |
2760 if (clip_data_format == CF_VIMCLIP) | |
2761 total_size++; /* extra byte for marker */ | |
2762 | |
2763 /* Data cannot be sent directly from a Vim string (pClipData) to | |
2764 * the Windows clipboard, because the Windows clipboard interface | |
2765 * expects a 16-bit (DOS) segment:offset address for the source | |
2766 * buffer. Therefore we must create a "transfer buffer" in the DOS | |
2767 * memory region (in the first 1 MByte of address space) and copy | |
2768 * the Vim string into that. From there, the data can then be sent | |
2769 * to the Windows clipboard. | |
2770 * | |
2771 * To allocate DOS memory, we must use __dpmi_allocate_dos_memory() | |
2772 * instead of lalloc() or alloc(). If the allocation fails, it will | |
2773 * almost invariably be because there is not enough DOS memory | |
2774 * available to accommodate the size of clip_data. There is nothing | |
2775 * we can do about this, we simply have to fail. | |
2776 */ | |
2777 real_mode_segment_address = __dpmi_allocate_dos_memory( | |
2778 (total_size + 15) >> 4, /* buffer size, in 16-byte paragraphs */ | |
2779 &protected_mode_selector); /* prot-mode selector for the address */ | |
2780 | |
2781 if (real_mode_segment_address == -1) | |
2782 { | |
2783 /* memory allocation failed. */ | |
2784 /* Technically we don't know why the allocation failed, but | |
2785 * almost always it will be because there wasn't enough DOS | |
2786 * memory to satisfy the request. On my system, DJGPP is able | |
2787 * to satisfy a DOS allocation request up to about 600K in size. | |
2788 * This depends however on HIMEM.SYS and EMM386.EXE settings. | |
2789 */ | |
2790 return FALSE; /* early exit */ | |
2791 } | |
2792 | |
2793 /* Copy data from Vim's buffer (clip_data) into the DOS transfer buffer. | |
2794 * This can be larger than 64K; movedata() takes care of crossing any | |
2795 * 16-bit segment boundaries. | |
2796 * | |
2797 * If we're using Vim's custom clipboard format, we must copy one extra | |
2798 * byte to indicate the type of selection: line, character, or block. | |
2799 */ | |
2800 if (clip_data_format == CF_VIMCLIP) | |
2801 { | |
2802 switch (clip_data_type) | |
2803 { | |
2804 default: | |
2805 case MLINE: clip_sel_type = "L"; break; | |
2806 case MCHAR: clip_sel_type = "C"; break; | |
2807 case MBLOCK: clip_sel_type = "B"; break; | |
2808 } | |
2809 | |
2810 movedata( | |
2811 _my_ds(), (unsigned)clip_sel_type, | |
2812 /* source: normal memory address */ | |
2813 protected_mode_selector, 0, /* target: DOS ad (via selector) */ | |
2814 1); /* how many bytes to copy */ | |
2815 | |
2816 protected_mode_offset += STRLEN(clip_sel_type); /* allow for marker */ | |
2817 } | |
2818 | |
2819 movedata( | |
2820 _my_ds(), (unsigned)clip_data, /* source: normal memory address */ | |
2821 protected_mode_selector, /* target: DOS address (via selector) */ | |
2822 protected_mode_offset, /* non-zero, if using clip_sel_type */ | |
2823 clip_data_size); /* how many bytes to copy */ | |
2824 | |
2825 /* Send data from the DOS transfer buffer to the Windows clipboard. | |
4352 | 2826 * int 0x2f, AX = 0x1703 sends SI:CX bytes of data from the buffer |
7 | 2827 * at ES:BX, to the clipboard. |
2828 */ | |
2829 dpmi_regs.x.ax = 0x1703; /* send clipboard data */ | |
2830 dpmi_regs.x.dx = clip_data_format; /* flag: format of the data */ | |
2831 dpmi_regs.x.si = ((total_size >> 16) | |
2832 & 0x0000ffffL); /* hi word of data size */ | |
2833 dpmi_regs.x.cx = (total_size & 0x0000ffffL); | |
2834 /* lo word of data size */ | |
2835 dpmi_regs.x.es = real_mode_segment_address; /* buffer address: segment */ | |
2836 dpmi_regs.x.bx = 0; /* buffer address: offset */ | |
2837 if (__dpmi_int(0x2f, &dpmi_regs) == -1) | |
2838 { | |
2839 /* real-mode interrupt failed. */ | |
2840 FreeDOSMemory(protected_mode_selector); /* clean up DOS memory */ | |
2841 return FALSE; /* early exit */ | |
2842 } | |
2843 | |
2844 /* Free the DOS buffer and release the DPMI prot-mode selector. */ | |
2845 FreeDOSMemory(protected_mode_selector); /* clean up DOS memory */ | |
2846 | |
2847 return TRUE; /* TRUE --> data successfully sent to clipboard */ | |
2848 } | |
2849 | |
2850 #endif /* FEAT_CLIPBOARD */ | |
2851 #endif /* DJGPP */ | |
2852 | |
2853 /* | |
2854 * End of MS-DOS only code | |
2855 */ | |
2856 #endif /* WIN16 */ | |
2857 | |
2858 /* common MS-DOS and Win16 code follows */ | |
2859 | |
2860 static int | |
2861 vim_chmod(char_u *name) | |
2862 { | |
2863 char_u *p; | |
2864 int f; | |
2865 int c = 0; | |
2866 | |
2867 /* chmod() can't handle a file name with a trailing slash, remove it. | |
2868 * But don't remove it for "/" or "c:/". */ | |
2869 p = name + STRLEN(name); | |
2870 if (p > name) | |
2871 --p; | |
2872 if (p > name && (*p == '\\' || *p == '/') && p[-1] != ':') | |
2873 { | |
2874 c = *p; /* remove trailing (back)slash */ | |
2875 *p = NUL; | |
2876 } | |
2877 else | |
2878 p = NULL; | |
2879 #if defined(__BORLANDC__) && (__BORLANDC__ > 0x410) | |
2880 /* this also sets the archive bit, supported by Borland C 4.0 and later, | |
2881 * where __BORLANDC__ is 0x450 (3.1 is 0x410) */ | |
2882 f = _rtl_chmod((char *)name, 0, 0); | |
2883 #else | |
2884 f = _chmod((char *)name, 0, 0); | |
2885 #endif | |
2886 if (p != NULL) | |
2887 *p = c; /* put back (back)slash */ | |
2888 return f; | |
2889 } | |
2890 | |
2891 /* | |
2892 * get file permissions for 'name' | |
2893 * Returns -1 for error. | |
2894 * Returns FA_attributes defined in dos.h | |
2895 */ | |
2896 long | |
2897 mch_getperm(char_u *name) | |
2898 { | |
2899 return (long)vim_chmod(name); /* get file mode */ | |
2900 } | |
2901 | |
2902 /* | |
2903 * set file permission for 'name' to 'perm' | |
2904 * | |
2905 * return FAIL for failure, OK otherwise | |
2906 */ | |
2907 int | |
2908 mch_setperm( | |
2909 char_u *name, | |
2910 long perm) | |
2911 { | |
2912 perm |= FA_ARCH; /* file has changed, set archive bit */ | |
2913 #if defined(__BORLANDC__) && (__BORLANDC__ > 0x410) | |
2914 return (_rtl_chmod((char *)name, 1, (int)perm) == -1 ? FAIL : OK); | |
2915 #else | |
2916 return (_chmod((char *)name, 1, (int)perm) == -1 ? FAIL : OK); | |
2917 #endif | |
2918 } | |
2919 | |
2920 /* | |
2921 * Set hidden flag for "name". | |
2922 */ | |
2923 void | |
2924 mch_hide(char_u *name) | |
2925 { | |
2926 /* DOS 6.2 share.exe causes "seek error on file write" errors when making | |
2927 * the swap file hidden. Thus don't do it. */ | |
2928 } | |
2929 | |
2930 /* | |
2931 * return TRUE if "name" is a directory | |
2932 * return FALSE if "name" is not a directory | |
2933 * return FALSE for error | |
2934 * | |
2935 * beware of a trailing (back)slash | |
2936 */ | |
2937 int | |
2938 mch_isdir(char_u *name) | |
2939 { | |
2940 int f; | |
2941 | |
2942 f = vim_chmod(name); | |
2943 if (f == -1) | |
2944 return FALSE; /* file does not exist at all */ | |
2945 if ((f & FA_DIREC) == 0) | |
2946 return FALSE; /* not a directory */ | |
2947 return TRUE; | |
2948 } | |
2949 | |
2950 /* | |
2951 * Return 1 if "name" can be executed, 0 if not. | |
6695 | 2952 * If "use_path" is FALSE only check if "name" is executable. |
7 | 2953 * Return -1 if unknown. |
2954 */ | |
2955 int | |
7842
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
2956 mch_can_exe( |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
2957 char_u *name, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
2958 char_u **path, |
cf744110897d
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Christian Brabandt <cb@256bit.org>
parents:
6695
diff
changeset
|
2959 int use_path) |
7 | 2960 { |
9 | 2961 char *p; |
6695 | 2962 int mode; |
9 | 2963 |
6695 | 2964 if (!use_path) |
2965 { | |
2966 /* TODO: proper check if file is executable. */ | |
2967 mode = vim_chmod(name); | |
2968 return mode != -1 && (mode & FA_DIREC) == 0; | |
2969 } | |
9 | 2970 p = searchpath(name); |
2971 if (p == NULL || mch_isdir(p)) | |
2972 return FALSE; | |
5782 | 2973 if (path != NULL) |
2974 *path = vim_strsave(p); | |
9 | 2975 return TRUE; |
7 | 2976 } |
2977 | |
2978 /* | |
2979 * Check what "name" is: | |
2980 * NODE_NORMAL: file or directory (or doesn't exist) | |
2981 * NODE_WRITABLE: writable device, socket, fifo, etc. | |
2982 * NODE_OTHER: non-writable things | |
2983 */ | |
2984 int | |
2985 mch_nodetype(char_u *name) | |
2986 { | |
2987 if (STRICMP(name, "AUX") == 0 | |
2988 || STRICMP(name, "CON") == 0 | |
2989 || STRICMP(name, "CLOCK$") == 0 | |
2990 || STRICMP(name, "NUL") == 0 | |
2991 || STRICMP(name, "PRN") == 0 | |
2992 || ((STRNICMP(name, "COM", 3) == 0 | |
2993 || STRNICMP(name, "LPT", 3) == 0) | |
2994 && VIM_ISDIGIT(name[3]) | |
2995 && name[4] == NUL)) | |
2996 return NODE_WRITABLE; | |
2997 /* TODO: NODE_OTHER? */ | |
2998 return NODE_NORMAL; | |
2999 } | |
3000 | |
3001 /* | |
3002 * Get name of current directory into buffer 'buf' of length 'len' bytes. | |
3003 * Return OK for success, FAIL for failure. | |
3004 */ | |
3005 int | |
3006 mch_dirname( | |
3007 char_u *buf, | |
3008 int len) | |
3009 { | |
3010 #ifdef DJGPP | |
3011 if (getcwd((char *)buf, len) == NULL) | |
3012 return FAIL; | |
3013 /* turn the '/'s returned by DJGPP into '\'s */ | |
3014 slash_adjust(buf); | |
3015 return OK; | |
3016 #else | |
3017 return (getcwd((char *)buf, len) != NULL ? OK : FAIL); | |
3018 #endif | |
3019 } | |
3020 | |
3021 /* | |
3022 * this version of remove is not scared by a readonly (backup) file | |
3023 * | |
3024 * returns -1 on error, 0 otherwise (just like remove()) | |
3025 */ | |
3026 int | |
3027 mch_remove(char_u *name) | |
3028 { | |
3029 (void)mch_setperm(name, 0); /* default permissions */ | |
3030 return unlink((char *)name); | |
3031 } | |
3032 | |
3033 /* | |
3034 * Special version of getenv(): Use uppercase name. | |
3035 */ | |
3036 char_u * | |
3037 mch_getenv(char_u *name) | |
3038 { | |
3039 int i; | |
3040 #define MAXENVLEN 50 | |
3041 char_u var_copy[MAXENVLEN + 1]; | |
3042 char_u *p; | |
3043 char_u *res; | |
3044 | |
3045 /* | |
3046 * Take a copy of the argument, and force it to upper case before passing | |
3047 * to getenv(). On DOS systems, getenv() doesn't like lower-case argument | |
3048 * (unlike Win32 et al.) If the name is too long to fit in var_copy[] | |
3049 * allocate memory. | |
3050 */ | |
3051 if ((i = STRLEN(name)) > MAXENVLEN) | |
3052 p = alloc(i + 1); | |
3053 else | |
3054 p = var_copy; | |
3055 if (p == NULL) | |
3056 p = name; /* out of memory, fall back to unmodified name */ | |
3057 else | |
3058 { | |
3059 for (i = 0; name[i] != NUL; ++i) | |
3060 p[i] = toupper(name[i]); | |
3061 p[i] = NUL; | |
3062 } | |
3063 | |
3064 res = (char_u *)getenv((char *)p); | |
3065 | |
3066 if (p != var_copy && p != name) | |
3067 vim_free(p); | |
3068 | |
3069 return res; | |
3070 } | |
3071 | |
3072 /* | |
3073 * Insert user name in s[len]. | |
3074 */ | |
3075 int | |
3076 mch_get_user_name( | |
3077 char_u *s, | |
3078 int len) | |
3079 { | |
3080 *s = NUL; | |
3081 return FAIL; | |
3082 } | |
3083 | |
3084 /* | |
3085 * Insert host name is s[len]. | |
3086 */ | |
3087 void | |
3088 mch_get_host_name( | |
3089 char_u *s, | |
3090 int len) | |
3091 { | |
3092 #ifdef DJGPP | |
418 | 3093 vim_strncpy(s, "PC (32 bits Vim)", len - 1); |
7 | 3094 #else |
418 | 3095 vim_strncpy(s, "PC (16 bits Vim)", len - 1); |
7 | 3096 #endif |
3097 } |