home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / vim-2.0.lha / Vim-2.0 / src / msdos.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-15  |  16.7 KB  |  913 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved
  4.  *
  5.  * Code Contributions By:        Bram Moolenaar            mool@oce.nl
  6.  *                                Tim Thompson            twitch!tjt
  7.  *                                Tony Andrews            onecom!wldrdg!tony
  8.  *                                G. R. (Fred) Walter     watmath!watcgl!grwalter
  9.  */
  10.  
  11. /*
  12.  * msdos.c
  13.  *
  14.  * MSDOS system-dependent routines.
  15.  * A cheap plastic imitation of the amiga dependent code.
  16.  * A lot in this file was made by Juergen Weigert (jw).
  17.  */
  18.  
  19. #include <io.h>
  20. #include "vim.h"
  21. #include "globals.h"
  22. #include "param.h"
  23. #include "proto.h"
  24. #include <conio.h>
  25. #include <fcntl.h>
  26. #include <bios.h>
  27.  
  28. static int WaitForChar __ARGS((int));
  29. static int cbrk_handler __ARGS(());
  30.  
  31. typedef struct filelist
  32. {
  33.     char    **file;
  34.     int        nfiles;
  35.     int        maxfiles;
  36. } FileList;
  37.  
  38. static void        addfile __ARGS((FileList *, char *, int));
  39. static int        pstrcmp();    /* __ARGS((char **, char **)); BCC does not like this */
  40. static void        strlowcpy __ARGS((char *, char *));
  41. static int        expandpath __ARGS((FileList *, char *, int, int, int));
  42.  
  43. static int cbrk_pressed = FALSE;    /* set by ctrl-break interrupt */
  44. static int ctrlc_pressed = FALSE;    /* set when ctrl-C or ctrl-break detected */
  45. static int delayed_redraw = FALSE;    /* set when ctrl-C detected */
  46.  
  47. #ifdef DEBUG
  48. /*
  49.  * Put two characters in the video buffer without calling BIOS or DOS.
  50.  */
  51. blink(n)
  52.     int n;
  53. {
  54.     char far *p;
  55.     static int counter;
  56.  
  57.     p = MK_FP(0xb800, 0x10 + n);        /* p points in screen buffer */
  58.     *p = counter;
  59.     *(p + 1) = counter;
  60.     *(p + 2) = counter;
  61.     *(p + 3) = counter;
  62.     ++counter;
  63. }
  64. #endif
  65.  
  66.     void
  67. vim_delay()
  68. {
  69.     delay(500);
  70. }
  71.  
  72. /*
  73.  * this version of remove is not scared by a readonly (backup) file
  74.  */
  75.     int
  76. vim_remove(name)
  77.     char *name;
  78. {
  79.     setperm(name, 0);    /* default permissions */
  80.     return unlink(name);
  81. }
  82.  
  83. /*
  84.  * mch_write(): write the output buffer to the screen
  85.  */
  86.     void
  87. mch_write(s, len)
  88.     char    *s;
  89.     int        len;
  90. {
  91.     char    *p;
  92.     int        row, col;
  93.  
  94.     if (term_console)        /* translate ESC | sequences into bios calls */
  95.         while (len--)
  96.         {
  97.             if (s[0] == '\n')
  98.                 putch('\r');
  99.             else if (s[0] == ESC && len > 1 && s[1] == '|')
  100.             {
  101.                 switch (s[2])
  102.                 {
  103.                 case 'J':    clrscr();
  104.                             goto got3;
  105.  
  106.                 case 'K':    clreol();
  107.                             goto got3;
  108.  
  109.                 case 'L':    insline();
  110.                             goto got3;
  111.  
  112.                 case 'M':    delline();
  113. got3:                        s += 3;
  114.                             len -= 2;
  115.                             continue;
  116.  
  117.                 case '0':
  118.                 case '1':
  119.                 case '2':
  120.                 case '3':
  121.                 case '4':
  122.                 case '5':
  123.                 case '6':
  124.                 case '7':
  125.                 case '8':
  126.                 case '9':    p = s + 2;
  127.                             row = getdigits(&p);        /* no check for length! */
  128.                             if (p > s + len)
  129.                                 break;
  130.                             if (*p == ';')
  131.                             {
  132.                                 ++p;
  133.                                 col = getdigits(&p);    /* no check for length! */
  134.                                 if (p > s + len)
  135.                                     break;
  136.                                 if (*p == 'H')
  137.                                 {
  138.                                     gotoxy(col, row);
  139.                                     len -= p - s;
  140.                                     s = p + 1;
  141.                                     continue;
  142.                                 }
  143.                             }
  144.                             else if (*p == 'm')
  145.                             {
  146.                                 if (row == 0)
  147.                                     normvideo();
  148.                                 else
  149.                                     textattr(row);
  150.                                 len -= p - s;
  151.                                 s = p + 1;
  152.                                 continue;
  153.                             }
  154.                 }
  155.             }
  156.             putch(*s++);
  157.         }
  158.     else
  159.         write(1, s, (unsigned)len);
  160. }
  161.  
  162. #define POLL_SPEED 10    /* milliseconds between polls */
  163.  
  164. /*
  165.  * Simulate WaitForChar() by slowly polling with bioskey(1) or kbhit().
  166.  *
  167.  * If Vim should work over the serial line after a 'ctty com1' we must use
  168.  * kbhit() and getch(). (jw)
  169.  * Usually kbhit() is not used, because then CTRL-C and CTRL-P
  170.  * will be catched by DOS (mool).
  171.  */
  172.  
  173.     static int
  174. WaitForChar(msec)
  175.     int msec;
  176. {
  177.     do
  178.     {
  179.         if ((p_biosk ? bioskey(1) : kbhit()) || cbrk_pressed)
  180.             return 1;
  181.         delay(POLL_SPEED);
  182.         msec -= POLL_SPEED;
  183.     }
  184.     while (msec >= 0);
  185.     return 0;
  186. }
  187.  
  188. /*
  189.  * GetChars(): low level input funcion.
  190.  * Get a characters from the keyboard.
  191.  * If time == 0 do not wait for characters.
  192.  * If time == n wait a short time for characters.
  193.  * If time == -1 wait forever for characters.
  194.  */
  195.     int
  196. GetChars(buf, maxlen, time)
  197.     char        *buf;
  198.     int         maxlen;
  199.     int         time;
  200. {
  201.     int         len = 0;
  202.     int            c;
  203.  
  204. /*
  205.  * if we got a ctrl-C when we were busy, there will be a "^C" somewhere
  206.  * on the sceen, so we need to redisplay it.
  207.  */
  208.     if (delayed_redraw)
  209.     {
  210.         delayed_redraw = FALSE;
  211.         updateScreen(CLEAR);
  212.         setcursor();
  213.         flushbuf();
  214.     }
  215.  
  216.     if (time >= 0)
  217.     {
  218.         if (time == 0)            /* don't know if time == 0 is allowed */
  219.             time = 1;
  220.         if (WaitForChar(time) == 0)     /* no character available */
  221.             return 0;
  222.     }
  223.     else    /* time == -1 */
  224.     {
  225.     /*
  226.      * If there is no character available within 2 seconds (default)
  227.      * write the autoscript file to disk
  228.      */
  229.         if (WaitForChar((int)p_ut) == 0)
  230.             updatescript(0);
  231.     }
  232.  
  233. /*
  234.  * Try to read as many characters as there are.
  235.  * Works for the controlling tty only.
  236.  */
  237.     --maxlen;        /* may get two chars at once */
  238.     /*
  239.      * we will get at least one key. Get more if they are available
  240.      * After a ctrl-break we have to read a 0 (!) from the buffer.
  241.      * bioskey(1) will return 0 if no key is available and when a
  242.      * ctrl-break was typed. When ctrl-break is hit, this does not always
  243.      * implies a key hit.
  244.      */
  245.     cbrk_pressed = FALSE;
  246.     if (p_biosk)
  247.         while ((len == 0 || bioskey(1)) && len < maxlen)
  248.         {
  249.             c = bioskey(0);            /* get the key */
  250.             if (c == 0)                /* ctrl-break */
  251.                 c = 3;                /* return a CTRL-C */
  252.             if ((c & 0xff) == 0)
  253.             {
  254.                 if (c == 0x0300)        /* CTRL-@ is 0x0300, translated into K_ZERO */
  255.                     c = K_ZERO;
  256.                 else        /* extended key code 0xnn00 translated into K_NUL, nn */
  257.                 {
  258.                     c >>= 8;
  259.                     *buf++ = K_NUL;
  260.                     ++len;
  261.                 }
  262.             }
  263.  
  264.             *buf++ = c;
  265.             len++;
  266.         }
  267.     else
  268.         while ((len == 0 || kbhit()) && len < maxlen)
  269.         {
  270.             switch (c = getch())
  271.             {
  272.             case 0:
  273.                     *buf++ = K_NUL;
  274.                     break;
  275.             case 3:
  276.                     cbrk_pressed = TRUE;
  277.                     /*FALLTHROUGH*/
  278.             default:
  279.                     *buf++ = c;
  280.             }
  281.             len++;
  282.         }
  283.     return len;
  284. }
  285.  
  286. /*
  287.  * We have no job control, fake it by starting a new shell.
  288.  */
  289.     void
  290. mch_suspend()
  291. {
  292.     outstr("new shell started\n");
  293.     call_shell(NULL, 0, TRUE);
  294. }
  295.  
  296. extern int _fmode;
  297. /*
  298.  * we do not use windows, there is not much to do here
  299.  */
  300.     void
  301. mch_windinit()
  302. {
  303.     _fmode = O_BINARY;        /* we do our own CR-LF translation */
  304.     flushbuf();
  305.     mch_get_winsize();
  306. }
  307.  
  308.     void
  309. check_win(argc, argv)
  310.     int        argc;
  311.     char    **argv;
  312. {
  313.     if (!isatty(0) || !isatty(1))
  314.     {
  315.         fprintf(stderr, "VIM: no controlling terminal\n");
  316.         exit(2);
  317.     }
  318.     /*
  319.      * In some cases with DOS 6.0 on a NEC notebook there is a 12 seconds
  320.      * delay when starting up that can be avoided by the next two lines.
  321.      * Don't ask me why!
  322.      * This could be fixed by removing setver.sys from config.sys. Forget it.
  323.     gotoxy(1,1);
  324.     cputs(" ");
  325.      */
  326. }
  327.  
  328. /*
  329.  * fname_case(): Set the case of the filename, if it already exists.
  330.  *                 msdos filesystem is far to primitive for that. do nothing.
  331.  */
  332.     void
  333. fname_case(name)
  334.     char *name;
  335. {
  336. }
  337.  
  338. /*
  339.  * settitle(): set titlebar of our window.
  340.  * Dos console has no title.
  341.  */
  342.     void
  343. settitle(str)
  344.     char *str;
  345. {
  346. }
  347.  
  348.     void
  349. resettitle()
  350. {
  351. }
  352.  
  353. /*
  354.  * Get name of current directory into buffer 'buf' of length 'len' bytes.
  355.  * Return non-zero for success.
  356.  */
  357.     int
  358. dirname(buf, len)
  359.     char    *buf;
  360.     int        len;
  361. {
  362.     return (getcwd(buf, len) != NULL);
  363. }
  364.  
  365. /*
  366.  * Change default drive (for Turbo C, Borland C already has it)
  367.  */
  368. #ifndef __BORLANDC__
  369.     int
  370. _chdrive(drive)
  371.     int drive;
  372. {
  373.     unsigned dummy;
  374.     union REGS regs;
  375.  
  376.     regs.h.ah = 0x0e;
  377.     regs.h.dl = drive - 1;
  378.     intdos(®s, ®s);    /* set default drive */
  379.     regs.h.ah = 0x19;
  380.     intdos(®s, ®s);    /* get default drive */
  381.     if (regs.h.al == drive - 1)
  382.         return 0;
  383.     else
  384.         return -1;
  385. }
  386. #endif
  387.  
  388. /*
  389.  * get absolute filename into buffer 'buf' of length 'len' bytes
  390.  */
  391.     int
  392. FullName(fname, buf, len)
  393.     char    *fname, *buf;
  394.     int        len;
  395. {
  396.     if (fname == NULL)    /* always fail */
  397.         return 0;
  398.  
  399. #ifdef __BORLANDC__        /* the old Turbo C does not have this */
  400.     if (_fullpath(buf, fname, len) == NULL)
  401.     {
  402.         strncpy(buf, fname, len);    /* failed, use the relative path name */
  403.         return 0;
  404.     }
  405.     return 1;
  406. #else                    /* almost the same as FullName in unix.c */
  407.     {
  408.         int        l;
  409.         char    olddir[MAXPATHL];
  410.         char    *p, *q;
  411.         int        c;
  412.         int        retval = 1;
  413.  
  414.         *buf = 0;
  415.         /*
  416.          * change to the directory for a moment,
  417.          * and then do the getwd() (and get back to where we were).
  418.          * This will get the correct path name with "../" things.
  419.          */
  420.         p = strrchr(fname, '/');
  421.         q = strrchr(fname, '\\');
  422.         if (q && (p == NULL || q > p))
  423.             p = q;
  424.         q = strrchr(fname, ':');
  425.         if (q && (p == NULL || q > p))
  426.             p = q;
  427.         if (p != NULL)
  428.         {
  429.             if (getcwd(olddir, MAXPATHL) == NULL)
  430.             {
  431.                 p = NULL;        /* can't get current dir: don't chdir */
  432.                 retval = 0;
  433.             }
  434.             else
  435.             {
  436.                 if (*p == ':' || (p > fname && p[-1] == ':'))
  437.                     q = p + 1;
  438.                 else
  439.                     q = p;
  440.                 c = *q;
  441.                 *q = NUL;
  442.                 if (chdir(fname))
  443.                     retval = 0;
  444.                 else
  445.                     fname = p + 1;
  446.                 *q = c;
  447.             }
  448.         }
  449.         if (getcwd(buf, len) == NULL)
  450.         {
  451.             retval = 0;
  452.             *buf = NUL;
  453.         }
  454.         l = strlen(buf);
  455.         if (l && buf[l - 1] != '/' && buf[l - 1] != '\\')
  456.             strcat(buf, "\\");
  457.         if (p)
  458.             chdir(olddir);
  459.         strcat(buf, fname);
  460.         return retval;
  461.     }
  462. #endif
  463. }
  464.  
  465. /*
  466.  * get file permissions for 'name'
  467.  * -1 : error
  468.  * else FA_attributes defined in dos.h
  469.  */
  470.     long
  471. getperm(name)
  472.     char *name;
  473. {
  474.     int r;
  475.  
  476.     r = _chmod(name, 0, 0);         /* get file mode */
  477.     return r;
  478. }
  479.  
  480. /*
  481.  * set file permission for 'name' to 'perm'
  482.  */
  483.     int
  484. setperm(name, perm)
  485.     char    *name;
  486.     long    perm;
  487. {
  488.     perm &= ~FA_ARCH;
  489.     return _chmod(name, 1, (int)perm);
  490. }
  491.  
  492. /*
  493.  * check if "name" is a directory
  494.  */
  495.     int
  496. isdir(name)
  497.     char *name;
  498. {
  499.     int f;
  500.  
  501.     f = _chmod(name, 0, 0);
  502.     if (f == -1)
  503.         return -1;                    /* file does not exist at all */
  504.     if ((f & FA_DIREC) == 0)
  505.         return 0;                    /* not a directory */
  506.     return 1;
  507. }
  508.  
  509. /*
  510.  * Careful: mch_windexit() may be called before mch_windinit()!
  511.  */
  512.     void
  513. mch_windexit(r)
  514.     int r;
  515. {
  516.     settmode(0);
  517.     stoptermcap();
  518.     flushbuf();
  519.     stopscript();                 /* remove autoscript file */
  520.     exit(r);
  521. }
  522.  
  523. /*
  524.  * function for ctrl-break interrupt
  525.  */
  526.     void interrupt
  527. catch_cbrk()
  528. {
  529.     cbrk_pressed = TRUE;
  530.     ctrlc_pressed = TRUE;
  531. }
  532.  
  533. /*
  534.  * ctrl-break handler for DOS. Never called when a ctrl-break is typed, because
  535.  * we catch interrupt 1b. If you type ctrl-C while Vim is waiting for a
  536.  * character this function is not called. When a ctrl-C is typed while Vim is
  537.  * busy this function may be called. By that time a ^C has been displayed on
  538.  * the screen, so we have to redisplay the screen. We can't do that here,
  539.  * because we may be called by DOS. The redraw is in GetChars().
  540.  */
  541.     static int
  542. cbrk_handler()
  543. {
  544.     delayed_redraw = TRUE;
  545.     return 1;                 /* resume operation after ctrl-break */
  546. }
  547.  
  548. /*
  549.  * function for critical error interrupt
  550.  * For DOS 1 and 2 return 0 (Ignore).
  551.  * For DOS 3 and later return 3 (Fail)
  552.  */
  553.     void interrupt
  554. catch_cint(bp, di, si, ds, es, dx, cx, bx, ax)
  555.     unsigned bp, di, si, ds, es, dx, cx, bx, ax;
  556. {
  557.     ax = (ax & 0xff00);        /* set AL to 0 */
  558.     if (_osmajor >= 3)
  559.         ax |= 3;            /* set AL to 3 */
  560. }
  561.  
  562. /*
  563.  * set the tty in (raw) ? "raw" : "cooked" mode
  564.  *
  565.  * Does not change the tty, as bioskey() and kbhit() work raw all the time.
  566.  */
  567.  
  568. extern void interrupt CINT_FUNC();
  569.  
  570.     void
  571. mch_settmode(raw)
  572.     int  raw;
  573. {
  574.     static int saved_cbrk;
  575.     static void interrupt (*old_cint)();
  576.     static void interrupt (*old_cbrk)();
  577.  
  578.     if (raw)
  579.     {
  580.         saved_cbrk = getcbrk();            /* save old ctrl-break setting */
  581.         setcbrk(0);                        /* do not check for ctrl-break */
  582.         old_cint = getvect(0x24);         /* save old critical error interrupt */
  583.         setvect(0x24, catch_cint);        /* install our critical error interrupt */
  584.         old_cbrk = getvect(0x1B);         /* save old ctrl-break interrupt */
  585.         setvect(0x1B, catch_cbrk);        /* install our ctrl-break interrupt */
  586.         ctrlbrk(cbrk_handler);            /* vim's ctrl-break handler */
  587.         if (term_console)
  588.             outstr(T_TP);                /* set colors */
  589.     }
  590.     else
  591.     {
  592.         setcbrk(saved_cbrk);            /* restore ctrl-break setting */
  593.         setvect(0x24, old_cint);        /* restore critical error interrupt */
  594.         setvect(0x1B, old_cbrk);        /* restore ctrl-break interrupt */
  595.         /* restore ctrl-break handler, how ??? */
  596.         if (term_console)
  597.             normvideo();                /* restore screen colors */
  598.     }
  599. }
  600.  
  601. /*
  602.  * Structure used by Turbo-C/Borland-C to store video parameters.
  603.  */
  604. extern struct text_info _video;
  605.  
  606.     int
  607. mch_get_winsize()
  608. {
  609.     int i;
  610.     struct text_info ti;
  611. /*
  612.  * The screenwidth is returned by the BIOS OK.
  613.  * The screenheight is in a location in the bios RAM, if the display is EGA or VGA.
  614.  */
  615.     if (!term_console)
  616.         return 1;
  617.     gettextinfo(&ti);
  618.     Columns = ti.screenwidth;
  619.     Rows = ti.screenheight;
  620.     if (ti.currmode > 10)
  621.         Rows = *(char far *)MK_FP(0x40, 0x84) + 1;
  622.     set_window();
  623.  
  624.     if (Columns < 5 || Columns > MAX_COLUMNS ||
  625.                     Rows < 2 || Rows > MAX_COLUMNS)
  626.     {
  627.         /* these values are overwritten by termcap size or default */
  628.         Columns = 80;
  629.         Rows = 25;
  630.         return 1;
  631.     }
  632.     Rows_max = Rows;                /* remember physical max height */
  633.  
  634.     check_winsize();
  635.     script_winsize();
  636.  
  637.     return 0;
  638. }
  639.  
  640. /*
  641.  * Set the active window for delline/insline.
  642.  */
  643.     void
  644. set_window()
  645. {
  646.     _video.screenheight = Rows;
  647.     window(1, 1, Columns, Rows);
  648. }
  649.  
  650.     void
  651. mch_set_winsize()
  652. {
  653.     /* should try to set the window size to Rows and Columns */
  654.     /* may involve switching display mode.... */
  655. }
  656.  
  657.     int
  658. call_shell(cmd, filter, cooked)
  659.     char    *cmd;
  660.     int     filter;         /* if != 0: called by dofilter() */
  661.     int        cooked;
  662. {
  663.     int        x;
  664.     char    newcmd[200];
  665.  
  666.     flushbuf();
  667.  
  668.     if (cooked)
  669.         settmode(0);        /* set to cooked mode */
  670.  
  671.     if (cmd == NULL)
  672.         x = system(p_sh);
  673.     else
  674.     {                     /* we use "command" to start the shell, slow but easy */
  675.         sprintf(newcmd, "%s /c %s", p_sh, cmd);
  676.         x = system(newcmd);
  677.     }
  678.     outchar('\n');
  679.     if (cooked)
  680.         settmode(1);        /* set to raw mode */
  681.  
  682.     if (x)
  683.     {
  684.         smsg("%d returned", x);
  685.         outchar('\n');
  686.     }
  687.  
  688.     resettitle();
  689.     return x;
  690. }
  691.  
  692. /*
  693.  * check for an "interrupt signal": CTRL-break or CTRL-C
  694.  */
  695.     void
  696. breakcheck()
  697. {
  698.     if (ctrlc_pressed)
  699.     {
  700.         ctrlc_pressed = FALSE;
  701.         got_int = TRUE;
  702.     }
  703. }
  704.  
  705. #define FL_CHUNK 32
  706.  
  707.     static void
  708. addfile(fl, f, isdir)
  709.     FileList    *fl;
  710.     char        *f;
  711.     int            isdir;
  712. {
  713.     char        *p;
  714.  
  715.     if (!fl->file)
  716.     {
  717.         fl->file = (char **)alloc(sizeof(char *) * FL_CHUNK);
  718.         if (!fl->file)
  719.             return;
  720.         fl->nfiles = 0;
  721.         fl->maxfiles = FL_CHUNK;
  722.     }
  723.     if (fl->nfiles >= fl->maxfiles)
  724.     {
  725.         char    **t;
  726.         int        i;
  727.  
  728.         t = (char **)lalloc(sizeof(char *) * (fl->maxfiles + FL_CHUNK), TRUE);
  729.         if (!t)
  730.             return;
  731.         for (i = fl->nfiles - 1; i >= 0; i--)
  732.             t[i] = fl->file[i];
  733.         free(fl->file);
  734.         fl->file = t;
  735.         fl->maxfiles += FL_CHUNK;
  736.     }
  737.     p = alloc((unsigned)(strlen(f) + 1 + isdir));
  738.     if (p)
  739.     {
  740.         strcpy(p, f);
  741.         if (isdir)
  742.             strcat(p, "\\");
  743.     }
  744.     fl->file[fl->nfiles++] = p;
  745. }
  746.  
  747.     static int
  748. pstrcmp(a, b)
  749.     char **a, **b;
  750. {
  751.     return (strcmp(*a, *b));
  752. }
  753.  
  754.     int
  755. has_wildcard(s)
  756.     char *s;
  757. {
  758.     if (s)
  759.         for ( ; *s; ++s)
  760.             if (*s == '?' || *s == '*')
  761.                 return 1;
  762.     return 0;
  763. }
  764.  
  765.     static void
  766. strlowcpy(d, s)
  767.     char *d, *s;
  768. {
  769.     while (*s)
  770.         *d++ = tolower(*s++);
  771.     *d = '\0';
  772. }
  773.  
  774.     static int
  775. expandpath(fl, path, fonly, donly, notf)
  776.     FileList    *fl;
  777.     char        *path;
  778.     int            fonly, donly, notf;
  779. {
  780.     char    buf[MAXPATH];
  781.     char    *p, *s, *e;
  782.     int        lastn, c, r;
  783.     struct    ffblk fb;
  784.  
  785.     lastn = fl->nfiles;
  786.  
  787. /*
  788.  * Find the first part in the path name that contains a wildcard.
  789.  * Copy it into buf, including the preceding characters.
  790.  */
  791.     p = buf;
  792.     s = NULL;
  793.     e = NULL;
  794.     while (*path)
  795.     {
  796.         if (*path == '\\' || *path == ':' || *path == '/')
  797.         {
  798.             if (e)
  799.                 break;
  800.             else
  801.                 s = p;
  802.         }
  803.         if (*path == '*' || *path == '?')
  804.             e = p;
  805.         *p++ = *path++;
  806.     }
  807.     e = p;
  808.     if (s)
  809.         s++;
  810.     else
  811.         s = buf;
  812.  
  813.     /* now we have one wildcard component between s and e */
  814.     *e = '\0';
  815.     r = 0;
  816.     /* If we are expanding wildcards we try both files and directories */
  817.     if ((c = findfirst(buf, &fb, (*path || !notf) ? FA_DIREC : 0)) != 0)
  818.     {
  819.         /* not found */
  820.         strcpy(e, path);
  821.         if (notf)
  822.             addfile(fl, buf, FALSE);
  823.         return 1; /* unexpanded or empty */
  824.     }
  825.     while (!c)
  826.     {
  827.         strlowcpy(s, fb.ff_name);
  828.         if (*s != '.' || (s[1] != '\0' && (s[1] != '.' || s[2] != '\0')))
  829.         {
  830.             strcat(buf, path);
  831.             if (!has_wildcard(path))
  832.                 addfile(fl, buf, (isdir(buf) > 0));
  833.             else
  834.                 r |= expandpath(fl, buf, fonly, donly, notf);
  835.         }
  836.         c = findnext(&fb);
  837.     }
  838.     qsort(fl->file + lastn, fl->nfiles - lastn, sizeof(char *), pstrcmp);
  839.     return r;
  840. }
  841.  
  842. /*
  843.  * MSDOS rebuilt of Scott Ballantynes ExpandWildCard for amiga/arp.
  844.  * jw
  845.  */
  846.  
  847.     int
  848. ExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
  849.     int     num_pat;
  850.     char    **pat;
  851.     int     *num_file;
  852.     char    ***file;
  853.     int     files_only, list_notfound;
  854. {
  855.     int            i, r = 0;
  856.     FileList    f;
  857.  
  858.     f.file = NULL;
  859.     f.nfiles = 0;
  860.     for (i = 0; i < num_pat; i++)
  861.     {
  862.         if (!has_wildcard(pat[i]))
  863.             addfile(&f, pat[i], files_only ? FALSE : (isdir(pat[i]) > 0));
  864.         else
  865.             r |= expandpath(&f, pat[i], files_only, 0, list_notfound);
  866.     }
  867.     if (r == 0)
  868.     {
  869.         *num_file = f.nfiles;
  870.         *file = f.file;
  871.     }
  872.     else
  873.     {
  874.         *num_file = 0;
  875.         *file = NULL;
  876.     }
  877.     return r;
  878. }
  879.  
  880.     void
  881. FreeWild(num, file)
  882.     int        num;
  883.     char    **file;
  884. {
  885.     if (file == NULL || num <= 0)
  886.         return;
  887.     while (num--)
  888.         free(file[num]);
  889.     free(file);
  890. }
  891.  
  892. /*
  893.  * The normal chdir() does not change the default drive.
  894.  * This one does.
  895.  */
  896. #undef chdir
  897.     int
  898. vim_chdir(path)
  899.     char *path;
  900. {
  901.     if (path[0] == NUL)                /* just checking... */
  902.         return 0;
  903.     if (path[1] == ':')                /* has a drive name */
  904.     {
  905.         if (_chdrive(toupper(path[0]) - 'A' + 1))
  906.             return -1;                /* invalid drive name */
  907.         path += 2;
  908.     }
  909.     if (*path == NUL)                /* drive name only */
  910.         return 0;
  911.     return chdir(path);                /* let the normal chdir() do the rest */
  912. }
  913.