home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / amiga / vim46src.lha / vim-4.6 / src / msdos.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-06  |  30.8 KB  |  1,541 lines

  1. /* vi:set ts=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.  */
  8.  
  9. /*
  10.  * msdos.c
  11.  *
  12.  * MSDOS system-dependent routines.
  13.  * A cheap plastic imitation of the amiga dependent code.
  14.  * A lot in this file was made by Juergen Weigert (jw).
  15.  *
  16.  * DJGPP changes by Gert van Antwerpen
  17.  */
  18.  
  19. #include <io.h>
  20. #include "vim.h"
  21. #include "globals.h"
  22. #include "option.h"
  23. #include "proto.h"
  24. #include <conio.h>
  25. #ifdef HAVE_FCNTL_H
  26. # include <fcntl.h>
  27. #endif
  28. #include <bios.h>
  29. #ifdef DJGPP
  30. # include <dpmi.h>
  31. # include <signal.h>
  32. #else
  33. # include <alloc.h>
  34. #endif
  35.  
  36. static int WaitForChar __ARGS((long));
  37. #ifdef USE_MOUSE
  38. static void show_mouse __ARGS((int));
  39. static void mouse_area __ARGS((void));
  40. #endif
  41. static int change_drive __ARGS((int));
  42. static void slash_adjust __ARGS((char_u *));
  43. static int cbrk_handler __ARGS(());
  44.  
  45. typedef struct filelist
  46. {
  47.     char_u    **file;
  48.     int        nfiles;
  49.     int        maxfiles;
  50. } FileList;
  51.  
  52. static void        addfile __ARGS((FileList *, char_u *, int));
  53. static int        pstrcmp();    /* __ARGS((char **, char **)); BCC does not like this */
  54. static void        strlowcpy __ARGS((char_u *, char_u *));
  55. static int        expandpath __ARGS((FileList *, char_u *, int, int, int));
  56.  
  57. static int cbrk_pressed = FALSE;    /* set by ctrl-break interrupt */
  58. static int ctrlc_pressed = FALSE;    /* set when ctrl-C or ctrl-break detected */
  59. static int delayed_redraw = FALSE;    /* set when ctrl-C detected */
  60.  
  61. #ifdef USE_MOUSE
  62. static int mouse_avail = FALSE;        /* mouse present */
  63. static int mouse_active;            /* mouse enabled */
  64. static int mouse_hidden;            /* mouse not shown */
  65. static int mouse_click = 0;            /* mouse status */
  66. static int mouse_x = -1;            /* mouse x coodinate */
  67. static int mouse_y = -1;            /* mouse y coodinate */
  68. static long mouse_click_time = 0;    /* biostime() of last click */
  69. static int mouse_click_count = 0;    /* count for multi-clicks */
  70. static int mouse_last_click = 0;    /* previous status at click */
  71. static int mouse_click_x = 0;        /* x of previous mouse click */
  72. static int mouse_click_y = 0;        /* y of previous mouse click */
  73. static linenr_t mouse_topline = 0;    /* topline at previous mouse click */
  74. static int mouse_x_div = 8;            /* column = x coord / mouse_x_div */
  75. static int mouse_y_div = 8;            /* line   = y coord / mouse_y_div */
  76. #endif
  77.  
  78. #define BIOSTICK    55                /* biostime() increases one tick about
  79.                                         every 55 msec */
  80.  
  81.     long
  82. mch_avail_mem(special)
  83.     int special;
  84. {
  85. #ifdef DJGPP
  86.     return _go32_dpmi_remaining_virtual_memory();
  87. #else
  88.     return coreleft();
  89. #endif
  90. }
  91.  
  92. /*
  93.  * don't do anything for about 500 msec
  94.  */
  95.     void
  96. mch_delay(msec, ignoreinput)
  97.     long    msec;
  98.     int        ignoreinput;
  99. {
  100.     long    starttime;
  101.  
  102.     if (ignoreinput)
  103.     {
  104.         starttime = biostime(0, 0L);
  105.         while (biostime(0, 0L) < starttime + msec / BIOSTICK)
  106.             ;
  107.     }
  108.     else
  109.         WaitForChar(msec);
  110. }
  111.  
  112. /*
  113.  * this version of remove is not scared by a readonly (backup) file
  114.  *
  115.  * returns -1 on error, 0 otherwise (just like remove())
  116.  */
  117.     int
  118. vim_remove(name)
  119.     char_u    *name;
  120. {
  121.     (void)setperm(name, 0);    /* default permissions */
  122.     return unlink((char *)name);
  123. }
  124.  
  125. /*
  126.  * mch_write(): write the output buffer to the screen
  127.  */
  128.     void
  129. mch_write(s, len)
  130.     char_u    *s;
  131.     int        len;
  132. {
  133.     char_u    *p;
  134.     int        row, col;
  135.  
  136.     if (term_console)        /* translate ESC | sequences into bios calls */
  137.         while (len--)
  138.         {
  139.             if (p_wd)        /* testing: wait a bit for each char */
  140.                 WaitForChar(p_wd);
  141.  
  142.             if (s[0] == '\n')
  143.                 putch('\r');
  144.             else if (s[0] == ESC && len > 1 && s[1] == '|')
  145.             {
  146.                 switch (s[2])
  147.                 {
  148. #ifdef DJGPP
  149.                 case 'B':    ScreenVisualBell();
  150.                             goto got3;
  151. #endif
  152.                 case 'J':    clrscr();
  153.                             goto got3;
  154.  
  155.                 case 'K':    clreol();
  156.                             goto got3;
  157.  
  158.                 case 'L':    insline();
  159.                             goto got3;
  160.  
  161.                 case 'M':    delline();
  162. got3:                        s += 3;
  163.                             len -= 2;
  164.                             continue;
  165.  
  166.                 case '0':
  167.                 case '1':
  168.                 case '2':
  169.                 case '3':
  170.                 case '4':
  171.                 case '5':
  172.                 case '6':
  173.                 case '7':
  174.                 case '8':
  175.                 case '9':    p = s + 2;
  176.                             row = getdigits(&p);        /* no check for length! */
  177.                             if (p > s + len)
  178.                                 break;
  179.                             if (*p == ';')
  180.                             {
  181.                                 ++p;
  182.                                 col = getdigits(&p);    /* no check for length! */
  183.                                 if (p > s + len)
  184.                                     break;
  185.                                 if (*p == 'H' || *p == 'r')
  186.                                 {
  187.                                     if (*p == 'H')        /* set cursor position */
  188.                                         gotoxy(col, row);
  189.                                     else                /* set scroll region  */
  190.                                         window(1, row, Columns, col);
  191.                                     len -= p - s;
  192.                                     s = p + 1;
  193.                                     continue;
  194.                                 }
  195.                             }
  196.                             else if (*p == 'm')
  197.                             {
  198.                                 if (row == 0)
  199.                                     normvideo();
  200.                                 else
  201.                                     textattr(row);
  202.                                 len -= p - s;
  203.                                 s = p + 1;
  204.                                 continue;
  205.                             }
  206.                 }
  207.             }
  208.             putch(*s++);
  209.         }
  210.     else
  211.         write(1, s, (unsigned)len);
  212. }
  213.  
  214. #ifdef DJGPP
  215. /*
  216.  * DJGPP provides a kbhit() function that goes to the BIOS instead of DOS.
  217.  * This doesn't work for terminals connected to a serial port.
  218.  * Redefine kbhit() here to make it work.
  219.  */
  220.     static int
  221. vim_kbhit(void)
  222. {
  223.     union REGS regs;
  224.  
  225.     regs.h.ah = 0x0b;
  226.     (void)intdos(®s, ®s);
  227.     return regs.h.al;
  228. }
  229.  
  230. #ifdef kbhit
  231. # undef kbhit        /* might have been defined in conio.h */
  232. #endif
  233.  
  234. #define kbhit()    vim_kbhit()
  235. #endif
  236.  
  237. /*
  238.  * Simulate WaitForChar() by slowly polling with bioskey(1) or kbhit().
  239.  *
  240.  * If Vim should work over the serial line after a 'ctty com1' we must use
  241.  * kbhit() and getch(). (jw)
  242.  * Usually kbhit() is not used, because then CTRL-C and CTRL-P
  243.  * will be catched by DOS (mool).
  244.  *
  245.  * return TRUE if a character is available, FALSE otherwise
  246.  */
  247.  
  248. #define FOREVER 1999999999L
  249.  
  250.     static    int
  251. WaitForChar(msec)
  252.     long    msec;
  253. {
  254.     static int    last_status = 0;
  255.     union REGS    regs;
  256.     long        starttime;
  257.     int            x, y;
  258.  
  259.     starttime = biostime(0, 0L);
  260.  
  261.     for (;;)
  262.     {
  263. #ifdef USE_MOUSE
  264.         long    clicktime;
  265.  
  266.         if (mouse_avail && mouse_active && !mouse_click)
  267.         {
  268.             regs.x.ax = 3;
  269.             int86(0x33, ®s, ®s);        /* check mouse status */
  270.                 /* only recognize button-down and button-up event */
  271.             x = regs.x.cx / mouse_x_div;
  272.             y = regs.x.dx / mouse_y_div;
  273.             if ((last_status == 0) != (regs.x.bx == 0))
  274.             {
  275.                 if (last_status)        /* button up */
  276.                     mouse_click = MOUSE_RELEASE;
  277.                 else                    /* button down */
  278.                 {
  279.                     mouse_click = regs.x.bx;
  280.  
  281.                     /*
  282.                      * Find out if this is a multi-click
  283.                      */
  284.                     clicktime = biostime(0, 0L);
  285.                     if (mouse_click_x == x && mouse_click_y == y &&
  286.                             mouse_topline == curwin->w_topline &&
  287.                             mouse_click_count != 4 &&
  288.                             mouse_click == mouse_last_click &&
  289.                             clicktime < mouse_click_time + p_mouset / BIOSTICK)
  290.                         ++mouse_click_count;
  291.                     else
  292.                         mouse_click_count = 1;
  293.                     mouse_click_time = clicktime;
  294.                     mouse_last_click = mouse_click;
  295.                     mouse_click_x = x;
  296.                     mouse_click_y = y;
  297.                     mouse_topline = curwin->w_topline;
  298.                     SET_NUM_MOUSE_CLICKS(mouse_click, mouse_click_count);
  299.                 }
  300.             }
  301.             else if (last_status && (x != mouse_x || y != mouse_y))
  302.                 mouse_click = MOUSE_DRAG;
  303.             last_status = regs.x.bx;
  304.             if (mouse_hidden && mouse_x >= 0 && (mouse_x != x || mouse_y != y))
  305.             {
  306.                 mouse_hidden = FALSE;
  307.                 show_mouse(TRUE);
  308.             }
  309.             mouse_x = x;
  310.             mouse_y = y;
  311.         }
  312. #endif
  313.  
  314.         if ((p_biosk ? bioskey(1) : kbhit()) || cbrk_pressed
  315. #ifdef USE_MOUSE
  316.                                                     || mouse_click
  317. #endif
  318.                 )
  319.             return TRUE;
  320.         /*
  321.          * Use biostime() to wait until our time is done.
  322.          * Don't use delay(), it doesn't work properly under Windows 95
  323.          * (because it disables interrupts?).
  324.          */
  325.         if (msec != FOREVER && biostime(0, 0L) > starttime + msec / BIOSTICK)
  326.             break;
  327.     }
  328.     return FALSE;
  329. }
  330.  
  331. /*
  332.  * mch_inchar(): low level input funcion.
  333.  * Get a characters from the keyboard.
  334.  * If time == 0 do not wait for characters.
  335.  * If time == n wait a short time for characters.
  336.  * If time == -1 wait forever for characters.
  337.  *
  338.  * return the number of characters obtained
  339.  */
  340.     int
  341. mch_inchar(buf, maxlen, time)
  342.     char_u        *buf;
  343.     int         maxlen;
  344.     long         time;
  345. {
  346.     int         len = 0;
  347.     int            c;
  348.  
  349. /*
  350.  * if we got a ctrl-C when we were busy, there will be a "^C" somewhere
  351.  * on the sceen, so we need to redisplay it.
  352.  */
  353.     if (delayed_redraw)
  354.     {
  355.         delayed_redraw = FALSE;
  356.         updateScreen(CLEAR);
  357.         setcursor();
  358.         flushbuf();
  359.     }
  360.  
  361. #ifdef USE_MOUSE
  362.     if (time != 0)
  363.         show_mouse(TRUE);
  364. #endif
  365.     if (time >= 0)
  366.     {
  367.         if (WaitForChar(time) == 0)     /* no character available */
  368.         {
  369. #ifdef USE_MOUSE
  370.             show_mouse(FALSE);
  371. #endif
  372.             return 0;
  373.         }
  374.     }
  375.     else    /* time == -1 */
  376.     {
  377.     /*
  378.      * If there is no character available within 2 seconds (default)
  379.      * write the autoscript file to disk
  380.      */
  381.         if (WaitForChar(p_ut) == 0)
  382.             updatescript(0);
  383.     }
  384.     WaitForChar(FOREVER);        /* wait for key or mouse click */
  385.  
  386. /*
  387.  * Try to read as many characters as there are.
  388.  * Works for the controlling tty only.
  389.  */
  390.     --maxlen;        /* may get two chars at once */
  391.     /*
  392.      * we will get at least one key. Get more if they are available
  393.      * After a ctrl-break we have to read a 0 (!) from the buffer.
  394.      * bioskey(1) will return 0 if no key is available and when a
  395.      * ctrl-break was typed. When ctrl-break is hit, this does not always
  396.      * implies a key hit.
  397.      */
  398.     cbrk_pressed = FALSE;
  399. #ifdef USE_MOUSE
  400.     if (mouse_click && maxlen >= 6)
  401.     {
  402.         len = 5;
  403.         *buf++ = ESC + 128;
  404.         *buf++ = 'M';
  405.         *buf++ = mouse_click;
  406.         *buf++ = mouse_x + '!';
  407.         *buf++ = mouse_y + '!';
  408.         mouse_click = 0;
  409.     }
  410.     else
  411. #endif
  412.     {
  413. #ifdef USE_MOUSE
  414.         mouse_hidden = TRUE;
  415. #endif
  416.         if (p_biosk)
  417.         {
  418.             while ((len == 0 || bioskey(1)) && len < maxlen)
  419.             {
  420.                 c = bioskey(0);            /* get the key */
  421.                 /*
  422.                  * translate a few things for inchar():
  423.                  * 0x0000 == CTRL-break            -> 3    (CTRL-C)
  424.                  * 0x0300 == CTRL-@             -> NUL
  425.                  * 0xnn00 == extended key code    -> K_NUL, nn
  426.                  * K_NUL                          -> K_NUL, 3
  427.                  */
  428.                 if (c == 0)
  429.                     c = 3;
  430.                 else if (c == 0x0300)
  431.                     c = NUL;
  432.                 else if ((c & 0xff) == 0 || c == K_NUL)
  433.                 {
  434.                     if (c == K_NUL)
  435.                         c = 3;
  436.                     else
  437.                         c >>= 8;
  438.                     *buf++ = K_NUL;
  439.                     ++len;
  440.                 }
  441.  
  442.                 *buf++ = c;
  443.                 len++;
  444.             }
  445.         }
  446.         else
  447.         {
  448.             while ((len == 0 || kbhit()) && len < maxlen)
  449.             {
  450.                 switch (c = getch())
  451.                 {
  452.                     case 0:
  453.                         /* NUL means that there is another character.
  454.                          * Get it immediately, because kbhit() doesn't always
  455.                          * return TRUE for the second character.
  456.                          */
  457.                         *buf++ = K_NUL;
  458.                         *buf++ = getch();
  459.                         len++;
  460.                         break;
  461.                     case K_NUL:
  462.                         *buf++ = K_NUL;
  463.                         *buf++ = 3;
  464.                         ++len;
  465.                         break;
  466.                     case 3:
  467.                         cbrk_pressed = TRUE;
  468.                         /*FALLTHROUGH*/
  469.                     default:
  470.                         *buf++ = c;
  471.                 }
  472.                 ++len;
  473.             }
  474.         }
  475.     }
  476. #ifdef USE_MOUSE
  477.     show_mouse(FALSE);
  478. #endif
  479.     beep_count = 0;            /* may beep again now that we got some chars */
  480.     return len;
  481. }
  482.  
  483. /*
  484.  * return non-zero if a character is available
  485.  */
  486.     int
  487. mch_char_avail()
  488. {
  489.     return WaitForChar(0L);
  490. }
  491.  
  492. /*
  493.  * We have no job control, fake it by starting a new shell.
  494.  */
  495.     void
  496. mch_suspend()
  497. {
  498.     MSG_OUTSTR("new shell started\n");
  499.     (void)call_shell(NULL, SHELL_COOKED);
  500.     need_check_timestamps = TRUE;
  501. }
  502.  
  503. extern int _fmode;
  504. /*
  505.  * we do not use windows, there is not much to do here
  506.  */
  507.     void
  508. mch_windinit()
  509. {
  510.     union REGS regs;
  511.  
  512.     term_console = TRUE;    /* assume using the console for the things here */
  513.     _fmode = O_BINARY;        /* we do our own CR-LF translation */
  514.     flushbuf();
  515.     (void)mch_get_winsize();
  516.  
  517. #ifdef USE_MOUSE
  518. /* find out if a MS compatible mouse is available */
  519.     regs.x.ax = 0;
  520.     (void)int86(0x33, ®s, ®s);
  521.     mouse_avail = regs.x.ax;
  522.     /* best guess for mouse coordinate computations */
  523.     if (Columns <= 40)
  524.         mouse_x_div = 16;
  525.     if (Rows == 30)
  526.         mouse_y_div = 16;
  527. #endif
  528. }
  529.  
  530. #ifdef USE_MOUSE
  531.     static void
  532. show_mouse(on)
  533.     int        on;
  534. {
  535.     static int        was_on = FALSE;
  536.     union REGS        regs;
  537.  
  538.     if (mouse_avail)
  539.     {
  540.         if (!mouse_active || mouse_hidden)
  541.             on = FALSE;
  542.         /*
  543.          * Careful: Each switch on must be compensated by exactly one switch
  544.          * off
  545.          */
  546.         if (on && !was_on || !on && was_on)
  547.         {
  548.             was_on = on;
  549.             regs.x.ax = on ? 1 : 2;
  550.             int86(0x33, ®s, ®s);    /* show mouse */
  551.             if (on)
  552.                 mouse_area();
  553.         }
  554.     }
  555. }
  556.  
  557. /*
  558.  * Set area where mouse can be moved to: The whole screen.
  559.  * Rows must be valid when calling!
  560.  */
  561.     static void
  562. mouse_area()
  563. {
  564.     union REGS        regs;
  565.     int                mouse_y_max;            /* maximum mouse y coord */
  566.  
  567.     if (mouse_avail)
  568.     {    
  569.         mouse_y_max = Rows * mouse_y_div - 1;
  570.         if (mouse_y_max < 199)        /* is this needed? */
  571.             mouse_y_max = 199;
  572.         regs.x.cx = 0;    /* mouse visible between cx and dx */
  573.         regs.x.dx = 639;
  574.         regs.x.ax = 7;
  575.         (void)int86(0x33, ®s, ®s);
  576.         regs.x.cx = 0;    /* mouse visible between cx and dx */
  577.         regs.x.dx = mouse_y_max;
  578.         regs.x.ax = 8;
  579.         (void)int86(0x33, ®s, ®s);
  580.     }
  581. }
  582.  
  583. #endif
  584.  
  585.     int
  586. mch_check_win(argc, argv)
  587.     int        argc;
  588.     char    **argv;
  589. {
  590.     if (isatty(1))
  591.         return OK;
  592.     return FAIL;
  593. }
  594.  
  595.     int
  596. mch_check_input()
  597. {
  598.     if (isatty(0))
  599.         return OK;
  600.     return FAIL;
  601. }
  602.  
  603. #ifdef USE_FNAME_CASE
  604. /*
  605.  * fname_case(): Set the case of the filename, if it already exists.
  606.  */
  607.     void
  608. fname_case(name)
  609.     char_u *name;
  610. {
  611.     char_u            *tail;
  612.     struct ffblk    fb;
  613.  
  614.     slash_adjust(name);
  615.     if (findfirst(name, &fb, 0) == 0)
  616.     {
  617.         tail = gettail(name);
  618.         if (STRLEN(tail) == STRLEN(fb.ff_name))
  619.             STRCPY(tail, fb.ff_name);
  620.     }
  621. }
  622. #endif
  623.  
  624. /*
  625.  * mch_settitle(): set titlebar of our window.
  626.  * Dos console has no title.
  627.  */
  628.     void
  629. mch_settitle(title, icon)
  630.     char_u *title;
  631.     char_u *icon;
  632. {
  633. }
  634.  
  635. /*
  636.  * Restore the window/icon title. (which we don't have)
  637.  */
  638.     void
  639. mch_restore_title(which)
  640.     int which;
  641. {
  642. }
  643.  
  644.     int
  645. mch_can_restore_title()
  646. {
  647.     return FALSE;
  648. }
  649.  
  650.     int
  651. mch_can_restore_icon()
  652. {
  653.     return FALSE;
  654. }
  655.  
  656. /*
  657.  * Insert user name in s[len].
  658.  */
  659.     int
  660. mch_get_user_name(s, len)
  661.     char_u    *s;
  662.     int        len;
  663. {
  664.     *s = NUL;
  665.     return FAIL;
  666. }
  667.  
  668. /*
  669.  * Insert host name is s[len].
  670.  */
  671.     void
  672. mch_get_host_name(s, len)
  673.     char_u    *s;
  674.     int        len;
  675. {
  676. #ifdef DJGPP
  677.     STRNCPY(s, "PC (32 bits Vim)", len);
  678. #else
  679.     STRNCPY(s, "PC (16 bits Vim)", len);
  680. #endif
  681. }
  682.  
  683. /*
  684.  * return process ID
  685.  */
  686.     long
  687. mch_get_pid()
  688. {
  689.     return (long)0;
  690. }
  691.  
  692. /*
  693.  * Get name of current directory into buffer 'buf' of length 'len' bytes.
  694.  * Return OK for success, FAIL for failure.
  695.  */
  696.     int
  697. mch_dirname(buf, len)
  698.     char_u    *buf;
  699.     int        len;
  700. {
  701.     return (getcwd(buf, len) != NULL ? OK : FAIL);
  702. }
  703.  
  704. /*
  705.  * Change default drive (just like _chdrive of Borland C 3.1)
  706.  */
  707.     static int
  708. change_drive(drive)
  709.     int drive;
  710. {
  711.     unsigned dummy;
  712.     union REGS regs;
  713.  
  714.     regs.h.ah = 0x0e;
  715.     regs.h.dl = drive - 1;
  716.     intdos(®s, ®s);    /* set default drive */
  717.     regs.h.ah = 0x19;
  718.     intdos(®s, ®s);    /* get default drive */
  719.     if (regs.h.al == drive - 1)
  720.         return 0;
  721.     else
  722.         return -1;
  723. }
  724.  
  725. /*
  726.  * Get absolute filename into buffer 'buf' of length 'len' bytes.
  727.  * All slashes are replaced with backslashes, to avoid trouble when comparing
  728.  * file names.
  729.  *
  730.  * return FAIL for failure, OK otherwise
  731.  */
  732.     int
  733. FullName(fname, buf, len, force)
  734.     char_u    *fname, *buf;
  735.     int        len;
  736.     int        force;
  737. {
  738.     if (fname == NULL)    /* always fail */
  739.     {
  740.         *buf = NUL;
  741.         return FAIL;
  742.     }
  743.  
  744.     if (!force && isFullName(fname))        /* allready expanded */
  745.     {
  746.         STRNCPY(buf, fname, len);
  747.         slash_adjust(buf);
  748.         return OK;
  749.     }
  750.  
  751. #ifdef __BORLANDC__        /* the old Turbo C does not have this */
  752.     if (_fullpath(buf, fname, len) == NULL)
  753.     {
  754.         STRNCPY(buf, fname, len);    /* failed, use the relative path name */
  755.         slash_adjust(buf);
  756.         return FAIL;
  757.     }
  758.     slash_adjust(buf);
  759.     return OK;
  760. #else                    /* almost the same as FullName in unix.c */
  761.     {
  762.         int        l;
  763.         char_u    olddir[MAXPATHL];
  764.         char_u    *p, *q;
  765.         int        c;
  766.         int        retval = OK;
  767.  
  768.         *buf = 0;
  769.         /*
  770.          * change to the directory for a moment,
  771.          * and then do the getwd() (and get back to where we were).
  772.          * This will get the correct path name with "../" things.
  773.          */
  774.         p = vim_strrchr(fname, '/');
  775.         q = vim_strrchr(fname, '\\');
  776.         if (q != NULL && (p == NULL || q > p))
  777.             p = q;
  778.         q = vim_strrchr(fname, ':');
  779.         if (q != NULL && (p == NULL || q > p))
  780.             p = q;
  781.         if (p != NULL)
  782.         {
  783.             if (getcwd(olddir, MAXPATHL) == NULL)
  784.             {
  785.                 p = NULL;        /* can't get current dir: don't chdir */
  786.                 retval = FAIL;
  787.             }
  788.             else
  789.             {
  790.                 q = p + 1;
  791.                 c = *q;                    /* truncate at start of fname */
  792.                 *q = NUL;
  793. #ifdef DJGPP
  794.                 STRCPY(buf, fname);
  795.                 slash_adjust(buf);        /* needed when fname starts with \ */
  796.                 if (vim_chdir(buf))        /* change to the directory */
  797. #else
  798.                 if (vim_chdir(fname))    /* change to the directory */
  799. #endif
  800.                     retval = FAIL;
  801.                 else
  802.                     fname = q;
  803.                 *q = c;
  804.             }
  805.         }
  806.         if (getcwd(buf, len) == NULL)
  807.         {
  808.             retval = FAIL;
  809.             *buf = NUL;
  810.         }
  811.         /*
  812.          * Concatenate the file name to the path.
  813.          */
  814.         l = STRLEN(buf);
  815.         if (l && buf[l - 1] != '/' && buf[l - 1] != '\\')
  816.             strcat(buf, "/");
  817.         if (p)
  818.             vim_chdir(olddir);
  819.         strcat(buf, fname);
  820.         slash_adjust(buf);
  821.         return retval;
  822.     }
  823. #endif
  824. }
  825.  
  826. /*
  827.  * Replace all slashes by backslashes.
  828.  * This used to be the other way around, but MS-DOS sometimes has problems
  829.  * with slashes (e.g. in a command name).  We can't have mixed slashes and
  830.  * backslashes, because comparing file names will not work correctly.  The
  831.  * commands that use a file name should try to avoid the need to type a
  832.  * backslash twice.
  833.  */
  834.     static void
  835. slash_adjust(p)
  836.     char_u    *p;
  837. {
  838. #ifdef DJGPP
  839.     /* DJGPP can't handle a file name that starts with a backslash, and when it
  840.      * starts with a slash there should be no backslashes */
  841.     if (*p == '\\' || *p == '/')
  842.         while (*p)
  843.         {
  844.             if (*p == '\\')
  845.                 *p = '/';
  846.             ++p;
  847.         }
  848.     else
  849. #endif
  850.     while (*p)
  851.     {
  852.         if (*p == '/')
  853.             *p = '\\';
  854.         ++p;
  855.     }
  856. }
  857.  
  858. /*
  859.  * return TRUE is fname is an absolute path name
  860.  */
  861.     int
  862. isFullName(fname)
  863.     char_u        *fname;
  864. {
  865.     return (vim_strchr(fname, ':') != NULL);
  866. }
  867.  
  868. /*
  869.  * get file permissions for 'name'
  870.  * -1 : error
  871.  * else FA_attributes defined in dos.h
  872.  */
  873.     long
  874. getperm(name)
  875.     char_u *name;
  876. {
  877.     int r;
  878.  
  879.     r = _chmod(name, 0, 0);         /* get file mode */
  880.     return r;
  881. }
  882.  
  883. /*
  884.  * set file permission for 'name' to 'perm'
  885.  *
  886.  * return FAIL for failure, OK otherwise
  887.  */
  888.     int
  889. setperm(name, perm)
  890.     char_u    *name;
  891.     long    perm;
  892. {
  893.     perm |= FA_ARCH;        /* file has changed, set archive bit */
  894.     return (_chmod((char *)name, 1, (int)perm) == -1 ? FAIL : OK);
  895. }
  896.  
  897. /*
  898.  * return TRUE if "name" is a directory
  899.  * return FALSE if "name" is not a directory
  900.  * return FALSE for error
  901.  *
  902.  * beware of a trailing backslash
  903.  */
  904.     int
  905. mch_isdir(name)
  906.     char_u *name;
  907. {
  908.     int        f;
  909.     char_u    *p;
  910.  
  911.     p = name + strlen(name);
  912.     if (p > name)
  913.         --p;
  914.     if (*p == '\\')                    /* remove trailing backslash for a moment */
  915.         *p = NUL;
  916.     else
  917.         p = NULL;
  918.     f = _chmod(name, 0, 0);
  919.     if (p != NULL)
  920.         *p = '\\';                    /* put back backslash */
  921.     if (f == -1)
  922.         return FALSE;                /* file does not exist at all */
  923.     if ((f & FA_DIREC) == 0)
  924.         return FALSE;                /* not a directory */
  925.     return TRUE;
  926. }
  927.  
  928. /*
  929.  * Careful: mch_windexit() may be called before mch_windinit()!
  930.  */
  931.     void
  932. mch_windexit(r)
  933.     int r;
  934. {
  935.     settmode(0);
  936.     stoptermcap();
  937.     outchar('\r');
  938.     outchar('\n');
  939.     flushbuf();
  940.     ml_close_all(TRUE);                /* remove all memfiles */
  941.     exit(r);
  942. }
  943.  
  944. #ifdef DJGPP
  945. # define INT_ARG    int
  946. #else
  947. # define INT_ARG
  948. #endif
  949.  
  950. /*
  951.  * function for ctrl-break interrupt
  952.  */
  953.     static void interrupt
  954. #ifdef DJGPP
  955. catch_cbrk(int a)
  956. #else
  957. catch_cbrk()
  958. #endif
  959. {
  960.     cbrk_pressed = TRUE;
  961.     ctrlc_pressed = TRUE;
  962. }
  963.  
  964. /*
  965.  * ctrl-break handler for DOS. Never called when a ctrl-break is typed, because
  966.  * we catch interrupt 1b. If you type ctrl-C while Vim is waiting for a
  967.  * character this function is not called. When a ctrl-C is typed while Vim is
  968.  * busy this function may be called. By that time a ^C has been displayed on
  969.  * the screen, so we have to redisplay the screen. We can't do that here,
  970.  * because we may be called by DOS. The redraw is in mch_inchar().
  971.  */
  972.     static int
  973. cbrk_handler()
  974. {
  975.     delayed_redraw = TRUE;
  976.     return 1;                 /* resume operation after ctrl-break */
  977. }
  978.  
  979. /*
  980.  * function for critical error interrupt
  981.  * For DOS 1 and 2 return 0 (Ignore).
  982.  * For DOS 3 and later return 3 (Fail)
  983.  */
  984.     static void interrupt
  985. catch_cint(bp, di, si, ds, es, dx, cx, bx, ax)
  986.     unsigned bp, di, si, ds, es, dx, cx, bx, ax;
  987. {
  988.     ax = (ax & 0xff00);        /* set AL to 0 */
  989.     if (_osmajor >= 3)
  990.         ax |= 3;            /* set AL to 3 */
  991. }
  992.  
  993. /*
  994.  * set the tty in (raw) ? "raw" : "cooked" mode
  995.  *
  996.  * Does not change the tty, as bioskey() and kbhit() work raw all the time.
  997.  */
  998.     void
  999. mch_settmode(raw)
  1000.     int  raw;
  1001. {
  1002.     static int saved_cbrk;
  1003. #ifndef DJGPP
  1004.     static void interrupt (*old_cint)();
  1005. #endif
  1006.     static void interrupt (*old_cbrk)(INT_ARG);
  1007.  
  1008.     if (raw)
  1009.     {
  1010.         saved_cbrk = getcbrk();            /* save old ctrl-break setting */
  1011.         setcbrk(0);                        /* do not check for ctrl-break */
  1012. #ifdef DJGPP
  1013.         old_cbrk = signal(SIGINT, catch_cbrk);    /* critical error interrupt */
  1014. #else
  1015.         old_cint = getvect(0x24);         /* save old critical error interrupt */
  1016.         setvect(0x24, catch_cint);        /* install our critical error interrupt */
  1017.         old_cbrk = getvect(0x1B);         /* save old ctrl-break interrupt */
  1018.         setvect(0x1B, catch_cbrk);        /* install our ctrl-break interrupt */
  1019.         ctrlbrk(cbrk_handler);            /* vim's ctrl-break handler */
  1020. #endif
  1021.         if (term_console)
  1022.             outstr(T_ME);                /* set colors */
  1023.     }
  1024.     else
  1025.     {
  1026.         setcbrk(saved_cbrk);            /* restore ctrl-break setting */
  1027. #ifdef DJGPP
  1028.         signal(SIGINT,old_cbrk);        /* critical error interrupt */
  1029. #else
  1030.         setvect(0x24, old_cint);        /* restore critical error interrupt */
  1031.         setvect(0x1B, old_cbrk);        /* restore ctrl-break interrupt */
  1032. #endif
  1033.         /* restore ctrl-break handler, how ??? */
  1034.         if (term_console)
  1035.             normvideo();                /* restore screen colors */
  1036.     }
  1037. }
  1038.  
  1039. #ifdef USE_MOUSE
  1040.     void
  1041. mch_setmouse(on)
  1042.     int        on;
  1043. {
  1044.     mouse_active = on;
  1045.     mouse_hidden = TRUE;        /* dont show it until moved */
  1046. }
  1047. #endif
  1048.  
  1049. /*
  1050.  * set screen mode
  1051.  * return FAIL for failure, OK otherwise
  1052.  */
  1053.     int
  1054. mch_screenmode(arg)
  1055.     char_u        *arg;
  1056. {
  1057.     int                mode;
  1058.     int                i;
  1059.     static char_u *(names[]) = {"BW40", "C40", "BW80", "C80", "MONO", "C4350"};
  1060.     static int        modes[]  = { BW40,   C40,   BW80,   C80,   MONO,   C4350};
  1061.  
  1062.     mode = -1;
  1063.     if (isdigit(*arg))                /* mode number given */
  1064.         mode = atoi((char *)arg);
  1065.     else
  1066.     {
  1067.         for (i = 0; i < sizeof(names) / sizeof(char_u *); ++i)
  1068.             if (stricmp((char *)names[i], (char *)arg) == 0)
  1069.             {
  1070.                 mode = modes[i];
  1071.                 break;
  1072.             }
  1073.     }
  1074.     if (mode == -1)
  1075.     {
  1076.         EMSG("Unsupported screen mode");
  1077.         return FAIL;
  1078.     }
  1079.     textmode(mode);                    /* use Borland function */
  1080.  
  1081.     /* Screen colors may have changed. */
  1082.     outstr(T_ME);
  1083. #ifdef USE_MOUSE
  1084.     if (mode <= 1 || mode == 4 || mode == 5 || mode == 13 || mode == 0x13)
  1085.         mouse_x_div = 16;
  1086.     else
  1087.         mouse_x_div = 8;
  1088.     if (mode == 0x11 || mode == 0x12)
  1089.         mouse_y_div = 16;
  1090.     else if (mode == 0x10)
  1091.         mouse_y_div = 14;
  1092.     else
  1093.         mouse_y_div = 8;
  1094.     mch_get_winsize();        /* Rows is used in mouse_area() */
  1095.     mouse_area();            /* set area where mouse can go */
  1096. #endif
  1097.     return OK;
  1098. }
  1099.  
  1100. /*
  1101.  * Structure used by Turbo-C/Borland-C to store video parameters.
  1102.  */
  1103. #ifndef DJGPP
  1104. extern struct text_info _video;
  1105. #endif
  1106.  
  1107. /*
  1108.  * try to get the real window size
  1109.  * return FAIL for failure, OK otherwise
  1110.  */
  1111.     int
  1112. mch_get_winsize()
  1113. {
  1114.     int i;
  1115.     struct text_info ti;
  1116. /*
  1117.  * The screenwidth is returned by the BIOS OK.
  1118.  * The screenheight is in a location in the bios RAM, if the display is EGA or
  1119.  * VGA.
  1120.  */
  1121.     if (!term_console)
  1122.         return FAIL;
  1123.     gettextinfo(&ti);
  1124.     Columns = ti.screenwidth;
  1125.     Rows = ti.screenheight;
  1126. #ifndef DJGPP
  1127.     if (ti.currmode > 10)
  1128.         Rows = *(char far *)MK_FP(0x40, 0x84) + 1;
  1129. #endif
  1130.     /*
  1131.      * don't call set_window() when not doing full screen, since it will move
  1132.      * the cursor.  Also skip this when exiting.
  1133.      */
  1134.     if (full_screen && !exiting)
  1135.         set_window();
  1136.  
  1137.     if (Columns < MIN_COLUMNS || Rows < MIN_ROWS + 1)
  1138.     {
  1139.         /* these values are overwritten by termcap size or default */
  1140.         Columns = 80;
  1141.         Rows = 25;
  1142.         return FAIL;
  1143.     }
  1144.     check_winsize();
  1145.  
  1146.     return OK;
  1147. }
  1148.  
  1149. /*
  1150.  * Set the active window for delline/insline.
  1151.  */
  1152.     void
  1153. set_window()
  1154. {
  1155. #ifndef DJGPP
  1156.     _video.screenheight = Rows;
  1157. #endif
  1158.     window(1, 1, Columns, Rows);
  1159.     screen_start();
  1160. }
  1161.  
  1162.     void
  1163. mch_set_winsize()
  1164. {
  1165.     /* should try to set the window size to Rows and Columns */
  1166.     /* may involve switching display mode.... */
  1167.  
  1168. #ifdef USE_MOUSE
  1169.     mouse_area();            /* set area where mouse can go */
  1170. #endif
  1171. }
  1172.  
  1173. /*
  1174.  * call shell, return FAIL for failure, OK otherwise
  1175.  */
  1176.     int
  1177. call_shell(cmd, options)
  1178.     char_u    *cmd;
  1179.     int        options;        /* SHELL_FILTER if called by do_filter() */
  1180.                             /* SHELL_COOKED if term needs cooked mode */
  1181.                             /* SHELL_EXPAND if called by ExpandWildCards() */
  1182. {
  1183.     int        x;
  1184.     char_u    *newcmd;
  1185.  
  1186.     flushbuf();
  1187.  
  1188.     if (options & SHELL_COOKED)
  1189.         settmode(0);        /* set to cooked mode */
  1190.  
  1191.     if (cmd == NULL)
  1192.         x = system(p_sh);
  1193.     else
  1194.     {                 /* we use "command" to start the shell, slow but easy */
  1195.         newcmd = alloc(STRLEN(p_sh) + STRLEN(cmd) + 5);
  1196.         if (newcmd == NULL)
  1197.             x = 1;
  1198.         else
  1199.         {
  1200.             sprintf(newcmd, "%s %s %s", p_sh, p_shcf, cmd);
  1201.             x = system(newcmd);
  1202.             vim_free(newcmd);
  1203.         }
  1204.     }
  1205.     settmode(1);            /* set to raw mode */
  1206.  
  1207.     if (x && !expand_interactively)
  1208.     {
  1209.         msg_outchar('\n');
  1210.         msg_outnum((long)x);
  1211.         MSG_OUTSTR(" returned\n");
  1212.     }
  1213.  
  1214.     /* resettitle();                we don't have titles */
  1215.     (void)mch_get_winsize();        /* display mode may have been changed */
  1216.     return (x ? FAIL : OK);
  1217. }
  1218.  
  1219. /*
  1220.  * check for an "interrupt signal": CTRL-break or CTRL-C
  1221.  */
  1222.     void
  1223. mch_breakcheck()
  1224. {
  1225.     if (ctrlc_pressed)
  1226.     {
  1227.         ctrlc_pressed = FALSE;
  1228.         got_int = TRUE;
  1229.     }
  1230. }
  1231.  
  1232. #define FL_CHUNK 32
  1233.  
  1234.     static void
  1235. addfile(fl, f, isdir)
  1236.     FileList    *fl;
  1237.     char_u        *f;
  1238.     int            isdir;
  1239. {
  1240.     char_u        *p;
  1241.  
  1242.     if (!fl->file)
  1243.     {
  1244.         fl->file = (char_u **)alloc(sizeof(char_u *) * FL_CHUNK);
  1245.         if (!fl->file)
  1246.             return;
  1247.         fl->nfiles = 0;
  1248.         fl->maxfiles = FL_CHUNK;
  1249.     }
  1250.     if (fl->nfiles >= fl->maxfiles)
  1251.     {
  1252.         char_u    **t;
  1253.         int        i;
  1254.  
  1255.         t = (char_u **)lalloc((long_u)(sizeof(char_u *) * (fl->maxfiles + FL_CHUNK)), TRUE);
  1256.         if (!t)
  1257.             return;
  1258.         for (i = fl->nfiles - 1; i >= 0; i--)
  1259.             t[i] = fl->file[i];
  1260.         vim_free(fl->file);
  1261.         fl->file = t;
  1262.         fl->maxfiles += FL_CHUNK;
  1263.     }
  1264.     p = alloc((unsigned)(STRLEN(f) + 1 + isdir));
  1265.     if (p)
  1266.     {
  1267.         STRCPY(p, f);
  1268.         slash_adjust(p);
  1269.         /*
  1270.          * Append a backslash after directory names.
  1271.          */
  1272.         if (isdir)
  1273.             strcat(p, "\\");
  1274.     }
  1275.     fl->file[fl->nfiles++] = p;
  1276. }
  1277.  
  1278.     static int
  1279. pstrcmp(a, b)
  1280.     char_u **a, **b;
  1281. {
  1282.     return (strcmp(*a, *b));
  1283. }
  1284.  
  1285.     int
  1286. mch_has_wildcard(s)
  1287.     char_u *s;
  1288. {
  1289.     for ( ; *s; ++s)
  1290.         if (*s == '?' || *s == '*' || *s == '$')
  1291.             return TRUE;
  1292.     return FALSE;
  1293. }
  1294.  
  1295.     static void
  1296. strlowcpy(d, s)
  1297.     char_u *d, *s;
  1298. {
  1299. #ifdef DJGPP
  1300.     if (USE_LONG_FNAME)        /* don't lower case on Windows 95/NT systems */
  1301.         while (*s)
  1302.             *d++ = *s++;
  1303.     else
  1304. #endif
  1305.         while (*s)
  1306.             *d++ = tolower(*s++);
  1307.     *d = NUL;
  1308. }
  1309.  
  1310.     static int
  1311. expandpath(fl, path, fonly, donly, notf)
  1312.     FileList    *fl;
  1313.     char_u        *path;
  1314.     int            fonly, donly, notf;
  1315. {
  1316.     char_u    *buf;
  1317.     char_u    *p, *s, *e;
  1318.     int        lastn, c, retval;
  1319.     struct ffblk fb;
  1320.  
  1321.     lastn = fl->nfiles;
  1322.     buf = alloc(STRLEN(path) + BASENAMELEN + 5);    /* make room for file name */
  1323.     if (buf == NULL)
  1324.         return 1;
  1325.  
  1326. /*
  1327.  * Find the first part in the path name that contains a wildcard.
  1328.  * Copy it into buf, including the preceding characters.
  1329.  */
  1330.     p = buf;
  1331.     s = NULL;
  1332.     e = NULL;
  1333.     while (*path)
  1334.     {
  1335.         if (*path == '\\' || *path == ':' || *path == '/')
  1336.         {
  1337.             if (e)
  1338.                 break;
  1339.             else
  1340.                 s = p;
  1341.         }
  1342.         if (*path == '*' || *path == '?')
  1343.             e = p;
  1344.         *p++ = *path++;
  1345.     }
  1346.     e = p;
  1347.     if (s)
  1348.         s++;
  1349.     else
  1350.         s = buf;
  1351.  
  1352.     /* if the file name ends in "*" and does not contain a ".", addd ".*" */
  1353.     if (e[-1] == '*' && vim_strchr(s, '.') == NULL)
  1354.     {
  1355.         *e++ = '.';
  1356.         *e++ = '*';
  1357.     }
  1358.     /* now we have one wildcard component between s and e */
  1359.     *e = NUL;
  1360.     retval = 0;
  1361.     /* If we are expanding wildcards we try both files and directories */
  1362.     if ((c = findfirst(buf, &fb, (*path || !notf) ? FA_DIREC : 0)) != 0)
  1363.     {
  1364.         /* not found */
  1365.         STRCPY(e, path);
  1366.         if (notf)
  1367.             addfile(fl, buf, FALSE);
  1368.         vim_free(buf);
  1369.         return 1; /* unexpanded or empty */
  1370.     }
  1371.     while (!c)
  1372.     {
  1373.         strlowcpy(s, fb.ff_name);    /* may expand "*" to "12345678.123" */
  1374.             /* ignore "." and ".." */
  1375.         if (*s != '.' || (s[1] != NUL && (s[1] != '.' || s[2] != NUL)))
  1376.         {
  1377.             strcat(buf, path);
  1378.             if (!mch_has_wildcard(path))
  1379.                 addfile(fl, buf, mch_isdir(buf));
  1380.             else
  1381.                 retval |= expandpath(fl, buf, fonly, donly, notf);
  1382.         }
  1383.         c = findnext(&fb);
  1384.     }
  1385.     vim_free(buf);
  1386.     qsort(fl->file + lastn, fl->nfiles - lastn, sizeof(char_u *), pstrcmp);
  1387.     return retval;
  1388. }
  1389.  
  1390. /*
  1391.  * MSDOS rebuilt of Scott Ballantynes ExpandWildCards for amiga/arp.
  1392.  * jw
  1393.  */
  1394.  
  1395.     int
  1396. ExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
  1397.     int     num_pat;
  1398.     char_u    **pat;
  1399.     int     *num_file;
  1400.     char_u    ***file;
  1401.     int     files_only, list_notfound;
  1402. {
  1403.     int            i, retval = 0;
  1404.     FileList    f;
  1405.     char_u        *p;
  1406.  
  1407.     f.file = NULL;
  1408.     f.nfiles = 0;
  1409.  
  1410.     for (i = 0; i < num_pat; i++)
  1411.     {
  1412.         /*
  1413.          * First expand environment variables.
  1414.          */
  1415.         if (vim_strchr(pat[i], '$') != NULL)
  1416.         {
  1417.             p = alloc(MAXPATHL);
  1418.             if (p != NULL)
  1419.                 expand_env(pat[i], p, MAXPATHL);
  1420.             else
  1421.                 p = pat[i];
  1422.         }
  1423.         else
  1424.             p = pat[i];
  1425.  
  1426.         if (!mch_has_wildcard(p))
  1427.             addfile(&f, p, files_only ? FALSE : mch_isdir(p));
  1428.         else
  1429.             retval |= expandpath(&f, p, files_only, 0, list_notfound);
  1430.         if (p != pat[i])
  1431.             vim_free(p);
  1432.     }
  1433.  
  1434.     *num_file = f.nfiles;
  1435.     *file = (*num_file > 0) ? f.file : (char_u **)"";
  1436.  
  1437.     return (*num_file > 0) ? OK : FAIL;
  1438. }
  1439.  
  1440. #ifdef USE_VIM_CHDIR
  1441. /*
  1442.  * The normal chdir() does not change the default drive.
  1443.  * This one does.
  1444.  */
  1445.     int
  1446. vim_chdir(path)
  1447.     char *path;
  1448. {
  1449.     if (path[0] == NUL)                /* just checking... */
  1450.         return 0;
  1451.     if (path[1] == ':')                /* has a drive name */
  1452.     {
  1453.         if (change_drive(toupper(path[0]) - 'A' + 1))
  1454.             return -1;                /* invalid drive name */
  1455.         path += 2;
  1456.     }
  1457.     if (*path == NUL)                /* drive name only */
  1458.         return 0;
  1459.     return chdir(path);                /* let the normal chdir() do the rest */
  1460. }
  1461. #endif
  1462.  
  1463. #ifdef DJGPP
  1464. /*
  1465.  * djgpp_rename() works around a bug in rename (aka MoveFile) in
  1466.  * Windows 95: rename("foo.bar", "foo.bar~") will generate a
  1467.  * file whose shortfilename is "FOO.BAR" (its longfilename will
  1468.  * be correct: "foo.bar~").  Because a file can be accessed by
  1469.  * either its SFN or its LFN, "foo.bar" has effectively been
  1470.  * renamed to "foo.bar", which is not at all what was wanted.  This
  1471.  * seems to happen only when renaming files with three-character
  1472.  * extensions by appending a suffix that does not include ".".
  1473.  * Windows NT gets it right, however, with an SFN of "FOO~1.BAR".
  1474.  * This works like win95rename in win32.c, but is a bit simpler.
  1475.  *
  1476.  * Like rename(), returns 0 upon success, non-zero upon failure.
  1477.  * Should probably set errno appropriately when errors occur.
  1478.  */
  1479.  
  1480. #undef rename
  1481.  
  1482.     int
  1483. djgpp_rename(const char *OldFile, const char *NewFile)
  1484. {
  1485.     char_u    *TempFile;
  1486.     int        retval;
  1487.     int        fd;
  1488.  
  1489.     /* rename() works correctly without long file names, so use that */
  1490.     if (!_USE_LFN)
  1491.         return rename(OldFile, NewFile);
  1492.  
  1493.     if ((TempFile = alloc((unsigned)(STRLEN(OldFile) + 13))) == NULL)
  1494.         return -1;
  1495.     
  1496.     STRCPY(TempFile, OldFile);
  1497.     STRCPY(gettail(TempFile), "axlqwqhy.ba~");
  1498.     if (rename(OldFile, TempFile))
  1499.         retval = -1;
  1500.     else
  1501.     {
  1502.         /* now create an empty file called OldFile; this prevents
  1503.          * the operating system using OldFile as an alias (SFN)
  1504.          * if we're renaming within the same directory.  For example,
  1505.          * we're editing a file called filename.asc.txt by its SFN,
  1506.          * filena~1.txt.  If we rename filena~1.txt to filena~1.txt~
  1507.          * (i.e., we're making a backup while writing it), the SFN
  1508.          * for filena~1.txt~ will be filena~1.txt, by default, which
  1509.          * will cause all sorts of problems later in buf_write.  So, we
  1510.          * create an empty file called filena~1.txt and the system will have
  1511.          * to find some other SFN for filena~1.txt~, such as filena~2.txt
  1512.          */
  1513.         if ((fd = open(OldFile, O_RDWR|O_CREAT|O_EXCL, 0444)) < 0)
  1514.             return -1;
  1515.         retval = rename(TempFile, NewFile);
  1516.         close(fd);
  1517.         vim_remove((char_u *)OldFile);
  1518.     }
  1519.     vim_free(TempFile);
  1520.  
  1521.     return retval;    /* success */
  1522. }
  1523. #endif
  1524.  
  1525. /*
  1526.  * Special version of getenv(): use $HOME when $VIM not defined.
  1527.  */
  1528.     char_u *
  1529. vim_getenv(var)
  1530.     char_u *var;
  1531. {
  1532.     char_u    *retval;
  1533.  
  1534.     retval = (char_u *)getenv((char *)var);
  1535.  
  1536.     if (retval == NULL && STRCMP(var, "VIM") == 0)
  1537.         retval = (char_u *)getenv("HOME");
  1538.  
  1539.     return retval;
  1540. }
  1541.