home *** CD-ROM | disk | FTP | other *** search
- From: mool@oce.nl (Bram Moolenaar)
- Newsgroups: comp.sources.misc
- Subject: v44i037: vim - Vi IMproved editor, v3.0, Part18/26
- Date: 18 Aug 1994 14:03:07 -0500
- Organization: Sterling Software
- Sender: kent@sparky.sterling.com
- Approved: kent@sparky.sterling.com
- Message-ID: <330b9b$e6c@sparky.sterling.com>
- X-Md4-Signature: 6253b2430ecefae3017729cc92c0314a
-
- Submitted-by: mool@oce.nl (Bram Moolenaar)
- Posting-number: Volume 44, Issue 37
- Archive-name: vim/part18
- Environment: UNIX, AMIGA, MS-DOS, Windows NT
- Supersedes: vim: Volume 41, Issue 50-75
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: vim/src/search.c vim/src/unix.c vim/tools/readme
- # vim/uganda.txt
- # Wrapped by kent@sparky on Mon Aug 15 21:44:10 1994
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 18 (of 26)."'
- if test -f 'vim/src/search.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vim/src/search.c'\"
- else
- echo shar: Extracting \"'vim/src/search.c'\" \(30917 characters\)
- sed "s/^X//" >'vim/src/search.c' <<'END_OF_FILE'
- X/* vi:ts=4:sw=4
- X *
- X * VIM - Vi IMproved by Bram Moolenaar
- X *
- X * Read the file "credits.txt" for a list of people who contributed.
- X * Read the file "uganda.txt" for copying and usage conditions.
- X */
- X/*
- X * search.c: code for normal mode searching commands
- X */
- X
- X#include "vim.h"
- X#include "globals.h"
- X#include "proto.h"
- X#include "param.h"
- X#include "ops.h" /* for mincl */
- X
- X/* modified Henry Spencer's regular expression routines */
- X#include "regexp.h"
- X
- Xstatic int inmacro __ARGS((char_u *, char_u *));
- Xstatic int cls __ARGS((void));
- X
- Xstatic char_u *top_bot_msg = (char_u *)"search hit TOP, continuing at BOTTOM";
- Xstatic char_u *bot_top_msg = (char_u *)"search hit BOTTOM, continuing at TOP";
- X
- X/*
- X * This file contains various searching-related routines. These fall into
- X * three groups:
- X * 1. string searches (for /, ?, n, and N)
- X * 2. character searches within a single line (for f, F, t, T, etc)
- X * 3. "other" kinds of searches like the '%' command, and 'word' searches.
- X */
- X
- X/*
- X * String searches
- X *
- X * The string search functions are divided into two levels:
- X * lowest: searchit(); called by dosearch() and edit().
- X * Highest: dosearch(); changes curwin->w_cursor, called by normal().
- X *
- X * The last search pattern is remembered for repeating the same search.
- X * This pattern is shared between the :g, :s, ? and / commands.
- X * This is in myregcomp().
- X *
- X * The actual string matching is done using a heavily modified version of
- X * Henry Spencer's regular expression library.
- X */
- X
- X/*
- X * Two search patterns are remembered: One for the :substitute command and
- X * one for other searches. last_pattern points to the one that was
- X * used the last time.
- X */
- Xstatic char_u *search_pattern = NULL;
- Xstatic char_u *subst_pattern = NULL;
- Xstatic char_u *last_pattern = NULL;
- X
- Xstatic int want_start; /* looking for start of line? */
- X
- X/*
- X * translate search pattern for regcomp()
- X *
- X * sub_cmd == 0: save pat in search_pattern (normal search command)
- X * sub_cmd == 1: save pat in subst_pattern (:substitute command)
- X * sub_cmd == 2: save pat in both patterns (:global command)
- X * which_pat == 0: use previous search pattern if "pat" is NULL
- X * which_pat == 1: use previous sustitute pattern if "pat" is NULL
- X * which_pat == 2: use last used pattern if "pat" is NULL
- X *
- X */
- X regexp *
- Xmyregcomp(pat, sub_cmd, which_pat)
- X char_u *pat;
- X int sub_cmd;
- X int which_pat;
- X{
- X regexp *retval;
- X
- X if (pat == NULL || *pat == NUL) /* use previous search pattern */
- X {
- X if (which_pat == 0)
- X {
- X if (search_pattern == NULL)
- X {
- X emsg(e_noprevre);
- X return (regexp *) NULL;
- X }
- X pat = search_pattern;
- X }
- X else if (which_pat == 1)
- X {
- X if (subst_pattern == NULL)
- X {
- X emsg(e_nopresub);
- X return (regexp *) NULL;
- X }
- X pat = subst_pattern;
- X }
- X else /* which_pat == 2 */
- X {
- X if (last_pattern == NULL)
- X {
- X emsg(e_noprevre);
- X return (regexp *) NULL;
- X }
- X pat = last_pattern;
- X }
- X }
- X
- X /*
- X * save the currently used pattern in the appropriate place,
- X * unless the pattern should not be remembered
- X */
- X if (!keep_old_search_pattern)
- X {
- X if (sub_cmd == 0 || sub_cmd == 2) /* search or global command */
- X {
- X if (search_pattern != pat)
- X {
- X free(search_pattern);
- X search_pattern = strsave(pat);
- X last_pattern = search_pattern;
- X reg_magic = p_magic; /* Magic sticks with the r.e. */
- X }
- X }
- X if (sub_cmd == 1 || sub_cmd == 2) /* substitute or global command */
- X {
- X if (subst_pattern != pat)
- X {
- X free(subst_pattern);
- X subst_pattern = strsave(pat);
- X last_pattern = subst_pattern;
- X reg_magic = p_magic; /* Magic sticks with the r.e. */
- X }
- X }
- X }
- X
- X want_start = (*pat == '^'); /* looking for start of line? */
- X reg_ic = p_ic; /* tell the regexec routine how to search */
- X retval = regcomp(pat);
- X return retval;
- X}
- X
- X/*
- X * lowest level search function.
- X * Search for 'count'th occurrence of 'str' in direction 'dir'.
- X * Start at position 'pos' and return the found position in 'pos'.
- X * Return OK for success, FAIL for failure.
- X */
- X int
- Xsearchit(pos, dir, str, count, end, message)
- X FPOS *pos;
- X int dir;
- X char_u *str;
- X long count;
- X int end;
- X int message;
- X{
- X int found;
- X linenr_t lnum = 0; /* init to shut up gcc */
- X linenr_t startlnum;
- X regexp *prog;
- X register char_u *s;
- X char_u *ptr;
- X register int i;
- X register char_u *match, *matchend;
- X int loop;
- X
- X if ((prog = myregcomp(str, 0, 2)) == NULL)
- X {
- X if (message)
- X emsg(e_invstring);
- X return FAIL;
- X }
- X/*
- X * find the string
- X */
- X found = 1;
- X while (count-- && found) /* stop after count matches, or no more matches */
- X {
- X startlnum = pos->lnum; /* remember start of search for detecting no match */
- X found = 0; /* default: not found */
- X
- X i = pos->col + dir; /* search starts one postition away */
- X lnum = pos->lnum;
- X
- X if (dir == BACKWARD && i < 0)
- X --lnum;
- X
- X for (loop = 0; loop != 2; ++loop) /* do this twice if 'wrapscan' is set */
- X {
- X for ( ; lnum > 0 && lnum <= curbuf->b_ml.ml_line_count; lnum += dir, i = -1)
- X {
- X s = ptr = ml_get(lnum);
- X if (dir == FORWARD && i > 0) /* first line for forward search */
- X {
- X if (want_start || STRLEN(s) <= (size_t)i) /* match not possible */
- X continue;
- X s += i;
- X }
- X
- X if (regexec(prog, s, dir == BACKWARD || i <= 0))
- X { /* match somewhere on line */
- X match = prog->startp[0];
- X matchend = prog->endp[0];
- X if (dir == BACKWARD && !want_start)
- X {
- X /*
- X * Now, if there are multiple matches on this line,
- X * we have to get the last one. Or the last one before
- X * the cursor, if we're on that line.
- X */
- X while (*match != NUL && regexec(prog, match + 1, (int)FALSE))
- X {
- X if ((i >= 0) && ((prog->startp[0] - s) > i))
- X break;
- X match = prog->startp[0];
- X matchend = prog->endp[0];
- X }
- X
- X if ((i >= 0) && ((match - s) > i))
- X continue;
- X }
- X
- X pos->lnum = lnum;
- X if (end)
- X pos->col = (int) (matchend - ptr - 1);
- X else
- X pos->col = (int) (match - ptr);
- X found = 1;
- X break;
- X }
- X /* breakcheck is slow, do it only once in 16 lines */
- X if ((lnum & 15) == 0)
- X breakcheck(); /* stop if ctrl-C typed */
- X if (got_int)
- X break;
- X
- X if (loop && lnum == startlnum) /* if second loop stop where started */
- X break;
- X }
- X /* stop the search if wrapscan isn't set, after an interrupt and after a match */
- X if (!p_ws || got_int || found)
- X break;
- X
- X /*
- X * If 'wrapscan' is set we continue at the other end of the file.
- X * If 'terse' is not set, we give a message.
- X * This message is also remembered in keep_msg for when the screen
- X * is redrawn. The keep_msg is cleared whenever another message is
- X * written.
- X */
- X if (dir == BACKWARD) /* start second loop at the other end */
- X {
- X lnum = curbuf->b_ml.ml_line_count;
- X if (!p_terse && message)
- X {
- X msg(top_bot_msg);
- X keep_msg = top_bot_msg;
- X }
- X }
- X else
- X {
- X lnum = 1;
- X if (!p_terse && message)
- X {
- X msg(bot_top_msg);
- X keep_msg = bot_top_msg;
- X }
- X }
- X }
- X if (got_int)
- X break;
- X }
- X
- X free(prog);
- X
- X if (!found) /* did not find it */
- X {
- X if (got_int)
- X emsg(e_interr);
- X else if (message)
- X {
- X if (p_ws)
- X emsg(e_patnotf);
- X else if (lnum == 0)
- X EMSG("search hit TOP without match");
- X else
- X EMSG("search hit BOTTOM without match");
- X }
- X return FAIL;
- X }
- X
- X return OK;
- X}
- X
- X/*
- X * Highest level string search function.
- X * Search for the 'count'th occurence of string 'str' in direction 'dirc'
- X * If 'dirc' is 0: use previous dir.
- X * If 'str' is 0 or 'str' is empty: use previous string.
- X * If 'reverse' is TRUE: go in reverse of previous dir.
- X * If 'echo' is TRUE: echo the search command and handle options
- X * If 'message' is TRUE: may give error message
- X *
- X * return 0 for failure, 1 for found, 2 for found and line offset added
- X */
- X int
- Xdosearch(dirc, str, reverse, count, echo, message)
- X int dirc;
- X char_u *str;
- X int reverse;
- X long count;
- X int echo;
- X int message;
- X{
- X FPOS pos; /* position of the last match */
- X char_u *searchstr;
- X static int lastsdir = '/'; /* previous search direction */
- X static int lastoffline;/* previous/current search has line offset */
- X static int lastend; /* previous/current search set cursor at end */
- X static long lastoff; /* previous/current line or char offset */
- X int old_lastsdir;
- X int old_lastoffline;
- X int old_lastend;
- X long old_lastoff;
- X int ret; /* Return value */
- X register char_u *p;
- X register long c;
- X char_u *dircp = NULL;
- X
- X /*
- X * save the values for when keep_old_search_pattern is set
- X * (no if around this because gcc wants them initialized)
- X */
- X old_lastsdir = lastsdir;
- X old_lastoffline = lastoffline;
- X old_lastend = lastend;
- X old_lastoff = lastoff;
- X
- X if (dirc == 0)
- X dirc = lastsdir;
- X else
- X lastsdir = dirc;
- X if (reverse)
- X {
- X if (dirc == '/')
- X dirc = '?';
- X else
- X dirc = '/';
- X }
- X searchstr = str;
- X /* use previous string */
- X if (str == NULL || *str == NUL || *str == dirc)
- X {
- X if (search_pattern == NULL)
- X {
- X emsg(e_noprevre);
- X ret = 0;
- X goto end_dosearch;
- X }
- X searchstr = (char_u *)""; /* will use search_pattern in myregcomp() */
- X }
- X if (str != NULL && *str != NUL) /* look for (new) offset */
- X {
- X /*
- X * Find end of regular expression.
- X * If there is a matching '/' or '?', toss it.
- X */
- X p = skip_regexp(str, dirc);
- X if (*p == dirc)
- X {
- X dircp = p; /* remember where we put the NUL */
- X *p++ = NUL;
- X }
- X lastoffline = FALSE;
- X lastend = FALSE;
- X lastoff = 0;
- X /*
- X * Check for a line offset or a character offset.
- X * for get_address (echo off) we don't check for a character offset,
- X * because it is meaningless and the 's' could be a substitute command.
- X */
- X if (*p == '+' || *p == '-' || isdigit(*p))
- X lastoffline = TRUE;
- X else if (echo && (*p == 'e' || *p == 's' || *p == 'b'))
- X {
- X if (*p == 'e') /* end */
- X lastend = TRUE;
- X ++p;
- X }
- X if (isdigit(*p) || *p == '+' || *p == '-') /* got an offset */
- X {
- X if (isdigit(*p) || isdigit(*(p + 1)))
- X lastoff = atol((char *)p); /* 'nr' or '+nr' or '-nr' */
- X else if (*p == '-') /* single '-' */
- X lastoff = -1;
- X else /* single '+' */
- X lastoff = 1;
- X ++p;
- X while (isdigit(*p)) /* skip number */
- X ++p;
- X }
- X searchcmdlen = p - str; /* compute lenght of search command
- X for get_address() */
- X }
- X
- X if (echo)
- X {
- X msg_start();
- X msg_outchar(dirc);
- X msg_outtrans(*searchstr == NUL ? search_pattern : searchstr, -1);
- X if (lastoffline || lastend || lastoff)
- X {
- X msg_outchar(dirc);
- X if (lastend)
- X msg_outchar('e');
- X else if (!lastoffline)
- X msg_outchar('s');
- X if (lastoff < 0)
- X {
- X msg_outchar('-');
- X msg_outnum((long)-lastoff);
- X }
- X else if (lastoff > 0 || lastoffline)
- X {
- X msg_outchar('+');
- X msg_outnum((long)lastoff);
- X }
- X }
- X msg_ceol();
- X (void)msg_check();
- X
- X gotocmdline(FALSE, NUL);
- X flushbuf();
- X }
- X
- X pos = curwin->w_cursor;
- X
- X c = searchit(&pos, dirc == '/' ? FORWARD : BACKWARD, searchstr, count, lastend, message);
- X if (dircp)
- X *dircp = dirc; /* put second '/' or '?' back for normal() */
- X if (c == FAIL)
- X {
- X ret = 0;
- X goto end_dosearch;
- X }
- X if (lastend)
- X mincl = TRUE; /* 'e' includes last character */
- X
- X if (!lastoffline) /* add the character offset to the column */
- X {
- X if (lastoff > 0) /* offset to the right, check for end of line */
- X {
- X p = ml_get_pos(&pos) + 1;
- X c = lastoff;
- X while (c-- && *p++ != NUL)
- X ++pos.col;
- X }
- X else /* offset to the left, check for start of line */
- X {
- X if ((c = pos.col + lastoff) < 0)
- X c = 0;
- X pos.col = c;
- X }
- X }
- X
- X if (!tag_busy)
- X setpcmark();
- X curwin->w_cursor = pos;
- X curwin->w_set_curswant = TRUE;
- X
- X if (!lastoffline)
- X {
- X ret = 1;
- X goto end_dosearch;
- X }
- X
- X/*
- X * add the offset to the line number.
- X */
- X c = curwin->w_cursor.lnum + lastoff;
- X if (c < 1)
- X curwin->w_cursor.lnum = 1;
- X else if (c > curbuf->b_ml.ml_line_count)
- X curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- X else
- X curwin->w_cursor.lnum = c;
- X curwin->w_cursor.col = 0;
- X
- X ret = 2;
- X
- Xend_dosearch:
- X if (keep_old_search_pattern)
- X {
- X lastsdir = old_lastsdir;
- X lastoffline = old_lastoffline;
- X lastend = old_lastend;
- X lastoff = old_lastoff;
- X }
- X return ret;
- X}
- X
- X
- X/*
- X * Character Searches
- X */
- X
- X/*
- X * searchc(c, dir, type, count)
- X *
- X * Search for character 'c', in direction 'dir'. If 'type' is 0, move to the
- X * position of the character, otherwise move to just before the char.
- X * Repeat this 'count' times.
- X */
- X int
- Xsearchc(c, dir, type, count)
- X int c;
- X register int dir;
- X int type;
- X long count;
- X{
- X static int lastc = NUL; /* last character searched for */
- X static int lastcdir; /* last direction of character search */
- X static int lastctype; /* last type of search ("find" or "to") */
- X register int col;
- X char_u *p;
- X int len;
- X
- X if (c != NUL) /* normal search: remember args for repeat */
- X {
- X lastc = c;
- X lastcdir = dir;
- X lastctype = type;
- X }
- X else /* repeat previous search */
- X {
- X if (lastc == NUL)
- X return FALSE;
- X if (dir) /* repeat in opposite direction */
- X dir = -lastcdir;
- X else
- X dir = lastcdir;
- X }
- X
- X p = ml_get(curwin->w_cursor.lnum);
- X col = curwin->w_cursor.col;
- X len = STRLEN(p);
- X
- X /*
- X * On 'to' searches, skip one to start with so we can repeat searches in
- X * the same direction and have it work right.
- X * REMOVED to get vi compatibility
- X * if (lastctype)
- X * col += dir;
- X */
- X
- X while (count--)
- X {
- X for (;;)
- X {
- X if ((col += dir) < 0 || col >= len)
- X return FALSE;
- X if (p[col] == lastc)
- X break;
- X }
- X }
- X if (lastctype)
- X col -= dir;
- X curwin->w_cursor.col = col;
- X return TRUE;
- X}
- X
- X/*
- X * "Other" Searches
- X */
- X
- X/*
- X * showmatch - move the cursor to the matching paren or brace
- X *
- X * Improvement over vi: Braces inside quotes are ignored.
- X */
- X FPOS *
- Xshowmatch(initc)
- X int initc;
- X{
- X static FPOS pos; /* current search position */
- X int findc; /* matching brace */
- X int c;
- X int count = 0; /* cumulative number of braces */
- X int idx = 0; /* init for gcc */
- X static char_u table[6] = {'(', ')', '[', ']', '{', '}'};
- X int inquote = 0; /* non-zero when inside quotes */
- X register char_u *linep; /* pointer to current line */
- X register char_u *ptr;
- X int do_quotes; /* check for quotes in current line */
- X int hash_dir = 0; /* Direction searched for # things */
- X int comment_dir = 0; /* Direction searched for comments */
- X
- X pos = curwin->w_cursor;
- X linep = ml_get(pos.lnum);
- X
- X /*
- X * if initc given, look in the table for the matching character
- X */
- X if (initc != NUL)
- X {
- X for (idx = 0; idx < 6; ++idx)
- X if (table[idx] == initc)
- X {
- X initc = table[idx = idx ^ 1];
- X break;
- X }
- X if (idx == 6) /* invalid initc! */
- X return NULL;
- X }
- X /*
- X * no initc given, look under the cursor
- X */
- X else
- X {
- X if (linep[0] == '#' && pos.col == 0)
- X hash_dir = 1;
- X
- X /*
- X * Are we on a comment?
- X */
- X if (linep[pos.col] == '/')
- X {
- X if (linep[pos.col + 1] == '*')
- X {
- X comment_dir = 1;
- X idx = 0;
- X }
- X else if (pos.col > 0 && linep[pos.col - 1] == '*')
- X {
- X comment_dir = -1;
- X idx = 1;
- X }
- X }
- X if (linep[pos.col] == '*')
- X {
- X if (linep[pos.col + 1] == '/')
- X {
- X comment_dir = -1;
- X idx = 1;
- X }
- X else if (pos.col > 0 && linep[pos.col - 1] == '/')
- X {
- X comment_dir = 1;
- X idx = 0;
- X }
- X }
- X
- X /*
- X * If we are not on a comment or the # at the start of a line, then
- X * look for brace anywhere on this line after the cursor.
- X */
- X if (!hash_dir && !comment_dir)
- X {
- X /*
- X * find the brace under or after the cursor
- X */
- X linep = ml_get(pos.lnum);
- X for (;;)
- X {
- X initc = linep[pos.col];
- X if (initc == NUL)
- X break;
- X
- X for (idx = 0; idx < 6; ++idx)
- X if (table[idx] == initc)
- X break;
- X if (idx != 6)
- X break;
- X ++pos.col;
- X }
- X if (idx == 6)
- X {
- X if (linep[0] == '#')
- X hash_dir = 1;
- X else
- X return NULL;
- X }
- X }
- X if (hash_dir)
- X {
- X /*
- X * Look for matching #if, #else, #elif, or #endif
- X */
- X mtype = MLINE; /* Linewise for this case only */
- X ptr = linep + 1;
- X while (*ptr == ' ' || *ptr == TAB)
- X ptr++;
- X if (STRNCMP(ptr, "if", (size_t)2) == 0 || STRNCMP(ptr, "el", (size_t)2) == 0)
- X hash_dir = 1;
- X else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
- X hash_dir = -1;
- X else
- X return NULL;
- X pos.col = 0;
- X while (!got_int)
- X {
- X if (hash_dir > 0)
- X {
- X if (pos.lnum == curbuf->b_ml.ml_line_count)
- X break;
- X }
- X else if (pos.lnum == 1)
- X break;
- X pos.lnum += hash_dir;
- X linep = ml_get(pos.lnum);
- X if ((pos.lnum & 15) == 0)
- X breakcheck();
- X if (linep[0] != '#')
- X continue;
- X ptr = linep + 1;
- X while (*ptr == ' ' || *ptr == TAB)
- X ptr++;
- X if (hash_dir > 0)
- X {
- X if (STRNCMP(ptr, "if", (size_t)2) == 0)
- X count++;
- X else if (STRNCMP(ptr, "el", (size_t)2) == 0)
- X {
- X if (count == 0)
- X return &pos;
- X }
- X else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
- X {
- X if (count == 0)
- X return &pos;
- X count--;
- X }
- X }
- X else
- X {
- X if (STRNCMP(ptr, "if", (size_t)2) == 0)
- X {
- X if (count == 0)
- X return &pos;
- X count--;
- X }
- X else if (STRNCMP(ptr, "endif", (size_t)5) == 0)
- X count++;
- X }
- X }
- X return NULL;
- X }
- X }
- X
- X findc = table[idx ^ 1]; /* get matching brace */
- X idx &= 1;
- X
- X do_quotes = -1;
- X while (!got_int)
- X {
- X /*
- X * Go to the next position, forward or backward. We could use
- X * inc() and dec() here, but that is much slower
- X */
- X if (idx) /* backward search */
- X {
- X if (pos.col == 0) /* at start of line, go to previous one */
- X {
- X if (pos.lnum == 1) /* start of file */
- X break;
- X --pos.lnum;
- X linep = ml_get(pos.lnum);
- X pos.col = STRLEN(linep); /* put pos.col on trailing NUL */
- X do_quotes = -1;
- X /* we only do a breakcheck() once for every 16 lines */
- X if ((pos.lnum & 15) == 0)
- X breakcheck();
- X }
- X else
- X --pos.col;
- X }
- X else /* forward search */
- X {
- X if (linep[pos.col] == NUL) /* at end of line, go to next one */
- X {
- X if (pos.lnum == curbuf->b_ml.ml_line_count) /* end of file */
- X break;
- X ++pos.lnum;
- X linep = ml_get(pos.lnum);
- X pos.col = 0;
- X do_quotes = -1;
- X /* we only do a breakcheck() once for every 16 lines */
- X if ((pos.lnum & 15) == 0)
- X breakcheck();
- X }
- X else
- X ++pos.col;
- X }
- X
- X if (comment_dir)
- X {
- X /* Note: comments do not nest, and we ignore quotes in them */
- X if (linep[pos.col] != '/' ||
- X (comment_dir == 1 && pos.col == 0) ||
- X linep[pos.col - comment_dir] != '*')
- X continue;
- X return &pos;
- X }
- X
- X if (do_quotes == -1) /* count number of quotes in this line */
- X {
- X /*
- X * count the number of quotes in the line, skipping \" and '"'
- X */
- X for (ptr = linep; *ptr; ++ptr)
- X if (*ptr == '"' && (ptr == linep || ptr[-1] != '\\') &&
- X (ptr == linep || ptr[-1] != '\'' || ptr[1] != '\''))
- X ++do_quotes;
- X do_quotes &= 1; /* result is 1 with even number of quotes */
- X
- X /*
- X * If we find an uneven count, check current line and previous
- X * one for a '\' at the end.
- X */
- X if (!do_quotes)
- X {
- X inquote = FALSE;
- X if (ptr[-1] == '\\')
- X {
- X do_quotes = 1;
- X if (idx) /* backward search */
- X inquote = TRUE;
- X }
- X if (pos.lnum > 1)
- X {
- X ptr = ml_get(pos.lnum - 1);
- X if (*ptr && *(ptr + STRLEN(ptr) - 1) == '\\')
- X {
- X do_quotes = 1;
- X if (!idx) /* forward search */
- X inquote = TRUE;
- X }
- X }
- X }
- X }
- X
- X /*
- X * Things inside quotes are ignored by setting 'inquote'.
- X * If we find a quote without a preceding '\' invert 'inquote'.
- X * At the end of a line not ending in '\' we reset 'inquote'.
- X *
- X * In lines with an uneven number of quotes (without preceding '\')
- X * we do not know which part to ignore. Therefore we only set
- X * inquote if the number of quotes in a line is even,
- X * unless this line or the previous one ends in a '\'.
- X * Complicated, isn't it?
- X */
- X switch (c = linep[pos.col])
- X {
- X case NUL:
- X inquote = FALSE;
- X break;
- X
- X case '"':
- X /* a quote that is preceded with a backslash is ignored */
- X if (do_quotes && (pos.col == 0 || linep[pos.col - 1] != '\\'))
- X inquote = !inquote;
- X break;
- X
- X /*
- X * Skip things in single quotes: 'x' or '\x'.
- X * Be careful for single single quotes, eg jon's.
- X * Things like '\233' or '\x3f' are not skipped, there is never a
- X * brace in them.
- X */
- X case '\'':
- X if (idx) /* backward search */
- X {
- X if (pos.col > 1)
- X {
- X if (linep[pos.col - 2] == '\'')
- X pos.col -= 2;
- X else if (linep[pos.col - 2] == '\\' && pos.col > 2 && linep[pos.col - 3] == '\'')
- X pos.col -= 3;
- X }
- X }
- X else if (linep[pos.col + 1]) /* forward search */
- X {
- X if (linep[pos.col + 1] == '\\' && linep[pos.col + 2] && linep[pos.col + 3] == '\'')
- X pos.col += 3;
- X else if (linep[pos.col + 2] == '\'')
- X pos.col += 2;
- X }
- X break;
- X
- X default:
- X if (!inquote) /* only check for match outside of quotes */
- X {
- X if (c == initc)
- X count++;
- X else if (c == findc)
- X {
- X if (count == 0)
- X return &pos;
- X count--;
- X }
- X }
- X }
- X }
- X return (FPOS *) NULL; /* never found it */
- X}
- X
- X/*
- X * findfunc(dir, what) - Find the next line starting with 'what' in direction 'dir'
- X *
- X * Return TRUE if a line was found.
- X */
- X int
- Xfindfunc(dir, what, count)
- X int dir;
- X int what;
- X long count;
- X{
- X linenr_t curr;
- X
- X curr = curwin->w_cursor.lnum;
- X
- X for (;;)
- X {
- X if (dir == FORWARD)
- X {
- X if (curr++ == curbuf->b_ml.ml_line_count)
- X break;
- X }
- X else
- X {
- X if (curr-- == 1)
- X break;
- X }
- X
- X if (*ml_get(curr) == what)
- X {
- X if (--count > 0)
- X continue;
- X setpcmark();
- X curwin->w_cursor.lnum = curr;
- X curwin->w_cursor.col = 0;
- X return TRUE;
- X }
- X }
- X
- X return FALSE;
- X}
- X
- X/*
- X * findsent(dir, count) - Find the start of the next sentence in direction 'dir'
- X * Sentences are supposed to end in ".", "!" or "?" followed by white space or
- X * a line break. Also stop at an empty line.
- X * Return TRUE if the next sentence was found.
- X */
- X int
- Xfindsent(dir, count)
- X int dir;
- X long count;
- X{
- X FPOS pos, tpos;
- X register int c;
- X int (*func) __PARMS((FPOS *));
- X int startlnum;
- X int noskip = FALSE; /* do not skip blanks */
- X
- X pos = curwin->w_cursor;
- X if (dir == FORWARD)
- X func = incl;
- X else
- X func = decl;
- X
- X while (count--)
- X {
- X /* if on an empty line, skip upto a non-empty line */
- X if (gchar(&pos) == NUL)
- X {
- X do
- X if ((*func)(&pos) == -1)
- X break;
- X while (gchar(&pos) == NUL);
- X if (dir == FORWARD)
- X goto found;
- X }
- X /* if on the start of a paragraph or a section and searching
- X * forward, go to the next line */
- X else if (dir == FORWARD && pos.col == 0 && startPS(pos.lnum, NUL, FALSE))
- X {
- X if (pos.lnum == curbuf->b_ml.ml_line_count)
- X return FALSE;
- X ++pos.lnum;
- X goto found;
- X }
- X else if (dir == BACKWARD)
- X decl(&pos);
- X
- X /* go back to the previous non-blank char */
- X while ((c = gchar(&pos)) == ' ' || c == '\t' ||
- X (dir == BACKWARD && strchr(".!?)]\"'", c) != NULL && c != NUL))
- X if (decl(&pos) == -1)
- X break;
- X
- X /* remember the line where the search started */
- X startlnum = pos.lnum;
- X
- X for (;;) /* find end of sentence */
- X {
- X if ((c = gchar(&pos)) == NUL ||
- X (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
- X {
- X if (dir == BACKWARD && pos.lnum != startlnum)
- X ++pos.lnum;
- X break;
- X }
- X if (c == '.' || c == '!' || c == '?')
- X {
- X tpos = pos;
- X do
- X if ((c = inc(&tpos)) == -1)
- X break;
- X while (strchr(")}\"'", c = gchar(&tpos)) != NULL && c != NUL);
- X if (c == -1 || c == ' ' || c == '\t' || c == NUL)
- X {
- X pos = tpos;
- X if (gchar(&pos) == NUL) /* skip NUL at EOL */
- X inc(&pos);
- X break;
- X }
- X }
- X if ((*func)(&pos) == -1)
- X {
- X if (count)
- X return FALSE;
- X noskip = TRUE;
- X break;
- X }
- X }
- Xfound:
- X /* skip white space */
- X while (!noskip && ((c = gchar(&pos)) == ' ' || c == '\t'))
- X if (incl(&pos) == -1)
- X break;
- X }
- X
- X setpcmark();
- X curwin->w_cursor = pos;
- X return TRUE;
- X}
- X
- X/*
- X * findpar(dir, count, what) - Find the next paragraph in direction 'dir'
- X * Paragraphs are currently supposed to be separated by empty lines.
- X * Return TRUE if the next paragraph was found.
- X * If 'what' is '{' or '}' we go to the next section.
- X * If 'both' is TRUE also stop at '}'.
- X */
- X int
- Xfindpar(dir, count, what, both)
- X register int dir;
- X long count;
- X int what;
- X int both;
- X{
- X register linenr_t curr;
- X int did_skip; /* TRUE after separating lines have
- X been skipped */
- X int first; /* TRUE on first line */
- X
- X curr = curwin->w_cursor.lnum;
- X
- X while (count--)
- X {
- X did_skip = FALSE;
- X for (first = TRUE; ; first = FALSE)
- X {
- X if (*ml_get(curr) != NUL)
- X did_skip = TRUE;
- X
- X if (!first && did_skip && startPS(curr, what, both))
- X break;
- X
- X if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
- X {
- X if (count)
- X return FALSE;
- X curr -= dir;
- X break;
- X }
- X }
- X }
- X setpcmark();
- X if (both && *ml_get(curr) == '}') /* include line with '}' */
- X ++curr;
- X curwin->w_cursor.lnum = curr;
- X if (curr == curbuf->b_ml.ml_line_count)
- X {
- X if ((curwin->w_cursor.col = STRLEN(ml_get(curr))) != 0)
- X --curwin->w_cursor.col;
- X mincl = TRUE;
- X }
- X else
- X curwin->w_cursor.col = 0;
- X return TRUE;
- X}
- X
- X/*
- X * check if the string 's' is a nroff macro that is in option 'opt'
- X */
- X static int
- Xinmacro(opt, s)
- X char_u *opt;
- X register char_u *s;
- X{
- X register char_u *macro;
- X
- X for (macro = opt; macro[0]; ++macro)
- X {
- X if (macro[0] == s[0] && (((s[1] == NUL || s[1] == ' ')
- X && (macro[1] == NUL || macro[1] == ' ')) || macro[1] == s[1]))
- X break;
- X ++macro;
- X if (macro[0] == NUL)
- X break;
- X }
- X return (macro[0] != NUL);
- X}
- X
- X/*
- X * startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
- X * If 'para' is '{' or '}' only check for sections.
- X * If 'both' is TRUE also stop at '}'
- X */
- X int
- XstartPS(lnum, para, both)
- X linenr_t lnum;
- X int para;
- X int both;
- X{
- X register char_u *s;
- X
- X s = ml_get(lnum);
- X if (*s == para || *s == '\f' || (both && *s == '}'))
- X return TRUE;
- X if (*s == '.' && (inmacro(p_sections, s + 1) || (!para && inmacro(p_para, s + 1))))
- X return TRUE;
- X return FALSE;
- X}
- X
- X/*
- X * The following routines do the word searches performed by the 'w', 'W',
- X * 'b', 'B', 'e', and 'E' commands.
- X */
- X
- X/*
- X * To perform these searches, characters are placed into one of three
- X * classes, and transitions between classes determine word boundaries.
- X *
- X * The classes are:
- X *
- X * 0 - white space
- X * 1 - letters, digits and underscore
- X * 2 - everything else
- X */
- X
- Xstatic int stype; /* type of the word motion being performed */
- X
- X/*
- X * cls() - returns the class of character at curwin->w_cursor
- X *
- X * The 'type' of the current search modifies the classes of characters if a 'W',
- X * 'B', or 'E' motion is being done. In this case, chars. from class 2 are
- X * reported as class 1 since only white space boundaries are of interest.
- X */
- X static int
- Xcls()
- X{
- X register int c;
- X
- X c = gchar_cursor();
- X if (c == ' ' || c == '\t' || c == NUL)
- X return 0;
- X
- X if (isidchar(c))
- X return 1;
- X
- X /*
- X * If stype is non-zero, report these as class 1.
- X */
- X return (stype == 0) ? 2 : 1;
- X}
- X
- X
- X/*
- X * fwd_word(count, type, eol) - move forward one word
- X *
- X * Returns TRUE if the cursor was already at the end of the file.
- X * If eol is TRUE, last word stops at end of line (for operators).
- X */
- X int
- Xfwd_word(count, type, eol)
- X long count;
- X int type;
- X int eol;
- X{
- X int sclass; /* starting class */
- X int i;
- X
- X stype = type;
- X while (--count >= 0)
- X {
- X sclass = cls();
- X
- X /*
- X * We always move at least one character.
- X */
- X i = inc_cursor();
- X if (i == -1)
- X return TRUE;
- X if (i == 1 && eol && count == 0) /* started at last char in line */
- X return FALSE;
- X
- X if (sclass != 0)
- X while (cls() == sclass)
- X {
- X i = inc_cursor();
- X if (i == -1 || (i == 1 && eol && count == 0))
- X return FALSE;
- X }
- X
- X /*
- X * go to next non-white
- X */
- X while (cls() == 0)
- X {
- X /*
- X * We'll stop if we land on a blank line
- X */
- X if (curwin->w_cursor.col == 0 && *ml_get(curwin->w_cursor.lnum) == NUL)
- X break;
- X
- X i = inc_cursor();
- X if (i == -1 || (i == 1 && eol && count == 0))
- X return FALSE;
- X }
- X }
- X return FALSE;
- X}
- X
- X/*
- X * bck_word(count, type) - move backward 'count' words
- X *
- X * Returns TRUE if top of the file was reached.
- X */
- X int
- Xbck_word(count, type)
- X long count;
- X int type;
- X{
- X int sclass; /* starting class */
- X
- X stype = type;
- X while (--count >= 0)
- X {
- X sclass = cls();
- X
- X if (dec_cursor() == -1) /* started at start of file */
- X return TRUE;
- X
- X if (cls() != sclass || sclass == 0)
- X {
- X /*
- X * We were at the start of a word. Go back to the end of the prior
- X * word.
- X */
- X while (cls() == 0) /* skip any white space */
- X {
- X /*
- X * We'll stop if we land on a blank line
- X */
- X if (curwin->w_cursor.col == 0 && *ml_get(curwin->w_cursor.lnum) == NUL)
- X goto finished;
- X
- X if (dec_cursor() == -1) /* hit start of file, stop here */
- X return FALSE;
- X }
- X sclass = cls();
- X }
- X
- X /*
- X * Move backward to start of this word.
- X */
- X if (skip_chars(sclass, BACKWARD))
- X return FALSE;
- X
- X inc_cursor(); /* overshot - forward one */
- Xfinished:
- X ;
- X }
- X return FALSE;
- X}
- X
- X/*
- X * end_word(count, type, stop) - move to the end of the word
- X *
- X * There is an apparent bug in the 'e' motion of the real vi. At least on the
- X * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
- X * motion crosses blank lines. When the real vi crosses a blank line in an
- X * 'e' motion, the cursor is placed on the FIRST character of the next
- X * non-blank line. The 'E' command, however, works correctly. Since this
- X * appears to be a bug, I have not duplicated it here.
- X *
- X * Returns TRUE if end of the file was reached.
- X *
- X * If stop is TRUE and we are already on the end of a word, move one less.
- X */
- X int
- Xend_word(count, type, stop)
- X long count;
- X int type;
- X int stop;
- X{
- X int sclass; /* starting class */
- X
- X stype = type;
- X while (--count >= 0)
- X {
- X sclass = cls();
- X if (inc_cursor() == -1)
- X return TRUE;
- X
- X /*
- X * If we're in the middle of a word, we just have to move to the end of it.
- X */
- X if (cls() == sclass && sclass != 0)
- X {
- X /*
- X * Move forward to end of the current word
- X */
- X if (skip_chars(sclass, FORWARD))
- X return TRUE;
- X }
- X else if (!stop || sclass == 0)
- X {
- X /*
- X * We were at the end of a word. Go to the end of the next word.
- X */
- X
- X if (skip_chars(0, FORWARD)) /* skip any white space */
- X return TRUE;
- X
- X /*
- X * Move forward to the end of this word.
- X */
- X if (skip_chars(cls(), FORWARD))
- X return TRUE;
- X }
- X dec_cursor(); /* overshot - backward one */
- X stop = FALSE; /* we move only one word less */
- X }
- X return FALSE;
- X}
- X
- X int
- Xskip_chars(class, dir)
- X int class;
- X int dir;
- X{
- X while (cls() == class)
- X if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
- X return TRUE;
- X return FALSE;
- X}
- END_OF_FILE
- if test 30917 -ne `wc -c <'vim/src/search.c'`; then
- echo shar: \"'vim/src/search.c'\" unpacked with wrong size!
- fi
- # end of 'vim/src/search.c'
- fi
- if test -f 'vim/src/unix.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vim/src/unix.c'\"
- else
- echo shar: Extracting \"'vim/src/unix.c'\" \(30140 characters\)
- sed "s/^X//" >'vim/src/unix.c' <<'END_OF_FILE'
- X/* vi:ts=4:sw=4
- X *
- X * VIM - Vi IMproved by Bram Moolenaar
- X *
- X * Read the file "credits.txt" for a list of people who contributed.
- X * Read the file "uganda.txt" for copying and usage conditions.
- X */
- X
- X/*
- X * unix.c -- BSD and SYSV code
- X *
- X * A lot of this file was written by Juergen Weigert.
- X */
- X
- X#include "vim.h"
- X#include "globals.h"
- X#include "param.h"
- X#include "proto.h"
- X
- X#include <fcntl.h>
- X#if !defined(pyr) && !defined(NOT_BOTH_TIME)
- X# include <time.h> /* on some systems time.h should not be
- X included together with sys/time.h */
- X#endif
- X#include <sys/ioctl.h>
- X#ifndef M_XENIX
- X# include <sys/types.h>
- X#endif
- X#include <signal.h>
- X
- X#ifndef USE_SYSTEM /* use fork/exec to start the shell */
- X# include <sys/wait.h>
- X# if !defined(SCO) && !defined(SOLARIS) && !defined(hpux) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(_SEQUENT_) && !defined(UNISYS) /* SCO returns pid_t */
- Xextern int fork();
- X# endif
- X# if !defined(linux) && !defined(SOLARIS) && !defined(USL) && !defined(sun) && !(defined(hpux) && defined(__STDC__)) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(USL) && !defined(UNISYS)
- Xextern int execvp __ARGS((const char *, const char **));
- X# endif
- X#endif
- X
- X#if defined(SYSV_UNIX) || defined(USL)
- X# if defined(__sgi) || defined(UTS2) || defined(UTS4) || defined(MIPS) || defined (MIPSEB) || defined(__osf__)
- X# include <sys/time.h>
- X# endif
- X# if defined(M_XENIX) || defined(SCO)
- X# include <stropts.h>
- X# endif
- X# if defined(M_XENIX) || defined(SCO) || defined(UNICOS)
- X# include <sys/select.h>
- X# define bzero(a, b) memset((a), 0, (b))
- X# endif
- X# if !defined(M_XENIX) && !defined(UNICOS)
- X# include <poll.h>
- X# endif
- X# if defined(SCO) || defined(ISC)
- X# include <sys/stream.h>
- X# include <sys/ptem.h>
- X# endif
- X# if defined(M_UNIX) && !defined(SCO)
- X# include <sys/time.h>
- X# endif /* M_UNIX */
- X# ifdef ISC
- X# include <termios.h>
- X# endif
- X# include <termio.h>
- X#else /* SYSV_UNIX */
- X# include <sys/time.h>
- X# if defined(hpux) || defined(linux)
- X# include <termio.h>
- X# if defined(hpux) && !defined(SIGWINCH) /* hpux 9.01 has it */
- X# define SIGWINCH SIGWINDOW
- X# endif
- X# else
- X# include <sgtty.h>
- X# endif /* hpux */
- X#endif /* !SYSV_UNIX */
- X
- X#if (defined(pyr) || defined(NO_FD_ZERO)) && defined(SYSV_UNIX) && defined(FD_ZERO)
- X# undef FD_ZERO
- X#endif
- X
- X#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
- X# ifdef SIGWINCH
- X# undef SIGWINCH
- X# endif
- X# ifdef TIOCGWINSZ
- X# undef TIOCGWINSZ
- X# endif
- X#endif
- X
- X#ifdef USE_X11
- X
- X# include <X11/Xlib.h>
- X# include <X11/Xutil.h>
- X
- XWindow x11_window = 0;
- XDisplay *x11_display = NULL;
- X
- Xstatic int get_x11_windis __ARGS((void));
- X#ifdef BUGGY
- Xstatic void set_x11_title __ARGS((char_u *));
- Xstatic void set_x11_icon __ARGS((char_u *));
- X#endif
- X#endif
- X
- Xstatic void get_x11_title __ARGS((void));
- Xstatic void get_x11_icon __ARGS((void));
- X
- Xstatic int Read __ARGS((char_u *, long));
- Xstatic int WaitForChar __ARGS((int));
- Xstatic int RealWaitForChar __ARGS((int));
- Xstatic void fill_inbuf __ARGS((void));
- X#ifdef USL
- Xstatic void sig_winch __ARGS((int));
- X#else
- X# if defined(SIGWINCH) && !defined(linux) && !defined(__alpha) && !defined(mips) && !defined(_SEQUENT_) && !defined(SCO) && !defined(SOLARIS) && !defined(ISC)
- Xstatic void sig_winch __ARGS((int, int, struct sigcontext *));
- X# endif
- X#endif
- X
- Xstatic int do_resize = FALSE;
- Xstatic char_u *oldtitle = NULL;
- Xstatic char_u *oldicon = NULL;
- Xstatic char_u *extra_shell_arg = NULL;
- Xstatic int show_shell_mess = TRUE;
- X
- X/*
- X * At this point TRUE and FALSE are defined as 1L and 0L, but we want 1 and 0.
- X */
- X#undef TRUE
- X#define TRUE 1
- X#undef FALSE
- X#define FALSE 0
- X
- X void
- Xmch_write(s, len)
- X char_u *s;
- X int len;
- X{
- X write(1, (char *)s, len);
- X}
- X
- X/*
- X * GetChars(): low level input funcion.
- X * Get a characters from the keyboard.
- X * If wtime == 0 do not wait for characters.
- X * If wtime == n wait a short time for characters.
- X * If wtime == -1 wait forever for characters.
- X */
- X int
- XGetChars(buf, maxlen, wtime)
- X char_u *buf;
- X int maxlen;
- X int wtime; /* don't use "time", MIPS cannot handle it */
- X{
- X int len;
- X
- X if (wtime >= 0)
- X {
- X while (WaitForChar(wtime) == 0) /* no character available */
- X {
- X if (!do_resize) /* return if not interrupted by resize */
- X return 0;
- X set_winsize(0, 0, FALSE);
- X do_resize = FALSE;
- X }
- X }
- X else /* wtime == -1 */
- X {
- X /*
- X * If there is no character available within 'updatetime' seconds
- X * flush all the swap files to disk
- X * Also done when interrupted by SIGWINCH.
- X */
- X if (WaitForChar((int)p_ut) == 0)
- X updatescript(0);
- X }
- X
- X for (;;) /* repeat until we got a character */
- X {
- X if (do_resize) /* window changed size */
- X {
- X set_winsize(0, 0, FALSE);
- X do_resize = FALSE;
- X }
- X /*
- X * we want to be interrupted by the winch signal
- X */
- X WaitForChar(-1);
- X if (do_resize) /* interrupted by SIGWINCHsignal */
- X continue;
- X len = Read(buf, (long)maxlen);
- X if (len > 0)
- X return len;
- X }
- X}
- X
- X/*
- X * return non-zero if a character is available
- X */
- X int
- Xmch_char_avail()
- X{
- X return WaitForChar(0);
- X}
- X
- X long
- Xmch_avail_mem(special)
- X int special;
- X{
- X return 0x7fffffff; /* virual memory eh */
- X}
- X
- X#ifndef FD_ZERO
- X void
- Xvim_delay()
- X{
- X poll(0, 0, 500);
- X}
- X#else
- X# if (defined(__STDC__) && !defined(hpux)) || defined(ultrix)
- Xextern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
- X# endif
- X
- X void
- Xvim_delay()
- X{
- X struct timeval tv;
- X
- X tv.tv_sec = 25 / 50;
- X tv.tv_usec = (25 % 50) * (1000000/50);
- X select(0, 0, 0, 0, &tv);
- X}
- X#endif
- X
- X static void
- X#if defined(__alpha) || (defined(mips) && !defined(USL))
- Xsig_winch()
- X#else
- X# if defined(_SEQUENT_) || defined(SCO) || defined(ISC)
- Xsig_winch(sig, code)
- X int sig;
- X int code;
- X# else
- X# if defined(USL)
- Xsig_winch(sig)
- X int sig;
- X# else
- Xsig_winch(sig, code, scp)
- X int sig;
- X int code;
- X struct sigcontext *scp;
- X# endif
- X# endif
- X#endif
- X{
- X#if defined(SIGWINCH)
- X /* this is not required on all systems, but it doesn't hurt anybody */
- X signal(SIGWINCH, (void (*)())sig_winch);
- X#endif
- X do_resize = TRUE;
- X}
- X
- X/*
- X * If the machine has job control, use it to suspend the program,
- X * otherwise fake it by starting a new shell.
- X */
- X void
- Xmch_suspend()
- X{
- X#ifdef SIGTSTP
- X settmode(0);
- X kill(0, SIGTSTP); /* send ourselves a STOP signal */
- X settmode(1);
- X#else
- X OUTSTR("new shell started\n");
- X (void)call_shell(NULL, 0, TRUE);
- X#endif
- X}
- X
- X void
- Xmch_windinit()
- X{
- X Columns = 80;
- X Rows = 24;
- X
- X flushbuf();
- X
- X (void)mch_get_winsize();
- X#if defined(SIGWINCH)
- X signal(SIGWINCH, (void (*)())sig_winch);
- X#endif
- X}
- X
- X/*
- X * Check_win checks whether we have an interactive window.
- X * If not, a new window is opened with the newcli command.
- X * If we would open a window ourselves, the :sh and :! commands would not
- X * work properly (Why? probably because we are then running in a background CLI).
- X * This also is the best way to assure proper working in a next Workbench release.
- X *
- X * For the -e option (quickfix mode) we open our own window and disable :sh.
- X * Otherwise we would never know when editing is finished.
- X */
- X#define BUF2SIZE 320 /* lenght of buffer for argument with complete path */
- X
- X void
- Xcheck_win(argc, argv)
- X int argc;
- X char **argv;
- X{
- X if (!isatty(0) || !isatty(1))
- X {
- X fprintf(stderr, "VIM: no controlling terminal\n");
- X exit(2);
- X }
- X}
- X
- X/*
- X * fname_case(): Set the case of the filename, if it already exists.
- X * This will cause the filename to remain exactly the same.
- X */
- X void
- Xfname_case(name)
- X char_u *name;
- X{
- X}
- X
- X#ifdef USE_X11
- X/*
- X * try to get x11 window and display
- X *
- X * return FAIL for failure, OK otherwise
- X */
- X static int
- Xget_x11_windis()
- X{
- X char *winid;
- X
- X /*
- X * If WINDOWID not set, should try another method to find out
- X * what the current window number is. The only code I know for
- X * this is very complicated.
- X * We assume that zero is invalid for WINDOWID.
- X */
- X if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
- X x11_window = (Window)atol(winid);
- X if (x11_window != 0 && x11_display == NULL)
- X x11_display = XOpenDisplay(NULL);
- X if (x11_window == 0 || x11_display == NULL)
- X return FAIL;
- X return OK;
- X}
- X
- X/*
- X * Determine original x11 Window Title
- X */
- X static void
- Xget_x11_title()
- X{
- X XTextProperty text_prop;
- X
- X if (get_x11_windis() == OK)
- X {
- X /* Get window name if any */
- X if (XGetWMName(x11_display, x11_window, &text_prop))
- X {
- X if (text_prop.value != NULL)
- X oldtitle = strsave((char_u *)text_prop.value);
- X XFree((void *)text_prop.value);
- X }
- X }
- X if (oldtitle == NULL) /* could not get old title */
- X oldtitle = (char_u *)"Thanks for flying Vim";
- X}
- X
- X/*
- X * Determine original x11 Window icon
- X */
- X
- X static void
- Xget_x11_icon()
- X{
- X XTextProperty text_prop;
- X
- X if (get_x11_windis() == OK)
- X {
- X /* Get icon name if any */
- X if (XGetWMIconName(x11_display, x11_window, &text_prop))
- X {
- X if (text_prop.value != NULL)
- X oldicon = strsave((char_u *)text_prop.value);
- X XFree((void *)text_prop.value);
- X }
- X }
- X
- X /* could not get old icon, use terminal name */
- X if (oldicon == NULL)
- X {
- X if (STRNCMP(term_strings.t_name, "builtin_", 8) == 0)
- X oldicon = term_strings.t_name + 8;
- X else
- X oldicon = term_strings.t_name;
- X }
- X}
- X
- X#if BUGGY
- X
- XThis is not included, because it probably does not work at all.
- XOn my FreeBSD/Xfree86 in a shelltool I get all kinds of error messages and
- XVim is stopped in an uncontrolled way.
- X
- X/*
- X * Set x11 Window Title
- X *
- X * get_x11_windis() must be called before this and have returned OK
- X */
- X static void
- Xset_x11_title(title)
- X char_u *title;
- X{
- X XTextProperty text_prop;
- X
- X /* Get icon name if any */
- X text_prop.value = title;
- X text_prop.nitems = STRLEN(title);
- X XSetWMName(x11_display, x11_window, &text_prop);
- X if (XGetWMName(x11_display, x11_window, &text_prop)) /* required? */
- X XFree((void *)text_prop.value);
- X}
- X
- X/*
- X * Set x11 Window icon
- X *
- X * get_x11_windis() must be called before this and have returned OK
- X */
- X static void
- Xset_x11_icon(icon)
- X char_u *icon;
- X{
- X XTextProperty text_prop;
- X
- X /* Get icon name if any */
- X text_prop.value = icon;
- X text_prop.nitems = STRLEN(icon);
- X XSetWMIconName(x11_display, x11_window, &text_prop);
- X if (XGetWMIconName(x11_display, x11_window, &text_prop)) /* required? */
- X XFree((void *)text_prop.value);
- X}
- X#endif
- X
- X#else /* USE_X11 */
- X
- X static void
- Xget_x11_title()
- X{
- X oldtitle = (char_u *)"Thanks for flying Vim";
- X}
- X
- X static void
- Xget_x11_icon()
- X{
- X if (STRNCMP(term_strings.t_name, "builtin_", 8) == 0)
- X oldicon = term_strings.t_name + 8;
- X else
- X oldicon = term_strings.t_name;
- X}
- X
- X#endif /* USE_X11 */
- X
- X
- X/*
- X * set the window title and icon
- X * Currently only works for x11.
- X */
- X void
- Xmch_settitle(title, icon)
- X char_u *title;
- X char_u *icon;
- X{
- X int type = 0;
- X
- X if (term_strings.t_name == NULL) /* no terminal name (yet) */
- X return;
- X
- X/*
- X * if the window ID and the display is known, we may use X11 calls
- X */
- X#ifdef USE_X11
- X if (get_x11_windis() == OK)
- X type = 1;
- X#endif
- X
- X /*
- X * note: if terminal is xterm, title is set with escape sequence rather
- X * than x11 calls, because the x11 calls don't always work
- X */
- X if ( STRCMP(term_strings.t_name, "xterm") == 0 ||
- X STRCMP(term_strings.t_name, "builtin_xterm") == 0)
- X type = 2;
- X
- X /*
- X * Note: getting the old window title for iris-ansi will only
- X * currently work if you set WINDOWID by hand, it is not
- X * done automatically like an xterm.
- X */
- X if (STRCMP(term_strings.t_name, "iris-ansi") == 0 ||
- X STRCMP(term_strings.t_name, "iris-ansi-net") == 0)
- X type = 3;
- X
- X if (type)
- X {
- X if (title != NULL)
- X {
- X if (oldtitle == NULL) /* first call, save title */
- X get_x11_title();
- X
- X switch(type)
- X {
- X#ifdef USE_X11
- X#ifdef BUGGY
- X case 1: set_x11_title(title); /* x11 */
- X break;
- X#endif
- X#endif
- X case 2: outstrn((char_u *)"\033]2;"); /* xterm */
- X outstrn(title);
- X outchar(Ctrl('G'));
- X flushbuf();
- X break;
- X
- X case 3: outstrn((char_u *)"\033P1.y"); /* iris-ansi */
- X outstrn(title);
- X outstrn((char_u *)"\234");
- X flushbuf();
- X break;
- X }
- X }
- X
- X if (icon != NULL)
- X {
- X if (oldicon == NULL) /* first call, save icon */
- X get_x11_icon();
- X
- X switch(type)
- X {
- X#ifdef USE_X11
- X#ifdef BUGGY
- X case 1: set_x11_icon(icon); /* x11 */
- X break;
- X#endif
- X#endif
- X case 2: outstrn((char_u *)"\033]1;"); /* xterm */
- X outstrn(icon);
- X outchar(Ctrl('G'));
- X flushbuf();
- X break;
- X
- X case 3: outstrn((char_u *)"\033P3.y"); /* iris-ansi */
- X outstrn(icon);
- X outstrn((char_u *)"\234");
- X flushbuf();
- X break;
- X }
- X }
- X }
- X}
- X
- X/*
- X * Restore the window/icon title.
- X * which is one of:
- X * 1 Just restore title
- X * 2 Just restore icon
- X * 3 Restore title and icon
- X */
- X void
- Xmch_restore_title(which)
- X int which;
- X{
- X mch_settitle((which & 1) ? oldtitle : NULL, (which & 2) ? oldicon : NULL);
- X}
- X
- X/*
- X * Get name of current directory into buffer 'buf' of length 'len' bytes.
- X * Return OK for success, FAIL for failure.
- X */
- X int
- Xvim_dirname(buf, len)
- X char_u *buf;
- X int len;
- X{
- X#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
- X extern int errno;
- X extern char *sys_errlist[];
- X
- X if (getcwd((char *)buf, len) == NULL)
- X {
- X STRCPY(buf, sys_errlist[errno]);
- X return FAIL;
- X }
- X return OK;
- X#else
- X return (getwd((char *)buf) != NULL ? OK : FAIL);
- X#endif
- X}
- X
- X/*
- X * get absolute filename into buffer 'buf' of length 'len' bytes
- X *
- X * return FAIL for failure, OK for success
- X */
- X int
- XFullName(fname, buf, len)
- X char_u *fname, *buf;
- X int len;
- X{
- X int l;
- X char_u olddir[MAXPATHL];
- X char_u *p;
- X int c;
- X int retval = OK;
- X
- X if (fname == NULL) /* always fail */
- X {
- X *buf = NUL;
- X return FAIL;
- X }
- X
- X *buf = 0;
- X if (!isFullName(fname)) /* if not an absolute path */
- X {
- X /*
- X * If the file name has a path, change to that directory for a moment,
- X * and then do the getwd() (and get back to where we were).
- X * This will get the correct path name with "../" things.
- X */
- X if ((p = STRRCHR(fname, '/')) != NULL)
- X {
- X#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
- X if (getcwd((char *)olddir, MAXPATHL) == NULL)
- X#else
- X if (getwd((char *)olddir) == NULL)
- X#endif
- X {
- X p = NULL; /* can't get current dir: don't chdir */
- X retval = FAIL;
- X }
- X else
- X {
- X c = *p;
- X *p = NUL;
- X if (chdir((char *)fname))
- X retval = FAIL;
- X else
- X fname = p + 1;
- X *p = c;
- X }
- X }
- X#if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
- X if (getcwd((char *)buf, len) == NULL)
- X#else
- X if (getwd((char *)buf) == NULL)
- X#endif
- X {
- X retval = FAIL;
- X *buf = NUL;
- X }
- X l = STRLEN(buf);
- X if (l && buf[l - 1] != '/')
- X STRCAT(buf, "/");
- X if (p)
- X chdir((char *)olddir);
- X }
- X STRCAT(buf, fname);
- X return retval;
- X}
- X
- X/*
- X * return TRUE is fname is an absolute path name
- X */
- X int
- XisFullName(fname)
- X char_u *fname;
- X{
- X return (*fname == '/');
- X}
- X
- X/*
- X * get file permissions for 'name'
- X */
- X long
- Xgetperm(name)
- X char_u *name;
- X{
- X struct stat statb;
- X
- X if (stat((char *)name, &statb))
- X return -1;
- X return statb.st_mode;
- X}
- X
- X/*
- X * set file permission for 'name' to 'perm'
- X *
- X * return FAIL for failure, OK otherwise
- X */
- X int
- Xsetperm(name, perm)
- X char_u *name;
- X int perm;
- X{
- X#ifdef SCO
- X return (chmod((char *)name, (mode_t)perm) == 0 ? OK : FAIL);
- X#else
- X return (chmod((char *)name, perm) == 0 ? OK : FAIL);
- X#endif
- X}
- X
- X/*
- X * return TRUE if "name" is a directory
- X * return FALSE if "name" is not a directory
- X * return -1 for error
- X */
- X int
- Xisdir(name)
- X char_u *name;
- X{
- X struct stat statb;
- X
- X if (stat((char *)name, &statb))
- X return -1;
- X#ifdef _POSIX_SOURCE
- X return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
- X#else
- X return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
- X#endif
- X}
- X
- X void
- Xmch_windexit(r)
- X int r;
- X{
- X settmode(0);
- X exiting = TRUE;
- X mch_settitle(oldtitle, oldicon); /* restore xterm title */
- X stoptermcap();
- X flushbuf();
- X ml_close_all(); /* remove all memfiles */
- X exit(r);
- X}
- X
- X void
- Xmch_settmode(raw)
- X int raw;
- X{
- X#if defined(ECHOE) && defined(ICANON) && !defined(__NeXT__)
- X /* for "new" tty systems */
- X# ifdef CONVEX
- X static struct termios told;
- X struct termios tnew;
- X# else
- X static struct termio told;
- X struct termio tnew;
- X# endif
- X#ifdef TIOCLGET
- X static unsigned long tty_local;
- X#endif
- X
- X if (raw)
- X {
- X#ifdef TIOCLGET
- X ioctl(0, TIOCLGET, &tty_local);
- X#endif
- X ioctl(0, TCGETA, &told);
- X tnew = told;
- X /*
- X * ICRNL enables typing ^V^M
- X */
- X tnew.c_iflag &= ~ICRNL;
- X tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
- X#ifdef IEXTEN
- X | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
- X#endif
- X );
- X tnew.c_cc[VMIN] = 1; /* return after 1 char */
- X tnew.c_cc[VTIME] = 0; /* don't wait */
- X ioctl(0, TCSETA, &tnew);
- X }
- X else
- X {
- X ioctl(0, TCSETA, &told);
- X#ifdef TIOCLGET
- X ioctl(0, TIOCLSET, &tty_local);
- X#endif
- X }
- X#else
- X# ifndef TIOCSETN
- X# define TIOCSETN TIOCSETP /* for hpux 9.0 */
- X# endif
- X /* for "old" tty systems */
- X static struct sgttyb ttybold;
- X struct sgttyb ttybnew;
- X
- X if (raw)
- X {
- X ioctl(0, TIOCGETP, &ttybold);
- X ttybnew = ttybold;
- X ttybnew.sg_flags &= ~(CRMOD | ECHO);
- X ttybnew.sg_flags |= RAW;
- X ioctl(0, TIOCSETN, &ttybnew);
- X }
- X else
- X ioctl(0, TIOCSETN, &ttybold);
- X#endif
- X}
- X
- X/*
- X * set screen mode, always fails.
- X */
- X int
- Xmch_screenmode(arg)
- X char_u *arg;
- X{
- X EMSG("Screen mode setting not supported");
- X return FAIL;
- X}
- X
- X/*
- X * Try to get the current window size:
- X * 1. with an ioctl(), most accurate method
- X * 2. from the environment variables LINES and COLUMNS
- X * 3. from the termcap
- X * 4. keep using the old values
- X */
- X int
- Xmch_get_winsize()
- X{
- X int old_Rows = Rows;
- X int old_Columns = Columns;
- X char_u *p;
- X
- X Columns = 0;
- X Rows = 0;
- X
- X/*
- X * 1. try using an ioctl. It is the most accurate method.
- X */
- X# ifdef TIOCGSIZE
- X {
- X struct ttysize ts;
- X
- X if (ioctl(0, TIOCGSIZE, &ts) == 0)
- X {
- X Columns = ts.ts_cols;
- X Rows = ts.ts_lines;
- X }
- X }
- X# else /* TIOCGSIZE */
- X# ifdef TIOCGWINSZ
- X {
- X struct winsize ws;
- X
- X if (ioctl(0, TIOCGWINSZ, &ws) == 0)
- X {
- X Columns = ws.ws_col;
- X Rows = ws.ws_row;
- X }
- X }
- X# endif /* TIOCGWINSZ */
- X# endif /* TIOCGSIZE */
- X
- X/*
- X * 2. get size from environment
- X */
- X if (Columns == 0 || Rows == 0)
- X {
- X if ((p = (char_u *)getenv("LINES")))
- X Rows = atoi((char *)p);
- X if ((p = (char_u *)getenv("COLUMNS")))
- X Columns = atoi((char *)p);
- X }
- X
- X#ifdef TERMCAP
- X/*
- X * 3. try reading the termcap
- X */
- X if (Columns == 0 || Rows == 0)
- X {
- X extern void getlinecol();
- X
- X getlinecol(); /* get "co" and "li" entries from termcap */
- X }
- X#endif
- X
- X/*
- X * 4. If everything fails, use the old values
- X */
- X if (Columns <= 0 || Rows <= 0)
- X {
- X Columns = old_Columns;
- X Rows = old_Rows;
- X return FAIL;
- X }
- X
- X check_winsize();
- X
- X/* if size changed: screenalloc will allocate new screen buffers */
- X return OK;
- X}
- X
- X void
- Xmch_set_winsize()
- X{
- X /* should try to set the window size to Rows and Columns */
- X}
- X
- X int
- Xcall_shell(cmd, dummy, cooked)
- X char_u *cmd;
- X int dummy;
- X int cooked;
- X{
- X#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
- X
- X int x;
- X char_u newcmd[1024];
- X
- X flushbuf();
- X
- X if (cooked)
- X settmode(0); /* set to cooked mode */
- X
- X if (cmd == NULL)
- X x = system(p_sh);
- X else
- X {
- X sprintf(newcmd, "%s %s -c \"%s\"", p_sh,
- X extra_shell_arg == NULL ? "" : extra_shell_arg, cmd);
- X x = system(newcmd);
- X }
- X if (x == 127)
- X {
- X outstrn((char_u *)"\nCannot execute shell sh\n");
- X }
- X#ifdef WEBB_COMPLETE
- X else if (x && !expand_interactively)
- X#else
- X else if (x)
- X#endif
- X {
- X outchar('\n');
- X outnum((long)x);
- X outstrn((char_u *)" returned\n");
- X }
- X
- X if (cooked)
- X settmode(1); /* set to raw mode */
- X resettitle();
- X return (x ? FAIL : OK);
- X
- X#else /* USE_SYSTEM */ /* first attempt at not using system() */
- X
- X char_u newcmd[1024];
- X int pid;
- X int status = -1;
- X char **argv = NULL;
- X int argc;
- X int i;
- X char_u *p;
- X int inquote;
- X
- X flushbuf();
- X signal(SIGINT, SIG_IGN); /* we don't want to be killed here */
- X if (cooked)
- X settmode(0); /* set to cooked mode */
- X
- X /*
- X * 1: find number of arguments
- X * 2: separate them and built argv[]
- X */
- X STRCPY(newcmd, p_sh);
- X for (i = 0; i < 2; ++i)
- X {
- X p = newcmd;
- X inquote = FALSE;
- X argc = 0;
- X for (;;)
- X {
- X if (i == 1)
- X argv[argc] = (char *)p;
- X ++argc;
- X while (*p && (inquote || (*p != ' ' && *p != TAB)))
- X {
- X if (*p == '"')
- X inquote = !inquote;
- X ++p;
- X }
- X if (*p == NUL)
- X break;
- X if (i == 1)
- X *p++ = NUL;
- X skipspace(&p);
- X }
- X if (i == 0)
- X {
- X argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
- X if (argv == NULL) /* out of memory */
- X goto error;
- X }
- X }
- X if (cmd != NULL)
- X {
- X if (extra_shell_arg != NULL)
- X argv[argc++] = (char *)extra_shell_arg;
- X argv[argc++] = "-c";
- X argv[argc++] = (char *)cmd;
- X }
- X argv[argc] = NULL;
- X
- X if ((pid = fork()) == -1) /* maybe we should use vfork() */
- X {
- X outstrn((char_u *)"\nCannot fork\n");
- X }
- X else if (pid == 0) /* child */
- X {
- X signal(SIGINT, SIG_DFL);
- X if (!show_shell_mess)
- X {
- X fclose(stdout);
- X fclose(stderr);
- X }
- X execvp(argv[0], (char **)argv);
- X exit(127); /* exec failed, return failure code */
- X }
- X else /* parent */
- X {
- X wait(&status);
- X status = (status >> 8) & 255;
- X if (status)
- X {
- X#ifdef WEBB_COMPLETE
- X if (status == 127)
- X {
- X outstrn((char_u *)"\nCannot execute shell ");
- X outstrn(p_sh);
- X outchar('\n');
- X }
- X else if (!expand_interactively)
- X {
- X outchar('\n');
- X outnum((long)status);
- X outstrn((char_u *)" returned\n");
- X }
- X#else
- X outchar('\n');
- X if (status == 127)
- X {
- X outstrn((char_u *)"Cannot execute shell ");
- X outstrn(p_sh);
- X }
- X else
- X {
- X outnum((long)status);
- X outstrn((char_u *)" returned");
- X }
- X outchar('\n');
- X#endif /* WEBB_COMPLETE */
- X }
- X }
- X free(argv);
- X
- Xerror:
- X if (cooked)
- X settmode(1); /* set to raw mode */
- X resettitle();
- X signal(SIGINT, SIG_DFL);
- X return (status ? FAIL : OK);
- X
- X#endif /* USE_SYSTEM */
- X}
- X
- X/*
- X * The input characters are buffered to be able to check for a CTRL-C.
- X * This should be done with signals, but I don't know how to do that in
- X * a portable way for a tty in RAW mode.
- X */
- X
- X#define INBUFLEN 250
- Xstatic char_u inbuf[INBUFLEN]; /* internal typeahead buffer */
- Xstatic int inbufcount = 0; /* number of chars in inbuf[] */
- X
- X static int
- XRead(buf, maxlen)
- X char_u *buf;
- X long maxlen;
- X{
- X if (inbufcount == 0) /* if the buffer is empty, fill it */
- X fill_inbuf();
- X if (maxlen > inbufcount)
- X maxlen = inbufcount;
- X memmove((char *)buf, (char *)inbuf, maxlen);
- X inbufcount -= maxlen;
- X if (inbufcount)
- X memmove((char *)inbuf, (char *)inbuf + maxlen, inbufcount);
- X return (int)maxlen;
- X}
- X
- X void
- Xbreakcheck()
- X{
- X/*
- X * check for CTRL-C typed by reading all available characters
- X */
- X if (RealWaitForChar(0)) /* if characters available */
- X fill_inbuf();
- X}
- X
- X static void
- Xfill_inbuf()
- X{
- X int len;
- X
- X if (inbufcount >= INBUFLEN) /* buffer full */
- X return;
- X len = read(0, inbuf + inbufcount, (long)(INBUFLEN - inbufcount));
- X if (len <= 0) /* cannot read input??? */
- X {
- X fprintf(stderr, "Vim: Error reading input, exiting...\n");
- X exit(1);
- X }
- X while (len-- > 0)
- X {
- X /*
- X * if a CTRL-C was typed, remove it from the buffer and set got_int
- X */
- X if (inbuf[inbufcount] == 3)
- X {
- X /* remove everything typed before the CTRL-C */
- X memmove((char *)inbuf, (char *)inbuf + inbufcount, len + 1);
- X inbufcount = 0;
- X got_int = TRUE;
- X }
- X ++inbufcount;
- X }
- X}
- X
- X/*
- X * Wait "ticks" until a character is available from the keyboard or from inbuf[]
- X * ticks = -1 will block forever
- X */
- X
- X static int
- XWaitForChar(ticks)
- X int ticks;
- X{
- X if (inbufcount) /* something in inbuf[] */
- X return 1;
- X return RealWaitForChar(ticks);
- X}
- X
- X/*
- X * Wait "ticks" until a character is available from the keyboard
- X * ticks = -1 will block forever
- X */
- X static int
- XRealWaitForChar(ticks)
- X int ticks;
- X{
- X#ifndef FD_ZERO
- X struct pollfd fds;
- X
- X fds.fd = 0;
- X fds.events = POLLIN;
- X return (poll(&fds, 1, ticks));
- X#else
- X struct timeval tv;
- X fd_set fdset;
- X
- X if (ticks >= 0)
- X {
- X tv.tv_sec = ticks / 1000;
- X tv.tv_usec = (ticks % 1000) * (1000000/1000);
- X }
- X
- X FD_ZERO(&fdset);
- X FD_SET(0, &fdset);
- X return (select(1, &fdset, NULL, NULL, (ticks >= 0) ? &tv : NULL));
- X#endif
- X}
- X
- X#if !defined(__alpha) && !defined(mips) && !defined(SCO) && !defined(remove) && !defined(CONVEX)
- X int
- Xremove(buf)
- X# if defined(linux) || defined(__STDC__) || defined(__NeXT__) || defined(M_UNIX)
- X const
- X# endif
- X char *buf;
- X{
- X return unlink(buf);
- X}
- X#endif
- X
- X/*
- X * ExpandWildCard() - this code does wild-card pattern matching using the shell
- X *
- X * Mool: return 0 for success, 1 for error (you may loose some memory) and
- X * put an error message in *file.
- X *
- X * num_pat is number of input patterns
- X * pat is array of pointers to input patterns
- X * num_file is pointer to number of matched file names
- X * file is pointer to array of pointers to matched file names
- X * On Unix we do not check for files only yet
- X * list_notfound is ignored
- X */
- X
- Xextern char *mktemp __ARGS((char *));
- X#ifndef SEEK_SET
- X# define SEEK_SET 0
- X#endif
- X#ifndef SEEK_END
- X# define SEEK_END 2
- X#endif
- X
- X int
- XExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
- X int num_pat;
- X char_u **pat;
- X int *num_file;
- X char_u ***file;
- X int files_only;
- X int list_notfound;
- X{
- X char_u tmpname[TMPNAMELEN];
- X char_u *command;
- X int i;
- X int dir;
- X size_t len;
- X FILE *fd;
- X char_u *buffer;
- X char_u *p;
- X int use_glob = FALSE;
- X
- X *num_file = 0; /* default: no files found */
- X *file = (char_u **)"";
- X
- X /*
- X * If there are no wildcards, just copy the names to allocated memory.
- X * Saves a lot of time, because we don't have to start a new shell.
- X */
- X if (!have_wildcard(num_pat, pat))
- X {
- X *file = (char_u **)alloc(num_pat * sizeof(char_u *));
- X if (*file == NULL)
- X {
- X *file = (char_u **)"";
- X return FAIL;
- X }
- X for (i = 0; i < num_pat; i++)
- X (*file)[i] = strsave(pat[i]);
- X *num_file = num_pat;
- X return OK;
- X }
- X
- X/*
- X * get a name for the temp file
- X */
- X STRCPY(tmpname, TMPNAME2);
- X if (*mktemp((char *)tmpname) == NUL)
- X {
- X emsg(e_notmp);
- X return FAIL;
- X }
- X
- X/*
- X * let the shell expand the patterns and write the result into the temp file
- X * If we use csh, glob will work better than echo.
- X */
- X if ((len = STRLEN(p_sh)) >= 3 && STRCMP(p_sh + len - 3, "csh") == 0)
- X use_glob = TRUE;
- X
- X len = TMPNAMELEN + 11;
- X for (i = 0; i < num_pat; ++i) /* count the length of the patterns */
- X len += STRLEN(pat[i]) + 3;
- X command = alloc(len);
- X if (command == NULL)
- X return FAIL;
- X if (use_glob)
- X STRCPY(command, "glob >"); /* built the shell command */
- X else
- X STRCPY(command, "echo >"); /* built the shell command */
- X STRCAT(command, tmpname);
- X for (i = 0; i < num_pat; ++i)
- X {
- X#ifdef USE_SYSTEM
- X STRCAT(command, " \""); /* need extra quotes because we */
- X STRCAT(command, pat[i]); /* start the shell twice */
- X STRCAT(command, "\"");
- X#else
- X STRCAT(command, " ");
- X STRCAT(command, pat[i]);
- X#endif
- X }
- X#ifdef WEBB_COMPLETE
- X if (expand_interactively)
- X show_shell_mess = FALSE;
- X#endif /* WEBB_COMPLETE */
- X if (use_glob) /* Use csh fast option */
- X extra_shell_arg = (char_u *)"-f";
- X i = call_shell(command, 0, FALSE); /* execute it */
- X extra_shell_arg = NULL;
- X show_shell_mess = TRUE;
- X free(command);
- X if (i == FAIL) /* call_shell failed */
- X {
- X remove((char *)tmpname);
- X#ifdef WEBB_COMPLETE
- X /* With interactive completion, the error message is not printed */
- X if (!expand_interactively)
- X#endif /* WEBB_COMPLETE */
- X {
- X must_redraw = CLEAR; /* probably messed up screen */
- X msg_outchar('\n'); /* clear bottom line quickly */
- X cmdline_row = Rows - 1; /* continue on last line */
- X }
- X return FAIL;
- X }
- X
- X/*
- X * read the names from the file into memory
- X */
- X fd = fopen((char *)tmpname, "r");
- X if (fd == NULL)
- X {
- X emsg2(e_notopen, tmpname);
- X return FAIL;
- X }
- X fseek(fd, 0L, SEEK_END);
- X len = ftell(fd); /* get size of temp file */
- X fseek(fd, 0L, SEEK_SET);
- X buffer = alloc(len + 1);
- X if (buffer == NULL)
- X {
- X remove((char *)tmpname);
- X fclose(fd);
- X return FAIL;
- X }
- X i = fread((char *)buffer, 1, len, fd);
- X fclose(fd);
- X remove((char *)tmpname);
- X if (i != len)
- X {
- X emsg2(e_notread, tmpname);
- X free(buffer);
- X return FAIL;
- X }
- X
- X if (use_glob) /* file names are separated with NUL */
- X {
- X buffer[len] = NUL; /* make sure the buffers ends in NUL */
- X i = 0;
- X for (p = buffer; p < buffer + len; ++p)
- X if (*p == NUL) /* count entry */
- X ++i;
- X if (len)
- X ++i; /* count last entry */
- X }
- X else /* file names are separated with SPACE */
- X {
- X buffer[len] = '\n'; /* make sure the buffers ends in NL */
- X p = buffer;
- X for (i = 0; *p != '\n'; ++i) /* count number of entries */
- X {
- X while (*p != ' ' && *p != '\n') /* skip entry */
- X ++p;
- X skipspace(&p); /* skip to next entry */
- X }
- X }
- X *num_file = i;
- X *file = (char_u **)alloc(sizeof(char_u *) * i);
- X if (*file == NULL)
- X {
- X free(buffer);
- X *file = (char_u **)"";
- X return FAIL;
- X }
- X p = buffer;
- X for (i = 0; i < *num_file; ++i)
- X {
- X (*file)[i] = p;
- X if (use_glob)
- X {
- X while (*p && p < buffer + len) /* skip entry */
- X ++p;
- X ++p; /* skip NUL */
- X }
- X else
- X {
- X while (*p != ' ' && *p != '\n') /* skip entry */
- X ++p;
- X if (*p == '\n') /* last entry */
- X *p = NUL;
- X else
- X {
- X *p++ = NUL;
- X skipspace(&p); /* skip to next entry */
- X }
- X }
- X }
- X for (i = 0; i < *num_file; ++i)
- X {
- X dir = (isdir((*file)[i]) == TRUE);
- X if (dir < 0) /* if file doesn't exist don't add '/' */
- X dir = 0;
- X p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
- X if (p)
- X {
- X STRCPY(p, (*file)[i]);
- X if (dir)
- X STRCAT(p, "/");
- X }
- X (*file)[i] = p;
- X }
- X free(buffer);
- X return OK;
- X}
- X
- X void
- XFreeWild(num, file)
- X int num;
- X char_u **file;
- X{
- X if (file == NULL || num == 0)
- X return;
- X while (num--)
- X free(file[num]);
- X free(file);
- X}
- X
- X int
- Xhas_wildcard(p)
- X char_u *p;
- X{
- X#ifdef __STDC__
- X return strpbrk((char *)p, "*?[{`~$") != NULL;
- X#else
- X for ( ; *p; ++p)
- X if (STRCHR("*?[{`~$", *p) != NULL)
- X return 1;
- X return 0;
- X#endif
- X}
- X
- X int
- Xhave_wildcard(num, file)
- X int num;
- X char_u **file;
- X{
- X register int i;
- X
- X for (i = 0; i < num; i++)
- X if (has_wildcard(file[i]))
- X return 1;
- X return 0;
- X}
- X
- X#if defined(M_XENIX) || defined(UTS2)
- X/*
- X * Scaled-down version of rename, which is missing in Xenix.
- X * This version can only move regular files and will fail if the
- X * destination exists.
- X */
- X int
- Xrename(src, dest)
- X char_u *src, *dest;
- X{
- X struct stat st;
- X
- X if (stat(dest, &st) >= 0) /* fail if destination exists */
- X return -1;
- X if (link(src, dest) != 0) /* link file to new name */
- X return -1;
- X if (unlink(src) == 0) /* delete link to old name */
- X return 0;
- X return -1;
- X}
- X#endif /* M_XENIX || UTS2 */
- END_OF_FILE
- if test 30140 -ne `wc -c <'vim/src/unix.c'`; then
- echo shar: \"'vim/src/unix.c'\" unpacked with wrong size!
- fi
- # end of 'vim/src/unix.c'
- fi
- if test -f 'vim/tools/readme' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vim/tools/readme'\"
- else
- echo shar: Extracting \"'vim/tools/readme'\" \(153 characters\)
- sed "s/^X//" >'vim/tools/readme' <<'END_OF_FILE'
- XSome tools that can be used with Vim:
- X
- Xvim132: shell script to edit in 132 column mode on vt100 compatible terminals
- Xref: shell script for the K command
- END_OF_FILE
- if test 153 -ne `wc -c <'vim/tools/readme'`; then
- echo shar: \"'vim/tools/readme'\" unpacked with wrong size!
- fi
- # end of 'vim/tools/readme'
- fi
- if test -f 'vim/uganda.txt' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vim/uganda.txt'\"
- else
- echo shar: Extracting \"'vim/uganda.txt'\" \(3139 characters\)
- sed "s/^X//" >'vim/uganda.txt' <<'END_OF_FILE'
- XVim is public domain. If you are happy with Vim and want to express that,
- Xdon't send me money. I don't need it. But I know a place where they do need
- Xyour money. Please read on.
- X
- XSummer 1993 I spent one month in Uganda with a Dutch team. I was very
- Ximpressed with what I experienced there. Together with local people we built a
- Xnursery school in Kibaale. In only three weeks from nothing to a roofed
- Xbuilding!
- X
- XKibaale is a small town in the south of Uganda. It is an area that is suffering
- Xfrom AIDS very badly. About 30% of the adults are infected. Because parents
- Xdie, there are many orphans. They need a lot of help. The Kibaale children
- Xcentre is working hard to provide the needy with food, medical care and
- Xeducation. Food and medical care to keep them healthy now, and education so
- Xthat they can take care of themselves in the future. This is the best charity
- Xprogram I have ever encountered.
- X
- XThe key to solving the problems in this area is education. This has been
- Xneglected in the past years with president Idi Amin and the following civil
- Xwars. Now that the governement is stable again the people have to learn how to
- Xtake care of themselves and how to avoid infections. There is also help for
- Xpeople who are ill and hungry, but the primary goal is to prevent people from
- Xgetting ill and learn them how to grow their own crops.
- X
- XI was impressed by the progress that is being made there. The work is very
- Xwell organized. Every dollar is spent on something useful. Our team brought
- Xabout $2000. For that money we were able to built most of a two classroom
- Xnursery school. They have further plans to build a primary school and houses
- Xfor the teachers. They also need money for books and other teaching materials.
- X
- XIf you want to support the Kibaale children centre, please send a contribution.
- X
- XHow do you know that the money will be spent right? First of all you have my
- Xpersonal guarantee as the author of Vim. Further the project is co-sponsored
- Xand inspected by World Vision, Save the Children Fund and International Child
- XCare Fund. I will work for the project as a volunteer from September 1994 to
- XAugust 1995.
- X
- XIf you have any further questions, send me e-mail: mool@oce.nl.
- X
- XThe director of the project is:
- XSekaran Vellasamy
- Xp.o. box 1658
- XMasaka, Uganda, East Africa
- X
- XTransfering money from Holland:
- XUse one of my accounts:
- XRabobank Venlo, nr. 3765.05.117
- XPostbank, nr. 1644503
- X
- XTransfering money from Europe:
- XTo avoid banking costs the best thing is to send me a Eurocheque, written out
- Xto "Bram Moolenaar" in Dutch Guilders (fl). But any other method should work.
- X
- XTransfering money from USA:
- XSend me a check that can be cashed in Holland. Any "standard" banking check
- Xshould be OK. Please consider adding $10 for banking costs.
- X
- XMy address: Bram Moolenaar
- X Kibaale Donation
- X Molenstraat 2
- X 2162 HP Lisse
- X The Netherlands.
- X
- XOr you can transfer the money directly to the director of the project:
- X
- XCitibank, N.A.
- Xa/c no. 36059709
- XGlobal Clearance Services
- X111 Wall Street 16th floor
- XNew York 10043
- XU.S.A.
- XBeneficiary Mr. Sekaran Vellasamy a/c no. 2100, Gold Trust Bank LTD - Kampala
- END_OF_FILE
- if test 3139 -ne `wc -c <'vim/uganda.txt'`; then
- echo shar: \"'vim/uganda.txt'\" unpacked with wrong size!
- fi
- # end of 'vim/uganda.txt'
- fi
- echo shar: End of archive 18 \(of 26\).
- cp /dev/null ark18isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 26 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-