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

  1. /* vi:ts=4:sw=4
  2.  *
  3.  *
  4.  * VIM - Vi IMproved
  5.  *
  6.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  7.  *                            Tim Thompson            twitch!tjt
  8.  *                            Tony Andrews            onecom!wldrdg!tony 
  9.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  10.  */
  11. /*
  12.  * unix.c -- BSD and SYSV code
  13.  *
  14.  * A lot of this file was written by Juergen Weigert.
  15.  */
  16.  
  17. #include "vim.h"
  18. #include "globals.h"
  19. #include "param.h"
  20. #include "proto.h"
  21.  
  22. #include <fcntl.h>
  23. #if !defined(pyr) && !defined(NOT_BOTH_TIME)
  24. # include <time.h>            /* on some systems time.h should not be
  25.                                included together with sys/time.h */
  26. #endif
  27. #include <sys/ioctl.h>
  28. #ifndef M_XENIX
  29. # include <sys/types.h>
  30. #endif
  31. #include <signal.h>
  32.  
  33. #ifndef USE_SYSTEM        /* use fork/exec to start the shell */
  34. # include <sys/wait.h>
  35. # if !defined(SCO) && !defined(SOLARIS)            /* SCO returns pid_t */
  36. extern int fork();
  37. # endif
  38. # if !defined(linux) && !defined(SOLARIS) && !defined(USL)
  39. extern int execvp __ARGS((const char *, const char **));
  40. # endif
  41. #endif
  42.  
  43. #ifdef SYSV_UNIX
  44. # if defined(__sgi) || defined(UTS2) || defined(UTS4)
  45. #  include <sys/time.h>
  46. # endif
  47. # if defined(M_XENIX) || defined(SCO) || defined(UNICOS)
  48. #  ifndef UNICOS
  49. #   include <stropts.h>
  50. #  endif
  51. #  include <sys/select.h>
  52. #  define bzero(a, b)    memset((a), 0, (b))
  53. # else
  54. #  include <poll.h>
  55. # endif
  56. # if defined(SCO) || defined(ISC)
  57. #  include <sys/stream.h>
  58. #  include <sys/ptem.h>
  59. # endif
  60. # if defined(M_UNIX) && !defined(SCO)
  61. #  include <sys/time.h>
  62. # endif       /* M_UNIX */
  63. # ifdef ISC
  64. #  include <termios.h>
  65. # endif
  66. # include <termio.h>
  67. #else    /* SYSV_UNIX */
  68. # include <sys/time.h>
  69. # if defined(hpux) || defined(linux)
  70. #  include <termio.h>
  71. #  if defined(hpux) && !defined(SIGWINCH)    /* hpux 9.01 has it */
  72. #   define SIGWINCH SIGWINDOW
  73. #  endif
  74. # else
  75. #  include <sgtty.h>
  76. # endif    /* hpux */
  77. #endif    /* !SYSV_UNIX */
  78.  
  79. #if (defined(pyr) || defined(NO_FD_ZERO)) && defined(SYSV_UNIX) && defined(FD_ZERO)
  80. # undef FD_ZERO
  81. #endif
  82.  
  83. #if defined(ESIX) || defined(M_UNIX)
  84. # ifdef SIGWINCH
  85. #  undef SIGWINCH
  86. # endif
  87. # ifdef TIOCGWINSZ
  88. #  undef TIOCGWINSZ
  89. # endif
  90. #endif
  91.  
  92. static int    Read __ARGS((char *, long));
  93. static int    WaitForChar __ARGS((int));
  94. static int    RealWaitForChar __ARGS((int));
  95. static void fill_inbuf __ARGS((void));
  96. #ifdef USL
  97. static void sig_winch __ARGS((int));
  98. #else
  99. # if defined(SIGWINCH) && !defined(linux) && !defined(__alpha) && !defined(mips) && !defined(_SEQUENT_) && !defined(SCO) && !defined(SOLARIS) && !defined(ISC)
  100. static void sig_winch __ARGS((int, int, struct sigcontext *));
  101. # endif
  102. #endif
  103.  
  104. static int do_resize = FALSE;
  105.  
  106. /*
  107.  * At this point TRUE and FALSE are defined as 1L and 0L, but we want 1 and 0.
  108.  */
  109. #undef TRUE
  110. #define TRUE 1
  111. #undef FALSE
  112. #define FALSE 0
  113.  
  114.     void
  115. mch_write(s, len)
  116.     char    *s;
  117.     int        len;
  118. {
  119.     write(1, s, len);
  120. }
  121.  
  122. /*
  123.  * GetChars(): low level input funcion.
  124.  * Get a characters from the keyboard.
  125.  * If time == 0 do not wait for characters.
  126.  * If time == n wait a short time for characters.
  127.  * If time == -1 wait forever for characters.
  128.  */
  129.     int
  130. GetChars(buf, maxlen, time)
  131.     char    *buf;
  132.     int        maxlen;
  133.     int        time;
  134. {
  135.     int        len;
  136.  
  137.     if (time >= 0)
  138.     {
  139.         if (time < 20)        /* don't know if this is necessary */
  140.             time = 20;
  141.         if (WaitForChar(time) == 0)        /* no character available */
  142.             return 0;
  143.     }
  144.     else        /* time == -1 */
  145.     {
  146.     /*
  147.      * If there is no character available within 2 seconds (default)
  148.      * write the autoscript file to disk
  149.      */
  150.         if (WaitForChar((int)p_ut) == 0)
  151.             updatescript(0);
  152.     }
  153.  
  154.     for (;;)    /* repeat until we got a character */
  155.     {
  156.         /* 
  157.          * we want to be interrupted by the winch signal
  158.          */
  159.         WaitForChar(-1);
  160.         if (do_resize)
  161.         {
  162.             debug("do_resize!\n");
  163.             set_winsize(0, 0, FALSE);
  164.             do_resize = FALSE;
  165.             continue;
  166.         }
  167.         len = Read(buf, (long)maxlen);
  168.         if (len > 0)
  169.             return len;
  170.     }
  171. }
  172.  
  173. #if defined(SYSV_UNIX) && !defined(M_XENIX) && !defined(UNICOS)
  174.     void
  175. vim_delay()
  176. {
  177.     poll(0, 0, 500);
  178. }
  179. #else
  180. extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
  181.  
  182.     void
  183. vim_delay()
  184. {
  185.     struct timeval tv;
  186.  
  187.     tv.tv_sec = 25 / 50;
  188.     tv.tv_usec = (25 % 50) * (1000000/50);
  189.     select(0, 0, 0, 0, &tv);
  190. }
  191. #endif
  192.  
  193.     static void
  194. #if defined(__alpha) || defined(mips)
  195. sig_winch()
  196. #else
  197. # if defined(_SEQUENT_) || defined(SCO) || defined(ISC)
  198. sig_winch(sig, code)
  199.     int        sig;
  200.     int        code;
  201. # else
  202. #  if defined(USL)
  203. sig_winch(sig)
  204.     int        sig;
  205. #  else
  206. sig_winch(sig, code, scp)
  207.     int        sig;
  208.     int        code;
  209.     struct sigcontext *scp;
  210. #  endif
  211. # endif
  212. #endif
  213. {
  214. #if defined(SIGWINCH) && (defined(SYSV_UNIX) || defined(linux) || defined(hpux) || defined(USL))
  215.     signal(SIGWINCH, (void (*)())sig_winch);
  216. #endif
  217.     do_resize = TRUE;
  218. }
  219.  
  220. /*
  221.  * If the machine has job control, use it to suspend the program,
  222.  * otherwise fake it by starting a new shell.
  223.  */
  224.     void
  225. mch_suspend()
  226. {
  227. #ifdef SIGTSTP
  228.     settmode(0);
  229.     kill(0, SIGTSTP);        /* send ourselves a STOP signal */
  230.     settmode(1);
  231. #else
  232.     outstr("new shell started\n");
  233.     call_shell(NULL, 0, TRUE);
  234. #endif
  235. }
  236.  
  237.     void
  238. mch_windinit()
  239. {
  240.     Columns = 80;
  241.     Rows = 24;
  242.  
  243.     flushbuf();
  244.  
  245.     mch_get_winsize();
  246. #if defined(SIGWINCH)
  247.     signal(SIGWINCH, (void (*)())sig_winch);
  248. #endif
  249. }
  250.  
  251. /*
  252.  * Check_win checks whether we have an interactive window.
  253.  * If not, a new window is opened with the newcli command.
  254.  * If we would open a window ourselves, the :sh and :! commands would not
  255.  * work properly (Why? probably because we are then running in a background CLI).
  256.  * This also is the best way to assure proper working in a next Workbench release.
  257.  *
  258.  * For the -e option (quickfix mode) we open our own window and disable :sh.
  259.  * Otherwise we would never know when editing is finished.
  260.  */
  261. #define BUF2SIZE 320        /* lenght of buffer for argument with complete path */
  262.  
  263.     void
  264. check_win(argc, argv)
  265.     int argc;
  266.     char **argv;
  267. {
  268.     if (!isatty(0) || !isatty(1))
  269.     {
  270.         fprintf(stderr, "VIM: no controlling terminal\n");
  271.         exit(2);
  272.     }
  273. }
  274.  
  275. /*
  276.  * fname_case(): Set the case of the filename, if it already exists.
  277.  *                 This will cause the filename to remain exactly the same.
  278.  */
  279.     void
  280. fname_case(name)
  281.     char *name;
  282. {
  283. }
  284.  
  285.     void
  286. settitle(str)
  287.     char *str;
  288. {
  289. }
  290.  
  291.     void
  292. resettitle()
  293. {
  294. }
  295.  
  296. /*
  297.  * Get name of current directory into buffer 'buf' of length 'len' bytes.
  298.  * Return non-zero for success.
  299.  */
  300.     int 
  301. dirname(buf, len)
  302.     char *buf;
  303.     int len;
  304. {
  305. #if defined(SYSV_UNIX) || defined(hpux) || defined(linux)
  306.     extern int        errno;
  307.     extern char        *sys_errlist[];
  308.  
  309.     if (getcwd(buf,len) == NULL)
  310.     {
  311.         strcpy(buf, sys_errlist[errno]);
  312.         return 0;
  313.     }
  314.     return 1;
  315. #else
  316.     return (getwd(buf) != NULL);
  317. #endif
  318. }
  319.  
  320. /*
  321.  * get absolute filename into buffer 'buf' of length 'len' bytes
  322.  */
  323.     int 
  324. FullName(fname, buf, len)
  325.     char *fname, *buf;
  326.     int len;
  327. {
  328.     int        l;
  329.     char    olddir[MAXPATHL];
  330.     char    *p;
  331.     int        c;
  332.     int        retval = 1;
  333.  
  334.     if (fname == NULL)    /* always fail */
  335.         return 0;
  336.  
  337.     *buf = 0;
  338.     if (*fname != '/')
  339.     {
  340.         /*
  341.          * If the file name has a path, change to that directory for a moment,
  342.          * and then do the getwd() (and get back to where we were).
  343.          * This will get the correct path name with "../" things.
  344.          */
  345.         if ((p = strrchr(fname, '/')) != NULL)
  346.         {
  347. #if defined(SYSV_UNIX) || defined(hpux) || defined(linux)
  348.             if (getcwd(olddir, MAXPATHL) == NULL)
  349. #else
  350.             if (getwd(olddir) == NULL)
  351. #endif
  352.             {
  353.                 p = NULL;        /* can't get current dir: don't chdir */
  354.                 retval = 0;
  355.             }
  356.             else
  357.             {
  358.                 c = *p;
  359.                 *p = NUL;
  360.                 if (chdir(fname))
  361.                     retval = 0;
  362.                 else
  363.                     fname = p + 1;
  364.                 *p = c;
  365.             }
  366.         }
  367. #if defined(SYSV_UNIX) || defined(hpux) || defined(linux)
  368.         if (getcwd(buf, len) == NULL)
  369. #else
  370.         if (getwd(buf) == NULL)
  371. #endif
  372.         {
  373.             retval = 0;
  374.             *buf = NUL;
  375.         }
  376.         l = strlen(buf);
  377.         if (l && buf[l - 1] != '/')
  378.             strcat(buf, "/");
  379.         if (p)
  380.             chdir(olddir);
  381.     }
  382.     strcat(buf, fname);
  383.     return retval;
  384. }
  385.  
  386. /*
  387.  * get file permissions for 'name'
  388.  */
  389.     long 
  390. getperm(name)
  391.     char *name;
  392. {
  393.     struct stat statb;
  394.  
  395.     if (stat(name, &statb))
  396.         return -1;
  397.     return statb.st_mode;
  398. }
  399.  
  400. /*
  401.  * set file permission for 'name' to 'perm'
  402.  */
  403.     int
  404. setperm(name, perm)
  405.     char *name;
  406.     int perm;
  407. {
  408. #ifdef SCO
  409.     return chmod(name, (mode_t)perm);
  410. #else
  411.     return chmod(name, perm);
  412. #endif
  413. }
  414.  
  415. /*
  416.  * check if "name" is a directory
  417.  */
  418.     int 
  419. isdir(name)
  420.     char *name;
  421. {
  422.     struct stat statb;
  423.  
  424.     if (stat(name, &statb))
  425.         return -1;
  426. #ifdef _POSIX_SOURCE
  427.     return S_ISDIR(statb.st_mode);
  428. #else
  429.     return (statb.st_mode & S_IFMT) == S_IFDIR;
  430. #endif
  431. }
  432.  
  433.     void
  434. mch_windexit(r)
  435.     int r;
  436. {
  437.     settmode(0);
  438.     stoptermcap();
  439.     flushbuf();
  440.     stopscript();                    /* remove autoscript file */
  441.     exit(r);
  442. }
  443.  
  444.     void
  445. mch_settmode(raw)
  446.     int                raw;
  447. {
  448. #if defined(ECHOE) && defined(ICANON) && !defined(__NeXT__)
  449.     /* for "new" tty systems */
  450. # ifdef CONVEX
  451.     static struct termios told;
  452.            struct termios tnew;
  453. # else
  454.     static struct termio told;
  455.            struct termio tnew;
  456. # endif
  457. #ifdef TIOCLGET
  458.     static unsigned long tty_local;
  459. #endif
  460.  
  461.     if (raw)
  462.     {
  463. #ifdef TIOCLGET
  464.         ioctl(0, TIOCLGET, &tty_local);
  465. #endif
  466.         ioctl(0, TCGETA, &told);
  467.         tnew = told;
  468.         tnew.c_iflag &= ~(ICRNL | IXON);        /* ICRNL enables typing ^V^M */
  469.                                                 /* IXON enables typing ^S/^Q */
  470.         tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
  471. #ifdef IEXTEN
  472.                     | IEXTEN        /* IEXTEN enables typing ^V on SOLARIS */
  473. #endif
  474.                         );
  475.         tnew.c_cc[VMIN] = 1;            /* return after 1 char */
  476.         tnew.c_cc[VTIME] = 0;            /* don't wait */
  477.         ioctl(0, TCSETA, &tnew);
  478.     }
  479.     else
  480.     {
  481.         ioctl(0, TCSETA, &told);
  482. #ifdef TIOCLGET
  483.         ioctl(0, TIOCLSET, &tty_local);
  484. #endif
  485.     }
  486. #else
  487. # ifndef TIOCSETN
  488. #  define TIOCSETN TIOCSETP        /* for hpux 9.0 */
  489. # endif
  490.     /* for "old" tty systems */
  491.     static struct sgttyb ttybold;
  492.            struct sgttyb ttybnew;
  493.  
  494.     if (raw)
  495.     {
  496.         ioctl(0, TIOCGETP, &ttybold);
  497.         ttybnew = ttybold;
  498.         ttybnew.sg_flags &= ~(CRMOD | ECHO);
  499.         ttybnew.sg_flags |= RAW;
  500.         ioctl(0, TIOCSETN, &ttybnew);
  501.     }
  502.     else
  503.         ioctl(0, TIOCSETN, &ttybold);
  504. #endif
  505. }
  506.  
  507. /*
  508.  * Try to get the current window size:
  509.  * 1. with an ioctl(), most accurate method
  510.  * 2. from the environment variables LINES and COLUMNS
  511.  * 3. from the termcap
  512.  * 4. keep using the old values
  513.  */
  514.     int
  515. mch_get_winsize()
  516. {
  517.     int            old_Rows = Rows;
  518.     int            old_Columns = Columns;
  519.     char        *p;
  520.  
  521.     Columns = 0;
  522.     Rows = 0;
  523.  
  524. /*
  525.  * 1. try using an ioctl. It is the most accurate method.
  526.  */
  527. # ifdef TIOCGSIZE
  528.     {
  529.         struct ttysize    ts;
  530.  
  531.         if (ioctl(0, TIOCGSIZE, &ts) == 0)
  532.         {
  533.             Columns = ts.ts_cols;
  534.             Rows = ts.ts_lines;
  535.         }
  536.     }
  537. # else /* TIOCGSIZE */
  538. #  ifdef TIOCGWINSZ
  539.     {
  540.         struct winsize    ws;
  541.  
  542.         if (ioctl(0, TIOCGWINSZ, &ws) == 0)
  543.         {
  544.             Columns = ws.ws_col;
  545.             Rows = ws.ws_row;
  546.         }
  547.     }
  548. #  endif /* TIOCGWINSZ */
  549. # endif /* TIOCGSIZE */
  550.  
  551. /*
  552.  * 2. get size from environment
  553.  */
  554.     if (Columns == 0 || Rows == 0)
  555.     {
  556.         if ((p = (char *)getenv("LINES")))
  557.             Rows = atoi(p);
  558.         if ((p = (char *)getenv("COLUMNS")))
  559.             Columns = atoi(p);
  560.     }
  561.  
  562. #ifdef TERMCAP
  563. /*
  564.  * 3. try reading the termcap
  565.  */
  566.     if (Columns == 0 || Rows == 0)
  567.     {
  568.         extern void getlinecol();
  569.  
  570.         getlinecol();    /* get "co" and "li" entries from termcap */
  571.     }
  572. #endif
  573.  
  574. /*
  575.  * 4. If everything fails, use the old values
  576.  */
  577.     if (Columns <= 0 || Rows <= 0)
  578.     {
  579.         Columns = old_Columns;
  580.         Rows = old_Rows;
  581.         return 1;
  582.     }
  583.     debug2("mch_get_winsize: %dx%d\n", (int)Columns, (int)Rows);
  584.  
  585.     Rows_max = Rows;                /* remember physical max height */
  586.  
  587.     check_winsize();
  588.     script_winsize();
  589.  
  590. /* if size changed: screenalloc will allocate new screen buffers */
  591.     return (0);
  592. }
  593.  
  594.     void
  595. mch_set_winsize()
  596. {
  597.     /* should try to set the window size to Rows and Columns */
  598. }
  599.  
  600.     int 
  601. call_shell(cmd, dummy, cooked)
  602.     char    *cmd;
  603.     int        dummy;
  604.     int        cooked;
  605. {
  606. #ifdef USE_SYSTEM        /* use system() to start the shell: simple but slow */
  607.  
  608.     int        x;
  609.     char    newcmd[1024];
  610.  
  611.     flushbuf();
  612.  
  613.     if (cooked)
  614.         settmode(0);                 /* set to cooked mode */
  615.  
  616.     if (cmd == NULL)
  617.         x = system(p_sh);
  618.     else
  619.     {
  620.         sprintf(newcmd, "%s -c \"%s\"", p_sh, cmd);
  621.         x = system(newcmd);
  622.     }
  623.     if (x == 127)
  624.     {
  625.         emsg("Cannot execute shell sh");
  626.         outchar('\n');
  627.     }
  628.     else if (x)
  629.     {
  630.         smsg("%d returned", x);
  631.         outchar('\n');
  632.     }
  633.  
  634.     if (cooked)
  635.         settmode(1);                         /* set to raw mode */
  636.     return x;
  637.  
  638. #else /* USE_SYSTEM */        /* first attempt at not using system() */
  639.  
  640.     char    newcmd[1024];
  641.     int        pid;
  642.     int        status = -1;
  643.     char    **argv = NULL;
  644.     int        argc;
  645.     int        i;
  646.     char    *p;
  647.     int        inquote;
  648.  
  649.     flushbuf();
  650.     signal(SIGINT, SIG_IGN);    /* we don't want to be killed here */
  651.     if (cooked)
  652.         settmode(0);            /* set to cooked mode */
  653.  
  654.     /*
  655.      * 1: find number of arguments
  656.      * 2: separate them and built argv[]
  657.      */
  658.     strcpy(newcmd, p_sh);
  659.     for (i = 0; i < 2; ++i)    
  660.     {
  661.         p = newcmd;
  662.         inquote = FALSE;
  663.         argc = 0;
  664.         for (;;)
  665.         {
  666.             if (i == 1)
  667.                 argv[argc] = p;
  668.             ++argc;
  669.             while (*p && (inquote || (*p != ' ' && *p != TAB)))
  670.             {
  671.                 if (*p == '"')
  672.                     inquote = !inquote;
  673.                 ++p;
  674.             }
  675.             if (*p == NUL)
  676.                 break;
  677.             if (i == 1)
  678.                 *p++ = NUL;
  679.             skipspace(&p);
  680.         }
  681.         if (i == 0)
  682.         {
  683.             argv = (char **)alloc((unsigned)((argc + 3) * sizeof(char *)));
  684.             if (argv == NULL)        /* out of memory */
  685.                 goto error;
  686.         }
  687.     }
  688.     if (cmd != NULL)
  689.     {
  690.         argv[argc++] = "-c";
  691.         argv[argc++] = cmd;
  692.     }
  693.     argv[argc] = NULL;
  694.  
  695.     if ((pid = fork()) == -1)        /* maybe we should use vfork() */
  696.         emsg("Cannot fork");
  697.     else if (pid == 0)        /* child */
  698.     {
  699.         signal(SIGINT, SIG_DFL);
  700.         execvp(argv[0], argv);
  701.         exit(127);            /* exec failed, return failure code */
  702.     }
  703.     else                    /* parent */
  704.     {
  705.         wait(&status);
  706.         status = (status >> 8) & 255;
  707.         if (status)
  708.         {
  709.             if (status == 127)
  710.                 emsg2("Cannot execute shell %s", p_sh);
  711.             else
  712.                 smsg("%d returned", status);
  713.             outchar('\n');
  714.         }
  715.     }
  716.     free(argv);
  717.  
  718. error:
  719.     if (cooked)
  720.         settmode(1);                         /* set to raw mode */
  721.     signal(SIGINT, SIG_DFL);
  722.     return status;
  723.  
  724. #endif /* USE_SYSTEM */
  725. }
  726.  
  727. /*
  728.  * The input characters are buffered to be able to check for a CTRL-C.
  729.  * This should be done with signals, but I don't know how to do that in
  730.  * a portable way for a tty in RAW mode.
  731.  */
  732.  
  733. #define INBUFLEN 50
  734. static char        inbuf[INBUFLEN];    /* internal typeahead buffer */
  735. static int        inbufcount = 0;        /* number of chars in inbuf[] */
  736.  
  737.     static int
  738. Read(buf, maxlen)
  739.     char    *buf;
  740.     long    maxlen;
  741. {
  742.     if (inbufcount == 0)        /* if the buffer is empty, fill it */
  743.         fill_inbuf();
  744.     if (maxlen > inbufcount)
  745.         maxlen = inbufcount;
  746.     memmove(buf, inbuf, maxlen);
  747.     inbufcount -= maxlen;
  748.     if (inbufcount)
  749.         memmove(inbuf, inbuf + maxlen, inbufcount);
  750.     return (int)maxlen;
  751. }
  752.  
  753.     void
  754. breakcheck()
  755. {
  756. /*
  757.  * check for CTRL-C typed by reading all available characters
  758.  */
  759.     if (RealWaitForChar(0))        /* if characters available */
  760.         fill_inbuf();
  761. }
  762.  
  763.     static void
  764. fill_inbuf()
  765. {
  766.     int        len;
  767.  
  768.     if (inbufcount >= INBUFLEN)        /* buffer full */
  769.         return;
  770.     len = read(0, inbuf + inbufcount, (long)(INBUFLEN - inbufcount));
  771.     if (len <= 0)    /* cannot read input??? */
  772.     {
  773.         fprintf(stderr, "Vim: Error reading input, exiting...\n");
  774.         exit(1);
  775.     }
  776.     while (len-- > 0)
  777.     {
  778.         /*
  779.          * if a CTRL-C was typed, remove it from the buffer and set got_int
  780.          */
  781.         if (inbuf[inbufcount] == 3)
  782.         {
  783.             /* remove everything typed before the CTRL-C */
  784.             memmove(inbuf, inbuf + inbufcount, len + 1);
  785.             inbufcount = 0;
  786.             got_int = TRUE;
  787.         }
  788.         ++inbufcount;
  789.     }
  790. }
  791.  
  792. /* 
  793.  * Wait "ticks" until a character is available from the keyboard or from inbuf[]
  794.  * ticks = -1 will block forever
  795.  */
  796.  
  797.     static int
  798. WaitForChar(ticks)
  799.     int ticks;
  800. {
  801.     if (inbufcount)        /* something in inbuf[] */
  802.         return 1;
  803.     return RealWaitForChar(ticks);
  804. }
  805.  
  806. /* 
  807.  * Wait "ticks" until a character is available from the keyboard
  808.  * ticks = -1 will block forever
  809.  */
  810.     static int
  811. RealWaitForChar(ticks)
  812.     int ticks;
  813. {
  814. #ifndef FD_ZERO
  815.     struct pollfd fds;
  816.  
  817.     fds.fd = 0;
  818.     fds.events = POLLIN;
  819.     return (poll(&fds, 1, ticks));
  820. #else
  821.     struct timeval tv;
  822.     fd_set fdset;
  823.  
  824.     if (ticks >= 0)
  825.     {
  826.            tv.tv_sec = ticks / 1000;
  827.         tv.tv_usec = (ticks % 1000) * (1000000/1000);
  828.     }
  829.  
  830.     FD_ZERO(&fdset);
  831.     FD_SET(0, &fdset);
  832.     return (select(1, &fdset, NULL, NULL, (ticks >= 0) ? &tv : NULL));
  833. #endif
  834. }
  835.  
  836. #if !defined(__alpha) && !defined(mips) && !defined(SCO) && !defined(remove) && !defined(CONVEX)
  837.     int 
  838. remove(buf)
  839. # if defined(linux) || defined(__STDC__) || defined(__NeXT__) || defined(M_UNIX)
  840.     const
  841. # endif
  842.             char *buf;
  843. {
  844.     return unlink(buf);
  845. }
  846. #endif
  847.  
  848. /*
  849.  * ExpandWildCard() - this code does wild-card pattern matching using the shell
  850.  *
  851.  * Mool: return 0 for success, 1 for error (you may loose some memory) and
  852.  *       put an error message in *file.
  853.  *
  854.  * num_pat is number of input patterns
  855.  * pat is array of pointers to input patterns
  856.  * num_file is pointer to number of matched file names
  857.  * file is pointer to array of pointers to matched file names
  858.  * On Unix we do not check for files only yet
  859.  * list_notfound is ignored
  860.  */
  861.  
  862. extern char *mktemp __ARGS((char *));
  863. #ifndef SEEK_SET
  864. # define SEEK_SET 0
  865. #endif
  866. #ifndef SEEK_END
  867. # define SEEK_END 2
  868. #endif
  869.  
  870.     int
  871. ExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
  872.     int             num_pat;
  873.     char          **pat;
  874.     int            *num_file;
  875.     char         ***file;
  876.     int                files_only;
  877.     int                list_notfound;
  878. {
  879.     char    tmpname[TMPNAMELEN];
  880.     char    *command;
  881.     int        i;
  882.     int        dir;
  883.     size_t    len;
  884.     FILE    *fd;
  885.     char    *buffer;
  886.     char    *p;
  887.     int        use_glob = FALSE;
  888.  
  889.     *num_file = 0;        /* default: no files found */
  890.     *file = (char **)"";
  891.  
  892.     /*
  893.      * If there are no wildcards, just copy the names to allocated memory.
  894.      * Saves a lot of time, because we don't have to start a new shell.
  895.      */
  896.     if (!have_wildcard(num_pat, pat))
  897.     {
  898.         *file = (char **)alloc(num_pat * sizeof(char *));
  899.         if (*file == NULL)
  900.         {
  901.             *file = (char **)"";
  902.             return 1;
  903.         }
  904.         for (i = 0; i < num_pat; i++)
  905.             (*file)[i] = strsave(pat[i]);
  906.         *num_file = num_pat;
  907.         return 0;
  908.     }
  909.  
  910. /*
  911.  * get a name for the temp file
  912.  */
  913.     strcpy(tmpname, TMPNAME2);
  914.     if (*mktemp(tmpname) == NUL)
  915.     {
  916.         emsg(e_notmp);
  917.         return 1;
  918.     }
  919.  
  920. /*
  921.  * let the shell expand the patterns and write the result into the temp file
  922.  * If we use csh, glob will work better than echo.
  923.  */
  924.     if ((len = strlen(p_sh)) >= 3 && strcmp(p_sh + len - 3, "csh") == 0)
  925.         use_glob = TRUE;
  926.  
  927.     len = TMPNAMELEN + 10;
  928.     for (i = 0; i < num_pat; ++i)        /* count the length of the patterns */
  929.         len += strlen(pat[i]) + 3;
  930.     command = (char *)alloc(len);
  931.     if (command == NULL)
  932.         return 1;
  933.     if (use_glob)
  934.         strcpy(command, "glob >");            /* built the shell command */
  935.     else
  936.         strcpy(command, "echo >");            /* built the shell command */
  937.     strcat(command, tmpname);
  938.     for (i = 0; i < num_pat; ++i)
  939.     {
  940. #ifdef USE_SYSTEM
  941.         strcat(command, " \"");                /* need extra quotes because we */
  942.         strcat(command, pat[i]);            /*   start the shell twice */
  943.         strcat(command, "\"");
  944. #else
  945.         strcat(command, " ");
  946.         strcat(command, pat[i]);
  947. #endif
  948.     }
  949.     i = call_shell(command, 0, FALSE);        /* execute it */
  950.     free(command);
  951.     if (i)                                    /* call_shell failed */
  952.     {
  953.         remove(tmpname);
  954.         sleep(1);            /* give the user a chance to read error messages */
  955.         must_redraw = CLEAR;                /* probably messed up screen */
  956.         return 1;
  957.     }
  958.  
  959. /*
  960.  * read the names from the file into memory
  961.  */
  962.      fd = fopen(tmpname, "r");
  963.     if (fd == NULL)
  964.     {
  965.         emsg(e_notopen);
  966.         return 1;
  967.     }
  968.     fseek(fd, 0L, SEEK_END);
  969.     len = ftell(fd);                /* get size of temp file */
  970.     fseek(fd, 0L, SEEK_SET);
  971.     buffer = (char *)alloc(len + 1);
  972.     if (buffer == NULL)
  973.     {
  974.         remove(tmpname);
  975.         fclose(fd);
  976.         return 1;
  977.     }
  978.     i = fread(buffer, 1, len, fd);
  979.     fclose(fd);
  980.     remove(tmpname);
  981.     if (i != len)
  982.     {
  983.         emsg(e_notread);
  984.         free(buffer);
  985.         return 1;
  986.     }
  987.  
  988.     if (use_glob)        /* file names are separated with NUL */
  989.     {
  990.         buffer[len] = NUL;                    /* make sure the buffers ends in NUL */
  991.         i = 0;
  992.         for (p = buffer; p < buffer + len; ++p)
  993.             if (*p == NUL)                    /* count entry */
  994.                 ++i;
  995.         if (len)
  996.             ++i;                            /* count last entry */
  997.     }
  998.     else                /* file names are separated with SPACE */
  999.     {
  1000.         buffer[len] = '\n';                    /* make sure the buffers ends in NL */
  1001.         p = buffer;
  1002.         for (i = 0; *p != '\n'; ++i)        /* count number of entries */
  1003.         {
  1004.             while (*p != ' ' && *p != '\n')    /* skip entry */
  1005.                 ++p;
  1006.             skipspace(&p);                    /* skip to next entry */
  1007.         }
  1008.     }
  1009.     *num_file = i;
  1010.     *file = (char **)alloc(sizeof(char *) * i);
  1011.     if (*file == NULL)
  1012.     {
  1013.         free(buffer);
  1014.         *file = (char **)"";
  1015.         return 1;
  1016.     }
  1017.     p = buffer;
  1018.     for (i = 0; i < *num_file; ++i)
  1019.     {
  1020.         (*file)[i] = p;
  1021.         if (use_glob)
  1022.         {
  1023.             while (*p && p < buffer + len)        /* skip entry */
  1024.                 ++p;
  1025.             ++p;                                /* skip NUL */
  1026.         }
  1027.         else
  1028.         {
  1029.             while (*p != ' ' && *p != '\n')        /* skip entry */
  1030.                 ++p;
  1031.             if (*p == '\n')                        /* last entry */
  1032.                 *p = NUL;
  1033.             else
  1034.             {
  1035.                 *p++ = NUL;
  1036.                 skipspace(&p);                    /* skip to next entry */
  1037.             }
  1038.         }
  1039.     }
  1040.     for (i = 0; i < *num_file; ++i)
  1041.     {
  1042.         dir = (isdir((*file)[i]) > 0);
  1043.         if (dir < 0)            /* if file doesn't exist don't add '/' */
  1044.             dir = 0;
  1045.         p = alloc((unsigned)(strlen((*file)[i]) + 1 + dir));
  1046.         if (p)
  1047.         {
  1048.             strcpy(p, (*file)[i]);
  1049.             if (dir)
  1050.                 strcat(p, "/");
  1051.         }
  1052.         (*file)[i] = p;
  1053.     }
  1054.     free(buffer);
  1055.     return 0;
  1056. }
  1057.  
  1058.     void
  1059. FreeWild(num, file)
  1060.     int        num;
  1061.     char    **file;
  1062. {
  1063.     if (file == NULL || num == 0)
  1064.         return;
  1065.     while (num--)
  1066.         free(file[num]);
  1067.     free(file);
  1068. }
  1069.  
  1070.     int
  1071. has_wildcard(p)
  1072.     char *p;
  1073. {
  1074. #ifdef __STDC__
  1075.     return strpbrk(p, "*?[{`~$") != NULL;
  1076. #else
  1077.     for ( ; *p; ++p)
  1078.         if (strchr("*?[{`~$", *p) != NULL)
  1079.             return 1;
  1080.     return 0;
  1081. #endif
  1082. }
  1083.  
  1084.     int
  1085. have_wildcard(num, file)
  1086.     int        num;
  1087.     char    **file;
  1088. {
  1089.     register int i;
  1090.  
  1091.     for (i = 0; i < num; i++)
  1092.         if (has_wildcard(file[i]))
  1093.             return 1;
  1094.     return 0;
  1095. }
  1096.  
  1097. #if defined(M_XENIX) || defined(UTS2)
  1098. /*
  1099.  * Scaled-down version of rename, which is missing in Xenix.
  1100.  * This version can only move regular files and will fail if the
  1101.  * destination exists.
  1102.  */
  1103.     int
  1104. rename(src, dest)
  1105.     char *src, *dest;
  1106. {
  1107.     struct stat        st;
  1108.  
  1109.     if (stat(dest, &st) >= 0)    /* fail if destination exists */
  1110.         return -1;
  1111.     if (link(src, dest) != 0)    /* link file to new name */
  1112.         return -1;
  1113.     if (unlink(src) == 0)        /* delete link to old name */
  1114.         return 0;
  1115.     return -1;
  1116. }
  1117. #endif /* M_XENIX || UTS2 */
  1118.