home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume35
/
zsh
/
part12
< prev
next >
Wrap
Text File
|
1993-02-20
|
56KB
|
2,403 lines
Newsgroups: comp.sources.misc
From: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
Subject: v35i062: zsh - The Z Shell, version 2.3.1, Part12/22
Message-ID: <1993Feb20.212458.28891@sparky.imd.sterling.com>
X-Md4-Signature: 0cd86aecea33fc29076b177ff3ea416b
Date: Sat, 20 Feb 1993 21:24:58 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 62
Archive-name: zsh/part12
Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113
#! /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".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents: help/zle src/utils.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:53 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 12 (of 22)."'
if test -f 'help/zle' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/zle'\"
else
echo shar: Extracting \"'help/zle'\" \(19344 characters\)
sed "s/^X//" >'help/zle' <<'END_OF_FILE'
X bindkey -mevd
X bindkey -r in-string ...
X bindkey [ -a ] in-string [ command ] ...
X bindkey -s [ -a ] in-string out-string ...
X If one of the -e, -v, or -d options is given, reset the
X keymaps for emacs mode, vi mode, or the default mode,
X respectively; if the -m option is also given, allow the
X use of a meta key. If the -r option is given, remove
X any binding for each in-string. If the -s option is
X not specified, bind each in-string to a specified com-
X mand. If no command is specified, print the binding of
X in-string if it is bound, or return a nonzero exit code
X if it is not bound. If the -s option is specified,
X bind each in-string to each specified out-string. When
X in-string is typed, out-string will be pushed back and
X treated as input to the line editor. If the -a option
X is specified, bind the in-strings in the alternative
X keymap instead of the standard one. The alternative
X keymap is used in vi command mode.
X
X For either in-string or out-string, control characters
X may be specified in the form ^X, and the backslash may
X be used to introduce one of the following escape
X sequences:
X \a bell character
X \n linefeed (newline)
X \b backspace
X \t horizontal tab
X \v vertical tab
X \f form feed
X \r carriage return
X \e escape
X \nnn character code in octal
X \M-xxx
X character or escape sequence with meta bit
X set
X
X In all other cases, \ escapes the following character.
X Delete is written as `^?'.
X
X vi-backward-blank-word (unbound) (B)
X Move backward one word, where a word is defined as a
X series of non-blank characters.
X
X backward-char (^B ESC-[D) ()
X Move backward one character.
X
X vi-backward-char () (h)
X Move backward one character, without changing lines.
X
X backward-word (ESC-B ESC-b) (unbound)
X Move to the beginning of the previous word.
X
X emacs-backward-word
X Move to the beginning of the previous word.
X
X vi-backward-word (unbound) (b)
X Move to the beginning of the previous word, vi-style.
X
X beginning-of-line (^A) (0)
X Move to the beginning of the line. If already at the
X beginning of the line, move to the beginning of the
X previous line, if any.
X
X vi-beginning-of-line
X Move to the beginning of the line, without changing
X lines.
X
X end-of-line (^E)
X Move to the end of the line. If already at the end of
X the line, move to the end of the next line, if any.
X
X vi-end-of-line (unbound) ($)
X Move to the end of the line.
X
X vi-forward-blank-word (unbound) (W)
X Move forward one word, where a word is defined as a
X series of non-blank characters.
X
X vi-forward-blank-word-end (unbound) (E)
X Move to the end of the current word, or, if at the end
X of the current word, to the end of the next word, where
X a word is defined as a series of non-blank characters.
X
X forward-char (^F ESC-[C)
X Move forward one character.
X
X vi-forward-char (unbound) (space l)
X Move forward one character.
X
X vi-find-next-char (^X^F) (f)
X Read a character from the keyboard, and move to the
X next occurrence of it in the line.
X
X vi-find-next-char-skip (unbound) (t)
X Read a character from the keyboard, and move to the
X position just before the next occurrence of it in the
X line.
X
X vi-find-prev-char (unbound) (F)
X Read a character from the keyboard, and move to the
X previous occurrence of it in the line.
X
X vi-find-prev-char-skip (unbound) (T)
X Read a character from the keyboard, and move to the
X position just after the previous occurrence of it in
X the line.
X
X vi-first-non-blank (unbound) (^)
X Move to the first non-blank character in the line.
X
X vi-forward-word (unbound) (w)
X Move forward one word, vi-style.
X
X forward-word (ESC-F ESC-f) (unbound)
X Move to the beginning of the next word. The editor's
X idea of a word is specified with the WORDCHARS parame-
X ter.
X
X emacs-forward-word
X Move to the end of the next word.
X
X vi-forward-word-end (unbound) (e)
X Move to the end of the next word.
X
X vi-goto-column (ESC-|) (|)
X Move to the column specified by the numeric argument.
X
X vi-goto-mark (unbound) (`)
X Move to the specified mark.
X
X vi-goto-mark-line (unbound) (')
X Move to beginning of the line containing the specified
X mark.
X
X vi-repeat-find (unbound) (;)
X Repeat the last vi-find command.
X
X vi-rev-repeat-find (unbound) (,)
X Repeat the last vi-find command in the opposite direc-
X tion.
X
X beginning-of-buffer-or-history (ESC-<)
X Move to the beginning of the buffer, or if already
X there, move to the first event in the history list.
X
X beginning-of-line-hist
X Move to the beginning of the line. If already at the
X beginning of the buffer, move to the previous history
X line.
X
X beginning-of-history
X Move to the first event in the history list.
X
X down-line-or-history (^N ESC-[B) (+ j)
X Move down a line in the buffer, or if already at the
X bottom line, move to the next event in the history
X list.
X
X down-history (unbound) (^N)
X Move to the next event in the history list.
X
X end-of-buffer-or-history (ESC->)
X Move to the end of the buffer, or if already there,
X move to the last event in the history list.
X
X end-of-line-hist
X Move to the end of the line. If already at the end of
X the buffer, move to the next history line.
X
X end-of-history
X Move to the last event in the history list.
X
X vi-fetch-history (unbound) (G)
X Fetch the history line specified by the numeric argu-
X ment.
X
X history-incremental-search-backward (^R ^Xr)
X Search backward incrementally for a specified string.
X The string may begin with `^' to anchor the search to
X the beginning of the line.
X
X history-incremental-search-forward (^Xs)
X Search forward incrementally for a specified string.
X The string may begin with `^' to anchor the search to
X the beginning of the line.
X
X history-search-backward (ESC-P ESC-p) (K)
X Search backward in the history for a line beginning
X with the first word in the buffer.
X
X vi-history-search-backward (unbound) (/)
X Search backward in the history for a specified string.
X The string may begin with `^' to anchor the search to
X the beginning of the line.
X
X history-search-forward (ESC-N ESC-n) (J)
X Search forward in the history for a line beginning with
X the first word in the buffer.
X
X vi-history-search-forward (unbound) (?)
X Search forward in the history for a specified string.
X The string may begin with `^' to anchor the search to
X the beginning of the line.
X
X infer-next-history (^X^N)
X Search in the history list for a line matching the
X current one and fetch the event following it.
X
X insert-last-word (ESC-_ ESC-.)
X Insert the last word from the previous history event at
X the cursor position.
X
X vi-repeat-search (unbound) (n)
X Repeat the last vi history search.
X
X vi-rev-repeat-search (unbound) (N)
X Repeat the last vi history search, but in reverse.
X
X toggle-literal-history (ESC-R ESC-r)
X Toggle between literal and lexical history. The
X default is lexical history unless the HISTLIT option is
X set.
X
X up-line-or-history (^P ESC-[A) (- k)
X Move up a line in the buffer, or if already at the top
X line, move to the previous event in the history list.
X
X up-history (unbound) (^P)
X Move to the previous event in the history list.
X
X vi-add-eol (unbound) (A)
X Move to the end of the line and enter insert mode.
X
X vi-add-next (unbound) (a)
X Move forward one character and enter insert mode.
X
X backward-delete-char (^H ^?) (^?)
X Delete the character behind the cursor.
X
X vi-backward-delete-char (unbound) (X)
X Delete the character behind the cursor, without chang-
X ing lines.
X
X backward-delete-word
X Delete the word behind the cursor.
X
X backward-kill-line
X Kill from the beginning of the line to the cursor posi-
X tion.
X
X backward-kill-word (^W ESC-^H ESC-^?)
X Kill the word behind the cursor.
X
X vi-backward-kill-word (unbound) (^W)
X Kill the word behind the cursor.
X
X capitalize-word (ESC-C ESC-c)
X Capitalize the current word and move past it.
X
X vi-change (unbound) (c)
X Read a movement command from the keyboard, and kill
X from the cursor position to the endpoint of the move-
X ment. Then enter insert mode. If the command is vi-
X change, kill the current line.
X
X vi-change-eol (unbound) (C)
X Kill to the end of the line and enter insert mode.
X
X vi-change-whole-line (unbound) (S s)
X Kill the current line and enter insert mode.
X
X copy-region-as-kill (ESC-W ESC-w)
X Copy the area from the cursor to the mark to the kill
X buffer.
X
X copy-prev-word (ESC-^_)
X Duplicate the word behind the cursor.
X
X vi-delete (unbound) (d)
X Read a movement command from the keyboard, and kill
X from the cursor position to the endpoint of the move-
X ment. If the command is vi-delete, kill the current
X line.
X
X delete-char (unbound) (x)
X Delete the character under the cursor.
X
X vi-delete-char (unbound) (x)
X Delete the character under the cursor.
X
X delete-word (ESC-D ESC-d)
X Delete the current word.
X
X down-case-word (ESC-L ESC-l)
X Convert the current word to all lowercase and move past
X it.
X
X kill-word
X Kill the current word.
X
X gosmacs-transpose-chars
X Exchange the two characters behind the cursor.
X
X vi-indent (unbound) (>)
X Indent a number of lines.
X
X vi-insert (unbound) (i)
X Enter insert mode.
X
X vi-insert-bol (unbound) (I)
X Move to the beginning of the line and enter insert
X mode.
X
X vi-join (^X^J)
X Join the current line with the next one.
X
X kill-line (^K) (D)
X Kill from the cursor to the end of the line.
X
X kill-region
X Kill from the cursor to the mark.
X
X kill-buffer (^X^U) (^U)
X Kill the entire buffer.
X
X kill-whole-line (^U) (unbound)
X Kill the current line.
X
X vi-match-bracket (^X^B) (%)
X Move to the bracket character (one of {}, (), or [])
X that matches the one under the cursor.
X
X vi-open-line-above (unbound) (O)
X Open a line above the cursor and enter insert mode.
X
X vi-open-line-below (unbound) (o)
X Open a line below the cursor and enter insert mode.
X
X vi-oper-swap-case
X Read a movement command from the keyboard, and swap the
X case of all characters from the cursor position to the
X endpoint of the movement. If the movement command is
X vi-oper-swap-case, swap the case of all characters on
X the current line.
X
X overwrite-mode (^X^O)
X Toggle between overwrite mode and insert mode.
X
X vi-put-after (unbound) (p)
X Insert the contents of the kill buffer after the cur-
X sor.
X
X quoted-insert (^V)
X Insert the next character typed into the buffer
X literally.
X
X quote-line (ESC-')
X Quote the current line; that is, put a ' character at
X the beginning and the end, and convert all ' characters
X to '\''.
X
X quote-region (ESC-")
X Quote the region from the cursor to the mark.
X
X vi-replace (unbound) (R)
X Enter overwrite mode.
X
X vi-repeat-change (unbound) (.)
X Repeat the last vi mode text modification.
X
X vi-replace-chars (unbound) (r)
X Replace the character under the cursor with a character
X read from the keyboard.
X
X self-insert (printable characters)
X Put a character in the buffer at the cursor position.
X
X self-insert-unmeta (ESC-^I ESC-^J ESC-^M)
X Put a character in the buffer after stripping the meta
X bit and converting ^M to ^J.
X
X vi-substitute (unbound) (s)
X Substitute the next character(s).
X
X vi-swap-case (unbound) (~)
X Swap the case of the character under the cursor and
X move past it.
X
X transpose-chars (^T)
X Exchange the two characters to the left of the cursor
X if at end of line, else exchange the character under
X the cursor with the character to the left.
X
X transpose-words (ESC-T ESC-t)
X Exchange the current word with the one before it.
X
X vi-unindent (unbound) (<)
X Unindent a number of lines.
X
X up-case-word (ESC-U ESC-u)
X Convert the current word to all caps and move past it.
X
X yank (^Y) (P)
X Insert the contents of the kill buffer at the cursor
X position.
X
X yank-pop (ESC-y) (unbound)
X Remove the text just yanked, rotate the kill-ring, and
X yank the new top. Only works following yank or yank-
X pop.
X
X vi-yank (unbound) (y)
X Read a movement command from the keyboard, and copy the
X region from the cursor position to the endpoint of the
X movement into the kill buffer. If the command is vi-
X yank, copy the current line.
X
X vi-yank-eol (unbound) (Y)
X Copy the region from the cursor position to the end of
X the line into the kill buffer.
X
X digit-argument (ESC-0..ESC-9) (0-9)
X Start a new numeric argument, or add to the current
X one.
X
X universal-argument
X Multiply the argument of the next command by 4.
X
X accept-and-menu-complete
X In a menu completion, insert the current completion
X into the buffer, and advance to the next possible com-
X pletion.
X
X complete-word (unbound) (\)
X Attempt completion on the current word.
X
X delete-char-or-list (^D)
X Delete the character under the cursor. If the cursor
X is at the end of the line, list possible completions
X for the current word.
X
X execute-named-cmd (ESC-x)
X Read the name of a editor command and execute it.
X
X execute-last-named-cmd (ESC-z)
X Redo the last function executed with execute-named-cmd.
X
X expand-cmd-path
X Expand the current command to its full pathname.
X
X expand-or-complete (TAB) (TAB ^X)
X Attempt shell expansion on the current word. If that
X fails, attempt completion.
X
X expand-history (ESC-space ESC-!)
X Perform history expansion on the edit buffer.
X
X expand-word (^X*)
X Attempt shell expansion on the current word.
X
X list-choices (ESC-^D) (^D =)
X List possible completions for the current word.
X
X list-expand (^Xg ^XG) (^G)
X List the expansion of the current word.
X
X magic-space
X Perform history expansion and insert a space into the
X buffer. This is intended to be bound to space.
X
X menu-complete
X Like complete-word, except that menu completion is
X used. See the MENU_COMPLETE option below.
X
X menu-expand-or-complete
X Like expand-or-complete, except that menu completion is
X used.
X
X reverse-menu-complete
X See the MENU_COMPLETE option below.
X
X accept-and-hold (ESC-A ESC-a)
X Push the contents of the buffer on the buffer stack and
X execute it.
X
X accept-and-infer-next-history
X Execute the contents of the buffer. Then search the
X history list for a line matching the current one and
X push the event following onto the buffer stack.
X
X accept-line (^J ^M)
X Execute the contents of the buffer.
X
X accept-line-and-down-history (^O)
X Execute the current line, and push the next history
X event on the the buffer stack.
X
X vi-cmd-mode (^X^V) (^[)
X Enter command mode; that is, use the alternate keymap.
X Yes, this is bound by default in emacs mode.
X
X vi-caps-lock-panic (unbound) (H K)
X Hang until any lowercase key is pressed. This is for
X vi users without the mental capacity to keep track of
X their caps lock key (like the author).
X
X clear-screen (^L ESC-^L)
X Clear the screen and redraw the prompt.
X
X exchange-point-and-mark (^X^X)
X Exchange the cursor position with the position of the
X mark.
X
X get-line (ESC-G ESC-g)
X Pop the top line off the buffer stack and insert it at
X the cursor position.
X
X pound-insert (unbound) (#)
X If there is no # character at the beginning of the
X current line, add one. If there is one, remove it. In
X either case, accept the current line. The
X INTERACTIVE_COMMENTS option must be set for this to
X have any usefulness.
X
X push-line (^Q ESC-Q ESC-q)
X Push the current buffer onto the buffer stack and clear
X the buffer. Next time the editor starts up, the buffer
X will be popped off the top of the buffer stack and
X loaded into the editing buffer.
X
X redisplay (unbound) (^R)
X Redisplays the edit buffer.
X
X run-help (ESC-H ESC-h)
X Push the buffer onto the buffer stack, and execute the
X command "run-help cmd", where cmd is the current com-
X mand. run-help is normally aliased to man.
X
X send-break (^C)
X Abort the parsing of the current line.
X
X vi-set-buffer (unbound) (")
X Specify a buffer to be used in the following command.
X
X vi-set-mark (unbound) (m)
X Set the specified mark at the cursor position.
X
X set-mark-command (^@)
X Set the mark at the cursor position.
X
X spell-word (ESC-$ ESC-S ESC-s)
X Attempt spelling correction on the current word.
X
X undefined-key
X Beep.
X
X undo (^_ ^X^U) (u)
X Incrementally undo the last text modification.
X
X which-command (ESC-?)
X Push the buffer onto the buffer stack, and execute the
X command "which-command cmd", where cmd is the current
X command. which-command is normally aliased to whence.
END_OF_FILE
if test 19344 -ne `wc -c <'help/zle'`; then
echo shar: \"'help/zle'\" unpacked with wrong size!
fi
# end of 'help/zle'
fi
if test -f 'src/utils.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/utils.c'\"
else
echo shar: Extracting \"'src/utils.c'\" \(32015 characters\)
sed "s/^X//" >'src/utils.c' <<'END_OF_FILE'
X/*
X *
X * utils.c - miscellaneous utilities
X *
X * This file is part of zsh, the Z shell.
X *
X * This software is Copyright 1992 by Paul Falstad
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made.
X *
X * The author make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk.
X *
X */
X
X#include "zsh.h"
X#include <pwd.h>
X#include <errno.h>
X#include <fcntl.h>
X
X/* source a file */
X
Xint source(s) /**/
Xchar *s;
X{
Xint fd,cj = thisjob;
Xint oldlineno = lineno,oldshst;
XFILE *obshin = bshin;
X
X fd = SHIN;
X lineno = 0;
X oldshst = opts[SHINSTDIN];
X opts[SHINSTDIN] = OPT_UNSET;
X if ((SHIN = movefd(open(s,O_RDONLY))) == -1)
X {
X SHIN = fd;
X thisjob = cj;
X opts[SHINSTDIN] = oldshst;
X return 1;
X }
X bshin = fdopen(SHIN,"r");
X loop(0);
X fclose(bshin);
X bshin = obshin;
X opts[SHINSTDIN] = oldshst;
X SHIN = fd;
X thisjob = cj;
X errflag = 0;
X retflag = 0;
X lineno = oldlineno;
X return 0;
X}
X
X/* try to source a file in the home directory */
X
Xvoid sourcehome(s) /**/
Xchar *s;
X{
Xchar buf[MAXPATHLEN];
Xchar *h;
X
X if (!(h = getsparam("ZDOTDIR")))
X h = home;
X sprintf(buf,"%s/%s",h,s);
X (void) source(buf);
X}
X
X/* print an error */
X
Xvoid zerrnam(cmd,fmt,str,num) /**/
Xchar *cmd; char *fmt; char *str;int num;
X{
X if (cmd)
X {
X if (errflag || noerrs)
X return;
X errflag = 1;
X trashzle();
X if (isset(SHINSTDIN))
X fprintf(stderr,"%s: ",cmd);
X else
X fprintf(stderr,"%s: %s: ",argzero,cmd);
X }
X while (*fmt)
X if (*fmt == '%')
X {
X fmt++;
X switch(*fmt++)
X {
X case 's':
X while (*str)
X niceputc(*str++,stderr);
X break;
X case 'l':
X while (num--)
X niceputc(*str++,stderr);
X break;
X case 'd':
X fprintf(stderr,"%d",num);
X break;
X case '%':
X putc('%',stderr);
X break;
X case 'c':
X niceputc(num,stderr);
X break;
X case 'e':
X if (num == EINTR)
X {
X fputs("interrupt\n",stderr);
X errflag = 1;
X return;
X }
X if (num == EIO)
X fputs(sys_errlist[num],stderr);
X else
X {
X fputc(tulower(sys_errlist[num][0]),stderr);
X fputs(sys_errlist[num]+1,stderr);
X }
X break;
X }
X }
X else
X putc(*fmt++,stderr);
X if (unset(SHINSTDIN) && lineno)
X fprintf(stderr," [%ld]\n",lineno);
X else
X putc('\n',stderr);
X fflush(stderr);
X}
X
Xvoid zerr(fmt,str,num) /**/
Xchar *fmt; char *str;int num;
X{
X if (errflag || noerrs)
X return;
X errflag = 1;
X trashzle();
X fprintf(stderr,"%s: ",(isset(SHINSTDIN)) ? "zsh" : argzero);
X zerrnam(NULL,fmt,str,num);
X}
X
Xvoid niceputc(c,f) /**/
Xint c;FILE *f;
X{
X if (itok(c))
X {
X if (c >= Pound && c <= Comma)
X putc(ztokens[c-Pound],f);
X return;
X }
X c &= 0xff;
X if (isprint(c))
X putc(c,f);
X else if (c == '\n')
X {
X putc('\\',f);
X putc('n',f);
X }
X else
X {
X putc('^',f);
X putc(c|'@',f);
X }
X}
X
X/* enable ^C interrupts */
X
Xvoid intr() /**/
X{
X#ifdef SV_INTERRUPT
Xstatic struct sigvec vec = { handler,sigmask(SIGINT),SV_INTERRUPT };
X
X if (interact)
X sigvec(SIGINT,&vec,NULL);
X#else
X if (interact)
X signal(SIGINT,handler);
X#endif
X}
X
Xvoid noholdintr() /**/
X{
X intr();
X}
X
Xvoid holdintr() /**/
X{
X#ifdef SV_INTERRUPT
Xstatic struct sigvec vec = { handler,sigmask(SIGINT),0 };
X
X if (interact) sigvec(SIGINT,&vec,NULL);
X#else
X if (interact) signal(SIGINT,SIG_IGN);
X#endif
X}
X
X/* get a symlink-free pathname for s relative to PWD */
X
Xchar *findpwd(s) /**/
Xchar *s;
X{
Xchar *t;
X
X if (*s == '/')
X return xsymlink(s);
X s = tricat((pwd[1]) ? pwd : "","/",s);
X t = xsymlink(s);
X free(s);
X return t;
X}
X
Xstatic char xbuf[MAXPATHLEN];
X
X#if 0
Xchar *fixpwd(s) /**/
Xchar *s;
X{
Xstruct stat sbuf,tbuf;
Xchar *t;
X
X strcpy(xbuf,"");
X if (*s == '/')
X t = ztrdup(s);
X else
X t = tricat((pwd[1]) ? pwd : "","/",s);
X (void) xsymlinks(t+1,0);
X free(t);
X if (!*xbuf)
X strcpy(xbuf,"/");
X if (stat(xbuf,&sbuf) == 0 && stat(".",&tbuf) == 0)
X if (!(sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino))
X chdir(xbuf);
X return ztrdup(xbuf);
X}
X#endif
X
Xint ispwd(s) /**/
Xchar *s;
X{
Xstruct stat sbuf,tbuf;
X
X if (stat(s,&sbuf) == 0 && stat(".",&tbuf) == 0)
X if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
X return 1;
X return 0;
X}
X
X/* expand symlinks in s, and remove other weird things */
X
Xchar *xsymlink(s) /**/
Xchar *s;
X{
X if (unset(CHASELINKS))
X return ztrdup(s);
X if (*s != '/')
X return NULL;
X strcpy(xbuf,"");
X if (xsymlinks(s+1,1))
X return ztrdup(s);
X if (!*xbuf)
X return ztrdup("/");
X return ztrdup(xbuf);
X}
X
Xchar **slashsplit(s) /**/
Xchar *s;
X{
Xchar *t,**r,**q;
Xint t0;
X
X if (!*s)
X return (char **) zcalloc(sizeof(char **));
X for (t = s, t0 = 0; *t; t++)
X if (*t == '/')
X t0++;
X q = r = (char **) zalloc(sizeof(char **)*(t0+2));
X while (t = strchr(s,'/'))
X {
X *t = '\0';
X *q++ = ztrdup(s);
X *t = '/';
X while (*t == '/')
X t++;
X if (!*t)
X {
X *q = NULL;
X return r;
X }
X s = t;
X }
X *q++ = ztrdup(s);
X *q = NULL;
X return r;
X}
X
Xint islink(s) /**/
Xchar *s;
X{
X return readlink(s,NULL,0) == 0;
X}
X
X/* expands symlinks and .. or . expressions */
X/* if flag = 0, only expand .. and . expressions */
X
Xint xsymlinks(s,flag) /**/
Xchar *s;int flag;
X{
Xchar **pp,**opp;
Xchar xbuf2[MAXPATHLEN],xbuf3[MAXPATHLEN];
Xint t0;
X
X opp = pp = slashsplit(s);
X for (; *pp; pp++)
X {
X if (!strcmp(*pp,"."))
X {
X free(*pp);
X continue;
X }
X if (!strcmp(*pp,".."))
X {
X char *p;
X
X free(*pp);
X if (!strcmp(xbuf,"/"))
X continue;
X p = xbuf+strlen(xbuf);
X while (*--p != '/');
X *p = '\0';
X continue;
X }
X if (unset(CHASELINKS))
X {
X strcat(xbuf,"/");
X strcat(xbuf,*pp);
X free(*pp);
X continue;
X }
X sprintf(xbuf2,"%s/%s",xbuf,*pp);
X t0 = readlink(xbuf2,xbuf3,MAXPATHLEN);
X if (t0 == -1 || !flag)
X {
X strcat(xbuf,"/");
X strcat(xbuf,*pp);
X free(*pp);
X }
X else
X {
X xbuf3[t0] = '\0'; /* STUPID */
X if (*xbuf3 == '/')
X {
X strcpy(xbuf,"");
X if (xsymlinks(xbuf3+1,flag))
X return 1;
X }
X else
X if (xsymlinks(xbuf3,flag))
X return 1;
X free(*pp);
X }
X }
X free(opp);
X return 0;
X}
X
X/* print a directory */
X
Xvoid fprintdir(s, f) /**/
Xchar *s; FILE *f;
X{
Xint t0;
X
X t0 = finddir(s);
X if (t0 == -1)
X {
X fputs(s,f);
X }
X else
X {
X putc('~', f);
X fputs(usernames[t0],f);
X fputs(s+strlen(userdirs[t0]),f);
X }
X}
X
Xvoid printdir(s) /**/
Xchar *s;
X{
X fprintdir(s, stdout);
X}
X
Xvoid printdircr(s) /**/
Xchar *s;
X{
X fprintdir(s, stdout);
X putchar('\n');
X}
X
X/* see if a path has a named directory as its prefix */
X/* Modified by Carl Edman, cedman@golem.ps.uci.edu.
X Exhaustive search is more expensive, but binary search just doesn't
X handle all the cases for directory prefixes very well.
X Caching improves performance */
X
Xint finddir(s) /**/
Xchar *s;
X{
Xint t0,t1 = -1;
Xint bestlen = -1,len,bestnlen = -1,nlen;
Xint hash;
Xstatic int cdir = -1,cval = -1;
X
X if (!s) /* Invalidate directory cache table */
X {
X cval = -1;
X return -1;
X }
X if (!userdirsz) return -1;
X
X hash = hasher(s);
X
X if (cval != -1 && cval == hash) return cdir;
X
X for(t0 = 0; t0 < userdirsz; t0++)
X if (userdirs[t0] && !dircmp(userdirs[t0],s))
X {
X len = strlen(userdirs[t0]);
X nlen = strlen(usernames[t0]);
X if ((len > bestlen) || ((len == bestlen) && (nlen < bestnlen)))
X {
X t1 = t0;
X bestlen = len;
X bestnlen = nlen;
X }
X }
X cval = hash;
X cdir = t1;
X return t1;
X}
X
X/* add a named directory */
X
Xvoid adduserdir(s,t) /**/
Xchar *s;char *t;
X{
Xint t0,t1;
X
X if (!interact || ((t0 = finddir(t)) != -1 && !strcmp(s,usernames[t0])))
X return;
X if (!strcmp(t,"/"))
X return;
X if ((t0 = finddir(t)) != -1 && !strcmp(s,usernames[t0]))
X return;
X finddir(0); /* Invalidate directory cache table */
X if (userdirsz == userdirct)
X {
X userdirsz *= 2;
X userdirs = (char **) realloc((char *) userdirs,
X sizeof(char **)*userdirsz);
X usernames = (char **) realloc((char *) usernames,
X sizeof(char **)*userdirsz);
X for (t0 = userdirct; t0 != userdirsz; t0++)
X userdirs[t0] = usernames[t0] = NULL;
X }
X for (t0 = 0; t0 != userdirct; t0++)
X if (strcmp(userdirs[t0],t) > 0)
X break;
X for (t1 = userdirct-1; t1 >= t0; t1--)
X {
X userdirs[t1+1] = userdirs[t1];
X usernames[t1+1] = usernames[t1];
X }
X userdirs[t0] = ztrdup(t);
X usernames[t0] = ztrdup(s);
X userdirct++;
X}
X
Xint dircmp(s,t) /**/
Xchar *s;char *t;
X{
X for (; *s && *t; s++,t++)
X if (*s != *t)
X return *s-*t;
X if (!*s && (!*t || *t == '/'))
X return 0;
X return *s-*t;
X}
X
Xint ddifftime(t1,t2) /**/
Xtime_t t1;time_t t2;
X{
X return ((long) t2-(long) t1);
X}
X
X/* see if jobs need printing */
X
Xvoid scanjobs() /**/
X{
Xint t0;
X
X for (t0 = 1; t0 != MAXJOB; t0++)
X if (jobtab[t0].stat & STAT_CHANGED)
X printjob(jobtab+t0,0);
X}
X
X/* do pre-prompt stuff */
X
Xvoid preprompt() /**/
X{
Xint diff;
XList list;
Xstruct schedcmd *sch,*schl;
X
X if (unset(NOTIFY))
X scanjobs();
X if (errflag)
X return;
X if (list = getshfunc("precmd")) doshfuncnoval(list,NULL,0);
X if (errflag)
X return;
X if (period && (time(NULL) > lastperiod+period) &&
X (list = getshfunc("periodic"))) {
X doshfuncnoval(list,NULL,0);
X lastperiod = time(NULL);
X }
X if (errflag)
X return;
X if (watch)
X {
X diff = (int) ddifftime(lastwatch,time(NULL));
X if (diff > logcheck)
X {
X dowatch();
X lastwatch = time(NULL);
X }
X }
X if (errflag)
X return;
X diff = (int) ddifftime(lastmailcheck,time(NULL));
X if (diff > mailcheck)
X {
X if (mailpath && *mailpath)
X checkmailpath(mailpath);
X else if (mailfile)
X {
X char *x[2];
X
X x[0] = mailfile;
X x[1] = NULL;
X checkmailpath(x);
X }
X lastmailcheck = time(NULL);
X }
X for (schl = (struct schedcmd *) &schedcmds, sch = schedcmds; sch;
X sch = (schl = sch)->next)
X {
X if (sch->time < time(NULL))
X {
X execstring(sch->cmd);
X schl->next = sch->next;
X free(sch->cmd);
X free(sch);
X }
X if (errflag)
X return;
X }
X}
X
Xint arrlen(s) /**/
Xchar **s;
X{
Xint t0;
X
X for (t0 = 0; *s; s++,t0++);
X return t0;
X}
X
Xvoid checkmailpath(s) /**/
Xchar **s;
X{
Xstruct stat st;
Xchar *v,*u,c;
X
X while (*s)
X {
X for (v = *s; *v && *v != '?'; v++);
X c = *v;
X *v = '\0';
X if (c != '?')
X u = NULL;
X else
X u = v+1;
X if (stat(*s,&st) == -1)
X {
X if (errno != ENOENT)
X zerr("%e: %s",*s,errno);
X }
X else if (S_ISDIR(st.st_mode))
X {
X Lklist l;
X DIR *lock = opendir(*s);
X char buf[MAXPATHLEN*2],**arr,**ap;
X struct direct *de;
X int ct = 1;
X
X if (lock)
X {
X pushheap();
X heapalloc();
X l = newlist();
X readdir(lock); readdir(lock);
X while (de = readdir(lock))
X {
X if (errflag)
X break;
X if (u)
X sprintf(buf,"%s/%s?%s",*s,de->d_name,u);
X else
X sprintf(buf,"%s/%s",*s,de->d_name);
X addnode(l,strdup(buf));
X ct++;
X }
X closedir(lock);
X ap = arr = (char **) alloc(ct*sizeof(char *));
X while (*ap++ = ugetnode(l));
X checkmailpath(arr);
X popheap();
X }
X }
X else
X {
X if (st.st_size && st.st_atime <= st.st_mtime &&
X st.st_mtime > lastmailcheck)
X if (!u)
X {
X fprintf(stderr,"You have new mail.\n");
X fflush(stderr);
X }
X else
X {
X char *z = u;
X
X while (*z)
X if (*z == '$' && z[1] == '_')
X {
X fprintf(stderr,"%s",*s);
X z += 2;
X }
X else
X fputc(*z++,stderr);
X fputc('\n',stderr);
X fflush(stderr);
X }
X if (isset(MAILWARNING) && st.st_atime > st.st_mtime &&
X st.st_atime > lastmailcheck && st.st_size)
X {
X fprintf(stderr,"The mail in %s has been read.\n",*s);
X fflush(stderr);
X }
X }
X *v = c;
X s++;
X }
X}
X
Xvoid saveoldfuncs(x,y) /**/
Xchar *x;Cmdnam y;
X{
XCmdnam cc;
X
X if (y->type == SHFUNC || y->type == DISABLED)
X {
X cc = (Cmdnam) zcalloc(sizeof *cc);
X *cc = *y;
X y->u.list = NULL;
X addhnode(ztrdup(x),cc,cmdnamtab,freecmdnam);
X }
X}
X
X/* create command hashtable */
X
Xvoid newcmdnamtab() /**/
X{
XHashtab oldcnt;
X
X oldcnt = cmdnamtab;
X permalloc();
X cmdnamtab = newhtable(101);
X addbuiltins();
X if (oldcnt) {
X listhtable(oldcnt,(HFunc) saveoldfuncs);
X freehtab(oldcnt,freecmdnam);
X }
X lastalloc();
X pathchecked = path;
X}
X
Xvoid freecmdnam(a) /**/
Xvptr a;
X{
Xstruct cmdnam *c = (struct cmdnam *) a;
X
X if (c->type == SHFUNC) {
X if (c->u.list)
X freestruct(c->u.list);
X } else if (c->type != BUILTIN && c->type != DISABLED)
X free(c->u.nam);
X free(c);
X}
X
Xvoid freecompctl(a) /**/
Xvptr a;
X{
XCompctl cc = (Compctl) a;
X
X free(cc);
X}
X
Xvoid freestr(a) /**/
Xvptr a;
X{
X free(a);
X}
X
Xvoid freeanode(a) /**/
Xvptr a;
X{
Xstruct alias *c = (struct alias *) a;
X
X free(c->text);
X free(c);
X}
X
Xvoid freepm(a) /**/
Xvptr a;
X{
Xstruct param *pm = (Param) a;
X
X free(pm);
X}
X
Xvoid restoretty() /**/
X{
X settyinfo(&shttyinfo);
X}
X
Xvoid gettyinfo(ti) /**/
Xstruct ttyinfo *ti;
X{
X if (SHTTY != -1)
X {
X#ifdef TERMIOS
X#ifdef HAS_TCCRAP
X if (tcgetattr(SHTTY,&ti->tio) == -1)
X#else
X if (ioctl(SHTTY,TCGETS,&ti->tio) == -1)
X#endif
X zerr("bad tcgets: %e",NULL,errno);
X#else
X#ifdef TERMIO
X ioctl(SHTTY,TCGETA,&ti->tio);
X#else
X ioctl(SHTTY,TIOCGETP,&ti->sgttyb);
X ioctl(SHTTY,TIOCLGET,&ti->lmodes);
X ioctl(SHTTY,TIOCGETC,&ti->tchars);
X ioctl(SHTTY,TIOCGLTC,&ti->ltchars);
X#endif
X#endif
X#ifdef TIOCGWINSZ
X if (ioctl(SHTTY,TIOCGWINSZ,&ti->winsize) == -1)
X /* zerr("bad tiocgwinsz: %e",NULL,errno)*/;
X#endif
X }
X}
X
Xvoid settyinfo(ti) /**/
Xstruct ttyinfo *ti;
X{
X if (SHTTY != -1)
X {
X#ifdef TERMIOS
X#ifdef HAS_TCCRAP
X#ifndef TCSADRAIN
X#define TCSADRAIN 1 /* XXX Princeton's include files are screwed up */
X#endif
X if (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1)
X#else
X if (ioctl(SHTTY,TCSETS,&ti->tio) == -1)
X#endif
X /* zerr("settyinfo: %e",NULL,errno)*/;
X#else
X#ifdef TERMIO
X ioctl(SHTTY,TCSETA,&ti->tio);
X#else
X ioctl(SHTTY,TIOCSETN,&ti->sgttyb);
X ioctl(SHTTY,TIOCLSET,&ti->lmodes);
X ioctl(SHTTY,TIOCSETC,&ti->tchars);
X ioctl(SHTTY,TIOCSLTC,&ti->ltchars);
X#endif
X#endif
X#ifdef TIOCGWINSZ
X signal(SIGWINCH,SIG_IGN);
X if (ioctl(SHTTY,TIOCSWINSZ,&ti->winsize) == -1)
X /* zerr("settyinfo: %e",NULL,errno)*/;
X signal(SIGWINCH,handler);
X#endif
X }
X}
X
X#define SANEKEY(X) \
X if (ti->X == -1 && savedttyinfo.X != -1) ti->X = savedttyinfo.X;
X
Xvoid sanetty(ti) /**/
Xstruct ttyinfo *ti;
X{
Xint t0;
X
X#ifdef TIO
X ti->tio.c_lflag |= ICANON|ECHO;
X#ifdef FLUSHO
X ti->tio.c_lflag &= ~FLUSHO;
X#endif
X for (t0 = 0; t0 !=
X#ifdef NCCS
X NCCS
X#else
X NCC
X#endif
X ; t0++)
X if (ti->tio.c_cc[t0] == VDISABLEVAL &&
X savedttyinfo.tio.c_cc[t0] != VDISABLEVAL)
X ti->tio.c_cc[t0] = savedttyinfo.tio.c_cc[t0];
X#else
X ti->sgttyb.sg_flags = (ti->sgttyb.sg_flags & ~CBREAK) | ECHO;
X ti->lmodes &= ~LFLUSHO;
X SANEKEY(tchars.t_quitc);
X SANEKEY(tchars.t_startc);
X SANEKEY(tchars.t_stopc);
X SANEKEY(ltchars.t_suspc);
X SANEKEY(ltchars.t_dsuspc);
X SANEKEY(ltchars.t_lnextc);
X SANEKEY(ltchars.t_flushc);
X#endif
X}
X
Xvoid adjustwinsize() /**/
X{
X#ifdef TIOCGWINSZ
X ioctl(SHTTY,TIOCGWINSZ,&shttyinfo.winsize);
X if (!(columns = shttyinfo.winsize.ws_col)) columns = 80;
X lines = shttyinfo.winsize.ws_row;
X setintenv("COLUMNS",columns);
X setintenv("LINES",lines);
X if (zleactive) refresh();
X#endif
X}
X
Xint zyztem(s,t) /**/
Xchar *s;char *t;
X{
Xint cj = thisjob;
X
X s = tricat(s," ",t);
X execstring(s); /* Depends on recursion condom in execute() */
X free(s);
X thisjob = cj;
X return lastval;
X}
X
X#ifndef WAITPID
X
X/* fork a process and wait for it to complete without confusing
X the SIGCHLD handler */
X
Xint waitfork() /**/
X{
Xint pipes[2];
Xchar x;
X
X pipe(pipes);
X if (!fork())
X {
X close(pipes[0]);
X signal(SIGCHLD,SIG_DFL);
X if (!fork())
X return 0;
X wait(NULL);
X _exit(0);
X }
X close(pipes[1]);
X read(pipes[0],&x,1);
X close(pipes[0]);
X return 1;
X}
X
X#endif
X
X/* move a fd to a place >= 10 */
X
Xint movefd(fd) /**/
Xint fd;
X{
Xint fe;
X
X if (fd == -1)
X return fd;
X#ifdef F_DUPFD
X fe = fcntl(fd,F_DUPFD,10);
X#else
X if ((fe = dup(fd)) < 10)
X fe = movefd(fe);
X#endif
X close(fd);
X return fe;
X}
X
X/* move fd x to y */
X
Xvoid redup(x,y) /**/
Xint x;int y;
X{
X if (x != y)
X {
X dup2(x,y);
X close(x);
X }
X}
X
Xvoid settrap(t0,l) /**/
Xint t0;List l;
X{
XCmd c;
X
X if (l)
X {
X c = l->left->left->left;
X if (c->type == SIMPLE && empty(c->args) && empty(c->redir)
X && empty(c->vars) && !c->flags)
X l = NULL;
X }
X if (t0 == -1)
X return;
X if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
X || t0 == SIGPIPE))
X {
X zerr("can't trap SIG%s in interactive shells",sigs[t0-1],0);
X return;
X }
X if (!l)
X {
X sigtrapped[t0] = 2;
X if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
X#ifdef SIGWINCH
X t0 != SIGWINCH &&
X#endif
X t0 != SIGHUP) signal(t0,SIG_IGN);
X }
X else
X {
X if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
X#ifdef SIGWINCH
X t0 != SIGWINCH &&
X#endif
X t0 != SIGHUP) signal(t0,handler);
X sigtrapped[t0] = 1;
X permalloc();
X sigfuncs[t0] = (List) dupstruct(l);
X heapalloc();
X }
X}
X
Xvoid unsettrap(t0) /**/
Xint t0;
X{
X if (t0 == -1)
X return;
X if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
X || t0 == SIGPIPE)) {
X return;
X }
X sigtrapped[t0] = 0;
X if (t0 == SIGINT) intr();
X else if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
X#ifdef SIGWINCH
X t0 != SIGWINCH &&
X#endif
X t0 != SIGHUP) signal(t0,SIG_DFL);
X if (sigfuncs[t0]) freestruct(sigfuncs[t0]);
X}
X
Xvoid dotrap(sig) /**/
Xint sig;
X{
Xint sav,savval;
X
X sav = sigtrapped[sig];
X savval = lastval;
X if (sav == 2)
X return;
X sigtrapped[sig] = 2;
X if (sigfuncs[sig]) {
X lexsave();
X doshfuncnoval(sigfuncs[sig],NULL,0);
X lexrestore();
X }
X if (sigtrapped[sig])
X sigtrapped[sig] = sav;
X lastval = savval;
X}
X
X/* copy len chars from t into s, and null terminate */
X
Xvoid ztrncpy(s,t,len) /**/
Xchar *s;char *t;int len;
X{
X while (len--) *s++ = *t++;
X *s = '\0';
X}
X
X/* copy t into *s and update s */
X
Xvoid strucpy(s,t) /**/
Xchar **s;char *t;
X{
Xchar *u = *s;
X
X while (*u++ = *t++);
X *s = u-1;
X}
X
Xvoid struncpy(s,t,n) /**/
Xchar **s;char *t;int n;
X{
Xchar *u = *s;
X
X while (n--)
X *u++ = *t++;
X *s = u;
X *u = '\0';
X}
X
Xint checkrmall(s) /**/
Xchar *s;
X{
X fflush(stdin);
X if (*s == '/')
X fprintf(stderr,"zsh: sure you want to delete all the files in %s? ",s);
X else
X fprintf(stderr,"zsh: sure you want to delete all the files in %s/%s? ",
X (pwd[1]) ? pwd : "",s);
X fflush(stderr);
X feep();
X return (getquery() == 'y');
X}
X
Xint getquery() /**/
X{
Xchar c;
Xlong val;
X
X setcbreak();
X#ifdef FIONREAD
X ioctl(SHTTY,FIONREAD,&val);
X if (val) { unsetcbreak(); write(2,"n\n",2); return 'n'; }
X#endif
X if (read(SHTTY,&c,1) == 1)
X if (c == 'y' || c == 'Y' || c == '\t') c = 'y';
X unsetcbreak();
X if (c != '\n')
X write(2,"\n",1);
X return (int) c;
X}
X
Xstatic int d;
Xstatic char *guess,*best;
X
Xvoid spscannodis(s,cn) /**/
Xchar *s;char *cn;
X{
X if (((Cmdnam) cn)->type != DISABLED)
X spscan(s,NULL);
X}
X
Xvoid spscan(s,junk) /**/
Xchar *s;char *junk;
X{
Xint nd;
X
X nd = spdist(s,guess,strlen(guess)/4+1);
X if (nd <= d) {
X best = s;
X d = nd;
X }
X}
X
X/* spellcheck a word */
X/* fix s and s2 ; if s2 is non-null, fix the history list too */
X
Xvoid spckword(s,s2,tptr,cmd,ask) /**/
Xchar **s;char **s2;char **tptr;int cmd;int ask;
X{
Xchar *t,*u;
Xchar firstchar;
Xint x;
Xint pram = 0;
X
X if (**s == '-' || **s == '%')
X return;
X if (!strcmp(*s,"in"))
X return;
X if (!(*s)[0] || !(*s)[1]) return;
X if (gethnode(*s,cmdnamtab) || gethnode(*s,aliastab)) return;
X t = *s;
X if (*t == Tilde || *t == Equals || *t == String) t++;
X for (; *t; t++) if (itok(*t)) return;
X best = NULL;
X for (t = *s; *t; t++) if (*t == '/') break;
X if (**s == String) {
X if (*t) return;
X pram = 1;
X guess = *s+1;
X d = 100;
X listhtable(paramtab,spscan);
X } else {
X if ((u = spname(guess = *s)) != *s)
X best = u;
X if (!*t && !cmd) {
X if (access(*s,F_OK) == 0) return;
X if (hashcmd(*s,pathchecked)) return;
X guess = *s;
X d = 100;
X listhtable(aliastab,spscan);
X listhtable(cmdnamtab,spscan);
X }
X }
X if (errflag) return;
X if (best && strlen(best) > 1 && strcmp(best,guess)) {
X if (ask) {
X char *pp;
X int junk;
X
X rstring = best; Rstring = guess;
X firstchar = *guess;
X if (*guess == Tilde) *guess = '~';
X else if (*guess == String) *guess = '$';
X else if (*guess == Equals) *guess = '=';
X pp = putprompt(sprompt,&junk,1);
X *guess = firstchar;
X fprintf(stderr,"%s",pp);
X fflush(stderr);
X feep();
X x = getquery();
X } else
X x = 'y';
X if (x == 'y') {
X if (!pram) {
X *s = strdup(best);
X } else {
X *s = alloc(strlen(best)+2);
X strcpy(*s+1,best);
X **s = String;
X }
X if (s2) {
X if (*tptr && !strcmp(hlastw,*s2) && hlastw < hptr) {
X char *z;
X hptr = hlastw;
X if (pram) hwaddc('$');
X for (z = best; *z; z++) hwaddc(*z);
X hwaddc(HISTSPACE);
X *tptr = hptr-1;
X **tptr = '\0';
X }
X *s2 = strdup(best);
X }
X } else if (x == 'a') {
X histdone |= HISTFLAG_NOEXEC;
X } else if (x == 'e') {
X histdone |= HISTFLAG_NOEXEC|HISTFLAG_RECALL;
X }
X }
X}
X
Xint ztrftime(buf,bufsize,fmt,tm) /**/
Xchar *buf;int bufsize;char *fmt;struct tm *tm;
X{
Xstatic char *astr[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
Xstatic char *estr[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
X "Aug","Sep","Oct","Nov","Dec"};
Xstatic char *lstr[] = {"12"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9",
X "10","11"};
Xchar tmp[3];
X#ifdef HAS_STRFTIME
Xchar *origbuf = buf;
X#endif
X
X tmp[0] = '%'; tmp[2] = '\0';
X while (*fmt)
X if (*fmt == '%')
X {
X fmt++;
X switch(*fmt++)
X {
X case 'a':
X strucpy(&buf,astr[tm->tm_wday]);
X break;
X case 'b':
X strucpy(&buf,estr[tm->tm_mon]);
X break;
X case 'd':
X *buf++ = '0'+tm->tm_mday/10;
X *buf++ = '0'+tm->tm_mday%10;
X break;
X case 'e':
X if (tm->tm_mday > 9)
X *buf++ = '0'+tm->tm_mday/10;
X *buf++ = '0'+tm->tm_mday%10;
X break;
X case 'k':
X if (tm->tm_hour > 9)
X *buf++ = '0'+tm->tm_hour/10;
X *buf++ = '0'+tm->tm_hour%10;
X break;
X case 'l':
X strucpy(&buf,lstr[tm->tm_hour%12]);
X break;
X case 'm':
X *buf++ = '0'+(tm->tm_mon+1)/10;
X *buf++ = '0'+(tm->tm_mon+1)%10;
X break;
X case 'M':
X *buf++ = '0'+tm->tm_min/10;
X *buf++ = '0'+tm->tm_min%10;
X break;
X case 'p':
X *buf++ = (tm->tm_hour > 11) ? 'p' : 'a';
X *buf++ = 'm';
X break;
X case 'S':
X *buf++ = '0'+tm->tm_sec/10;
X *buf++ = '0'+tm->tm_sec%10;
X break;
X case 'y':
X *buf++ = '0'+tm->tm_year/10;
X *buf++ = '0'+tm->tm_year%10;
X break;
X default:
X#ifdef HAS_STRFTIME
X *buf = '\0';
X tmp[1] = fmt[-1];
X strftime(buf,bufsize-strlen(origbuf),tmp,tm);
X buf += strlen(buf);
X#else
X *buf++ = '%';
X *buf++ = fmt[-1];
X#endif
X break;
X }
X }
X else
X *buf++ = *fmt++;
X *buf = '\0';
X return 0;
X}
X
Xchar *join(arr,delim) /**/
Xchar **arr;int delim;
X{
Xint len = 0;
Xchar **s,*ret,*ptr;
Xstatic char *lastmem = NULL;
X
X for (s = arr; *s; s++)
X len += strlen(*s)+1;
X if (!len) return "";
X if (lastmem) free(lastmem);
X lastmem = ptr = ret = zalloc(len);
X for (s = arr; *s; s++) {
X strucpy(&ptr,*s);
X *ptr++ = delim;
X }
X ptr[-1] = '\0';
X return ret;
X}
X
Xchar *spacejoin(s) /**/
Xchar **s;
X{
X return join(s,*ifs);
X}
X
Xchar *colonjoin(s) /**/
Xchar **s;
X{
X return join(s,':');
X}
X
Xchar **colonsplit(s) /**/
Xchar *s;
X{
Xint ct;
Xchar *t,**ret,**ptr;
X
X for (t = s, ct = 0; *t; t++) if (*t == ':') ct++;
X ptr = ret = (char **) zalloc(sizeof(char **)*(ct+2));
X t = s;
X do {
X for (s = t; *t && *t != ':'; t++);
X *ptr = zalloc((t-s)+1);
X ztrncpy(*ptr++,s,t-s);
X }
X while (*t++);
X *ptr = NULL;
X return ret;
X}
X
Xchar **spacesplit(s) /**/
Xchar *s;
X{
Xint ct;
Xchar *t,**ret,**ptr;
X
X for (t = s, ct = 0; *t; t++)
X if (isep(*t)) ct++;
X ptr = ret = (char **) zalloc(sizeof(char **)*(ct+2));
X t = s;
X do {
X for (s = t; *t && !isep(*t); t++);
X *ptr = zalloc((t-s)+1);
X ztrncpy(*ptr++,s,t-s);
X } while (*t++);
X *ptr = NULL;
X return ret;
X}
X
XList getshfunc(nam) /**/
Xchar *nam;
X{
XCmdnam x = (Cmdnam) gethnode(nam,cmdnamtab);
X
X return (x && x->type == SHFUNC) ? x->u.list : NULL;
X}
X
X/* allocate a tree element */
X
Xvptr allocnode(type) /**/
Xint type;
X{
Xint t0;
Xstruct node *n = (struct node *) alloc(sizeof *n);
Xstatic int typetab[N_COUNT][4] = {
X {NT_NODE,NT_NODE,0,0},
X {NT_NODE,NT_NODE,0,0},
X {NT_NODE,NT_NODE,0,0},
X {NT_STR|NT_LIST,NT_NODE,NT_NODE|NT_LIST,NT_NODE|NT_LIST},
X {NT_STR,0,0,0},
X {NT_NODE,NT_NODE,0,0},
X {NT_STR,NT_NODE,0,0},
X {NT_NODE,NT_STR,NT_NODE,0},
X {NT_NODE,NT_NODE,NT_NODE,0},
X {NT_NODE,NT_NODE,0,0},
X {NT_STR,NT_STR,NT_STR|NT_LIST,0}
X };
X
X n->type = type;
X for (t0 = 0; t0 != 4; t0++)
X n->types[t0] = typetab[type][t0];
X return (vptr) n;
X}
X
X/* duplicate a syntax tree */
X
Xvptr dupstruct(a) /**/
Xvptr a;
X{
Xstruct node *n = a,*m;
Xint t0;
X
X if (!a) return NULL;
X m = alloc(sizeof *m);
X *m = *n;
X for (t0 = 0; t0 != 4; t0++)
X if (m->ptrs[t0])
X switch(m->types[t0])
X {
X case NT_NODE: m->ptrs[t0] = dupstruct(m->ptrs[t0]); break;
X case NT_STR: m->ptrs[t0] =
X (useheap) ? strdup(m->ptrs[t0]) : ztrdup(m->ptrs[t0]); break;
X case NT_LIST|NT_NODE:
X m->ptrs[t0] = duplist(m->ptrs[t0],dupstruct); break;
X case NT_LIST|NT_STR:
X m->ptrs[t0] = duplist(m->ptrs[t0],(VFunc)
X ((useheap) ? strdup : ztrdup));
X break;
X }
X return (vptr) m;
X}
X
X/* free a syntax tree */
X
Xvoid freestruct(a) /**/
Xvptr a;
X{
Xstruct node *n = (struct node *) a;
Xint t0;
X
X for (t0 = 0; t0 != 4; t0++)
X if (n->ptrs[t0])
X switch(n->types[t0])
X {
X case NT_NODE: freestruct(n->ptrs[t0]); break;
X case NT_STR: free(n->ptrs[t0]); break;
X case NT_LIST|NT_STR: freetable(n->ptrs[t0],freestr); break;
X case NT_LIST|NT_NODE: freetable(n->ptrs[t0],freestruct); break;
X }
X free(n);
X}
X
XLklist duplist(l,func) /**/
XLklist l;VFunc func;
X{
XLklist ret;
XLknode node;
X
X ret = newlist();
X for (node = firstnode(l); node; incnode(node))
X addnode(ret,func(getdata(node)));
X return ret;
X}
X
Xchar **mkarray(s) /**/
Xchar *s;
X{
Xchar **t = (char **) zalloc((s) ? (2*sizeof s) : (sizeof s));
X
X if (*t = s) t[1] = NULL;
X return t;
X}
X
Xvoid feep() /**/
X{
X if (unset(NOBEEP))
X write(2,"\07",1);
X}
X
Xvoid freearray(s) /**/
Xchar **s;
X{
Xchar **t = s;
X
X while (*s)
X free(*s++);
X free(t);
X}
X
Xint equalsplit(s,t) /**/
Xchar *s;char **t;
X{
X for (; *s && *s != '='; s++);
X if (*s == '=')
X {
X *s++ = '\0';
X *t = s;
X return 1;
X }
X return 0;
X}
X
X/* see if the right side of a list is trivial */
X
Xvoid simplifyright(l) /**/
XList l;
X{
XCmd c;
X
X if (!l->right)
X return;
X if (l->right->right || l->right->left->right ||
X l->right->left->flags || l->right->left->left->right ||
X l->left->flags)
X return;
X c = l->left->left->left;
X if (c->type != SIMPLE || full(c->args) || full(c->redir)
X || full(c->vars))
X return;
X l->right = NULL;
X return;
X}
X
X/* initialize the ztypes table */
X
Xvoid inittyptab() /**/
X{
Xint t0;
Xchar *s;
X
X for (t0 = 0; t0 != 256; t0++)
X typtab[t0] = 0;
X for (t0 = 0; t0 != 32; t0++)
X typtab[t0] = typtab[t0+128] = ICNTRL;
X typtab[127] = ICNTRL;
X for (t0 = '0'; t0 <= '9'; t0++)
X typtab[t0] = IDIGIT|IALNUM|IWORD|IIDENT|IUSER;
X for (t0 = 'a'; t0 <= 'z'; t0++)
X typtab[t0] = typtab[t0-'a'+'A'] = IALPHA|IALNUM|IIDENT|IUSER|IWORD;
X for (t0 = 0240; t0 != 0400; t0++)
X typtab[t0] = IALPHA|IALNUM|IIDENT|IUSER|IWORD;
X typtab['_'] = IIDENT|IUSER;
X typtab['-'] = IUSER;
X typtab[' '] |= IBLANK|INBLANK;
X typtab['\t'] |= IBLANK|INBLANK;
X typtab['\n'] |= INBLANK;
X for (t0 = (int) STOUC(ALPOP); t0 <= (int) STOUC(Nularg);
X t0++)
X typtab[t0] |= ITOK;
X for (s = ifs; *s; s++)
X typtab[(int) (unsigned char) *s] |= ISEP;
X for (s = wordchars; *s; s++)
X typtab[(int) (unsigned char) *s] |= IWORD;
X for (s = SPECCHARS; *s; s++)
X typtab[(int) (unsigned char) *s] |= ISPECIAL;
X}
X
Xchar **arrdup(s) /**/
Xchar **s;
X{
Xchar **x,**y;
X
X y = x = (char **) ncalloc(sizeof(char *)*(arrlen(s)+1));
X while (*x++ = strdup(*s++));
X return y;
X}
X
X/* next few functions stolen (with changes) from Kernighan & Pike */
X/* "The UNIX Programming Environment" (w/o permission) */
X
Xchar *spname (oldname) /**/
Xchar *oldname;
X{
X char *p,guess[MAXPATHLEN+1],best[MAXPATHLEN+1];
X static char newname[MAXPATHLEN+1];
X char *new = newname, *old;
X
X if (itok(*oldname)) {
X singsub(&oldname);
X if (!oldname) return NULL;
X }
X if (access(oldname,F_OK) == 0) return NULL;
X old = oldname;
X for (;;) {
X while (*old == '/') *new++ = *old++;
X *new = '\0';
X if (*old == '\0') return newname;
X p = guess;
X for (; *old != '/' && *old != '\0'; old++)
X if (p < guess+MAXPATHLEN) *p++ = *old;
X *p = '\0';
X if (mindist(newname,guess,best) >= 3) return NULL;
X for (p = best; *new = *p++; ) new++;
X }
X}
X
Xint mindist(dir,guess,best) /**/
Xchar *dir;char *guess;char *best;
X{
X int d,nd;
X DIR *dd;
X struct direct *de;
X char buf[MAXPATHLEN];
X
X if (dir[0] == '\0')
X dir = ".";
X d = 100;
X sprintf(buf,"%s/%s",dir,guess);
X if (access(buf,F_OK) == 0) { strcpy(best,guess); return 0; }
X if (!(dd = opendir(dir))) return d;
X while (de = readdir(dd)) {
X nd = spdist(de->d_name,guess,strlen(guess)/4+1);
X if (nd <= d) {
X strcpy(best,de->d_name);
X d = nd;
X if (d == 0) break;
X }
X }
X closedir(dd);
X return d;
X}
X
Xint spdist(s,t,thresh) /**/
Xchar *s;char *t;int thresh;
X{
Xchar *p,*q;
Xchar *keymap =
X"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
X\t1234567890-=\t\
X\tqwertyuiop[]\t\
X\tasdfghjkl;'\n\t\
X\tzxcvbnm,./\t\t\t\
X\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
X\t!@#$%^&*()_+\t\
X\tQWERTYUIOP{}\t\
X\tASDFGHJKL:\"\n\t\
X\tZXCVBNM<>?\n\n\t\
X\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
X
X if (!strcmp(s,t))
X return 0;
X /* any number of upper/lower mistakes allowed (dist = 1) */
X for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++,q++);
X if (!*p && !*q)
X return 1;
X if (!thresh)
X return 200;
X for (p = s, q = t; *p && *q; p++,q++)
X if (*p == *q) continue; /* don't consider "aa" transposed, ash */
X else if (p[1] == q[0] && q[1] == p[0]) /* transpositions */
X return spdist(p+2,q+2,thresh-1)+1;
X else if (p[1] == q[0]) /* missing letter */
X return spdist(p+1,q+0,thresh-1)+2;
X else if (p[0] == q[1]) /* missing letter */
X return spdist(p+0,q+1,thresh-1)+2;
X else if (*p != *q)
X break;
X if ((!*p && strlen(q) == 1) || (!*q && strlen(p) == 1))
X return 2;
X for (p = s, q = t; *p && *q; p++,q++)
X if (p[0] != q[0] && p[1] == q[1])
X {
X int t0;
X char *z;
X
X /* mistyped letter */
X
X if (!(z = strchr(keymap,p[0])) || *z == '\n' || *z == '\t')
X return spdist(p+1,q+1,thresh-1)+1;
X t0 = z-keymap;
X if (*q == keymap[t0-15] || *q == keymap[t0-14] ||
X *q == keymap[t0-13] ||
X *q == keymap[t0-1] || *q == keymap[t0+1] ||
X *q == keymap[t0+13] || *q == keymap[t0+14] ||
X *q == keymap[t0+15])
X return spdist(p+1,q+1,thresh-1)+2;
X return 200;
X }
X else if (*p != *q)
X break;
X return 200;
X}
X
Xchar *zgetenv(s) /**/
Xchar *s;
X{
Xchar **av,*p,*q;
X
X for (av = environ; *av; av++)
X {
X for (p = *av, q = s; *p && *p != '=' && *q && *p == *q; p++,q++);
X if (*p == '=' && !*q)
X return p+1;
X }
X return NULL;
X}
X
Xint tulower(c) /**/
Xint c;
X{
X c &= 0xff;
X return (isupper(c) ? tolower(c) : c);
X}
X
Xint tuupper(c) /**/
Xint c;
X{
X c &= 0xff;
X return (islower(c) ? toupper(c) : c);
X}
X
X#ifdef SYSV
X#include <sys/utsname.h>
X
Xint gethostname(nameptr, maxlength)
Xchar *nameptr;
Xint maxlength;
X{
Xstruct utsname name;
Xint result;
X
X result = uname(&name);
X if (result >= 0) {
X strncpy(nameptr,name.nodename,maxlength);
X return 0;
X } else return -1;
X}
X#endif
X
X/* set cbreak mode, or the equivalent */
X
Xvoid setcbreak() /**/
X{
Xstruct ttyinfo ti;
X
X ti = shttyinfo;
X#ifdef TIO
X ti.tio.c_lflag &= ~ICANON;
X ti.tio.c_cc[VMIN] = 1;
X ti.tio.c_cc[VTIME] = 0;
X#else
X ti.sgttyb.sg_flags |= CBREAK;
X#endif
X settyinfo(&ti);
X}
X
Xint getlineleng() /**/
X{
Xint z;
X
X#ifdef TIOCSWINSZ
X z = shttyinfo.winsize.ws_col;
X return (z) ? z : 80;
X#else
X return 80;
X#endif
X}
X
Xvoid unsetcbreak() /**/
X{
X settyinfo(&shttyinfo);
X}
X
X/* give the tty to some process */
X
Xvoid attachtty(pgrp) /**/
Xlong pgrp;
X{
Xstatic int ep = 0;
X
X if (jobbing) {
X#ifdef HAS_TCSETPGRP
X if (SHTTY != -1 && tcsetpgrp(SHTTY,pgrp) == -1 && !ep)
X#else
X int arg = pgrp;
X if (SHTTY != -1 && ioctl(SHTTY,TIOCSPGRP,&arg) == -1 && !ep)
X#endif
X {
X zerr("can't set tty pgrp: %e",NULL,errno);
X fflush(stderr);
X opts[MONITOR] = OPT_UNSET;
X ep =1;
X errflag = 0;
X }
X }
X}
X
X/* get the tty pgrp */
X
Xlong gettygrp() /**/
X{
Xint arg;
X
X if (SHTTY == -1) return -1;
X#ifdef HAS_TCSETPGRP
X arg = tcgetpgrp(SHTTY);
X#else
X ioctl(SHTTY,TIOCGPGRP,&arg);
X#endif
X return arg;
X}
END_OF_FILE
if test 32015 -ne `wc -c <'src/utils.c'`; then
echo shar: \"'src/utils.c'\" unpacked with wrong size!
fi
# end of 'src/utils.c'
fi
echo shar: End of archive 12 \(of 22\).
cp /dev/null ark12isdone
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 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 22 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...