File:  [MW Coherent from dump] / coherent / f / tmp / ksh / ksh4.7.tar
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:40 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

./pdksh/  2755    653   1762           0  5302773755   7360 5ustar  hlu./pdksh/README   644    653   1762       11455  5243743631  10316 0ustar  hlu		Public Domain Korn Shell
		      Version 4.5

PD KSH:

This is the latest version of the PD ksh (pdksh).  It is not
intended to be the ultimate shell but rather a usable ksh work
alike.  For those of us who have to work on multiple systems it
is nice to have the same user interface on all.  I resisted
moving to the ksh on a Bull system at work for nearly a year due
to the lack of a ksh on my Sun systems.  When I first picked up
the 3.2 PD KSH a couple of years ago, it took only a few minutes
to convert a C-shell fan to a ksh fan :-)  Pdksh is not 100%
compatible with the ksh.  Having said that, I use it daily
beside a real ksh88 and find them virtually indistinguishable.

I only run this shell on sun's and only for interactive use.  I
use it on sun4c, sun3 and sun386 systems.  The shell itself has
been compiled on each of these both with and without the
POSIX/ANSI compatability libraries in ./std.  See the file
MACHINES for details of systems that the shell has been built
on.

I have released this version of the shell (with the kind
permission of the previous maintainers and major contributors) to
ensure that it is available from usenet archive sites.  Of
course it remains in the Public Domain.  Equally obviously
neither myself nor any other contributors make any claims of
suitability etc.  Ie. NO WARRANTY!!!  If you make any changes
and distribute them, please leave your own finger prints in the
source.  Its bad enough being flamed for my own bugs let alone
anyone elses :-)

WHATS NEW:

This update includes Job Control for System V (POSIX), many bug
fixes and a simple history file mechanism.  See sh/ChangeLog.

HISTORY:

This shell was written by Eric Gisin.  It is based on Charles
Forsyth's public domain V7 shell, which he later contributed to
Minix.  John R MacMillan picked up Eric Gisin's version after
Eric moved on to other projects (see ReadMe.jrm).

Since then there have been many contributors to this shell.
Most have left their fingerprints within the source and various
ReadMe.xxx and Changes.xxx files reflect their input.

This version is basically that known as Eric Gisin's version 3.3
alpha which I obtained indirectly from John R MacMillan who is
the most recent maintainer.  This version has much improved
emacs-mode command line editing (my main contribution) plus
enough extra emacs-mode features to make it difficult to
distinguish from ksh88.  Bug fixes from various contributors are
the only other changes from John MacMillan's version.

I have upped the version number for this release to distinguish
it from the original 3.3 version.  This version is much improved
despite the small number of new features.

INSTALLATION:

The file INSTALL contains intructions for building and
installing the shell.  

The original instructions indicated that a POSIX compliant
environment and possibly an ANSI compiler are required.  I have
used both gcc and native Sun and the GreenHills ANSI compiler
without problems.

The POSIX/STDC compatability stuff in ./std seems to cause lots
of problems for some systems.  This was at least in part because
I distributed it with half the librraies disabled :-), in any
case the shell itself in ./sh can now be compiled without any of
the ./std stuff which makes things much simpler on systems that
have a real POSIX environment.

Porting to new environemnts can be a real pain.  I don't really
plan to make a huge effort in this area since I expect that this
shell will be mainly required on exotic or obscure systems (the
ones that the vendor does not provide a ksh for).  Thus the
small "market" does not warrant a C-news or X11 style
portability effort.  Of course if people send patches for
various systems I'm happy to try and integrate them.

ENVIRONMENT:

My main interest in this shell is for Sun workstations.  Every
other UNIX system I use comes with a real ksh.  Being a strictly
C-shell environment, some improved profile files are in order on
Sun's.

The etc directory contains a set of useful environment files.
These are the same files I use on several systems (many use a
real ksh):
./etc/profile
./etc/sys_config.sh
./etc/ksh.kshrc	

The first one is obvious.  The second, sys_config.sh is sourced
by /etc/profile and several other scripts.  It is used to
determine the system type so that scripts like profile can be
used on multiple platforms.
The third one is also quite useful, add 
. /etc/ksh.kshrc 
to user's ~/.kshrc to simplify alias management.

BUGS:

Many folk have contributed to this shell.  
I have attempted to credit (in sh/ChangeLog) the authors of bug
fixes received since the previous release.
There are surely still plenty of bugs to be found/fixed.

There is a template bug report in bug-report [borrowed from the
X11R5 mit tree], just fill in the blanks and mail to
[email protected].  

I hope you find this shell as useful as I do...

Simon J. Gerraty <[email protected]>
./pdksh/etc/  2755    653   1762           0  5302550265  10120 5ustar  hlu./pdksh/etc/profile   644    653   1762       14461  5243743647  11603 0ustar  hlu:
# NAME:
#	profile - global initialization for sh,ksh
#
# DESCRIPTION:
#	This file is processed during login by /bin/sh
#	and /bin/ksh.  It is used to setup the default user
#	environment.
#
# SEE ALSO:
#	$HOME/.profile
#	/etc/ksh.kshrc

# RCSid:
#	$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
#
#	@(#)Copyright (c) 1991 Simon J. Gerraty
#
#	This file is provided in the hope that it will
#	be of use.  There is absolutely NO WARRANTY.
#	Permission to copy, redistribute or otherwise
#	use this file is hereby granted provided that 
#	the above copyright notice and this notice are
#	left intact. 

case "$_INIT_" in
*env*) ;;
*)	# do these once
	_INIT_="$_INIT_"env
	export _INIT_
	case `echo -n ""` in
	-n*)
	  _N_=""; _C_="\c";;
	*)
	  _N_="-n"; _C_="";;
	esac

	if [ -f /unix ]; then
          # System V
	  [ -z "$TZ" -a -f /etc/TIMEZONE ] && . /etc/TIMEZONE

  	  set -- `who -r`
    	  case "$3" in
	      S|5|0)	SINGLE=y;;
	      *)	SINGLE=n;;
	  esac
  	  # sys_config.sh should set ARCH,OS,C,N,HOSTNAME,uname
    	  # we use these in lots of scripts...
      	  [ "$SINGLE" = n -a -f /etc/sys_config.sh ] && . /etc/sys_config.sh
        else
          [ -f /etc/sys_config.sh ] && . /etc/sys_config.sh
          SINGLE=n		# doesn't matter so much
	fi
	# pick one of the following for the default umask
	# umask 002	# relaxed	-rwxrwxr-x
	umask 022	# cautious	-rwxr-xr-x
	# umask 027	# uptight	-rwxr-x---
	# umask 077	# paranoid	-rwx------
	# you can override the default umask
	# for specific groups later...

	if [ -d /local ]; then
		LOCAL=/local
	else
		LOCAL=/usr/local
	fi

	# set system specific things,
	# eg. set PATH,MANPATH 
	# override default ulimit if desired.
	# defult ulmit is unlimited on SunOS
	# and 4Mb for most System V
	case $OS in
	SunOS)
		# On sun's /bin -> /usr/bin so leave it out!
		PATH=/usr/bin:/usr/ucb:/usr/5bin:.
		MANPATH=/usr/man
		defterm=vt220
		;;
	SCO-UNIX)
		PATH=/bin:/usr/bin:/usr/lbin:/usr/dbin:/usr/ldbin:.
		MANPATH=/usr/man
		defterm=ansi
		;;
	B.O.S.)
		PATH=/bin:/usr/bin:.
		if [ -d /usr/ucb ]; then
			PATH=$PATH:/usr/ucb
		fi
		MANPATH=/usr/catman
		defterm=vt220
		SRC_COMPAT=_SYSV
		export SRC_COMPAT
		;;
	*)
		PATH=/bin:/usr/bin:.
		if [ -d /usr/ucb ]; then
			PATH=$PATH:/usr/ucb
		fi
		MANPATH=/usr/catman
		defterm=vt220
		;;
	esac
	if [ -d ${LOCAL}/bin ]; then
		PATH=$PATH:${LOCAL}/bin
	fi
	case "$HOME" in
	/)	;;
	""|/tmp)
		echo "Using /tmp for HOME"
		HOME=/tmp; export HOME
		;;
	*)
		if [ -d $HOME/bin ]; then
			PATH=$PATH:$HOME/bin
		fi
		;;
	esac
	if [ -d ${LOCAL}/man ]; then
		MANPATH=$MANPATH:${LOCAL}/man
	fi
	# make sure these are set at least once
	LOGNAME=${LOGNAME:-`logname`}
	USER=${USER:-$LOGNAME}

	# we expect id to produce output like:
	# uid=100(sjg) gid=10(staff) groups=10(staff),...
	S='('
	E=')'
	GROUP=`id | cut -d= -f3 | \
		sed -e "s;^[^${S}][^${S}]*${S}\([^${E}][^${E}]*\)${E}.*$;\1;"`
	UID=`id | cut -d= -f2 | \
                sed -e "s;\([^${S}]*\)${S}.*;\1;"`
	# set some group specific defaults
	case "$GROUP" in
	staff)	# staff deal with things that non-staff 
		# have no business looking at
		umask 027
		;;
	extern)	# we put external accounts in group "extern"
		# give them as much privacy as we can...
		umask 077
		ulimit 16384	# 8Mb file limit
		TMOUT=600	# idle timeout
		;;
	esac

	unset S E GROUP
	export LOCAL TTY PATH LOGNAME USER

	if [ -t 1 ]; then
		# we are interactive
		TTY=`tty`
		TTY=`basename $TTY`
		ORGANIZATION=""
		COPYRIGHT="Copyright (c) `date +19%y` $ORGANIZATION"
		export ORGANIZATION COPYRIGHT

		# set up some env variables
		MAIL=/usr/spool/mail/$USER
		MAILPATH=/usr/spool/mail/$USER:/etc/motd
		EMACSDIR=${LOCAL}/lib/emacs
		PAGER=${PAGER:-more}
		export MAIL EMACSDIR MANPATH MAILPATH PAGER

		CVSROOT=${LOCAL}/src/master
		EDITOR=emacs
		FCEDIT=$EDITOR
		export CVSROOT FCEDIT EDITOR
#		EMACSLOADPATH=$EMACSDIR/lisp
#		[ -d $LOCAL/lib/lisp ] && EMACSLOADPATH=$LOCAL/lib/lisp:$EMACSLOADPATH
#		[ -d $HOME/lisp ] && EMACSLOADPATH=$HOME/lisp:$EMACSLOADPATH
		case $UID in 
		0)	PROMPT="<$LOGNAME@$HOSTNAME># ";;
		*)	PROMPT="<$LOGNAME@$HOSTNAME>$ ";;
		esac
#		PUBDIR=/usr/spool/uucppublic
#		export PUBDIR EMACSLOADPATH
		[ -f /etc/profile.TeX ] && . /etc/profile.TeX
	else
		TTY=none
	fi

	# test (and setup if we are Korn shell)
	if [ "$RANDOM" != "$RANDOM" ]; then
		# we are Korn shell
		SHELL=/bin/ksh
		ENV=${HOME%/}/.kshrc
		HISTFILE=${HOME%/}/.ksh_hist
		case $UID in
		0)
			PROMPT="<$LOGNAME@$HOSTNAME:!># ";;
		*)	PROMPT="<$LOGNAME@$HOSTNAME:!>$ ";;
		esac
		export HISTSIZE HISTFILE ENV
		CDPATH=.:$HOME
		if [ "$TMOUT" ]; then
			typeset -r TMOUT
		fi
	else
		SHELL=/bin/sh
	fi
	PS1=$PROMPT
	export SHELL PS1 EDITOR PATH PROMPT HOSTNAME CDPATH
;;
esac

# login time initialization
case "$_INIT_" in
*log*) ;;
*)	_INIT_="$_INIT_"log
	case "$SINGLE" in
	y)	;;
	*)
	if [ TTY != none -a "$0" != "-su" -a "$LOGNAME" = "`logname`" -a ! -f ~/.hushlogin ]
	then
		case $OS in
		B.O.S.)
			case $TTY in
			ttyp*)	stty sane	# problems with telnetd
				;;
			esac
			;;
		esac
		# ensure known state
		stty isig icanon intr '^c' erase '^h' kill '^u' eof '^d' 
		mesg y
		case $TERM in
		network|unknown|dialup|"") 
		  echo ${_N_} "Enter terminal type [$defterm]: ${_C_}" 1>&2
		  read tmpterm
		  TERM=${tmpterm:-$defterm}
		  ;;
		esac
		# not all of the following are appropriate at all sites
		# Sun's don't need to cat /etc/motd for instance
		case "$OS" in
		SunOS)	;;
		SCO-UNIX)	
			[ -s /etc/motd ] && cat /etc/motd
			[ -x /usr/bin/mail -a -s "$MAIL" ] && 
				echo "You have mail."
			[ -x /usr/bin/news ] && /usr/bin/news -n
			;;
		*)
			[ -s /etc/motd ] && cat /etc/motd
			if [ -x /usr/bin/mailx ]; then
		 	  if mailx -e; then
			    echo "You have mail."
			    # show the the headers, this might
			    # be better done in .profile so they
			    # can override it.
#			    mailx -H
			  fi
			fi
			[ -x /usr/bin/news ] && /usr/bin/news -n
			;;
		esac
#		[ -x /usr/games/fortune ] && /usr/games/fortune -a
		# remind folk who turned on reply.pl to turn it off.
		if [ -f $HOME/.forward ]; then
			echo "Your mail is being forwarded to:"
			cat $HOME/.forward
			if [ -f $HOME/.recording ]; then
				echo "Perhaps you should run \"reply.pl off\""
			fi
		fi
	fi
	unset tmpterm defterm C N _C_ _N_
	esac
	case "$TERM" in
	network|unknown|"")	TERM=vt100;;
	esac
	export TERM TTY
;;
esac
# Handle X-terminals if necessary
[ "$SINGLE" = n -a -f /etc/profile.X11 ] && . /etc/profile.X11
./pdksh/etc/ksh.kshrc   644    653   1762        4573  5243743646  12023 0ustar  hlu:
# NAME:
#	ksh.kshrc - global initialization for ksh 
#
# DESCRIPTION:
#	Each invocation of /bin/ksh processes the file pointed
#	to by $ENV (usually $HOME/.kshrc).
#	This file is intended as a global .kshrc file for the
#	Korn shell.  A user's $HOME/.kshrc file simply requires
#	the line:
#		. /etc/ksh.kshrc
#	at or near the start to pick up the defaults in this
#	file which can then be overridden as desired.
#
# SEE ALSO:
#	$HOME/.kshrc
#

# RCSid:
#	$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
#
#	@(#)Copyright (c) 1991 Simon J. Gerraty
#
#	This file is provided in the hope that it will
#	be of use.  There is absolutely NO WARRANTY.
#	Permission to copy, redistribute or otherwise
#	use this file is hereby granted provided that 
#	the above copyright notice and this notice are
#	left intact. 

case "$-" in
*i*)	# we are interactive
	# we may have su'ed so reset these
	# NOTE: SCO-UNIX doesn't have whoami,
	#	install whoami.sh
	USER=`whoami`
	PROMPT="<$USER@$HOSTNAME:!>$ "
	PPROMPT='<$USER@$HOSTNAME:$PWD:!>$ '
	PS1=$PPROMPT
	# $TTY is the tty we logged in on,
	# $tty is that which we are in now (might by pty)
	tty=`tty`
	tty=`basename $tty`

	set -o $EDITOR

	alias ls='ls -CF'
	alias h='fc -l | more'
	# the PD ksh is not 100% compatible
	case "$KSH_VERSION" in
	*PD*)	# PD ksh
		case "$TERM" in
		xterm*)
			# bind arrow keys
			bind '^[['=prefix-2
			bind '^XA'=up-history
			bind '^XB'=down-history
			bind '^XC'=forward-char
			bind '^XD'=backward-char
			;;
		esac
		;;
	*)	# real ksh ?
		;;
	esac
	case "$TERM" in
	sun*)
		# these are not as neat as their csh equivalents
		if [ "$tty" != console ]; then
			# ilabel
			ILS='\033]L'; ILE='\033\\'
			# window title bar
			WLS='\033]l'; WLE='\033\\'
		fi
		;;
	xterm*)
		ILS='\033]1;'; ILE='\007'
		WLS='\033]2;xterm: '; WLE='\007'
		;;
	*)	;;
	esac
	# do we want window decorations?
	if [ "$ILS" ]; then
		wftp () { ilabel "ftp $*"; "ftp" $*; 
			ilabel "$USER@$HOSTNAME"; }
		wcd () { "cd" $*; eval stripe; }
		ilabel () { print -n "${ILS}$*${ILE}"; }
		label () { print -n "${WLS}$*${WLE}"; }
		alias stripe='label $USER @ $HOSTNAME \($tty\) - $PWD'
		alias cd=wcd
		alias ftp=wftp
		eval stripe
		eval ilabel "$USER@$HOSTNAME"
		PS1=$PROMPT
	fi
	alias quit=exit
	alias cls=clear
	alias logout=exit
	alias bye=exit


# add your favourite aliases here
;;
*)	# non-interactive
;;
esac
# commands for both interactive and non-interactive shells
./pdksh/etc/sys_config.sh   644    653   1762        2616  5243743647  12676 0ustar  hlu:
# NAME:
#	sys_config.sh - set system specific variables
#
# SYNOPSIS:
#	. /etc/sys_config.sh
#
# DESCRIPTION:
#	Source this script into shell scripts that want to handle
#	various system types.
#	You may well want to edit this on a particular system replacing 
#	`uname -s` etc with the result.  So that the facility will work 
#	even when in single user mode and uname et al are not available.
#
# SEE ALSO:
#	/etc/profile

# RCSid:
#	$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
#
#	@(#)Copyright (c) 1991 Simon J. Gerraty
#
#	This file is provided in the hope that it will
#	be of use.  There is absolutely NO WARRANTY.
#	Permission to copy, redistribute or otherwise
#	use this file is hereby granted provided that 
#	the above copyright notice and this notice are
#	left intact. 
#

# determin machine type
if [ -f /usr/bin/arch ]; then
	ARCH=`arch`
elif [ -f /usr/bin/uname -o -f /bin/uname ]; then
	ARCH=`uname -m`
fi
#
case "$ARCH" in
sun386)	uname=/usr/5bin/uname
	OS=SunOS
	;;
*)	uname=uname;;
esac

# set the operating system type
# you can't use `uname -s` with SCO UNIX
# it returns the same string as `uname -n`
# so set it manually
# OS=SCO-UNIX
# The eval below is a workaround for a bug in the PD ksh.
OS=${OS:-`eval $uname -s`}
HOSTNAME=${HOSTNAME:-`eval $uname -n`}

case `echo -n ""` in
-n*)	_C_=""; _N_="-n";;
*)	_C_="\c"; _N_="";;
esac
N="${_N_}"
C="${_C_}"
export OS ARCH HOSTNAME uname
./pdksh/sh/  2755    653   1762           0  5303017545   7757 5ustar  hlu./pdksh/sh/emacs.c   644    653   1762      106051  5243743654  11326 0ustar  hlu/*
 *  Emacs-like command line editing and history
 *
 *  created by Ron Natalie at BRL
 *  modified by Doug Kingston, Doug Gwyn, and Lou Salkind
 *  adapted to PD ksh by Eric Gisin
 */

#include "config.h"
#ifdef EMACS

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <signal.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <setjmp.h>
#include "sh.h"
#include "expand.h"
#include "edit.h"

#define PUSH_DELETE 1			/* push all deletes of >1 char */

static	Area	aedit;
#define	AEDIT	&aedit		/* area for kill ring and macro defns */

#undef CTRL			/* _BSD brain damage */
#define	CTRL(x)		((x) == '?' ? 0x7F : (x) & 0x1F)	/* ASCII */
#define	UNCTRL(x)	((x) == 0x7F ? '?' : (x) | 0x40)	/* ASCII */

#ifndef S_ISDIR
#define S_ISDIR(mode)	(((mode) & S_IFMT) == S_IFDIR)
#endif

#ifndef S_ISREG
#define S_ISREG(mode)	(((mode) & S_IFMT) == S_IFREG)
#endif

/* values returned by keyboard functions */
#define	KSTD	0
#define	KPREF	1		/* ^[, ^X */
#define	KEOL	2		/* ^M, ^J */
#define	KINTR	3		/* ^G, ^C */
#define	KNULL	4
	
struct	x_ftab  {
	int	(*xf_func)();
	char	*xf_name;
	char	xf_db_tab;
	char	xf_db_char;
	short	xf_flags;
};

#define	XF_ALLOC	2
#define	XF_NOBIND	4

#define	iscfs(c)	(c == ' ' || c == '\t')	/* Separator for completion */
#define	ismfs(c)	(!(isalnum(c)|| c == '$'))  /* Separator for motion */
#define	BEL		0x07
#define	CMASK		0x7F	/* 7-bit ASCII character mask */

#define X_TABSZ	128			/* size of keydef tables etc */

static	int	x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
static	char   **x_histp;	/* history position */
static	char   **x_nextcmdp;	/* for newline-and-next */
static	char	*xmp;		/* mark pointer */
static	int    (*x_last_command)();
static	struct	x_ftab const *(*x_tab)[X_TABSZ] = NULL; /* key definition */
static	char    *(*x_atab)[X_TABSZ] = NULL; /* macro definitions */
#define	KILLSIZE	20
static	char    *killstack[KILLSIZE];
static	int	killsp, killtp;
static	int	x_curprefix;
static	char    *macroptr;
static	int	x_maxlen;	/* to determine column width */

static int      x_insert    ARGS((int c));
static int      x_ins_string ARGS((int c));
static void     x_ins       ARGS((char *cp));
static int      x_del_back  ARGS((int c));
static int      x_del_char  ARGS((int c));
static void     x_delete    ARGS((int nc));
static int      x_del_bword ARGS((int c));
static int      x_mv_bword  ARGS((int c));
static int      x_mv_fword  ARGS((int c));
static int      x_del_fword ARGS((int c));
static int      x_bword     ARGS((void));
static int      x_fword     ARGS((void));
static void     x_goto      ARGS((char *cp));
static void     x_bs        ARGS((int c));
static int      x_size_str  ARGS((char *cp));
static int      x_size      ARGS((int c));
static void     x_zots      ARGS((char *str));
static void     x_zotc      ARGS((int c));
static int      x_mv_back   ARGS((int c));
static int      x_mv_forw   ARGS((int c));
static int      x_search_char ARGS((int c));
static int      x_newline   ARGS((int c));
static int      x_end_of_text ARGS((int c));
static int      x_beg_hist  ARGS((int c));
static int      x_end_hist  ARGS((int c));
static int      x_prev_com  ARGS((int c));
static int      x_next_com  ARGS((int c));
static void     x_load_hist ARGS((char **hp));
static int      x_nl_next_com ARGS((int c));
static int      x_eot_del   ARGS((int c));
static int      x_search_hist ARGS((int c));
static int      x_search    ARGS((char *pat, int offset));
static int      x_match     ARGS((char *str, char *pat));
static int      x_del_line  ARGS((int c));
static int      x_mv_end    ARGS((int c));
static int      x_mv_begin  ARGS((int c));
static int      x_draw_line ARGS((int c));
static int      x_transpose ARGS((int c));
static int      x_literal   ARGS((int c));
static int      x_meta1     ARGS((int c));
static int      x_meta2     ARGS((int c));
static int      x_kill      ARGS((int c));
static void     x_push      ARGS((int nchars));
static int      x_yank      ARGS((int c));
static int      x_meta_yank ARGS((int c));
static int      x_abort     ARGS((int c));
static int      x_error     ARGS((int c));
static int      x_stuffreset ARGS((int c));
static int      x_stuff     ARGS((int c));
static void     x_mapin     ARGS((char *cp));
static char *   x_mapout    ARGS((int c));
static void     x_print     ARGS((int prefix, int key));
static int      x_set_mark  ARGS((int c));
static int      x_kill_region ARGS((int c));
static int      x_xchg_point_mark ARGS((int c));
static int      x_copy_arg  ARGS((int c));
static int      x_noop      ARGS((int c));
#ifdef SILLY
static int      x_game_of_life ARGS((int c));
#endif
static void     add_stash   ARGS((char *dirnam, char *name));
static void     list_stash  ARGS((void));
static int      x_comp_comm ARGS((int c));
static int      x_list_comm ARGS((int c));
static int      x_complete  ARGS((int c));
static int      x_enumerate ARGS((int c));
static int      x_comp_file ARGS((int c));
static int      x_list_file ARGS((int c));
static int      x_comp_list ARGS((int c));
static void     compl_dec   ARGS((int type));
static void     compl_file  ARGS((int type));
static void     compl_command ARGS((int type));
static int      strmatch    ARGS((char *s1, char *s2));
static int      x_set_arg   ARGS((int c));
static int      x_prev_histword ARGS((void));
static int      x_fold_case ARGS((int c));

static	struct x_ftab const x_ftab[] = {
 	{x_insert,	"auto-insert",		0,	 0,	0 },
	{x_error,	"error",		0,	 0,	0 },
 	{x_ins_string,	"macro-string",		0,	 0,	XF_NOBIND|XF_ALLOC},
	{x_del_back,	"delete-char-backward",	0, CTRL('H'),	0 },
	{x_eot_del,	"eot-or-delete",	0, CTRL('D'),	0 },
	{x_del_bword,	"delete-word-backward",	1, CTRL('H'),	0 },
	{x_mv_bword,	"backward-word", 	1,	'b',	0 },
	{x_del_line,	"kill-line",		0, 	0,	0 },
	{x_abort,	"abort",		0,	0,	0 },
	{x_noop,	"no-op",		0,	0,	0 },
/* Do not move the above! */
	{x_mv_fword,	"forward-word",		1,	'f',	0 },
	{x_del_char,	"delete-char-forward",	0,	0,	0 },
	{x_del_fword,	"delete-word-forward", 	1,	'd',	0 },
	{x_mv_back,	"backward-char",	0, CTRL('B'),	0 },
	{x_mv_forw,	"forward-char",		0, CTRL('F'),	0 },
	{x_search_char,	"search-character",	0, CTRL(']'),	0 },
	{x_newline,	"newline",		0, CTRL('M'),	0 },
	{x_newline,	"newline",		0, CTRL('J'),	0 },
	{x_end_of_text,	"eot",			0, CTRL('_'),	0 },
	{x_abort,	"abort",		0, CTRL('G'),	0 },
	{x_prev_com,	"up-history",		0, CTRL('P'),	0},
	{x_next_com,	"down-history",		0, CTRL('N'),	0},
	{x_search_hist,	"search-history",	0, CTRL('R'),	0},
	{x_beg_hist,	"beginning-of-history",	1,	'<',	0},
	{x_end_hist,	"end-of-history",	1,	'>',	0},
	{x_mv_end,	"end-of-line",		0, CTRL('E'),	0 },
	{x_mv_begin,	"beginning-of-line",	0, CTRL('A'),	0 },
	{x_draw_line,	"redraw",		0, CTRL('L'),	0 },
	{x_meta1,	"prefix-1",		0, CTRL('['),	0 },
	{x_meta2,	"prefix-2",		0, CTRL('X'),	0 },
	{x_kill,	"kill-to-eol",		0, CTRL('K'),	0 },
	{x_yank,	"yank",			0, CTRL('Y'),	0 },
	{x_meta_yank,	"yank-pop", 		1,	'y',	0 },
	{x_literal,	"quote",		0, CTRL('^'),	0 },
	{x_stuffreset, 	"stuff-reset",		0,	 0,	0 },
#if defined(BRL) && defined(TIOCSTI)
	{x_stuff, 	"stuff",		0, CTRL('T'),	0 },
	{x_transpose,	"transpose-chars",	0,	 0,	0 },
#else
	{x_stuff, 	"stuff",		0,	 0,	0 },
	{x_transpose,	"transpose-chars",	0, CTRL('T'),	0 },
#endif
#ifdef COMPLETE_LIST
	{x_complete,	"complete",		1, 	0,	0 },
 	{x_comp_list,	"complete-list",	1, CTRL('['),	0 },
#else
	{x_complete,	"complete",		1, CTRL('['),	0 },
 	{x_comp_list,	"complete-list",	1, 	 0,	0 },
#endif
	{x_enumerate,	"list",			1,	'?',	0 },
	{x_comp_file,	"complete-file",	1, CTRL('X'),	0 },
	{x_comp_comm,	"complete-command",	2, CTRL('['),	0 },
	{x_list_file,	"list-file",		0,	 0,	0 },
	{x_list_comm,	"list-command",		2,	'?',	0 },
	{x_nl_next_com,	"newline-and-next",	0, CTRL('O'),	0 },
	{x_set_mark,	"set-mark-command",	1,	' ',	0 },
	{x_kill_region,	"kill-region",		0, CTRL('W'),	0 },
	{x_xchg_point_mark, "exchange-point-and-mark", 2, CTRL('X'), 0 },
#if 0
	{x_copy_arg,	"copy-last-arg",	1,	'_',	0},
#endif
#ifdef SILLY
	{x_game_of_life, "play-game-of-life",	0,	0,	0 },
#endif 
#ifdef DEBUG
        {x_debug_info,	"debug-info",		1, CTRL('H'),	0 },
#endif
	{x_prev_histword, "prev-hist-word", 	1,	'.',	0 },
	{x_prev_histword, "prev-hist-word", 	1,	'_',	0 },
        {x_set_arg,	"",			1,	'0',	0 },
        {x_set_arg,	"",			1,	'1',	0 },
        {x_set_arg,	"",			1,	'2',	0 },
        {x_set_arg,	"",			1,	'3',	0 },
        {x_set_arg,	"",			1,	'4',	0 },
        {x_set_arg,	"",			1,	'5',	0 },
        {x_set_arg,	"",			1,	'6',	0 },
        {x_set_arg,	"",			1,	'7',	0 },
        {x_set_arg,	"",			1,	'8',	0 },
        {x_set_arg,	"",			1,	'9',	0 },
        {x_fold_case,	"upcase-word",		1,	'U',	0 },
        {x_fold_case,	"downcase-word",	1,	'L',	0 },
        {x_fold_case,	"capitalize-word",	1,	'C',	0 },
        {x_fold_case,	"upcase-word",		1,	'u',	0 },
        {x_fold_case,	"downcase-word",	1,	'l',	0 },
        {x_fold_case,	"capitalize-word",	1,	'c',	0 },
	{ 0 }
};

#define	xft_insert &x_ftab[0]
#define	xft_error &x_ftab[1]
#define	xft_ins_string &x_ftab[2]
#define	xft_erase &x_ftab[3]
#define	xft_kill &x_ftab[7]
#define	xft_werase &x_ftab[5]
#define xft_intr &x_ftab[8]
#define	xft_quit &x_ftab[9]

int
x_emacs(buf, len)
	char *buf;
	size_t len;
{
	char	c;
	int	i;
	int   (*func)();
	extern	x_insert();

	xbp = xbuf = buf; xend = buf + len;
	xlp = xcp = xep = buf;
	*xcp = 0;
	xlp_valid = TRUE;
	xmp = NULL;
	x_curprefix = 0;
	macroptr = null;
	x_histp = histptr + 1;

	if (x_nextcmdp != NULL) {
		x_load_hist(x_nextcmdp);
		x_nextcmdp = NULL;
	}

	x_col = promptlen(prompt);
	x_adj_ok = 1;
	x_displen = x_cols - 2 - x_col;
	x_adj_done = 0;

	while (1)  {
		x_flush();
		if (*macroptr)  {
			c = *macroptr++;
			if (*macroptr == 0)
				macroptr = null;
		}
		else {
			if ((c = x_getc()) < 0)
				return i;
		}

		if (x_curprefix == -1)
			func = x_insert;
		else
			func = x_tab[x_curprefix][c&CMASK]->xf_func;
		if (func == NULL)
			func = x_error;
		i = c | (x_curprefix << 8);
		x_curprefix = 0;
		switch (i = (*func)(i))  {
		  case KSTD:
			x_last_command = func;
		  case KPREF:
		  case KNULL:
			break;
		  case KEOL:
			i = xep - xbuf;
			x_last_command = 0;
			return i;
		  case KINTR:	/* special case for interrupt */
			errno = EINTR;
			return -1;
		}
	}
}

static int
x_insert(c)  {
	char	str[2];

	/*
	 *  Should allow tab and control chars.
	 */
	if (c == 0)  {
		x_putc(BEL);
		return KSTD;
	}
	str[0] = c;
	str[1] = 0;
	x_ins(str);
	return KSTD;
}

static int
x_ins_string(c)
{
	if (*macroptr)   {
		x_putc(BEL);
		return KSTD;
	}
	macroptr = x_atab[c>>8][c & CMASK];
	return KSTD;
}

static void
x_ins(cp)
	char	*cp;
{
	int	count;
	register int	adj = x_adj_done;

	count = strlen(cp);
	if (xep+count >= xend) {
		x_putc(BEL);
		return;
	}

	if (xcp != xep)
		memmove(xcp+count, xcp, xep - xcp + 1);
	else
		xcp[count] = 0;
	memmove(xcp, cp, count);
	/*
	 * x_zots() may result in a call to x_adjust()
	 * we want xcp to reflect the new position.
	 */
	cp = xcp;
	xcp += count;
	xep += count;
	xlp_valid = FALSE;
	x_lastcp();
	x_adj_ok = (xcp >= xlp);
	x_zots(cp);
	if (adj == x_adj_done)	/* has x_adjust() been called? */
	{
	  /* no */
	  for (cp = xlp; cp > xcp; )
	    x_bs(*--cp);
	}

	x_adj_ok = 1;
	return;
}

static int
x_del_back(c)  {
	if (xcp == xbuf)  {
		x_putc(BEL);
		return KSTD;
	}
	x_goto(xcp - 1);
	x_delete(1);
	return KSTD;
}

static int
x_del_char(c)  {
	if (xcp == xep)  {
		x_putc(BEL);
		return KSTD;
	}
	x_delete(1);
	return KSTD;
}

static void
x_delete(nc)
  int nc;
{
	int	i,j;
	char	*cp;
	
	if (nc == 0)
		return;
	if (xmp != NULL) {
		if (xcp + nc > xmp)
			xmp = xcp;
		else if (xmp > xcp)
			xmp -= nc;
	}
#ifdef PUSH_DELETE
	/*
	 * This lets us yank a word we have deleted.
	 */
	if (nc > 1)
	  x_push(nc);
#endif
	xep -= nc;
	cp = xcp;
	j = 0;
	i = nc;
	while (i--)  {
		j += x_size(*cp++);
	}
	memmove(xcp, xcp+nc, xep - xcp + 1);	/* Copies the null */
	x_adj_ok = 0;			/* don't redraw */
	x_zots(xcp);
	/*
	 * if we are already filling the line,
	 * there is no need to ' ','\b'.
	 * But if we must, make sure we do the minimum.
	 */
	if ((i = x_cols - 2 - x_col) > 0)
	{
	  j = (j < i) ? j : i;
	  i = j;
	  while (i--)
	    x_putc(' ');
	  i = j;
	  while (i--)
	    x_putc('\b');
	}
	/*x_goto(xcp);*/
	x_adj_ok = 1;
	xlp_valid = FALSE;
	for (cp = x_lastcp(); cp > xcp; )
	  x_bs(*--cp);

	return;	
}

static int
x_del_bword(c)  {
	x_delete(x_bword());
	return KSTD;
}

static int
x_mv_bword(c)  {
	(void)x_bword();
	return KSTD;
}

static int
x_mv_fword(c)  {
	x_goto(xcp + x_fword());
	return KSTD;
}

static int
x_del_fword(c)  {
	x_delete(x_fword());
	return KSTD;
}

static int
x_bword()  {
	int	nc = 0;
	register char *cp = xcp;

	if (cp == xbuf)  {
		x_putc(BEL);
		return 0;
	}
	if (x_last_command != x_set_arg)
	  x_arg = 1;
	while (x_arg--)
	{
	  while (cp != xbuf && ismfs(cp[-1]))
	  {
	    cp--;
	    nc++;
	  }
	  while (cp != xbuf && !ismfs(cp[-1]))
	  {
	    cp--;
	    nc++;
	  }
	}
	x_goto(cp);
	return nc;
}

static int
x_fword()  {
	int	nc = 0;
	register char	*cp = xcp;

	if (cp == xep)  {
		x_putc(BEL);
		return 0;
	}
	if (x_last_command != x_set_arg)
	  x_arg = 1;
	while (x_arg--)
	{
	  while (cp != xep && !ismfs(*cp))
	  {
	    cp++;
	    nc++;
	  }
	  while (cp != xep && ismfs(*cp))
	  {
	    cp++;
	    nc++;
	  }
	}
	return nc;
}

static void
x_goto(cp)
	register char *cp;
{
  if (cp < xbp || cp >= (xbp + x_displen))
  {
    /* we are heading off screen */
    xcp = cp;
    x_adjust();
  }
  else
  {
    if (cp < xcp)		/* move back */
    {
      while (cp < xcp)
	x_bs(*--xcp);
    }
    else
    {
      if (cp > xcp) 		/* move forward */
      {
	while (cp > xcp)
	  x_zotc(*xcp++);
      }
    }
  }
}

static void
x_bs(c)  {
	register i;
	i = x_size(c);
	while (i--)
		x_putc('\b');
}

static int
x_size_str(cp)
	register char *cp;
{
	register size = 0;
	while (*cp)
		size += x_size(*cp++);
	return size;
}

static int
x_size(c)  {
	if (c=='\t')
		return 4;	/* Kludge, tabs are always four spaces. */
	if (c < ' ' || c == 0x7F) /* ASCII control char */
		return 2;
	return 1;
}

static void
x_zots(str)
	register char *str;
{
  register int	adj = x_adj_done;

  x_lastcp();
  while (*str && str < xlp && adj == x_adj_done)
    x_zotc(*str++);
}

static void
x_zotc(c)
	int c;
{
	if (c == '\t')  {
		/*  Kludge, tabs are always four spaces.  */
		x_puts("    ");
	} else if (c < ' ' || c == 0x7F)  { /* ASCII */
		x_putc('^');
		x_putc(UNCTRL(c));
	} else
		x_putc(c);
}

static int
x_mv_back(c)  {
	if (xcp == xbuf)  {
		x_putc(BEL);
		return KSTD;
	}
	x_goto(xcp-1);
	return KSTD;
}

static int
x_mv_forw(c)  {
	if (xcp == xep)  {
		x_putc(BEL);
		return KSTD;
	}
	x_goto(xcp+1);
	return KSTD;
}

static int
x_search_char(c)
	int c;
{
	char *cp;

	*xep = '\0';
	if ((c = x_getc()) < 0 ||
	    /* we search forward, I don't know what Korn does */
	    ((cp = (xcp == xep) ? NULL : strchr(xcp+1, c)) == NULL &&
	    (cp = strchr(xbuf, c)) == NULL)) {
		x_putc(BEL);
		return KSTD;
	}
	x_goto(cp);
	return KSTD;
}

static int
x_newline(c)  {
	x_putc('\n');
	x_flush();
	*xep++ = '\n';
	return KEOL;
}

static int
x_end_of_text(c)  {
#if 0
	x_store_hist();
#endif
	return KEOL;
}

static int x_beg_hist(c) {x_load_hist(history); return KSTD;}

static int x_end_hist(c) {x_load_hist(histptr); return KSTD;}

static int x_prev_com(c) {x_load_hist(x_histp-1); return KSTD;}

static int x_next_com(c) {x_load_hist(x_histp+1); return KSTD;}

static void
x_load_hist(hp)
	register char **hp;
{
	int	oldsize;

	if (hp < history || hp > histptr) {
		x_putc(BEL);
		return;
	}
	x_histp = hp;
	oldsize = x_size_str(xbuf);
	(void)strcpy(xbuf, *hp);
	xbp = xbuf;
	xep = xcp = xbuf + strlen(*hp);
	xlp_valid = FALSE;
	if (xep > x_lastcp())
	  x_goto(xep);
	else
	  x_redraw(oldsize);
}

static int
x_nl_next_com(c)
int	c;
{
	x_nextcmdp = x_histp + 1;
	return (x_newline(c));
}

static int
x_eot_del(c)
int	c;
{
	if (xep == xbuf)
		return (x_end_of_text(c));
	else
		return (x_del_char(c));
}

static int x_search(), x_match();

/* reverse incremental history search */
static int
x_search_hist(c)
	int c;
{
	int offset = -1;	/* offset of match in xbuf, else -1 */
	char pat [256+1];	/* pattern buffer */
	register char *p = pat;
	int (*func)();

	*p = 0;
	while (1) {
		if (offset < 0) {
			x_puts("\nI-search: ");
			x_zots(pat);
		}
		x_flush();
		if ((c = x_getc()) < 0)
			return KSTD;
		func = x_tab[0][c&CMASK]->xf_func;
		if (c == CTRL('['))
			break;
		else if (func == x_search_hist)
			offset = x_search(pat, offset);
		else if (func == x_del_back)
			continue;	/* todo */
		else if (func == x_insert) {
			/* add char to pattern */
			*p++ = c, *p = 0;
			if (offset >= 0) {
				/* already have partial match */
				offset = x_match(xbuf, pat);
				if (offset >= 0) {
					x_goto(xbuf + offset + (p - pat) - (*pat == '^'));
					continue;
				}
			}
			offset = x_search(pat, offset);
		} else { /* other command */
			static char push[2];
			push[0] = c;
			macroptr = push; /* push command */
			break;
		}
	}
	if (offset < 0)
		x_redraw(-1);
	return KSTD;
}

/* search backward from current line */
static int
x_search(pat, offset)
	char *pat;
	int offset;
{
	register char **hp;
	int i;

	for (hp = x_histp; --hp >= history; ) {
		i = x_match(*hp, pat);
		if (i >= 0) {
			if (offset < 0)
				x_putc('\n');
			x_load_hist(hp);
			x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
			return i;
		}
	}
	x_putc(BEL);
	x_histp = histptr;
	return -1;
}

/* return position of first match of pattern in string, else -1 */
static int
x_match(str, pat)
	char *str, *pat;
{
	if (*pat == '^') {
		return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
	} else {
		char *q = strstr(str, pat);
		return (q == NULL) ? -1 : q - str;
	}
}

static int
x_del_line(c)  {
	int	i, j;

	*xep = 0;
	i = xep- xbuf;
	j = x_size_str(xbuf);
	xcp = xbuf;
	x_push(i);
	xlp = xbp = xep = xbuf;
	xlp_valid = TRUE;
	*xcp = 0;
	xmp = NULL;
	x_redraw(j);
	return KSTD;
}

static int
x_mv_end(c)  {
	x_goto(xep);
	return KSTD;
}

static int
x_mv_begin(c)  {
	x_goto(xbuf);
	return KSTD;
}

static int
x_draw_line(c)
{
	x_redraw(-1);
	return KSTD;

}

void
x_redraw(limit)
  int limit;
{
	int	i, j;
	char	*cp;
	
	x_adj_ok = 0;
	if (limit == -1)
		x_putc('\n');
	else 
		x_putc('\r');
	x_flush();
	if (xbp == xbuf)
	{
	  pprompt(prompt);
	  x_col = promptlen(prompt);
	}
	x_displen = x_cols - 2 - x_col;
	xlp_valid = FALSE;
	cp = x_lastcp();
	x_zots(xbp);
	if (xbp != xbuf || xep > xlp)
	  limit = x_cols;
	if (limit >= 0)
	{
	  if (xep > xlp)
	    i = 0;			/* we fill the line */
	  else
	    i = limit - (xlp - xbp);

	  for (j = 0; j < i && x_col < (x_cols - 2); j++)
	    x_putc(' ');
	  i = ' ';
	  if (xep > xlp)		/* more off screen */
	  {
	    if (xbp > xbuf)
	      i = '*';
	    else
	      i = '>';
	  }
	  else
	    if (xbp > xbuf)
	      i = '<';
	  x_putc(i);
	  j++;
	  while (j--)
	    x_putc('\b');
	}
	for (cp = xlp; cp > xcp; )
	  x_bs(*--cp);
	x_adj_ok = 1;
	_D_(x_flush();)
	return;
}

static int
x_transpose(c)  {
	char	tmp;
	if (xcp == xbuf) {
		x_putc(BEL);
		return KSTD;
	} else if (xcp == xep) {
		if (xcp - xbuf == 1) {
			x_putc(BEL);
			return KSTD;
		}
		x_bs(xcp[-1]);
		x_bs(xcp[-2]);
		x_zotc(xcp[-1]);
		x_zotc(xcp[-2]);
		tmp = xcp[-1];
		xcp[-1] = xcp[-2];
		xcp[-2] = tmp;
	} else {
		x_bs(xcp[-1]);
		x_zotc(xcp[0]);
		x_zotc(xcp[-1]);
		tmp = xcp[-1];
		xcp[-1] = xcp[0];
		xcp[0] = tmp;
		x_bs(xcp[0]);
	}
	return KSTD;
}

static int
x_literal(c)  {
	x_curprefix = -1;
	return KSTD;
}

static int
x_meta1(c)  {
	x_curprefix = 1;
	return KPREF;
}

static int
x_meta2(c)  {
	x_curprefix = 2;
	return KPREF;
}

static int
x_kill(c)  {
	int	i;

	i = xep - xcp;
	xlp = xcp;
	xlp_valid = TRUE;
	x_push(i);
	x_delete(i);
	return KSTD;
}

static void
x_push(nchars)  {
	char	*cp;
	cp = alloc((size_t)(nchars+1), AEDIT);
	memmove(cp, xcp, nchars);
	cp[nchars] = 0;
	if (killstack[killsp])
		afree((void *)killstack[killsp], AEDIT);
	killstack[killsp] = cp;
	killsp = (killsp + 1) % KILLSIZE;
}

static int
x_yank(c)  {
	if (killsp == 0)
		killtp = KILLSIZE;
	else
		killtp = killsp;
	killtp --;
	if (killstack[killtp] == 0)  {
		x_puts("\nnothing to yank");
		x_redraw(-1);
		return KSTD;
	}
	xmp = xcp;
	x_ins(killstack[killtp]);
	return KSTD;
}

static int
x_meta_yank(c)  {
	int	len;
	if (x_last_command != x_yank && x_last_command != x_meta_yank)  {
		x_puts("\nyank something first");
		x_redraw(-1);
		return KSTD;
	}
	len = strlen(killstack[killtp]);
	x_goto(xcp - len);
	x_delete(len);
	do  {
		if (killtp == 0)
			killtp = KILLSIZE - 1;
		else
			killtp--;
	}  while (killstack[killtp] == 0);
	x_ins(killstack[killtp]);
	return KSTD;
}

static int
x_abort(c) {
	/* x_zotc(c); */
	xlp = xep = xcp = xbp = xbuf;
	xlp_valid = TRUE;
	*xcp = 0;
	return KINTR;
}

static int
x_error(c) {
	x_putc(BEL);
	return KSTD;
}

static int
x_stuffreset(c)
{
#ifdef TIOCSTI
	(void)x_stuff(c);
	return KINTR;
#else
	x_zotc(c);
	xlp = xcp = xep = xbp = xbuf;
	xlp_valid = TRUE;
	*xcp = 0;
	x_redraw(-1);
	return KSTD;
#endif
}

static int
x_stuff(c)
{
#if 0 || defined TIOCSTI
	char	ch = c;
	bool_t	savmode = x_mode(FALSE);

	(void)ioctl(ttyfd, TIOCSTI, &ch);
	(void)x_mode(savmode);
	x_redraw(-1);
#endif
	return KSTD;
}

static void
x_mapin(cp)
	char	*cp;
{
	char	*op;

	op = cp;
	while (*cp)  {
		/* XXX -- should handle \^ escape? */
		if (*cp == '^')  {
			cp++;
			if (*cp >= '?')	/* includes '?'; ASCII */
				*op++ = CTRL(*cp);
			else  {
				*op++ = '^';
				cp--;
			}
		} else
			*op++ = *cp;
		cp++;
	}
	*op = 0;
}

static char *
x_mapout(c)
	int c;
{
	static char buf[8];
	register char *p = buf;

	if (c < ' ' || c == 0x7F)  { /* ASCII */
		*p++ = '^';
		*p++ = (c == 0x7F) ? '?' : (c | 0x40);
	} else
		*p++ = c;
	*p = 0;
	return buf;
}

static void
x_print(prefix, key)
	int prefix, key;
{
	if (prefix == 1)
		shellf("%s", x_mapout(x_prefix1));
	if (prefix == 2)
		shellf("%s", x_mapout(x_prefix2));
	shellf("%s = ", x_mapout(key));
	if (x_tab[prefix][key]->xf_func != x_ins_string)
		shellf("%s\n", x_tab[prefix][key]->xf_name);
	else
		shellf("'%s'\n", x_atab[prefix][key]);
}

void
x_bind(a1, a2, macro)
	char *a1, *a2;
	int macro;		/* bind -m */
{
	struct x_ftab const *fp;
	int prefix, key;
	char *sp = NULL;

	if (x_tab == NULL)
		errorf("cannot bind, not a tty\n");

	if (a1 == NULL) {
		for (prefix = 0; prefix < 3; prefix++)
		    for (key = 0; key < 0x80; key++) {
			fp = x_tab[prefix][key];
			if (fp == NULL ||
			    fp->xf_func == x_insert || fp->xf_func == x_error)
				continue;
			x_print(prefix, key);
		    }
		return;
	}

	x_mapin(a1);
	prefix = key = 0;
	for (;; a1++) {
		key = *a1;
		if (x_tab[prefix][key]->xf_func == x_meta1)
			prefix = 1;
		else
		if (x_tab[prefix][key]->xf_func == x_meta2)
			prefix = 2;
		else
			break;
	}

	if (a2 == NULL) {
		x_print(prefix, key);
		return;
	}

	if (*a2 == 0)
		fp = xft_insert;
	else if (!macro) {
		for (fp = x_ftab; fp->xf_func; fp++)
			if (strcmp(fp->xf_name, a2) == 0)
				break;
		if (fp->xf_func == NULL || (fp->xf_flags & XF_NOBIND))
			errorf("%s: no such function\n", a2);
		if (fp->xf_func == x_meta1)
			x_prefix1 = key;
		if (fp->xf_func == x_meta2)
			x_prefix2 = key;
	} else {
		fp = xft_ins_string;
		x_mapin(a2);
		sp = strsave(a2, AEDIT);
	}

	if ((x_tab[prefix][key]->xf_flags & XF_ALLOC) && x_atab[prefix][key])
		afree((void *)x_atab[prefix][key], AEDIT);
	x_tab[prefix][key] = fp;
	x_atab[prefix][key] = sp;
}

void
x_init_emacs()
{
	register int i, j;
	struct x_ftab const *fp;

	ainit(AEDIT);

	x_tab = (struct x_ftab *(*)[X_TABSZ]) alloc(sizeofN(*x_tab, 3), AEDIT);
	for (j = 0; j < 128; j++)
		x_tab[0][j] = xft_insert;
	for (i = 1; i < 3; i++)
		for (j = 0; j < 128; j++)
			x_tab[i][j] = xft_error;
	for (fp = x_ftab; fp->xf_func; fp++)
		if (fp->xf_db_char || fp->xf_db_tab)
			x_tab[fp->xf_db_tab][fp->xf_db_char] = fp;

	x_atab = (char *(*)[X_TABSZ]) alloc(sizeofN(*x_atab, 3), AEDIT);
	for (i = 1; i < 3; i++)
		for (j = 0; j < 128; j++)
			x_atab[i][j] = NULL;
}

void
x_emacs_keys(erase, kill, werase, intr, quit)
	int erase, kill, werase, intr, quit;
{
	x_tab[0][erase] = xft_erase;
	x_tab[0][kill] = xft_kill;
	x_tab[0][werase] = xft_werase;
	x_tab[0][intr] = xft_intr;
	x_tab[0][quit] = xft_quit;
	x_tab[1][erase] = xft_werase;
}

static int
x_set_mark(c) {
	xmp = xcp;
	return KSTD;
}

static int
x_kill_region(c) {
	int	rsize;
	char	*xr;

	if (xmp == NULL) {
		x_putc(BEL);
		return KSTD;
	}
	if (xmp > xcp) {
		rsize = xmp - xcp;
		xr = xcp;
	} else {
		rsize = xcp - xmp;
		xr = xmp;
	}
	x_goto(xr);
	x_push(rsize);
	x_delete(rsize);
	xmp = xr;
	return KSTD;
}

static int
x_xchg_point_mark(c) {
	char	*tmp;

	if (xmp == NULL) {
		x_putc(BEL);
		return KSTD;
	}
	tmp = xmp;
	xmp = xcp;
	x_goto( tmp );
	return KSTD;
}

#if 0
static int
x_copy_arg(c)	{
	char *last;
	if ((last = strval(local("_"))) && *last)
		x_ins(last);
	return KSTD;
}
#endif

static int
x_noop(c) {
	return KNULL;
}

#ifdef SILLY
static int
x_game_of_life(c)  {
	char	newbuf [256+1];
	register char *ip, *op;
	int	i, len;

	i = xep - xbuf;
	*xep = 0;
	len = x_size_str(xbuf);
	xcp = xbp = xbuf;
	memmove(newbuf+1, xbuf, i);
	newbuf[0] = 'A';
	newbuf[i] = 'A';
	for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++)  {
		/*  Empty space  */
		if (*ip < '@' || *ip == '_' || *ip == 0x7F)  {
			/*  Two adults, make whoopee */
			if (ip[-1] < '_' && ip[1] < '_')  {
				/*  Make kid look like parents.  */
				*op = '`' + ((ip[-1] + ip[1])/2)%32;
				if (*op == 0x7F) /* Birth defect */
					*op = '`';
			}
			else
				*op = ' ';	/* nothing happens */
			continue;
		}
		/*  Child */
		if (*ip > '`')  {
			/*  All alone, dies  */
			if (ip[-1] == ' ' && ip[1] == ' ')
				*op = ' ';
			else	/*  Gets older */
				*op = *ip-'`'+'@';
			continue;
		}
		/*  Adult  */
		/*  Overcrowded, dies */
		if (ip[-1] >= '@' && ip[1] >= '@')  {
			*op = ' ';
			continue;
		}
		*op = *ip;
	}
	*op = 0;
	x_redraw(len);
	return KSTD;
}
#endif

/*
 *	File/command name completion routines
 */

/* type: 0 for list, 1 for completion */

static	XPtrV words;

static void
add_stash(dirnam, name)
	char *dirnam;	/* directory name, if file */
	char *name;
{
	char *cp;
	register int type = 0;	/* '*' if executable, '/' if directory, else 0 */
	register int len = strlen(name);

	/* determine file type */
	if (dirnam)  {
		struct stat statb;
		char *buf = alloc((size_t)(strlen(dirnam)+len+2), ATEMP);

		if (strcmp(dirnam, ".") == 0)
			*buf = '\0';
		else if (strcmp(dirnam, "/") == 0)
			(void)strcpy(buf, "/");
		else
			(void)strcat(strcpy(buf, dirnam), "/");
		(void)strcat(buf, name);
		if (stat(buf, &statb)==0)
			if (S_ISDIR(statb.st_mode))
				type = '/';
			else if (S_ISREG(statb.st_mode) && access(buf, 01)==0)
				type = '*';
		if (type)
			++len;
		afree((void *)buf, ATEMP);
	}

	if (len > x_maxlen)
		x_maxlen = len;

	/* stash name for later sorting */
	cp = alloc((size_t)(len+1), ATEMP);
	(void)strcpy(cp = alloc((size_t)(len+1), ATEMP), name);
	if (dirnam && type)  {	/* append file type indicator */
		cp[len-1] = type;
		cp[len] = '\0';
	}
	XPput(words, cp);
}

static void
list_stash()
{
	register char **array, **record;
	int items = 0, tabstop, loc, nrows, jump, offset;

	items = XPsize(words);
	array = (char**) XPptrv(words);
	if (items == 0)
		return;
	qsortp(XPptrv(words), (size_t)XPsize(words), xstrcmp);

	/* print names */
	x_maxlen = (x_maxlen/8 + 1) * 8;	/* column width */
	nrows = (items-1) / (x_cols/x_maxlen) + 1;
	for (offset = 0; offset < nrows; ++offset)  {
		tabstop = loc = 0;
		x_putc('\n');
		for (jump = 0; offset+jump < items; jump += nrows)  {
			if (jump)
				while (loc < tabstop)  {
					x_putc('\t');
					loc = (loc/8 + 1) * 8;
				}
			record = array + (offset + jump);
			x_puts(*record);
			loc += strlen(*record);
			tabstop += x_maxlen;	/* next tab stop */
			afree((void *)*record, ATEMP);
		}
	}

	afree((void*)array, ATEMP);
	x_redraw(-1);
}

static int
x_comp_comm(c)  {
	compl_command(1);
	return KSTD;
}
static int
x_list_comm(c)  {
	compl_command(0);
	return KSTD;
}
static int
x_complete(c)  {
	compl_dec(1);
	return KSTD;
}
static int
x_enumerate(c)  {
	compl_dec(0);
	return KSTD;
}
static int
x_comp_file(c)   {
	compl_file(1);
	return KSTD;
}
static int
x_list_file(c)  {
	compl_file(0);
	return KSTD;
}
static int
x_comp_list(c)   {
	compl_dec(2);
	return KSTD;
}

static void compl_dec(type) { 	char	*cp; 	cp = xcp; 
	while (cp != xbuf && !iscfs(*cp))
		cp--;
	if (cp == xbuf && strchr(cp, '/') == NULL)
		compl_command(type);
	else
		compl_file(type);
}

static void
compl_file(type)
{
	char	*str;
	register char *cp, *xp;
	char	*lastp;
	char	*dirnam;
	char	buf [256+1];
	char	bug [256+1];
	DIR    *dirp;
	struct dirent *dp;
	long	loc = -1;
	int	len;
	int	multi = 0;

	/* type == 0 for list, 1 for complete and 2 for complete-list */
	str = xcp;
	cp = buf;
	xp = str;
	while (xp != xbuf)  {
		--xp;
		if (iscfs(*xp))  {
			xp++;
			break;
		}
	}
	if (digit(*xp) && (xp[1] == '<' || xp[1] == '>'))
		xp++;
	while (*xp == '<' || *xp == '>')
		xp++;
	if (type) {			/* for complete */
		while (*xcp && !iscfs(*xcp))
			x_zotc(*xcp++);
	}
	if (type != 1) {		/* for list */
		x_maxlen = 0;
		XPinit(words, 16);
	}
	while (*xp && !iscfs(*xp))
		*cp++ = *xp++;

	*cp = 0;
	strcpy(buf, cp = substitute(buf, DOTILDE));
	afree((void*)cp, ATEMP);
	lastp = strrchr(buf, '/');
	if (lastp)
		*lastp = 0;

	dirnam = (lastp == NULL) ? "." : (lastp == buf) ? "/" : buf;
	dirp = opendir(dirnam);
	if (dirp == NULL) {
		x_putc(BEL);
		return;
	}

	if (lastp == NULL)
		lastp = buf;
	else
		lastp++;
	len = strlen(lastp);

	while ((dp = readdir(dirp)) != NULL)  {
		cp = dp->d_name;
		if (cp[0] == '.' &&
		    (cp[1] == '\0' || (cp[1] == '.' && cp[2] == '\0')))
			continue;	/* always ignore . and .. */
		if (strncmp(lastp, cp, len) == 0) {
			if (type	/* for complete */) {
				if (loc == -1)  {
					(void)strcpy(bug, cp);
					loc = strlen(cp);
				} else {
					multi = 1;
					loc = strmatch(bug, cp);
					bug[loc] = 0;
				}
			}
			if (type != 1) { /* for list */
				add_stash(dirnam, cp);
			}
		}
	}
	(void)closedir(dirp);

	if (type) {			/* for complete */
		if (loc < 0 ||
		    (loc == 0 && type != 2))  {
			x_putc(BEL);
			return;
		}
		cp = bug + len;
		x_ins(cp);
		if (!multi)  {
			struct stat statb;
			if (lastp == buf)
				buf[0] = 0;
			else if (lastp == buf + 1)  {
				buf[1] = 0;
				buf[0] = '/';
			}  else
				(void)strcat(buf, "/");
			(void)strcat(buf, bug);
			if (stat(buf, &statb) == 0 && S_ISDIR(statb.st_mode))
				x_ins("/");
			else
				x_ins(" ");
		}
	}
	if (type == 0 ||		/* if list */
	    (type == 2 && multi)) {	/* or complete-list and ambiguous */
		list_stash();
	}
}

static void
compl_command(type)
{
	register struct tbl *tp;
	char	*str;
	char	buf [256+1];
	char	bug [256+1];
	char	*xp;
	char	*cp;
	int  len;
	int  multi;
	int  loc;

	/* type == 0 for list, 1 for complete and 2 for complete-list */
	str = xcp;
	cp = buf;
	xp = str;
	while (xp != xbuf)  {
		--xp;
		if (iscfs(*xp))  {
			xp++;
			break;
		}
	}
	if (type)			/* for complete */
		while (*xcp && !iscfs(*xcp))
			x_zotc(*xcp++);
	if (type != 1) {		/* for list */
		x_maxlen = 0;
		XPinit(words, 16);
	}
	while (*xp && !iscfs(*xp))
		*cp++ = *xp++;
	*cp = 0;

	len = strlen(buf);
	loc = -1;
	multi = 0;

	for (twalk(&commands); (tp = tnext()) != NULL; ) {
		int	klen;

		if (!(tp->flag&ISSET))
			continue;
		klen = strlen(tp->name);
		if (klen < len)
			continue;
		if (strncmp(buf, tp->name, len) ==0) {
			if (type)  {	/* for complete */
				if (loc == -1)  {
					(void)strcpy(bug, tp->name);
					loc = klen;
				} else {
					multi = 1;
					loc = strmatch(bug, tp->name);
					bug[loc] = 0;
				}
			}
			if (type != 1) { /* for list */
				add_stash((char *)0, tp->name);
			}
		}
	}

	if (type)  {			/* for complete */
		if (loc < 0 ||
		    (loc == 0 && type != 2))  {
			x_putc(BEL);
			return;
		}
		cp = bug + len;
		x_ins(cp);
		if (!multi)
			x_ins(" ");
		else if (type == 2)	/* complete and list rest */
			list_stash();
	}

	if (type == 0 ||		/* if list */
	    (type == 2 && multi)) {	/* or complete-list and ambiguous */
		list_stash();
	}
}

static int
strmatch(s1, s2)
	register char *s1, *s2;
{
	register char *p;

	for (p = s1; *p == *s2++ && *p != 0; p++)
		;
	return p - s1;
}



/* NAME:
 *      x_set_arg - set an arg value for next function
 *
 * DESCRIPTION:
 *      This is a simple implementation of M-[0-9].
 *
 * RETURN VALUE:
 *      KSTD
 */

static int
x_set_arg(c)
  int c;
{
  if ((x_arg = (c &= CMASK) - '0') < 0 || x_arg > 9)
  {
    x_arg = 1;
    x_putc(BEL);
  }
  return KSTD;
}


/* NAME:
 *      x_prev_histword - recover word from prev command
 *
 * DESCRIPTION:
 *      This function recovers the last word from the previous 
 *      command and inserts it into the current edit line.  If a 
 *      numeric arg is supplied then the n'th word from the 
 *      start of the previous command is used.  
 *      
 *      Bound to M-.
 *
 * RETURN VALUE:
 *      KSTD
 */

static int
x_prev_histword()
{
  register char *rcp;
  char *cp;
  char **hp;

  hp = x_histp-1;
  if (hp < history || hp > histptr)
  {
    x_putc(BEL);
    return;
  }
  cp = *hp;
  if (x_last_command != x_set_arg)
  {
    rcp = &cp[strlen(cp) - 1];
    /*
     * ignore white-space after the last word
     */
    while (rcp > cp && iscfs(*rcp))
      rcp--;
    while (rcp > cp && !iscfs(*rcp))
      rcp--;
    if (iscfs(*rcp))
      rcp++;
    x_ins(rcp);
  }
  else
  {
    int c;
    
    rcp = cp;
    /*
     * ignore white-space at start of line
     */
    while (*rcp && iscfs(*rcp))
      rcp++;
    while (x_arg-- > 1)
    {
      while (*rcp && !iscfs(*rcp))
	rcp++;
      while (*rcp && iscfs(*rcp))
	rcp++;
    }
    cp = rcp;
    while (*rcp && !iscfs(*rcp))
      rcp++;
    c = *rcp;
    *rcp = '\0';
    x_ins(cp);
    *rcp = c;
  }
  return KSTD;
}

/* NAME:
 *      x_fold_case - convert word to UPPER/lower case
 *
 * DESCRIPTION:
 *      This function is used to implement M-u,M-l and M-c
 *      to upper case, lower case or Capitalize words.
 *
 * RETURN VALUE:
 *      None
 */

static int
x_fold_case(c)
  int c;
{
  register char	*cp = xcp;
  
  if (cp == xep)
  {
    x_putc(BEL);
    return 0;
  }
  c &= 0137;				/* strip prefixes and case */
  if (x_last_command != x_set_arg)
    x_arg = 1;
  while (x_arg--)
  {
    /*
     * fisrt skip over any white-space
     */
    while (cp != xep && ismfs(*cp))
    {
      cp++;
    }
    /*
     * do the first char on its own since it may be
     * a different action than for the rest.
     */
    if (cp != xep)
    {
      if (c == 'L')			/* M-l */
      {
	if (isupper(*cp))
	  *cp = tolower(*cp);
      }
      else				/* M-u or M-c */
      {
	if (islower(*cp))
	  *cp = toupper(*cp);
      }
      cp++;
    }
    /*
     * now for the rest of the word
     */
    while (cp != xep && !ismfs(*cp))
    {
      if (c == 'U')			/* M-u */
      {
	if (islower(*cp))
	  *cp = toupper(*cp);
      }
      else				/* M-l or M-c */
      {
	if (isupper(*cp))
	  *cp = tolower(*cp);
      }
      cp++;
    }
  }
  x_goto(cp);
  return 0;
}

/* NAME:
 *      x_lastcp - last visible char
 *
 * SYNOPSIS:
 *      x_lastcp()
 *
 * DESCRIPTION:
 *      This function returns a pointer to that  char in the 
 *      edit buffer that will be the last displayed on the 
 *      screen.  The sequence:
 *      
 *      for (cp = x_lastcp(); cp > xcp; cp)
 *        x_bs(*--cp);
 *      
 *      Will position the cursor correctly on the screen.
 *
 * RETURN VALUE:
 *      cp or NULL
 */

char *
x_lastcp()
{
  register char *rcp;
  register int i;

  if (!xlp_valid)
  {
    for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++)
      i += x_size(*rcp);
    xlp = rcp;
  }
  xlp_valid = TRUE;
  return (xlp);
}

#endif /* EDIT */

./pdksh/sh/var.c   644    653   1762       27675  5243743667  11030 0ustar  hlu#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include <time.h>
#include "sh.h"
#include "expand.h"

/*
 * Variables
 *
 * WARNING: unreadable code, needs a rewrite
 *
 * if (flag&INTEGER), val.i contains integer value, and type contains base.
 * otherwise, (val.s + type) contains string value.
 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
 */
char	null []	= "";
static	struct tbl vtemp;
static void     export      ARGS((struct tbl *vp, char *val));
static int      special     ARGS((char *name));
static void     getspec     ARGS((struct tbl *vp));
static void     setspec     ARGS((struct tbl *vp));

/*
 * create a new block for function calls and simple commands
 * assume caller has allocated and set up e.loc
 */
void
newblock()
{
	register struct block *l = e.loc;
	static char *empty[] = {""};

	ainit(&l->area);
	l->argc = 0;
	l->argv = empty;
	l->exit = l->error = NULL;
	tinit(&l->vars, &l->area);
	tinit(&l->funs, &l->area);
}

/*
 * pop a block handling special variables
 */
void
popblock()
{
	register struct block *l = e.loc;
	register struct tbl *vp, **vpp = l->vars.tbls;
	register int i;

	e.loc = l->next;	/* pop block */
	for (i = l->vars.size; --i >= 0; )
		if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
			setspec(global(vp->name));
	afreeall(&l->area);
}

/*
 * Search for variable, if not found create globally.
 */
struct tbl *
global(n)
	register char *n;
{
	register struct block *l = e.loc;
	register struct tbl *vp;
	register int c;
	unsigned h = hash(n);

	c = n[0];
	if (digit(c)) {
		vp = &vtemp;
		lastarea = ATEMP;
		vp->flag = (DEFINED|RDONLY);
		vp->type = 0;
		*vp->name = c;	/* should strncpy */
		for (c = 0; digit(*n) && c < 1000; n++)
			c = c*10 + *n-'0';
		if (c <= l->argc)
			setstr(vp, l->argv[c]);
		return vp;
	} else
	if (!letter(c)) {
		vp = &vtemp;
		lastarea = ATEMP;
		vp->flag = (DEFINED|RDONLY);
		vp->type = 0;
		*vp->name = c;
		if (n[1] != '\0')
			return vp;
		vp->flag |= ISSET|INTEGER;
		switch (c) {
		  case '$':
			vp->val.i = kshpid;
			break;
		  case '!':
			vp->val.i = async;
			break;
		  case '?':
			vp->val.i = exstat;
			break;
		  case '#':
			vp->val.i = l->argc;
			break;
		  case '-':
			vp->flag &= ~ INTEGER;
			vp->val.s = getoptions();
			break;
		  default:
			vp->flag &= ~(ISSET|INTEGER);
		}
		return vp;
	}
	for (l = e.loc; l != NULL; l = l->next) {
		vp = tsearch(&l->vars, n, h);
		lastarea = &l->area;
		if (vp != NULL)
			return vp;
		if (l->next == NULL)
			break;
	}
	vp = tenter(&l->vars, n, h);
	vp->flag |= DEFINED;
	if (special(n))
		vp->flag |= SPECIAL;
	return vp;
}

/*
 * Search for local variable, if not found create locally.
 */
struct tbl *
local(n)
	register char *n;
{
	register struct block *l = e.loc;
	register struct tbl *vp;
	unsigned h = hash(n);

	if (!letter(*n)) {
		vp = &vtemp;
		lastarea = ATEMP;
		vp->flag = (DEFINED|RDONLY);
		vp->type = 0;
		return vp;
	}
	vp = tenter(&l->vars, n, h);
	lastarea = &l->area;
	vp->flag |= DEFINED;
	if (special(n))
		vp->flag |= SPECIAL;
	return vp;
}

/* get variable string value */
char *
strval(vp)
	register struct tbl *vp;
{
	register char *s;
	static char strbuf[40];

	if ((vp->flag&SPECIAL))
		getspec(vp);
	if (!(vp->flag&ISSET))
		return null;	/* special to dollar() */
	if (!(vp->flag&INTEGER))	/* string source */
		s = vp->val.s + vp->type;
	else {				/* integer source */
		register unsigned long n;
		register int base;

		s = strbuf + sizeof(strbuf);
		n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
		base = (vp->type == 0) ? 10 : vp->type;

		*--s = '\0';
		do {
			*--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base];
			n /= base;
		} while (n != 0);
		/* todo: should we output base# ? */
		if (vp->val.i < 0)
			*--s = '-';
	}
	return s;
}

/* get variable integer value */
long
intval(vp)
	register struct tbl *vp;
{
	register struct tbl *vq;

	if ((vp->flag&SPECIAL))
		getspec(vp);
	if ((vp->flag&INTEGER))
		return vp->val.i;
	vq = &vtemp;
	vq->flag = (INTEGER);
	vq->type = 0;
	if (strint(vq, vp) == NULL)
		errorf("%s: bad number\n", vp->val.s);
	return vq->val.i;
}

/* set variable to string value */
void
setstr(vq, s)
	register struct tbl *vq;
	char *s;
{
	if (!(vq->flag&INTEGER)) { /* string dest */
		if ((vq->flag&ALLOC))
			afree((void*)vq->val.s, lastarea);
		vq->flag &= ~ (ISSET|ALLOC);
		vq->type = 0;
		if ((vq->flag&EXPORT))
			export(vq, s);
		else
			vq->val.s = strsave(s, lastarea);
		vq->flag |= ALLOC;
	} else {		/* integer dest */
		register struct tbl *vp = &vtemp;	
		vp->flag = (DEFINED|ISSET);
		vp->type = 0;
		vp->val.s = s;
		if (strint(vq, vp) == NULL)
			errorf("%s: bad number\n", s);
	}
	vq->flag |= ISSET;
	if ((vq->flag&SPECIAL))
		setspec(vq);
}
	
/* convert variable to integer variable */
struct tbl *
strint(vq, vp)
	register struct tbl *vq, *vp;
{
	register char *s = vp->val.s + vp->type;
	register int c;
	int base, neg = 0;
	
	vq->flag |= INTEGER;
	if (!(vp->flag&ISSET) || (s == NULL && !(vp->flag&INTEGER))) {
		vq->flag &= ~ ISSET;
		return NULL;
	}
	if ((vp->flag&INTEGER)) {
		vq->val.i = vp->val.i;
		return vq;
	}
	vq->val.i = 0;
	base = 10;
	for (c = *s++; c ; c = *s++)
		if (c == '-') {
			neg++;
		} else if (c == '#') {
			base = vq->type = vq->val.i;
			vq->val.i = 0;
		} else if (letnum(c)) {
			if ('0' <= c && c <= '9')
				c -= '0';
			else if ('a' <= c && c <= 'z') /* fuck EBCDIC */
				c -= 'a'-10;
			else if ('A' <= c && c <= 'Z')
				c -= 'A'-10;
			if (c < 0 || c >= base) {
				vq->flag &= ~ ISSET;
				return NULL;
			}
			vq->val.i = (vq->val.i*base) + c;
		} else
			break;
	if (neg)
		vq->val.i = -vq->val.i;
	if (vq->type < 2 || vq->type > 36)
		vq->type = 0;	/* default base (10) */
	return vq;
}

/* set variable to integer */
void
setint(vq, n)
	register struct tbl *vq;
	long n;
{
	if (!(vq->flag&INTEGER)) {
		register struct tbl *vp = &vtemp;
		vp->flag = (ISSET|INTEGER);
		vp->type = 0;
		vp->val.i = n;
		setstr(vq, strval(vp));	/* ? */
	} else
		vq->val.i = n;
	vq->flag |= ISSET;
	if ((vq->flag&SPECIAL))
		setspec(vq);
}

/* set variable from enviroment */
import(thing)
	char *thing;
{
	register struct tbl *vp;
	register char *val;

	val = strchr(thing, '=');
	if (val == NULL)
		return 0;
	*val = '\0';
	vp = local(thing);
	*val++ = '=';
	vp->flag |= DEFINED|ISSET|EXPORT;
	vp->val.s = thing;
	vp->type = val - thing;
	if ((vp->flag&SPECIAL))
		setspec(vp);
	return 1;
}

/*
 * make vp->val.s be "name=value" for quick exporting.
 */
static void
export(vp, val)
	register struct tbl *vp;
	char *val;
{
	register char *cp, *xp;
	char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;

	xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea);
	vp->flag |= ALLOC;
	vp->val.s = xp;
	for (cp = vp->name; (*xp = *cp++) != '\0'; xp++)
		;
	*xp++ = '=';
	vp->type = xp - vp->val.s; /* offset to value */
	for (cp = val; (*xp++ = *cp++) != '\0'; )
		;
	if (op != NULL)
		afree((void*)op, lastarea);
}

/*
 * lookup variable (according to (set&LOCAL)),
 * set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
 * and optionally set its value if an assignment.
 */
struct tbl *
typeset(var, set, clr)
	register char *var;
	int clr, set;
{
	register struct tbl *vp;
	register char *val;

	/* check for valid variable name, search for value */
	val = var;
	if (!letter(*val))
		return NULL;
	for (val++; *val != '\0'; val++)
		if (*val == '=')
			break;
		else if (letnum(*val))
			;
		else
			return NULL;
	if (*val == '=')
		*val = '\0';
	else
		val = NULL;
	vp = (set&LOCAL) ? local(var) : global(var);
	set &= ~ LOCAL;
	if (val != NULL)
		*val++ = '=';

	if (!(vp->flag&ISSET))
		vp->flag = (vp->flag & ~clr) | set;
	else
	    if (!(vp->flag&INTEGER) && (set&INTEGER)) {
		/* string to integer */
		vtemp.flag = (ISSET);
		vtemp.type = 0;
		vtemp.val.s = vp->val.s + vp->type;
		if ((vp->flag&ALLOC))
			afree((void*)vp->val.s, lastarea); /* dangerous, used later */
		vp->flag &= ~ ALLOC;
		vp->flag |= INTEGER;
		vp->type = 0;
		if (val == NULL && strint(vp, &vtemp) == NULL) {
			vp->flag &= ~ ISSET;
			errorf("%s: bad number\n", vtemp.val.s);
		}
	    } else
	    if ((clr&INTEGER) && (vp->flag&INTEGER)) {
		/* integer to string */
		vtemp.val.s = strval(vp);
		vp->flag &= ~ INTEGER;
		setstr(vp, vtemp.val.s);
	    }

	vp->flag = (vp->flag & ~clr) | set;

	if (val != NULL) {
		if ((vp->flag&RDONLY))
			errorf("cannot set readonly %s\n", var);
		if ((vp->flag&INTEGER))
			/* setstr should be able to handle this */
			(void)evaluate(var);
		else
			setstr(vp, val);
	}

	if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0)
		export(vp, (vp->flag&ISSET) ? vp->val.s : null);

	return vp;
}

void
unset(vp)
	register struct tbl *vp;
{
	if ((vp->flag&ALLOC))
		afree((void*)vp->val.s, lastarea);
	vp->flag &= SPECIAL;	/* Should ``unspecial'' some vars */
}

int
isassign(s)
	register char *s;
{
	if (!letter(*s))
		return (0);
	for (s++; *s != '='; s++)
		if (*s == 0 || !letnum(*s))
			return (0);
	return (1);
}

/*
 * Make the exported environment from the exported names in the dictionary.
 */
char **
makenv()
{
	struct block *l = e.loc;
	XPtrV env;
	register struct tbl *vp, **vpp;
	register int i;

	XPinit(env, 64);
	for (l = e.loc; l != NULL; l = l->next)
		for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
			if ((vp = *vpp++) != NULL
			    && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
				register struct block *l2;
				register struct tbl *vp2;
				unsigned h = hash(vp->name);

				lastarea = &l->area;

				/* unexport any redefined instances */
				for (l2 = l->next; l2 != NULL; l2 = l2->next) {
					vp2 = tsearch(&l2->vars, vp->name, h);
					if (vp2 != NULL)
						vp2->flag &= ~ EXPORT;
				}
				if ((vp->flag&INTEGER)) {
					/* integer to string */
					char *val;
					val = strval(vp);
					vp->flag &= ~ INTEGER;
					setstr(vp, val);
				}
				XPput(env, vp->val.s);
			}
	XPput(env, NULL);
	return (char **) XPclose(env);
}

/*
 * handle special variables with side effects - PATH, SECONDS.
 */
#define STREQ(a, b) ((*a) == (*b) && strcmp((a), (b)) == 0)
static int
special(name)
	register char * name;
{
	if (STREQ("PATH", name))
		return V_PATH;
	if (STREQ("IFS", name))
		return V_IFS;
	if (STREQ("SECONDS", name))
		return V_SECONDS;
	if (STREQ("OPTIND", name))
		return V_OPTIND;
	if (STREQ("MAIL", name))
		return V_MAIL;
	if (STREQ("MAILPATH", name))
		return V_MAILPATH;
	if (STREQ("RANDOM", name))
		return V_RANDOM;
#ifndef EASY_HISTORY
	if (STREQ("HISTSIZE", name))
		return V_HISTSIZE;
	if (STREQ("HISTFILE", name))
		return V_HISTFILE;
#endif
	if (STREQ("FCEDIT", name))
		return V_FCEDIT;
	if (STREQ("COLUMNS", name))
		return V_COLUMNS;
	return V_NONE;
}

extern	time_t time();
static	time_t	seconds;		/* time SECONDS last set */
#ifdef NOSTDHDRS
extern	int	rand();
extern	void	srand();
#endif

static void
getspec(vp)
	register struct tbl *vp;
{
	switch (special(vp->name)) {
	case V_SECONDS:
		vp->flag &= ~ SPECIAL;
		setint(vp, time((time_t *)0) - seconds);
		vp->flag |= SPECIAL;
		break;
	case V_RANDOM:
		vp->flag &= ~ SPECIAL;
		setint(vp, (rand() & 0x7fff));
		vp->flag |= SPECIAL;
		break;
#ifndef EASY_HISTORY
	case V_HISTSIZE:
		vp->flag &= ~ SPECIAL;
		setint(vp, histsize);
		vp->flag |= SPECIAL;
		break;
#endif
	}
}

static void
setspec(vp)
	register struct tbl *vp;
{
	extern void	mbset(), mpset();

	switch (special(vp->name)) {
	  case V_PATH:
		path = strval(vp);
		flushcom(1);	/* clear tracked aliases */
		break;
	  case V_IFS:
		setctypes(strval(vp), C_IFS);
		break;
	  case V_SECONDS:
		seconds = time((time_t *)0);
		break;
	  case V_OPTIND:
		if (intval(vp) == 1)
			resetopts();
		break;
	  case V_MAIL:
		mbset(strval(vp));
		break;
	  case V_MAILPATH:
		mpset(strval(vp));
		break;
	  case V_RANDOM:
		vp->flag &= ~ SPECIAL;
		srand((unsigned int)intval(vp));
		vp->flag |= SPECIAL;
		break;
#ifndef EASY_HISTORY
	  case V_HISTSIZE:
		vp->flag &= ~ SPECIAL;
		sethistsize(intval(vp));
		vp->flag |= SPECIAL;
		break;
	  case V_HISTFILE:
		sethistfile(strval(vp));
		break;
#endif
	  case V_FCEDIT:
		set_editmode(strval(vp));
		break;
	  case V_COLUMNS:
		if ((x_cols = intval(vp)) <= 0)
		  x_cols=80;
		break;
	}
}

./pdksh/sh/jobs.c   644    653   1762       47556  5302766161  11163 0ustar  hlu/*
 * Process and job control
 */
#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

/*
 * based on version by Ron Natalie, BRL
 * modified by Simon J. Gerraty <[email protected]>
 *
 * TODO:
 *	change Proc table to Job table, with array of pids.
 *	make %+ be jobs, %- be jobs->next.
 *	do not JFREE members of pipeline.
 *	consider procs[] related critical sections.
 */

#include "stdh.h"
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/times.h>
#include <sys/wait.h>
#include "sh.h"
#ifdef JOBS
#ifdef _BSDI
#define _BSD
#define WIFCORED(x) WCOREDUMP(x)
#endif
#ifdef _BSD
#include <sys/ioctl.h>
#else
#include "termios.h"
#endif
#endif
#ifdef linux
#include <fcntl.h>
#endif

#ifdef _BSD
/*
 * These macros are for the benefit of SunOS 4.0.2 and 4.0.3
 * SunOS 4.1.1 already defines most of them.
 * Clearly these are aimed at SunOS, they may work for other
 * BSD systems but I can't promise.
 */
# ifndef WIFSTOPPED
#   define WIFSTOPPED(x)	((x).w_stopval == WSTOPPED)
# endif
# ifndef WIFSIGNALED
#   define WIFSIGNALED(x) ((x).w_stopval != WSTOPPED && (x).w_termsig != 0)
# endif
# ifndef WIFEXITED
#   define WIFEXITED(x)	((x).w_stopval != WSTOPPED && (x).w_termsig == 0)
# endif
# ifndef WSTOPSIG
#   define WSTOPSIG(x)	((x).w_stopsig)
# endif
# ifndef WTERMSIG
#   define WTERMSIG(x)	((x).w_termsig)
# endif
# ifndef WIFCORED
#   define WIFCORED(x)	((x).w_coredump)
# endif
# ifndef WEXITSTATUS
#   define WEXITSTATUS(x)	((x).w_retcode)
# endif
# ifndef HAVE_WAITPID
#   define	waitpid(pid, sp, opts)	wait3(sp, opts, (void*)NULL)
# endif
#else					/* not _BSD */
# ifndef WIFCORED
#   define	WIFCORED(x)	(!!((x)&0x80)) /* non-standard */
# endif
#endif

/* as of P1003.1 Draft 12.3:
 *	pid_t getpgrp(void);		// Get process group id
 *	pid_t setsid(void);		// Create session and Set process group id
 *	int setpgid(pid_t pid, pid_t pgid); // Set process group id for job control
 */


#ifdef JOBS
#ifdef _BSD			/* _BSD 4.* */
#define	setpgid(p, pg)	setpgrp(p, pg)
#define	getpgid(p)	getpgrp(p)
#define	tcsetpgrp(fd,p)	ioctl(fd, TIOCSPGRP, &(p))
#else				/* POSIX-compatible */
#define	getpgid(p)	getpgrp() /* 1003.1 stupidity */
#define	killpg(p, s)	kill(-(p), s)
#endif
#endif


#ifndef	SIGCHLD
#define	SIGCHLD	SIGCLD
#endif
#ifndef WAIT_T
#ifdef _BSD
#define WAIT_T union wait
#else
#define WAIT_T int
#endif
#ifdef _BSDI
#undef WAIT_T
#define WAIT_T int
#endif
#endif
#ifndef SA_RESTART
#define SA_RESTART	0
#endif

typedef struct Proc Proc;
struct Proc {
	Proc   *next;		/* `procs' list link */
	int	job;		/* job number: %n */
	short	volatile state;	/* proc state */
	short	volatile notify; /* proc state has changed */
	Proc   *prev;		/* prev member of pipeline */
	pid_t	proc;		/* process id */
	pid_t	pgrp;		/* process group if flag[FMONITOR] */
	short	flags;		/* execute flags */
	WAIT_T	status;		/* wait status */
	clock_t	utime, stime;	/* user/system time when JDONE */
	char	com [48];	/* command */
};

/* proc states */
#define	JFREE	0		/* unused proc */
#define	JRUN	1		/* foreground */
#define JEXIT	2		/* exit termination */
#define	JSIGNAL	3		/* signal termination */
#define	JSTOP	4		/* stopped */

static	Proc *procs = NULL;	/* job/process table */

clock_t	j_utime, j_stime;	/* user and system time for last job a-waited */
#ifdef JOBS
# ifdef USE_SIGACT
sigset_t sm_default, sm_sigchld;	/* signal masks */
# else
static	int	sm_default, sm_sigchld;	/* signal masks */
# endif
static	int	our_pgrp;		/* shell's pgrp */
#endif
static	Proc   *j_lastj;		/* last proc created by exchild */
static	int	j_lastjob = 0;		/* last created job */
static	int	j_current = 0;		/* current job */
static	int	j_previous = 0;		/* previous job */

static int      j_waitj     ARGS((Proc *aj, int intr));
static void     j_print     ARGS((Proc *j));
static int      j_newjob    ARGS((void));
static Proc *   j_search    ARGS((int job));
static void	j_sigchld   ARGS((int sig));
  
/* initialize job control */
void
j_init()
{
#ifdef JOBS
# if defined(NTTYDISC) && defined(TIOCSETD)
	int ldisc = NTTYDISC;	/* BSD brain damage */

	if (ttyfd >= 0)
		ioctl(ttyfd, TIOCSETD, &ldisc);
# endif
	our_pgrp = getpgid(0);
	sigchld_caught = 0;
# ifdef USE_SIGACT
	sigemptyset(&sm_default);
	sigemptyset(&sm_sigchld);
	sigaddset(&sm_sigchld, SIGCHLD);
# else
	sm_default = 0;
	sm_sigchld = sigmask(SIGCHLD);
	_TRACE(5, ("j_init: sm_sigchld == 0x%x", sm_sigchld));
# endif
#endif 
#ifndef JOBS
# ifdef USE_SIGACT
	sigaction(SIGCHLD, &Sigact_dfl, NULL);
# else
#   ifdef _SYSV
	signal(SIGCHLD, SIG_DFL);	/* necessary ??? */
#   endif
# endif
#endif
}

/* job cleanup before shell exit */
void
j_exit()
{
	register Proc *j;
	int killed = 0;

#ifdef JOBS
	/* kill stopped jobs */
	for (j = procs; j != NULL; j = j->next)
		if (j->state == JSTOP) {
			killed ++;
			killpg(j->pgrp, SIGHUP);
			killpg(j->pgrp, SIGCONT);
		}
	if (killed)
		sleep(1);
#endif
	j_notify();

#ifdef JOBS
	if (flag[FMONITOR]) {
		flag[FMONITOR] = 0;
		j_change();
	}
#endif
}

#ifdef JOBS
/* turn job control on or off according to flag[FMONITOR] */
void
j_change()
{
#ifdef USE_SIGACT
	static struct sigaction old_tstp, old_ttin, old_ttou;
#else
	static handler_t old_tstp, old_ttin, old_ttou;
#endif
	if (flag[FMONITOR]) {
		if (ttyfd < 0) {
			flag[FMONITOR] = 0;
			shellf("job control requires tty\n");
			return;
		}
#ifdef USE_SIGACT
		Sigact.sa_handler = j_sigchld;
		sigemptyset(&Sigact.sa_mask);
		Sigact.sa_flags = SA_RESTART;
		sigaction(SIGCHLD, &Sigact, NULL);
		Sigact.sa_flags = 0;
		sigtraps[SIGCHLD].sig_dfl = 1; /* restore on fork */
		sigaction(SIGTSTP, &Sigact_ign, &old_tstp);
		sigtraps[SIGTSTP].sig_dfl = 1;
		sigaction(SIGTTIN, &Sigact_ign, &old_ttin);
		sigtraps[SIGTTIN].sig_dfl = 1;
		sigaction(SIGTTOU, &Sigact_ign, &old_ttou);
		sigtraps[SIGTTOU].sig_dfl = 1;
#else
		(void) signal(SIGCHLD, j_sigchld);
		sigtraps[SIGCHLD].sig_dfl = 1; /* restore on fork */
		old_tstp = signal(SIGTSTP, SIG_IGN);
		sigtraps[SIGTSTP].sig_dfl = 1;
		old_ttin = signal(SIGTTIN, SIG_IGN);
		sigtraps[SIGTTIN].sig_dfl = 1;
		old_ttou = signal(SIGTTOU, SIG_IGN);
		sigtraps[SIGTTOU].sig_dfl = 1;
#endif
#ifdef USE_SIGACT
		sigprocmask(SIG_SETMASK, &sm_default, NULL);
#else
		sigsetmask(sm_default);
#endif
		tcsetpgrp(ttyfd, our_pgrp);
	} else {
#ifdef USE_SIGACT
		sigaction(SIGCHLD, &Sigact_dfl, NULL);
		sigaction(SIGTSTP, &old_tstp, NULL);
		sigtraps[SIGTSTP].sig_dfl = 0;
		sigaction(SIGTTIN, &old_ttin, NULL);
		sigtraps[SIGTTIN].sig_dfl = 0;
		sigaction(SIGTTOU, &old_ttou, NULL);
		sigtraps[SIGTTOU].sig_dfl = 0;
#else
		(void) signal(SIGCHLD, SIG_DFL);
		(void) signal(SIGTSTP, old_tstp);
		sigtraps[SIGTSTP].sig_dfl = 0;
		(void) signal(SIGTTIN, old_ttin);
		sigtraps[SIGTTIN].sig_dfl = 0;
		(void) signal(SIGTTOU, old_ttou);
		sigtraps[SIGTTOU].sig_dfl = 0;
#endif
	}
}
#endif

/* execute tree in child subprocess */
int
exchild(t, flags)
	struct op *t;
	int flags;
{
	register int i;
	register Proc *j;
	int rv = 0;
	int forksleep;

	flags &= ~XFORK;
	if ((flags&XEXEC))
		return execute(t, flags);

	/* get free Proc entry */
	for (j = procs; j != NULL; j = j->next)
		if (j->state == JFREE)
			goto Found;
	j = (Proc*) alloc(sizeof(Proc), APERM);
	j->next = procs;
	j->state = JFREE;
	procs = j;
  Found:

	j->prev = ((flags&XPIPEI)) ? j_lastj : NULL;
	j->proc = j->pgrp = 0;
	j->flags = flags;
	j->job = (flags&XPIPEI) ? j_lastjob : j_newjob();
	snptreef(j->com, sizeof(j->com), "%T", t); /* save proc's command */
	j->com[sizeof(j->com)-1] = '\0';
	j->state = JRUN;

	/* stdio buffer must be flushed and invalidated */
	for (i = (flags&XXWHL) ? 1 : 0; i < NUFILE; i++)
		flushshf(i);

	/* create child process */
	forksleep = 0;
#ifdef JOBS
	/* don't allow SIGCHLD until we are ready */

#ifdef USE_SIGACT
	sigprocmask(SIG_SETMASK, &sm_sigchld, NULL);
# else
	sigsetmask(sm_sigchld);
# endif
#endif
	while ((i = fork()) < 0 && errno == EAGAIN && forksleep < 32) {
		if (forksleep) {
			sleep(forksleep);
			forksleep <<= 1;
		} else
			forksleep = 1;
	}
	if (i < 0) {
		j->state = JFREE;
		errorf("cannot fork - try again\n");
	}
	j->proc = (i != 0) ? i : getpid();

#ifdef JOBS
	/* job control set up */
	if (flag[FMONITOR] && !(flags&XXCOM))
	{
	  j->pgrp = !(flags&XPIPEI) ? j->proc : j_lastj->pgrp;
	  /* do in both parent and child to avoid fork race condition */
	  if (!(flags&XBGND))
	    tcsetpgrp(ttyfd, j->pgrp); /* could be trouble */
	  setpgid(j->proc, j->pgrp);
	}
#endif
	j_lastj = j;

	if (i == 0) {		/* child */
		e.oenv = NULL;
		if (flag[FTALKING])
			restoresigs();
		if ((flags&XBGND) && !flag[FMONITOR])
		{
#ifdef USE_SIGACT
		  sigaction(SIGINT, &Sigact_dfl, NULL);
		  sigaction(SIGQUIT, &Sigact_dfl, NULL);
		  if (flag[FTALKING])
		    sigaction(SIGTERM, &Sigact_dfl, NULL);
#else
		  signal(SIGINT, SIG_IGN);
		  signal(SIGQUIT, SIG_IGN);
		  if (flag[FTALKING])
		    signal(SIGTERM, SIG_DFL);
#endif
			if (!(flags&XPIPEI)) {
				i = open("/dev/null", 0);
				(void) dup2(i, 0);
				close(i);
			}
		}
		for (j = procs; j != NULL; j = j->next)
			j->state = JFREE;
		ttyfd = -1;
#ifdef JOBS
		/* is this needed in the child? */
# ifdef USE_SIGACT
		sigprocmask(SIG_SETMASK, &sm_default, NULL);
# else
		sigsetmask(sm_default);
# endif
#endif
		flag[FMONITOR] = flag[FTALKING] = 0;
		cleartraps();
		execute(t, flags|XEXEC); /* no return */
		/* NOTREACHED */
	}

	/* shell (parent) stuff */
	if ((flags&XBGND)) { /* async statement */
		async = j->proc;
		j_previous = j_current;
		j_current = j->job;
		if (flag[FTALKING])
			j_print(j);
	}
#ifdef JOBS
# ifdef USE_SIGACT
	sigprocmask(SIG_SETMASK, &sm_default, NULL);
# else
	sigsetmask(sm_default);
# endif
#endif
	if (!(flags&XBGND))
	{ 		/* sync statement */
		if (!(flags&XPIPE))
			rv = j_waitj(j, 0);
	}

	return rv;
}

/* wait for last job: pipeline or $() sub-process */
int
waitlast()
{
	return j_waitj(j_lastj, 0);
}

/* wait for job to complete or change state */
static int
j_waitj(aj, intr)
	Proc *aj;
	int intr;		/* interruptable */
{
	register Proc *j;
	int rv = 1;
	int ttysig = 0;

#ifdef JOBS
	if (flag[FMONITOR])
	{
# ifdef USE_SIGACT
	  sigprocmask(SIG_SETMASK, &sm_sigchld, NULL);
# else
	  _TRACE(5, ("j_waitj: sigsetmask(sm_sigchld==0x%x)", sm_sigchld));
	  sigsetmask(sm_sigchld);
# endif
	}
#endif
	/* wait for all members of pipeline */
	for (j = aj; j != NULL; j = j->prev) {
		/* wait for job to finish, stop, or ^C of built-in wait */
		while (j->state == JRUN) {
#ifdef JOBS
			if (flag[FMONITOR])
			{
			  /*
			   * 91-07-07 <sjg@sun0>
			   * we don't want to wait for a signal
			   * that has already arrived :-)
			   */
			  if (!sigchld_caught)
			  {
# ifdef USE_SIGACT
			    sigsuspend(&sm_default);
# else
			    _TRACE(4, ("j_waitj: sigpause(%d), sigchld_caught==%d", sm_default, sigchld_caught));
			    sigpause(sm_default);
			    _TRACE(4, ("j_waitj: sigpause() returned %d, sigchld_caught==%d", errno, sigchld_caught));
# endif /* USE_SIGACT */
			  }
			}
			else
#endif /* JOBS */
				j_sigchld(0);
			/*
			 * Children to reap
			 */
			if (sigchld_caught)
			  j_reapchld();
			_TRACE(4, ("j_waitj: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
			
			if (sigtraps[SIGINT].set && intr)
				goto Break;
		}
		if (j->state == JEXIT) { /* exit termination */
			if (!(j->flags&XPIPEO))
				rv = WEXITSTATUS(j->status);
			j->notify = 0;
		} else
		if (j->state == JSIGNAL) { /* signalled to death */
			if (!(j->flags&XPIPEO))
				rv = 0x80 + WTERMSIG(j->status);
			if (WTERMSIG(j->status) == SIGINT ||
			    (WTERMSIG(j->status) == SIGPIPE &&
			     (j->flags&XPIPEO)))
				j->notify = 0;
			if (WTERMSIG(j->status) == SIGINT ||
			    WTERMSIG(j->status) == SIGQUIT)
				ttysig = 1;
		} else
#ifdef JOBS
		if (j->state == JSTOP)
			if (WSTOPSIG(j->status) == SIGTSTP)
				ttysig = 1;
#else
		;
#endif
	}

	/* compute total child time for time statement */
	for (j = aj; j != NULL; j = j->prev)
		j_utime += j->utime, j_stime += j->stime;

	/* find new current job */
#ifdef JOBS
	if (aj->state == JSTOP) {
		j_previous = j_current;
		j_current = aj->job;
	} else {
#else
	if (1) {
#endif
		int hijob = 0;

		/* todo: this needs to be done in j_notify */
		/* todo: figure out what to do with j_previous */
		j_current = 0;
		for (j = procs; j != NULL; j = j->next)
			if ((j->state == JRUN || j->state == JSTOP)
			    && j->job > hijob) {
				hijob = j->job;
				j_current = j->job;
			}
	}

  Break:
#ifdef JOBS
	if (flag[FMONITOR])
	{
	  /* reset shell job control state */
# ifdef USE_SIGACT
	  sigprocmask(SIG_SETMASK, &sm_default, NULL);
# else
	  sigsetmask(sm_default);
# endif
	  tcsetpgrp(ttyfd, our_pgrp);
	}
#endif
	if (ttysig)
		fputc('\n', shlout);
	j_notify();

	return rv;
}

/* SIGCHLD handler to reap children */
/*
 * 91-07-07 <sjg@sun0>
 * On the Sun SS2 this appears to get called
 * too quickly!
 * So just record the event and process later.
 */
static void
j_sigchld(sig)
	int sig;
{
	sigchld_caught++;	/* acknowledge it */
}

/*
 * 91-07-07 <sjg@sun0>
 * This now gets called when j_sigchld()
 * has recorded some signals...
 */
j_reapchld()
{
	struct tms t0, t1;
#if defined(JOBS)
# ifdef USE_SIGACT
	sigset_t	sm_old;

	sigprocmask(SIG_SETMASK, NULL, &sm_old);
# else
	int sm_old;

	sm_old = sigblock(0);	/* just get current mask */
	_TRACE(5, ("j_reapchld: sm_old==0x%x, sigchld_caught==%d", sm_old, sigchld_caught));
# endif
#endif
	(void) times(&t0);

	do {
		register Proc *j;
		int pid;
		WAIT_T status;
#ifdef JOBS
		if (flag[FMONITOR])
			pid = waitpid(-1, &status, (WNOHANG|WUNTRACED));
		else
#endif
			pid = wait(&status);
		if (pid < 0 && errno == ECHILD)
		{
		  /* no children - what are we doing here? */
		  _TRACE(5, ("j_reapchld: no children"));
		  sigchld_caught = 0;
		  break;
		}
		if (pid <= 0)	/* return if would block (0) ... */
			break;	/* ... or no children or interrupted (-1) */
		(void) times(&t1);

		_TRACE(5, ("j_reapchld: looking for pid==%d", pid));

		for (j = procs; j != NULL; j = j->next)
		{
		  _TRACE(6, ("j_reapchld: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
		  if (j->state != JFREE && j->proc == pid)
		    goto Found;
		}
		_TRACE(5, ("j_reapchld: did not find pid==%d", pid));
		continue;
	  Found:
		_TRACE(5, ("j_reapchld: found pid==%d", pid));
		j->notify = 1;
		j->status = status;
#ifdef JOBS
		if (WIFSTOPPED(status))
			j->state = JSTOP;
		else
#endif
		if (WIFEXITED(status))
			j->state = JEXIT;
		else
		if (WIFSIGNALED(status))
			j->state = JSIGNAL;

		/* compute child's time */
		/* todo: what does a stopped job do? */
		j->utime = t1.tms_cutime - t0.tms_cutime;
		j->stime = t1.tms_cstime - t0.tms_cstime;
		t0 = t1;
#ifdef JOBS
# ifdef USE_SIGACT
		sigprocmask(SIG_BLOCK, &sm_sigchld, NULL);
# else
		sigblock(sm_sigchld);
# endif
#endif
		if (--sigchld_caught < 0) /* reduce the count */
		  sigchld_caught = 0;
#ifdef JOBS
# ifdef USE_SIGACT
		sigprocmask(SIG_SETMASK, &sm_old, NULL);
# else
		_TRACE(5, ("j_reapchld: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
		sigsetmask(sm_old); /* restore old mask */
# endif
#endif
		
#ifdef JOBS
	} while (flag[FMONITOR]);
#else
	} while (0);		/* only once if wait()ing */
#endif
/*
 * this should be safe
 */
#if defined(_SYSV) && !defined(JOBS) && !defined(USE_SIGACT)
	signal(SIGCHLD, j_sigchld);
#if 0
	/* why was this here??? */
	signal(SIGCLD, SIG_DFL);
#endif
#endif
}

j_reap()
{
  if (sigchld_caught)
    j_reapchld();
/*
 * now done in j_reapchld()
 */
#if 0 && defined(_SYSV) && !defined(JOBS) && !defined(USE_SIGACT)
	signal(SIGCHLD, j_sigchld);
	signal(SIGCLD, SIG_DFL);
#endif
	return(0);
}

/* wait for child, interruptable */
int
waitfor(job)
	int job;
{
	register Proc *j;

	if (job == 0 && j_current == 0)
		errorf("no current job\n");
	j = j_search((job == 0) ? j_current : job);
	if (j == NULL)
		errorf("no such job: %d\n", job);
	if (flag[FTALKING])
		j_print(j);
	if (e.interactive) {	/* flush stdout, shlout */
		fflush(shf[1]);
		fflush(shf[2]);
	}
	return j_waitj(j, 1);
}

/* kill (built-in) a job */
void
j_kill(job, sig)
	int job;
	int sig;
{
	register Proc *j;

	j = j_search(job);
	if (j == NULL)
		errorf("cannot find job\n");
	if (j->pgrp == 0) {	/* !flag[FMONITOR] */
		if (kill(j->proc, sig) < 0) /* todo: all member of pipeline */
			errorf("kill: %s\n", strerror(errno));
#ifdef JOBS
	} else {
		if (sig == SIGTERM || sig == SIGHUP)
			(void) killpg(j->pgrp, SIGCONT);
		if (killpg(j->pgrp, sig) < 0)
			errorf("killpg: %s\n", strerror(errno));
#endif
	}
}

#ifdef JOBS

/* fg and bg built-ins */
int
j_resume(job, bg)
	int job;
	int bg;
{
	register Proc *j; 
	
	j = j_search((job == 0) ? j_current : job);
	if (j == NULL)
		errorf("cannot find job\n", job);
	if (j->pgrp == 0)
		errorf("job not job-controlled\n");

	j->state = JRUN;
	j_print(j);
	flushshf(2);

	if (!bg)
  		tcsetpgrp(ttyfd, j->pgrp); /* attach shell to job */
	if (killpg(j->pgrp, SIGCONT) < 0)
		errorf("cannot continue job %%%d\n", job);
	if (!bg)
		return j_waitj(j, 0);
	return 0;
}

#endif

/* list jobs for jobs built-in */
void
j_jobs()
{
	register Proc *j; 

	for (j = procs; j != NULL; j = j->next)
		if (j->state != JFREE)
			j_print(j);
}

/* list jobs for top-level notification */
void
j_notify()
{
	register Proc *j; 

	/*
	 * since reaping is no longer done in the signal handler
	 * we had better try here...
	 */
	if (sigchld_caught)
	  j_reapchld();
	
	for (j = procs; j != NULL; j = j->next) {
		if (j->state == JEXIT && !flag[FTALKING])
			j->notify = 0;
		if (j->state != JFREE && j->notify)
			j_print(j);
		if (j->state == JEXIT || j->state == JSIGNAL)
			j->state = JFREE;
		j->notify = 0;
	}
}

static void
j_print(j)
	register Proc *j;
{
	char buf [64], *s = buf;

	switch (j->state) {
	  case JRUN:
		s = "Running";
		break;

#ifdef JOBS
	  case JSTOP:
		strcpy(buf, "Stopped ");
		s = strchr(sigtraps[WSTOPSIG(j->status)].mess, '(');
		if (s != NULL)
			strcat(buf, s);
		s = buf;
		break;
#endif

	  case JEXIT: {
		int rv;
		rv = WEXITSTATUS(j->status);
		sprintf(buf, "Done (%d)", rv);
		if (rv == 0)
			*strchr(buf, '(') = 0;
		j->state = JFREE;
		} break;

	  case JSIGNAL: {
		int sig = WTERMSIG(j->status);
		char *n = sigtraps[sig].mess;
		if (n != NULL)
			sprintf(buf, "%s", n);
		else
			sprintf(buf, "Signal %d", sig);
		if (WIFCORED(j->status))
			strcat(buf, " - core dumped");
		j->state = JFREE;
		} break;

	  default:
		s = "Hideous job state";
		j->state = JFREE;
		break;
	}
	shellf("%%%-2d%c %5d %-20s %s%s\n", j->job,
	       (j_current==j->job) ? '+' : (j_previous==j->job) ? '-' : ' ',
	       j->proc, s, j->com, (j->flags&XPIPEO) ? "|" : "");
}

/* convert % sequence to job number */
int
j_lookup(cp)
	char *cp;
{
	register Proc *j;
	int len, job = 0;

	if (*cp == '%')		/* leading % is optional */
		cp++;
	switch (*cp) {
	  case '\0':
	  case '+':
		job = j_current;
		break;

	  case '-':
		job = j_previous;
		break;

	  case '0': case '1': case '2': case '3': case '4':
	  case '5': case '6': case '7': case '8': case '9': 
		job = atoi(cp);
		break;

	  case '?':		/* %?string */
		for (j = procs; j != NULL; j = j->next)
			if (j->state != JFREE && strstr(j->com, cp+1) != NULL)
				job = j->job;
		break;

	  default:		/* %string */
		len = strlen(cp);
		for (j = procs; j != NULL; j = j->next)
			if (j->state != JFREE && strncmp(cp, j->com, len) == 0)
				job = j->job;
		break;
	}
	if (job == 0)
		errorf("%s: no such job\n", cp);
	return job;
}

/* are any stopped jobs ? */
#ifdef JOBS
int
j_stopped()
{
	register Proc *j; 

	for (j = procs; j != NULL; j = j->next)
		if (j->state == JSTOP)
			return 1;
	return 0;
}
#endif

/* create new job number */
static int
j_newjob()
{
	register Proc *j; 
	register int max = 0;
	
	j_lastjob ++;
	for (j = procs; j != NULL; j = j->next)
		if (j->state != JFREE && j->job)
			if (j->job > max)
				max = j->job;
	if (j_lastjob > max)
		j_lastjob = max + 1;
	return j_lastjob;
}

/* search for job by job number */
static Proc *
j_search(job)
	int job;
{
	register Proc *j;

	for (j = procs; j != NULL; j = j->next)
		if (j->state != JFREE && job == j->job && !(j->flags&XPIPEO))
			return j;
	return NULL;
}

./pdksh/sh/trace.c   644    653   1762        6007  5243743615  11271 0ustar  hlu/* NAME:
 *      trace.c - a simple trace facility
 *
 * SYNOPSIS:
 *      TRACE(level, (fmt [, ...]));
 *
 * DESCRIPTION:
 *      This module provides a simple trace facility via
 *      a call to checkpoint() which opens a log file and writes 
 *      an entry and closes the log (so that process crashes 
 *      won't destroy the log :-).  checkpoint() takes options 
 *      like printf().  If Trace_log is not initialized then
 *      stderr is used.
 *      
 *      The header file trace.h defines a macro TRACE() which 
 *      is useful in that it allows checkpoint to be called 
 *      based on the value of Trace_level, and the calls can be 
 *      eliminated by undefining USE_TRACE.
 *
 * RETURN VALUE:
 *      None.
 *
 * FILES:
 *      None.
 *
 * SEE ALSO:
 *      
 *
 * BUGS:
 *      
 *
 * AMENDED:
 *      91/11/22  22:53:56  (sjg)
 *
 * RELEASED:
 *      91/11/22  22:54:17  v1.2
 *
 *      @(#)Copyright (c) 1990 Simon J. Gerraty.
 */
#ifdef USE_TRACE

#ifndef lint
static char  sccs_id[] = "@(#)trace.c     1.2  91/11/22  22:53:56  (sjg)";
#endif

/* include files */
#include <stdio.h>
#ifdef __STDC__
# include <stdlib.h>
#endif

#define EXTERN
#include "trace.h"
#undef EXTERN

/* some useful #defines */
#ifndef ENTRY
# define ENTRY
# define LOCAL static
# define BOOLEAN int
#endif
#ifndef TRUE
# define TRUE  1
# define FALSE 0
#endif
#ifndef ARGS
# if defined(__STDC__) || defined(PROTO)
#   define ARGS(p) p
# else
#   define ARGS(p) ()
# endif
#endif


/* NAME:
 *      checkpoint - write a logfile entry
 *
 * SYNOPSIS:
 *      checkpoint(fmt, ...)
 *
 * DESCRIPTION:
 *      This function takes a variable number or args  
 *      like the printf(3S) family of functions.
 *
 * RETURN VALUE:
 *      None
 */
extern char * _CDECL strdup	ARGS((char *s));
  
#ifdef __STDC__
# include <stdarg.h>

ENTRY void _CDECL
checkpoint(fmt)
	char *fmt;
{
  int c;
  va_list arg_ptr;
  FILE *fp;
  register char *rcp;
  char  *mode;
  static  setup;
  
  va_start(arg_ptr, fmt);
#else  /* __STDC__ */
# include <varargs.h>
  
ENTRY void _CDECL
checkpoint(va_alist)
  va_dcl
{
  extern char *getenv	ARGS((char *var));
  char *fmt;
  int c;
  va_list arg_ptr;
  FILE *fp;
  register char *rcp;
  char  *mode;
  static  setup;
  
  va_start(arg_ptr);
  fmt = va_arg(arg_ptr, char *);
#endif /* __STDC__ */
  
  /* 42 is a "magic" number */
  if (setup == 42)
    mode = "a";
  else
  {
    if (Trace_level == 0 && (rcp = getenv("TRACE_LEVEL")))
      Trace_level = atoi(rcp);
    if (Trace_log == NULL || *Trace_log == '\0')
    {
      if (rcp = getenv("TRACE_LOG"))
	Trace_log = strdup(rcp);
      else
	Trace_log = NULL;
    }
    setup = 42;
    mode= "w";
  }
  if (Trace_log)
    fp = fopen(Trace_log, mode);
  else
    fp = stderr;
  if (fp != (FILE *)NULL)
  {
    vfprintf(fp, fmt, arg_ptr);
    fputc('\n', fp);
    if (fp == stderr)
      fflush(fp);
    else
      fclose(fp);
  }
}

#endif /* USE_TRACE */

/* This lot (for GNU-Emacs) goes at the end of the file. */
/* 
 * Local Variables:
 * version-control:t
 * comment-column:40
 * End:
 */
./pdksh/sh/exec.c   644    653   1762       44176  5243743655  11154 0ustar  hlu/*
 * execute command tree
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "sh.h"
#include "edit.h"

static int      comexec     ARGS((struct op *t, char **vp, char **ap, int flags));
#ifdef	SHARPBANG
static void     scriptexec  ARGS((struct op *tp, char **ap));
#endif
static void     iosetup     ARGS((struct ioword *iop));
static int      herein      ARGS((char *hname, int sub));
static void     echo        ARGS((char **vp, char **ap));
static	char 	*do_selectargs ARGS((char **ap, char *));
static	int	selread	    ARGS((void));


/*
 * handle systems that don't have F_SETFD
 */
#ifndef F_SETFD
# ifndef MAXFD
#   define  MAXFD 64
# endif
/*
 * a bit field would be smaller, but this
 * will work
 */
static char clexec_tab[MAXFD+1];

/* this is so that main() can clear it */
void
init_clexec()
{
  (void) memset(clexec_tab, 0, sizeof(clexec_tab)-1);
}

int
fd_clexec(fd)
  int fd;
{
  if (fd < sizeof(clexec_tab))
  {
    clexec_tab[fd] = 1;
    return 0;
  }
  return -1;
}
#endif


/*
 * execute command tree
 */
int
execute(t, flags)
	register struct op *t;
	volatile int flags;	/* if XEXEC don't fork */
{
	int i;
	int volatile rv = 0;
	int pv[2];
	register char **ap;
	char *s, *cp;
	struct ioword **iowp;

	if (t == NULL)
		return 0;

	if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
		return exchild(t, flags); /* run in sub-process */

	newenv(E_EXEC);
	if (trap)
		runtraps();
 
	if (t->ioact != NULL || t->type == TPIPE) {
		e.savefd = (short*) alloc(sizeofN(short, NUFILE), ATEMP);
		for (i = 0; i < NUFILE; i++)
			e.savefd[i] = 0; /* not redirected */
		/* mark fd 0/1 in-use if pipeline */
		if (flags&XPIPEI)
			e.savefd[0] = -1;
		if (flags&XPIPEO)
			e.savefd[1] = -1;
	}

	/* do redirection, to be restored in quitenv() */
	if (t->ioact != NULL)
		for (iowp = t->ioact; *iowp != NULL; iowp++)
			iosetup(*iowp);

	switch(t->type) {
	  case TCOM:
		e.type = E_TCOM;
		rv = comexec(t, eval(t->vars, DOTILDE),
			     eval(t->args, DOBLANK|DOGLOB|DOTILDE), flags);
		break;

	  case TPAREN:
		exstat = rv = execute(t->left, flags|XFORK);
		break;

	  case TPIPE:
		flags |= XFORK;
		flags &= ~XEXEC;
		e.savefd[0] = savefd(0);
		e.savefd[1] = savefd(1);
		flags |= XPIPEO;
		(void) dup2(e.savefd[0], 0); /* stdin of first */
		while (t->type == TPIPE) {
			openpipe(pv);
			(void) dup2(pv[1], 1);	/* stdout of curr */
			exchild(t->left, flags);
			(void) dup2(pv[0], 0);	/* stdin of next */
			closepipe(pv);
			flags |= XPIPEI;
			t = t->right;
		}
		flags &= ~ XPIPEO;
		(void) dup2(e.savefd[1], 1); /* stdout of last */
		exchild(t, flags);
		(void) dup2(e.savefd[0], 0); /* close pipe in */
		if (!(flags&XBGND))
			exstat = rv = waitlast();
		break;

	  case TLIST:
		while (t->type == TLIST) {
			execute(t->left, 0);
			t = t->right;
		}
		rv = execute(t, 0);
		break;

	  case TASYNC:
		rv = execute(t->left, flags|XBGND|XFORK);
		break;

	  case TOR:
	  case TAND:
		rv = execute(t->left, 0);
		if (t->right != NULL && (rv == 0) == (t->type == TAND))
			rv = execute(t->right, 0);
		break;

	  case TFOR:
		e.type = E_LOOP;
		ap = (t->vars != NULL) ?
			eval(t->vars, DOBLANK|DOGLOB|DOTILDE) : e.loc->argv + 1;
		while ((i = setjmp(e.jbuf)))
			if (i == LBREAK)
				goto Break1;
		while (*ap != NULL) {
			setstr(global(t->str), *ap++);
			rv = execute(t->left, 0);
		}
	  Break1:
		break;

	  case TSELECT:
		e.type = E_LOOP;
		ap = (t->vars != NULL) ?
			eval(t->vars, DOBLANK|DOGLOB|DOTILDE) : e.loc->argv + 1;
		while ((i = setjmp(e.jbuf)))
			if (i == LBREAK)
				goto Break1;
		signal(SIGINT, trapsig); /* needs change to trapsig */
		cp = NULL;
		for (;;) {
			if ((cp = do_selectargs(ap, cp)) == (char *)1)
				break;
			setstr(global(t->str), cp);
			rv = execute(t->left, 0);
		}
		break;
		
	  case TWHILE:
	  case TUNTIL:
		e.type = E_LOOP;
		while ((i = setjmp(e.jbuf)))
			if (i == LBREAK)
				goto Break2;
		while ((execute(t->left, 0) == 0) == (t->type == TWHILE))
			rv = execute(t->right, XXWHL);
	  Break2:
		break;

	  case TIF:
	  case TELIF:
		if (t->right == NULL)
			break;	/* should be error */
		rv = execute(t->left, 0) == 0 ?
			execute(t->right->left, 0) :
			execute(t->right->right, 0);
		break;

	  case TCASE:
		cp = evalstr(t->str, 0);
		for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
		    for (ap = t->vars; *ap; ap++)
			if ((s = evalstr(*ap, DOPAT)) && gmatch(cp, s))
				goto Found;
		break;
	  Found:
		rv = execute(t->left, 0);
		break;

	  case TBRACE:
		rv = execute(t->left, 0);
		break;

	  case TFUNCT:
		rv = define(t->str, t->left);
		break;

	  case TTIME:
		rv = timex(t, flags);
		break;

	  case TEXEC:		/* an eval'd TCOM */
		s = t->args[0];
		ap = makenv();
#ifndef F_SETFD
		for (i = 0; i < sizeof(clexec_tab); i++)
		  if (clexec_tab[i])
		  {
		    close(i);
		    clexec_tab[i] = 0;
		  }
#endif
		execve(t->str, t->args, ap);
		if (errno == ENOEXEC) {
			char *shell;
#ifdef	SHARPBANG
			scriptexec(t, ap);
#else
			shell = strval(global("EXECSHELL"));
			if (shell && *shell) {
				if ((shell = search(shell,path,1)) == NULL)
					shell = SHELL;
			} else {
				shell = SHELL;
			}
			*t->args-- = t->str;
			*t->args = shell;
			execve(t->args[0], t->args, ap);
			errorf("No shell\n");
#endif	/* SHARPBANG */
		}
		errorf("%s: %s\n", s, strerror(errno));
	}

	quitenv();		/* restores IO */
	if (e.interactive) {	/* flush stdout, shlout */
		fflush(shf[1]);
		fflush(shf[2]);
	}
	if ((flags&XEXEC))
		exit(rv);	/* exit child */
	return rv;
}

/*
 * execute simple command
 */

static int
comexec(t, vp, ap, flags)
	struct op *t;
	register char **ap, **vp;
	int flags;
{
	int i;
	int rv = 0;
	register char *cp;
	register char **lastp;
	register struct tbl *tp = NULL;
	register struct block *l;
	static struct op texec = {TEXEC};
	extern int c_exec(), c_builtin();

	if (flag[FXTRACE])
		echo(vp, ap);

	/* snag the last argument for $_ */
	if ((lastp = ap) && *lastp) {
		while (*++lastp)
			;
		setstr(typeset("_",LOCAL,0),*--lastp);
	}	

	/* create new variable/function block */
	l = (struct block*) alloc(sizeof(struct block), ATEMP);
	l->next = e.loc; e.loc = l;
	newblock();

 Doexec:
	if ((cp = *ap) == NULL)
		cp = ":";
	tp = findcom(cp, flag[FHASHALL]);

	switch (tp->type) {
	  case CSHELL:			/* shell built-in */
		while (tp->val.f == c_builtin) {
			if ((cp = *++ap) == NULL)
				break;
			tp = tsearch(&builtins, cp, hash(cp));
			if (tp == NULL)
				errorf("%s: not builtin\n", cp);
		}
		if (tp->val.f == c_exec) {
			if (*++ap == NULL) {
				e.savefd = NULL; /* don't restore redirection */
				break;
			}
			flags |= XEXEC;
			goto Doexec;
		}
		if ((tp->flag&TRACE))
			e.loc = l->next; /* no local block */
		i = (tp->flag&TRACE) ? 0 : LOCAL;
		while (*vp != NULL)
			(void) typeset(*vp++, i, 0);
		rv = (*tp->val.f)(ap);
		break;

	case CFUNC:			/* function call */
		if (!(tp->flag&ISSET))
			errorf("%s: undefined function\n", cp);
		l->argv = ap;
		for (i = 0; *ap++ != NULL; i++)
			;
		l->argc = i - 1;
		resetopts();
		while (*vp != NULL)
			(void) typeset(*vp++, LOCAL, 0);
		e.type = E_FUNC;
		if (setjmp(e.jbuf))
			rv = exstat; /* return # */
		else
			rv = execute(tp->val.t, 0);
		break;

	case CEXEC:		/* executable command */
		if (!(tp->flag&ISSET)) {
			/*
			 * mlj addition:
			 *
			 * If you specify a full path to a file
			 * (or type the name of a file in .) which
			 * doesn't have execute priv's, it used to
			 * just say "not found".  Kind of annoying,
			 * particularly if you just wrote a script
			 * but forgot to say chmod 755 script.
			 *
			 * This should probably be done in eaccess(),
			 * but it works here (at least I haven't noticed
			 * changing errno here breaking something
			 * else).
			 *
			 * So, we assume that if the file exists, it
			 * doesn't have execute privs; else, it really
			 * is not found.
			 */
			if (access(cp, 0) < 0)
			    shellf("%s: not found\n", cp);
			else
			    shellf("%s: cannot execute\n", cp);
			rv = 1;
			break;
		}

		/* set $_ to program's full path */
		setstr(typeset("_", LOCAL|EXPORT, 0), tp->val.s);
		while (*vp != NULL)
			(void) typeset(*vp++, LOCAL|EXPORT, 0);

		if ((flags&XEXEC)) {
			j_exit();
			if (flag[FMONITOR] || !(flags&XBGND))
			{
#ifdef USE_SIGACT
			  sigaction(SIGINT, &Sigact_dfl, NULL);
			  sigaction(SIGQUIT, &Sigact_dfl, NULL);
#else
			  signal(SIGINT, SIG_DFL);
			  signal(SIGQUIT, SIG_DFL);
#endif
			}
		}

		/* to fork we set up a TEXEC node and call execute */
		texec.left = t;	/* for tprint */
		texec.str = tp->val.s;
		texec.args = ap;
		rv = exchild(&texec, flags);
		break;
	}
	if (rv != 0 && flag[FERREXIT])
		leave(rv);
	return (exstat = rv);
}

#ifdef	SHARPBANG
static void
scriptexec(tp, ap)
	register struct op *tp;
	register char **ap;
{
	char line[LINE];
	register char *cp;
	register int fd, n;
	char *shell;

	shell = strval(global("EXECSHELL"));
	if (shell && *shell) {
		if ((shell = search(shell,path,1)) == NULL)
			shell = SHELL;
	} else {
		shell = SHELL;
	}

	*tp->args-- = tp->str;
	line[0] = '\0';
	if ((fd = open(tp->str,0)) >= 0) {
		if ((n = read(fd, line, LINE - 1)) > 0)
			line[n] = '\0';
		(void) close(fd);
	}
	if (line[0] == '#' && line[1] == '!') {
		cp = &line[2];
		while (*cp && (*cp == ' ' || *cp == '\t'))
			cp++;
		if (*cp && *cp != '\n') {
			*tp->args = cp;
			while (*cp && *cp != '\n' && *cp != ' ' && *cp != '\t')
				cp++;
			if (*cp && *cp != '\n') {
				*cp++ = '\0';
				while (*cp && (*cp == ' ' || *cp == '\t'))
					cp++;
				if (*cp && *cp != '\n') {
					tp->args--;
					tp->args[0] = tp->args[1];
					tp->args[1] = cp;
					while (*cp && *cp != '\n' &&
					       *cp != ' ' && *cp != '\t')
						cp++;
				}
			}
			*cp = '\0';
		} else
			*tp->args = shell;
	} else
		*tp->args = shell;

	(void) execve(tp->args[0], tp->args, ap);
	errorf( "No shell\n" );
}
#endif	/* SHARPBANG */

int
shcomexec(wp)
	register char **wp;
{
	register struct tbl *tp;

	tp = tsearch(&builtins, *wp, hash(*wp));
	if (tp == NULL)
		errorf("%s: shcomexec botch\n", *wp);
	return (*tp->val.f)(wp);
}

/*
 * define function
 */
int
define(name, t)
	char	*name;
	struct op *t;
{
	register struct block *l;
	register struct tbl *tp;

	for (l = e.loc; l != NULL; l = l->next) {
		lastarea = &l->area;
		tp = tsearch(&l->funs, name, hash(name));
		if (tp != NULL && (tp->flag&DEFINED))
			break;
		if (l->next == NULL) {
			tp = tenter(&l->funs, name, hash(name));
			tp->flag = DEFINED|FUNCT;
			tp->type = CFUNC;
		}
	}

	if ((tp->flag&ALLOC))
		tfree(tp->val.t, lastarea);
	tp->flag &= ~(ISSET|ALLOC);

	if (t == NULL) {		/* undefine */
		tdelete(tp);
		return 0;
	}

	tp->val.t = tcopy(t, lastarea);
	tp->flag |= (ISSET|ALLOC);

	return 0;
}

/*
 * add builtin
 */
builtin(name, func)
	char *name;
	int (*func)();
{
	register struct tbl *tp;
	int flag = DEFINED;

	if (*name == '=') {		/* sets keyword variables */
		name++;
		flag |= TRACE;	/* command does variable assignment */
	}

	tp = tenter(&builtins, name, hash(name));
	tp->flag |= flag;
	tp->type = CSHELL;
	tp->val.f = func;
}

/*
 * find command
 * either function, hashed command, or built-in (in that order)
 */
struct tbl *
findcom(name, insert)
	char	*name;
	int	insert;			/* insert if not found */
{
	register struct block *l = e.loc;
	unsigned int h = hash(name);
	register struct	tbl *tp = NULL;
	static struct tbl temp;

	if (strchr(name, '/') != NULL) {
		tp = &temp;
		tp->type = CEXEC;
		tp->flag = 0;	/* make ~ISSET */
		goto Search;
	}
	for (l = e.loc; l != NULL; l = l->next) {
		tp = tsearch(&l->funs, name, h);
		if (tp != NULL && (tp->flag&DEFINED))
			break;
	}
	if (tp == NULL) {
		tp = tsearch(&commands, name, h);
		if (tp != NULL && eaccess(tp->val.s,1) != 0) {
			if (tp->flag&ALLOC)
				afree(tp->val.s, commands.areap);
			tp->type = CEXEC;
			tp->flag = DEFINED;
		}
	}
	if (tp == NULL)
		tp = tsearch(&builtins, name, h);
	if (tp == NULL) {
		tp = tenter(&commands, name, h);
		tp->type = CEXEC;
		tp->flag = DEFINED;
	}
  Search:
	if (tp->type == CEXEC && !(tp->flag&ISSET)) {
		if (!insert) {
			tp = &temp;
			tp->type = CEXEC;
			tp->flag = 0;	/* make ~ISSET */
		}
		name = search(name, path, 1);
		if (name != NULL) {
			tp->val.s = strsave(name,
					    (tp == &temp) ? ATEMP : APERM);
			tp->flag |= ISSET|ALLOC;
		}
	}
	return tp;
}

/*
 * flush executable commands with relative paths
 */
flushcom(all)
	int all;		/* just relative or all */
{
	register struct tbl *tp;

	for (twalk(&commands); (tp = tnext()) != NULL; )
		if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
			if ((tp->flag&ALLOC))
				afree(tp->val.s, commands.areap);
			tp->flag = DEFINED; /* make ~ISSET */
		}
}

/*
 * search for command with PATH
 */
char *
search(name, path, mode)
	char *name, *path;
	int mode;		/* 0: readable; 1: executable */
{
	register int i;
	register char *sp, *tp;
	struct stat buf;

	if (strchr(name, '/'))
		return (eaccess(name, mode) == 0) ? name : NULL;

	sp = path;
	while (sp != NULL) {
		tp = line;
		for (; *sp != '\0'; tp++)
			if ((*tp = *sp++) == ':') {
				--sp;
				break;
			}
		if (tp != line)
			*tp++ = '/';
		for (i = 0; (*tp++ = name[i++]) != '\0';)
			;
		i = eaccess(line, mode);
		if (i == 0 && (mode != 1 || (stat(line,&buf) == 0 &&
		    (buf.st_mode & S_IFMT) == S_IFREG)))
			return line;
		/* what should we do about EACCES? */
		if (*sp++ == '\0')
			sp = NULL;
	}
	return NULL;
}

/*
 * set up redirection, saving old fd's in e.savefd
 */
static void
iosetup(iop)
	register struct ioword *iop;
{
	register int u = -1;
	char *cp = iop->name;
	extern long lseek();

	if (iop->unit == 0 || iop->unit == 1 || iop->unit == 2)
		e.interactive = 0;
#if 0
	if (e.savefd[iop->unit] != 0)
		errorf("file descriptor %d already redirected\n", iop->unit);
#endif
	e.savefd[iop->unit] = savefd(iop->unit);

	if ((iop->flag&IOTYPE) != IOHERE)
		cp = evalonestr(cp, DOTILDE|DOGLOB);

	switch (iop->flag&IOTYPE) {
	  case IOREAD:
		u = open(cp, 0);
		break;

	  case IOCAT:
		if ((u = open(cp, 1)) >= 0) {
			(void) lseek(u, (long)0, 2);
			break;
		}
		/* FALLTHROUGH */
	  case IOWRITE:
		u = creat(cp, 0666);
		break;

	  case IORDWR:
		u = open(cp, 2);
		break;

	  case IOHERE:
		u = herein(cp, iop->flag&IOEVAL);
		/* cp may have wrong name */
		break;

	  case IODUP:
		if (*cp == '-')
			close(u = iop->unit);
		else
		if (digit(*cp))
			u = *cp - '0';
		else
			errorf("%s: illegal >& argument\n", cp);
		break;
	}
	if (u < 0)
		errorf("%s: cannot %s\n", cp,
		       (iop->flag&IOTYPE) == IOWRITE ? "create" : "open");
	if (u != iop->unit) {
		(void) dup2(u, iop->unit);
		if (iop->flag != IODUP)
			close(u);
	}

	fopenshf(iop->unit);
}

/*
 * open here document temp file.
 * if unquoted here, expand here temp file into second temp file.
 */
static int
herein(hname, sub)
	char *hname;
	int sub;
{
	int fd;
	FILE * volatile f = NULL;

	f = fopen(hname, "r");
	if (f == NULL)
		return -1;
	setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);

	if (sub) {
		char *cp;
		struct source *s;
		struct temp *h;

		newenv(E_ERRH);
		if (setjmp(e.jbuf)) {
			if (f != NULL)
				fclose(f);
			quitenv();
			return -1; /* todo: error()? */
		}

		/* set up yylex input from here file */
		s = pushs(SFILE);
		s->u.file = f;
		source = s;
		if (yylex(ONEWORD) != LWORD)
			errorf("exec:herein error\n");
		cp = evalstr(yylval.cp, 0);

		/* write expanded input to another temp file */
		h = maketemp(ATEMP);
		h->next = e.temps; e.temps = h;
		if (h == NULL)
			error();
		f = fopen(h->name, "w+");
		if (f == NULL)
			error();
		setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
		fputs(cp, f);
		rewind(f);

		quitenv();
	}
	fd = dup(fileno(f));
	fclose(f);
	return fd;
}

static void
echo(vp, ap)
	register char **vp, **ap;
{
	shellf("+");
	while (*vp != NULL)
		shellf(" %s", *vp++);
	while (*ap != NULL)
		shellf(" %s", *ap++);
	shellf("\n");
}

/*
 *	ksh special - the select command processing section
 *	print the args in column form - assuming that we can
 */
#define	COLARGS		20

static char *
do_selectargs(ap, secondtime)
	register char **ap;
	char	*secondtime;
{
	char *rv;

	register int i, c;
	static char *replybase = NULL;
	static int replymax;
	static int repct;
	static int argct;
	
	/*
	 * deal with REPLY variable
	 */
	if (replybase == NULL) {
		replybase = alloc(64, APERM);
		replymax = 64;
	}

	if (!secondtime)
		argct = pr_menu(ap, 0);
	
	/*
	 * and now ask for an answer
	 */
retry:
	shellf("%s", strval(global("PS3")));
	fflush(shlout);
	repct = 0;
	i = 0;
	rv = NULL;
	while ((c = selread()) != EOF) {
		if (c == -2) {
			shellf("Read error\n");
			rv = (char*)1;
			break;
		}
		if (repct+1 >= replymax)
		{	replymax += 64;
			replybase = aresize(replybase, replymax, APERM);
		}
		if (i >= 0 && c >= '0' && c <= '9') {
			replybase[repct++] = c;
			if (i >= 0)
				i = i*10 + (c - '0');
		}
		else
		if (c == '\n') {
			if (repct == 0) {
				pr_menu(ap, 1);
				goto retry;
			}
				
			if (i >= 1 && i <= argct)
				rv = ap[i-1];
			else	rv = "";
			break;
		} else
			i = -1,	replybase[repct++] = c;
	}
	if (rv == NULL) {
		shellf("\n");
		rv = (char *)1;
	}
	replybase[repct] = '\0';
	setstr(global("REPLY"), replybase);
	return rv;
}

/*
 *	print a select style menu
 */
int
pr_menu(ap, usestored)
	register char **ap;
	int usestored;
{
	register char **pp;
	register i, j;
	register int ix;
	static int argct;
	static int nwidth;
	static int dwidth;
	static int ncols;
	static int nrows;

	if (usestored == 0) {
		/*
		 * get dimensions of the list
		 */
		for (argct = 0, nwidth = 0, pp = ap; *pp; argct++, pp++) {
			i = strlen(*pp);
			nwidth = (i > nwidth) ? i : nwidth;
		}
		/*
		 * we will print an index of the form
		 *	%d)
		 * in front of each entry
		 * get the max width of this
		 */
		for (i = argct, dwidth = 1; i >= 10; i /= 10)
			dwidth++;

		if (argct < COLARGS)
			ncols = 1, nrows = argct;
		else {
			ncols = x_cols/(nwidth+dwidth+3);
			nrows = argct/ncols;
			if (argct%ncols) nrows++;
			if (ncols > nrows)
			i = nrows, nrows = ncols, ncols = 1;
		}

	}
	/*
	 * display the menu
	 */
	for (i = 0; i < nrows; i++) {
		for (j = 0; j < ncols; j++) {
			ix = j*nrows + i;
			if (ix < argct)
				shellf("%*d) %-*.*s ", dwidth, ix+1, nwidth, nwidth, ap[ix]);
			}
		shellf("\n");
	}
	return argct;
}

static int
selread()
{	char c;
	register int	rv;
	
	switch (read(0, &c, 1)) {
	   case 1:
		rv = c&0xff;
		break;
	   case 0:
		rv = EOF;
		break;
	   case -1:
		rv = -2;
		break;
	}
	return rv;
}
./pdksh/sh/vi.c   644    653   1762       75042  5243743671  10640 0ustar  hlu/*
 *	vi command editing
 *	written by John Rochester (initially for nsh)
 *	bludgeoned to fit PD ksh by Larry Bouzane and Eric Gisin
 *	Further hacked (bugfixes and tweaks) by Mike Jetzer
 */

#include "config.h"
#ifdef VI

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <setjmp.h>
#include "sh.h"
#include "expand.h"
#include "edit.h"

#define CMDLEN		256
#define Ctrl(c)		(c&0x1f)
extern	int	histN();

static int      nextstate   ARGS((int ch));
static int      vi_insert   ARGS((int ch));
static int      vi_cmd      ARGS((int argcnt, char *cmd));
static int      domove      ARGS((int argcnt, char *cmd, int sub));
static int      redo_insert ARGS((int count));
static          yank_range  ARGS((int a, int b));
static int      bracktype   ARGS((int ch));
static          edit_reset  ARGS((char *buf, int len));
static int      putbuf      ARGS((char *buf, int len, int repl));
static          stripblanks ARGS((void));
static          del_range   ARGS((int a, int b));
static int      findch      ARGS((int ch, int cnt, int forw, int incl));
static int      forwword    ARGS((int argcnt));
static int      backword    ARGS((int argcnt));
static int      endword     ARGS((int argcnt));
static int      Forwword    ARGS((int argcnt));
static int      Backword    ARGS((int argcnt));
static int      Endword     ARGS((int argcnt));
static int      grabhist    ARGS((int save, int n));
static int      grabsearch  ARGS((int save, int start, int fwd, char *pat));
static          redraw_line ARGS((void));
static          refresh     ARGS((int leftside));
static int      outofwin    ARGS((void));
static          rewindow    ARGS((void));
static int      newcol      ARGS((int ch, int col));
static          display     ARGS((char *wb1, char *wb2, int leftside));
static          ed_mov_opt  ARGS((int col, char *wb));

#define C_	0x1
#define M_	0x2
#define E_	0x4
#define X_	0x8
#define U_	0x10
#define B_	0x20
#define O_	0x40
#define S_	0x80

#define isbad(c)	(classify[c]&B_)
#define iscmd(c)	(classify[c]&(M_|E_|C_|U_))
#define ismove(c)	(classify[c]&M_)
#define isextend(c)	(classify[c]&E_)
#define islong(c)	(classify[c]&X_)
#define ismeta(c)	(classify[c]&O_)
#define isundoable(c)	(!(classify[c]&U_))
#define issrch(c)	(classify[c]&S_)

char	classify[128] = {
	B_,	0,	0,	0,	0,	0,	O_,	0,
#if 1	/* Mike B. changes */
	C_|M_,	0,	O_,	0,	O_,	O_,	O_,	0,
#else
	C_,	0,	O_,	0,	O_,	O_,	O_,	0,
#endif
	O_,	0,	C_|U_,	0,	0,	0,	0,	0,
	0,	0,	O_,	0,	0,	0,	0,	0,
#if 1	/* Mike B. changes */
	C_|M_,	0,	0,	C_,	M_,	C_,	0,	0,
#else
	C_,	0,	0,	C_,	M_,	C_,	0,	0,
#endif
	0,	0,	C_,	C_,	M_,	C_,	0,	C_|S_,
	M_,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	M_,	0,	C_,	0,	C_|S_,
	0,	C_,	M_,	C_,	C_,	M_,	M_|X_,	C_,
	0,	C_,	0,	0,	0,	0,	C_,	0,
	C_,	0,	C_,	C_,	M_|X_,	0,	0,	M_,
	C_,	C_,	0,	0,	0,	0,	M_,	C_,
	0,	C_,	M_,	E_,	E_,	M_,	M_|X_,	0,
	M_,	C_,	C_,	C_,	M_,	0,	C_,	0,
	C_,	0,	C_,	C_,	M_|X_,	C_|U_,	0,	M_,
	C_,	E_,	0,	0,	0,	0,	C_,	0
};

#define MAXVICMD	3
#define SRCHLEN		40

#define INSERT		1
#define REPLACE		2

#define VNORMAL		0
#define VARG1		1
#define VEXTCMD		2
#define VARG2		3
#define VXCH		4
#define VFAIL		5
#define VCMD		6
#define VREDO		7
#define VLIT		8
#define VSEARCH		9
#define VREPLACE1CHAR	10

struct edstate {
	int	winleft;
	char	*cbuf;
	int	cbufsize;
	int	linelen;
	int	cursor;
};

static char		undocbuf[CMDLEN];

static struct edstate	ebuf;
static struct edstate	undobuf = { 0, undocbuf, CMDLEN, 0, 0 };

static struct edstate	*es;			/* current editor state */
static struct edstate	*undo;

static char	ibuf[CMDLEN];		/* input buffer */
static int	inslen;			/* length of input buffer */
static int	srchlen;		/* length of current search pattern */
static char	ybuf[CMDLEN];		/* yank buffer */
static int	yanklen;		/* length of yank buffer */
static int	fsavecmd = ' ';		/* last find command */
static int	fsavech;		/* character to find */
static char	lastcmd[MAXVICMD];	/* last non-move command */
static int	lastac;			/* argcnt for lastcmd */
static int	lastsearch = ' ';	/* last search command */
static char	srchpat[SRCHLEN];	/* last search pattern */
static int	insert;			/* non-zero in insert mode */
static int	hnum;			/* position in history */
static int	hlast;			/* 1 past last position in history */
static int	modified;		/* buffer has been "modified" */
static int	state;

#if 0
vi_init()
{
	es = (struct edstate *) malloc((unsigned) sizeof(struct edstate));
	fsavecmd = ' ';
	lastsearch = ' ';
}

edit_init()
{
	wbuf[0] = malloc((unsigned) (x_cols - 3));
	wbuf[1] = malloc((unsigned) (x_cols - 3));
}
#endif

void
vi_reset(buf, len)
	char	*buf;
	int	len;
{
	state = VNORMAL;
	hnum = hlast = histnum(-1) + 1;
	insert = INSERT;
	yanklen = 0;
	inslen = 0;
	lastcmd[0] = 'a';
	lastac = 1;
	modified = 1;
	edit_reset(buf, len);
}

int
vi_hook(ch)
	int		ch;
{
	static char	curcmd[MAXVICMD];
	static char	locpat[SRCHLEN];
	static int	cmdlen;
	static int	argc1, argc2;

	if (state != VSEARCH && (ch == '\r' || ch == '\n')) {
		x_putc('\r');
		x_putc('\n');
		x_flush();
		return 1;
	}

	switch (state) {

	case VREPLACE1CHAR:
		curcmd[cmdlen++] = ch;
		state = VCMD;
		break;

	case VNORMAL:
		if (insert != 0) {
			if (ch == Ctrl('v')) {
				state = VLIT;
				ch = '^';
			}
			if (vi_insert(ch) != 0) {
				x_putc(Ctrl('g'));
				state = VNORMAL;
			} else {
				if (state == VLIT) {
					es->cursor--;
					refresh(0);
				} else
					refresh(insert != 0);
			}
		} else {
			cmdlen = 0;
			argc1 = 0;
			if (ch >= '1' && ch <= '9') {
				argc1 = ch - '0';
				state = VARG1;
			} else {
				curcmd[cmdlen++] = ch;
				state = nextstate(ch);
				if (state == VSEARCH) {
					save_cbuf();
					es->cursor = 0;
					es->linelen = 0;
					if (ch == '/') {
						if (putbuf("/", 1, 0) != 0) {
							return -1;
						}
					} else if (putbuf("?", 1, 0) != 0) 
							return -1;
					refresh(0);
				}
			}
		}
		break;

	case VLIT:
		if (isbad(ch)) {
			del_range(es->cursor, es->cursor + 1);
			x_putc(Ctrl('g'));
		} else
			es->cbuf[es->cursor++] = ch;
		refresh(1);
		state = VNORMAL;
		break;

	case VARG1:
		if (isdigit(ch))
			argc1 = argc1 * 10 + ch - '0';
		else {
			curcmd[cmdlen++] = ch;
			state = nextstate(ch);
		}
		break;

	case VEXTCMD:
		argc2 = 0;
		if (ch >= '1' && ch <= '9') {
			argc2 = ch - '0';
			state = VARG2;
			return 0;
		} else {
			curcmd[cmdlen++] = ch;
			if (ch == curcmd[0])
				state = VCMD;
			else if (ismove(ch))
				state = nextstate(ch);
			else
				state = VFAIL;
		}
		break;

	case VARG2:
		if (isdigit(ch))
			argc2 = argc2 * 10 + ch - '0';
		else {
			if (argc1 == 0)
				argc1 = argc2;
			else
				argc1 *= argc2;
			curcmd[cmdlen++] = ch;
			if (ch == curcmd[0])
				state = VCMD;
			else if (ismove(ch))
				state = nextstate(ch);
			else
				state = VFAIL;
		}
		break;

	case VXCH:
		if (ch == Ctrl('['))
			state = VNORMAL;
		else {
			curcmd[cmdlen++] = ch;
			state = VCMD;
		}
		break;

	case VSEARCH:
		switch (ch) {

		/* case Ctrl('['): */
		case '\r':
		case '\n':
			locpat[srchlen] = '\0';
			(void) strcpy(srchpat, locpat);
			/* redraw_line(); */
			state = VCMD;
			break;

		case 0x7f:
			if (srchlen == 0) {
				restore_cbuf();
				state = VNORMAL;
			} else {
				srchlen--;
				if (locpat[srchlen] < ' ' ||
						locpat[srchlen] == 0x7f) {
					es->linelen--;
				}
				es->linelen--;
				es->cursor = es->linelen;
				refresh(0);
				return 0;
			}
			refresh(0);
			break;

		case Ctrl('u'):
			srchlen = 0;
			es->linelen = 1;
			es->cursor = 1;
			refresh(0);
			return 0;

		default:
			if (srchlen == SRCHLEN - 1)
				x_putc(Ctrl('g'));
			else {
				locpat[srchlen++] = ch;
				if (ch < ' ' || ch == 0x7f) {
					es->cbuf[es->linelen++] = '^';
					es->cbuf[es->linelen++] = ch ^ '@';
				} else
					es->cbuf[es->linelen++] = ch;
				es->cursor = es->linelen;
				refresh(0);
			}
			return 0;
			break;
		}
		break;
	}
	switch (state) {

	case VCMD:
		state = VNORMAL;
		switch (vi_cmd(argc1, curcmd)) {
		case -1:
			x_putc(Ctrl('g'));
			break;
		case 0:
			if (insert != 0)
				inslen = 0;
			refresh(insert != 0);
			break;
		case 1:
			refresh(0);
			x_putc('\r');
			x_putc('\n');
			x_flush();
			return 1;
		}
		break;

	case VREDO:
		state = VNORMAL;
		if (argc1 != 0)
			lastac = argc1;
		switch (vi_cmd(lastac, lastcmd) != 0) {
		case -1:
			x_putc(Ctrl('g'));
			refresh(0);
			break;
		case 0:
			if (insert != 0) {
				if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
						lastcmd[0] == 'C') {
					if (redo_insert(1) != 0)
						x_putc(Ctrl('g'));
				} else {
					if (redo_insert(lastac) != 0)
						x_putc(Ctrl('g'));
				}
			}
			refresh(0);
			break;
		case 1:
			refresh(0);
			x_putc('\r');
			x_putc('\n');
			x_flush();
			return 1;
		}
		break;

	case VFAIL:
		state = VNORMAL;
		x_putc(Ctrl('g'));
		break;
	}
	return 0;
}

static int
nextstate(ch)
	int	ch;
{
	/*
	 * probably could have been done more elegantly than
	 * by creating a new state, but it works
	 */
	if (ch == 'r')
		return VREPLACE1CHAR;
	else if (isextend(ch))
		return VEXTCMD;
	else if (issrch(ch))
		return VSEARCH;
	else if (islong(ch))
		return VXCH;
	else if (ch == '.')
		return VREDO;
	else if (iscmd(ch))
		return VCMD;
	else
		return VFAIL;
}

static int
vi_insert(ch)
	int	ch;
{
	int	tcursor;

	switch (ch) {

	case '\0':
		return -1;

	case Ctrl('['):
		if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
				lastcmd[0] == 'C')
			return redo_insert(0);
		else
			return redo_insert(lastac - 1);

	case 0x7f:		/* delete */
		/* tmp fix */
		/* general fix is to get stty erase char and use that
		*/
	case Ctrl('H'):		/* delete */
		if (es->cursor != 0) {
			if (inslen > 0)
				inslen--;
			es->cursor--;
			if (insert != REPLACE) {
				memmove(&es->cbuf[es->cursor],
						&es->cbuf[es->cursor+1],
						es->linelen - es->cursor);
				es->linelen--;
			}
		}
		break;

	case Ctrl('U'):
		if (es->cursor != 0) {
			inslen = 0;
			memmove(es->cbuf, &es->cbuf[es->cursor],
						es->linelen - es->cursor);
			es->linelen -= es->cursor;
			es->cursor = 0;
		}
		break;

	case Ctrl('W'):
		if (es->cursor != 0) {
			tcursor = backword(1);
			memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor],
						es->linelen - es->cursor);
			es->linelen -= es->cursor - tcursor;
			if (inslen < es->cursor - tcursor)
				inslen = 0;
			else
				inslen -= es->cursor - tcursor;
			es->cursor = tcursor;
		}
		break;

	default:
		if (es->linelen == es->cbufsize - 1)
			return -1;
		ibuf[inslen++] = ch;
		if (insert == INSERT) {
			memmove(&es->cbuf[es->cursor+1], &es->cbuf[es->cursor],
					es->linelen - es->cursor);
			es->linelen++;
		}
		es->cbuf[es->cursor++] = ch;
		if (insert == REPLACE && es->cursor > es->linelen)
			es->linelen++;
	}
	return 0;
}

static int
vi_cmd(argcnt, cmd)
	int		argcnt;
	char		*cmd;
{
	int		ncursor;
	int		cur, c1, c2, c3 = 0;
	struct edstate	*t;


	if (argcnt == 0) {
		if (*cmd == 'G')
			argcnt = hlast + 1;
		else if (*cmd != '_')
			argcnt = 1;
	}

	if (ismove(*cmd)) {
		if ((cur = domove(argcnt, cmd, 0)) >= 0) {
			if (cur == es->linelen && cur != 0)
				cur--;
			es->cursor = cur;
		} else
			return -1;
	} else {
		if (isundoable(*cmd)) {
			undo->winleft = es->winleft;
			memmove(undo->cbuf, es->cbuf, es->linelen);
			undo->linelen = es->linelen;
			undo->cursor = es->cursor;
			lastac = argcnt;
			memmove(lastcmd, cmd, MAXVICMD);
		}
		switch (*cmd) {

		case Ctrl('r'):
			redraw_line();
			break;

		case 'a':
			modified = 1;
			if (es->linelen != 0)
				es->cursor++;
			insert = INSERT;
			break;

		case 'A':
			modified = 1;
			del_range(0, 0);
			es->cursor = es->linelen;
			insert = INSERT;
			break;

		case 'c':
		case 'd':
		case 'y':
			if (*cmd == cmd[1]) {
				c1 = 0;
				c2 = es->linelen;
			} else if (!ismove(cmd[1]))
				return -1;
			else {
				if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0)
					return -1;
				if (*cmd == 'c' &&
						(cmd[1]=='w' || cmd[1]=='W') &&
						!isspace(es->cbuf[es->cursor])) {
					while (isspace(es->cbuf[--ncursor]))
						;
					ncursor++;
				}
				if (ncursor > es->cursor) {
					c1 = es->cursor;
					c2 = ncursor;
				} else {
					c1 = ncursor;
					c2 = es->cursor;
				}
			}
			if (*cmd != 'c' && c1 != c2)
				yank_range(c1, c2);
			if (*cmd != 'y') {
				del_range(c1, c2);
				es->cursor = c1;
			}
			if (*cmd == 'c') {
				modified = 1;
				insert = INSERT;
			}
			break;

		case 'p':
			modified = 1;
			if (es->linelen != 0)
				es->cursor++;
			while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
				;
			if (es->cursor != 0)
				es->cursor--;
			if (argcnt != 0)
				return -1;
			break;

		case 'P':
			modified = 1;
			while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
				;
			if (es->cursor != 0)
				es->cursor--;
			if (argcnt != 0)
				return -1;
			break;

		case 'C':
			modified = 1;
			del_range(es->cursor, es->linelen);
			insert = INSERT;
			break;

		case 'D':
			yank_range(es->cursor, es->linelen);
			del_range(es->cursor, es->linelen);
			if (es->cursor != 0)
				es->cursor--;
			break;

		case 'G':
			if (grabhist(modified, argcnt - 1) < 0)
				return -1;
			else {
				modified = 0;
				hnum = argcnt - 1;
			}
			break;

		case 'i':
			modified = 1;
			insert = INSERT;
			break;

		case 'I':
			modified = 1;
			es->cursor = 0;
			insert = INSERT;
			break;

		case '+':
		case 'j':
			if (grabhist(modified, hnum + argcnt) < 0)
				return -1;
			else {
				modified = 0;
				hnum += argcnt;
			}
			break;

		case '-':
		case 'k':
			if (grabhist(modified, hnum - argcnt) < 0)
				return -1;
			else {
				modified = 0;
				hnum -= argcnt;
			}
			break;

		case 'r':
			if (es->linelen == 0)
				return -1;
			modified = 1;
			es->cbuf[es->cursor] = cmd[1];
			break;

		case 'R':
			modified = 1;
			insert = REPLACE;
			break;

		case 's':
			if (es->linelen == 0)
				return -1;
			modified = 1;
			if (es->cursor + argcnt > es->linelen)
				argcnt = es->linelen - es->cursor;
			del_range(es->cursor, es->cursor + argcnt);
			insert = INSERT;
			break;

		case 'x':
			if (es->linelen == 0)
				return -1;
			modified = 1;
			if (es->cursor + argcnt > es->linelen)
				argcnt = es->linelen - es->cursor;
			yank_range(es->cursor, es->cursor + argcnt);
			del_range(es->cursor, es->cursor + argcnt);
			break;

		case 'X':
			if (es->cursor > 0) {
				modified = 1;
				if (es->cursor < argcnt)
					argcnt = es->cursor;
				yank_range(es->cursor - argcnt, es->cursor);
				del_range(es->cursor - argcnt, es->cursor);
				es->cursor -= argcnt;
			} else
				return -1;
			break;

		case 'u':
			t = es;
			es = undo;
			undo = t;
			break;

		case '?':
			hnum = -1;
			/* ahhhhhh... */
		case '/':
			c3 = 1;
			srchlen = 0;
			lastsearch = *cmd;
			/* fall through */
		case 'n':
		case 'N':
			if (lastsearch == ' ')
				return -1;
			if (lastsearch == '?')
				c1 = 1; 
			else
				c1 = 0;
			if (*cmd == 'N')
				c1 = !c1;
			if ((c2 = grabsearch(modified, hnum,
							c1, srchpat)) < 0) {
				if (c3) {
					restore_cbuf();
					refresh(0);
				}
				return -1;
			} else {
				modified = 0;
				hnum = c2;
			}
			break;
		case '_': {
			int	space;
			char	*p, *sp;

			(void) histnum(-1);
			p = *histpos();
#define issp(c)		(isspace((c)) || (c) == '\n')
			if (argcnt) {
				while (*p && issp(*p))
					p++;
				while (*p && --argcnt) {
					while (*p && !issp(*p))
						p++;
					while (*p && issp(*p))
						p++;
				}
				if (!*p)
					return -1;
				sp = p;
			} else {
				sp = p;
				space = 0;
				while (*p) {
					if (issp(*p))
						space = 1;
					else if (space) {
						space = 0;
						sp = p;
					}
					p++;
				}
				p = sp;
			}
			modified = 1;
			if (es->linelen != 0)
				es->cursor++;
			while (*p && !issp(*p)) {
				argcnt++;
				p++;
			}
			if (putbuf(" ", 1, 0) != 0)
				argcnt = -1;
			else if (putbuf(sp, argcnt, 0) != 0)
				argcnt = -1;
			if (argcnt < 0) {
				if (es->cursor != 0)
					es->cursor--;
				return -1;
			}
			insert = INSERT;
			}
			break;

		case '~': {
			char	*p;

			if (es->linelen == 0)
				return -1;
			p = &es->cbuf[es->cursor];
			if (islower(*p)) {
				modified = 1;
				*p = toupper(*p);
			} else if (isupper(*p)) {
				modified = 1;
				*p = tolower(*p);
			}
			if (es->cursor < es->linelen - 1)
				es->cursor++;
			}
			break;

		case '#':
			es->cursor = 0;
			if (putbuf("#", 1, 0) != 0)
				return -1;
			return 1;

		case '*':
		case '=': {
			int	rval = 0;
			int	start, end;
			char	*toglob = undo->cbuf;
			char	**ap;
			char	**ap2;
			char	**globstr();

			if (isspace(es->cbuf[es->cursor]))
				return -1;
			start = es->cursor;
			while (start > -1 && !isspace(es->cbuf[start]))
				start--;
			start++;
			end = es->cursor;
			while (end < es->linelen && !isspace(es->cbuf[end]))
				end++;
			/* use undo buffer to build word up in */
			memmove(toglob, &es->cbuf[start], end-start);
			if (toglob[end-start-1] != '*') {
				toglob[end-start] = '*';
				toglob[end-start+1] = '\0';
			} else
				toglob[end-start] = '\0';
			ap = globstr(toglob);
			ap2 = ap;
			if (strcmp(ap[0], toglob) == 0 && ap[1] == (char *) 0)
				rval = -1;
			/* restore undo buffer that we used temporarily */
			memmove(toglob, es->cbuf, es->linelen);
			if (rval < 0)
				return rval;
			if (*cmd == '=') {
				fputc('\n', shlout);
				pr_menu(ap2, 0);
				fflush(shlout);
				if (es->linelen != 0)
					es->cursor++;
				redraw_line();
				insert = INSERT;
				state = VNORMAL;
				return 0;
			} else {
				del_range(start, end);
				es->cursor = start;
				while (1) {
					if (putbuf(*ap, strlen(*ap), 0) != 0) {
						rval = -1;
						break;
					}
					if (*++ap == (char *) 0)
						break;
					if (putbuf(" ", 1, 0) != 0) {
						rval = -1;
						break;
					}

				}
#if 0
				/*
				 * this is definitely wrong
				 */
				for (ap = ap2; *ap; ap++)
					free(*ap);

				free(ap2);
#endif

				modified = 1;
				insert = INSERT;
				refresh(0);
			}
			if (rval != 0)
				return rval;
			}
			break;
		}
		if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
			es->cursor--;
	}
	return 0;
}

static int
domove(argcnt, cmd, sub)
	int	argcnt;
	char	*cmd;
	int	sub;
{
	int	bcount, i = 0, t;	/* = 0 kludge for gcc -W */
	int	ncursor = 0;		/* = 0 kludge for gcc -W */

	switch (*cmd) {

	case 'b':
		if (!sub && es->cursor == 0)
			return -1;
		ncursor = backword(argcnt);
		break;

	case 'B':
		if (!sub && es->cursor == 0)
			return -1;
		ncursor = Backword(argcnt);
		break;

	case 'e':
		if (!sub && es->cursor + 1 >= es->linelen)
			return -1;
		ncursor = endword(argcnt);
		if (sub)
			ncursor++;
		break;

	case 'E':
		if (!sub && es->cursor + 1 >= es->linelen)
			return -1;
		ncursor = Endword(argcnt);
		if (sub)
			ncursor++;
		break;

	case 'f':
	case 'F':
	case 't':
	case 'T':
		fsavecmd = *cmd;
		fsavech = cmd[1];
		/* drop through */

	case ',':
	case ';':
		if (fsavecmd == ' ')
			return -1;
		i = fsavecmd == 'f' || fsavecmd == 'F';
		t = fsavecmd > 'a';
		if (*cmd == ',')
			t = !t;
		if ((ncursor = findch(fsavech, argcnt, t, i)) < 0)
			return -1;
		if (sub && t)
			ncursor++;
		break;

	case 'h':
		/* tmp fix */
	case Ctrl('H'):
		if (!sub && es->cursor == 0)
			return -1;
		ncursor = es->cursor - argcnt;
		if (ncursor < 0)
			ncursor = 0;
		break;

	case ' ':
	case 'l':
		if (!sub && es->cursor + 1 >= es->linelen)
			return -1;
		if (es->linelen != 0) {
			ncursor = es->cursor + argcnt;
			if (ncursor >= es->linelen)
				ncursor = es->linelen - 1;
		}
		break;

	case 'w':
		if (!sub && es->cursor + 1 >= es->linelen)
			return -1;
		ncursor = forwword(argcnt);
		break;

	case 'W':
		if (!sub && es->cursor + 1 >= es->linelen)
			return -1;
		ncursor = Forwword(argcnt);
		break;

	case '0':
		ncursor = 0;
		break;

	case '^':
		ncursor = 0;
		while (ncursor < es->linelen - 1 && isspace(es->cbuf[ncursor]))
			ncursor++;
		break;

	case '$':
		if (es->linelen != 0)
			ncursor = es->linelen;
		else
			ncursor = 0;
		break;

	case '%':
		ncursor = es->cursor;
		while (ncursor < es->linelen &&
				(i = bracktype(es->cbuf[ncursor])) == 0)
			ncursor++;
		if (ncursor == es->linelen)
			return -1;
		bcount = 1;
		do {
			if (i > 0) {
				if (++ncursor >= es->linelen)
					return -1;
			} else {
				if (--ncursor < 0)
					return -1;
			}
			t = bracktype(es->cbuf[ncursor]);
			if (t == i)
				bcount++;
			else if (t == -i)
				bcount--;
		} while (bcount != 0);
		if (sub)
			ncursor++;
		break;

	default:
		return -1;
	}
	return ncursor;
}

static int
redo_insert(count)
	int	count;
{
	while (count-- > 0)
		if (putbuf(ibuf, inslen, insert==REPLACE) != 0)
			return -1;
	if (es->cursor > 0)
		es->cursor--;
	insert = 0;
	return 0;
}

static
yank_range(a, b)
	int	a, b;
{
	yanklen = b - a;
	if (yanklen != 0)
		memmove(ybuf, &es->cbuf[a], yanklen);
}

static int
bracktype(ch)
	int	ch;
{
	switch (ch) {

	case '(':
		return 1;

	case '[':
		return 2;

	case '{':
		return 3;

	case ')':
		return -1;

	case ']':
		return -2;

	case '}':
		return -3;

	default:
		return 0;
	}
}

/*
 *	Non user interface editor routines below here
 */

static int	cur_col;		/* current column on line */
static int	pwidth;			/* width of prompt */
static int	winwidth;		/* width of window */
/*static char	*wbuf[2];		/* window buffers */
static char	wbuf[2][80-3];	/* window buffers */ /* TODO */
static int	win;			/* window buffer in use */
static char	morec;			/* more character at right of window */
static int	lastref;		/* argument to last refresh() */
static char	holdbuf[CMDLEN];	/* place to hold last edit buffer */
static int	holdlen;		/* length of holdbuf */

save_cbuf()
{
	memmove(holdbuf, es->cbuf, es->linelen);
	holdlen = es->linelen;
	holdbuf[holdlen] = '\0';
}

restore_cbuf()
{
	es->cursor = 0;
	es->linelen = holdlen;
	memmove(es->cbuf, holdbuf, holdlen);
}

static
edit_reset(buf, len)
	char	*buf;
	int	len;
{
	es = &ebuf;
	es->cbuf = buf;
	es->cbufsize = len;
	undo = &undobuf;
	undo->cbufsize = len;

	es->linelen = undo->linelen = 0;
	es->cursor = undo->cursor = 0;
	es->winleft = undo->winleft = 0;

	cur_col = pwidth = promptlen(prompt);
	winwidth = x_cols - pwidth - 3;
	x_putc('\r');
	x_flush();
	pprompt(prompt);
	/* docap(CLR_EOL, 0); */
	win = 0;
	morec = ' ';
	lastref = 1;
}

static int
putbuf(buf, len, repl)
	char	*buf;
	int	len;
	int	repl;
{
	if (len == 0)
		return 0;
	if (repl) {
		if (es->cursor + len >= es->cbufsize - 1)
			return -1;
		if (es->cursor + len > es->linelen)
			es->linelen = es->cursor + len;
	} else {
		if (es->linelen + len >= es->cbufsize - 1)
			return -1;
		memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor],
			es->linelen - es->cursor);
		es->linelen += len;
	}
	memmove(&es->cbuf[es->cursor], buf, len);
	es->cursor += len;
	return 0;
}

static
stripblanks()
{
	int	ncursor;

	ncursor = 0;
	while (ncursor < es->linelen && isspace(es->cbuf[ncursor]))
		ncursor++;
	del_range(0, ncursor);
}

static
del_range(a, b)
	int	a, b;
{
	if (es->linelen != b)
		memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b);
	es->linelen -= b - a;
}

static int
findch(ch, cnt, forw, incl)
	int	ch;
	int	forw;
	int	incl;
{
	int	ncursor;

	if (es->linelen == 0)
		return -1;
	ncursor = es->cursor;
	while (cnt--) {
		do {
			if (forw) {
				if (++ncursor == es->linelen)
					return -1;
			} else {
				if (--ncursor < 0)
					return -1;
			}
		} while (es->cbuf[ncursor] != ch);
	}
	if (!incl) {
		if (forw)
			ncursor--;
		else
			ncursor++;
	}
	return ncursor;
}

#define Isalnum(x) (isalnum(x) || (x == '_'))
static int
forwword(argcnt)
	int	argcnt;
{
	int	ncursor;

	ncursor = es->cursor;
	while (ncursor < es->linelen && argcnt--) {
		if (Isalnum(es->cbuf[ncursor]))
			while (Isalnum(es->cbuf[ncursor]) &&
					++ncursor < es->linelen)
				;
		else if (!isspace(es->cbuf[ncursor]))
			while (!Isalnum(es->cbuf[ncursor]) &&
					!isspace(es->cbuf[ncursor]) &&
					++ncursor < es->linelen)
				;
		while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
			;
	}
	return ncursor;
}

static int
backword(argcnt)
	int	argcnt;
{
	int	ncursor;

	ncursor = es->cursor;
	while (ncursor > 0 && argcnt--) {
		while (--ncursor > 0 && isspace(es->cbuf[ncursor]))
			;
		if (ncursor > 0) {
			if (Isalnum(es->cbuf[ncursor]))
				while (--ncursor >= 0 &&
				   Isalnum(es->cbuf[ncursor]))
					;
			else
				while (--ncursor >= 0 &&
				   !Isalnum(es->cbuf[ncursor]) &&
				   !isspace(es->cbuf[ncursor]))
					;
			ncursor++;
		}
	}
	return ncursor;
}

static int
endword(argcnt)
	int	argcnt;
{
	int	ncursor;

	ncursor = es->cursor;
	while (ncursor < es->linelen && argcnt--) {
		while (++ncursor < es->linelen - 1 &&
				isspace(es->cbuf[ncursor]))
			;
		if (ncursor < es->linelen - 1) {
			if (Isalnum(es->cbuf[ncursor]))
				while (++ncursor < es->linelen &&
					  Isalnum(es->cbuf[ncursor]))
					;
			else
				while (++ncursor < es->linelen &&
				   !Isalnum(es->cbuf[ncursor]) &&
				   !isspace(es->cbuf[ncursor]))
					;
			ncursor--;
		}
	}
	return ncursor;
}

static int
Forwword(argcnt)
	int	argcnt;
{
	int	ncursor;

	ncursor = es->cursor;
	while (ncursor < es->linelen && argcnt--) {
		while (!isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
			;
		while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
			;
	}
	return ncursor;
}

static int
Backword(argcnt)
	int	argcnt;
{
	int	ncursor;

	ncursor = es->cursor;
	while (ncursor > 0 && argcnt--) {
		while (--ncursor >= 0 && isspace(es->cbuf[ncursor]))
			;
		while (ncursor >= 0 && !isspace(es->cbuf[ncursor]))
			ncursor--;
		ncursor++;
	}
	return ncursor;
}

static int
Endword(argcnt)
	int	argcnt;
{
	int	ncursor;

	ncursor = es->cursor;
	while (ncursor < es->linelen - 1 && argcnt--) {
		while (++ncursor < es->linelen - 1 &&
				isspace(es->cbuf[ncursor]))
			;
		if (ncursor < es->linelen - 1) {
			while (++ncursor < es->linelen &&
					!isspace(es->cbuf[ncursor]))
				;
			ncursor--;
		}
	}
	return ncursor;
}

static int
grabhist(save, n)
	int	save;
	int	n;
{
	char	*hptr;

	if (n < 0 || n > hlast)
		return -1;
	if (n == hlast) {
		restore_cbuf();
		return 0;
	}
	(void) histnum(n);
	if ((hptr = *histpos()) == NULL) {
		shellf("grabhist: bad history array\n");
		return -1;
	}
	if (save)
		save_cbuf();
	es->linelen = strlen(hptr);
	memmove(es->cbuf, hptr, es->linelen);
	es->cursor = 0;
	return 0;
}

static int
grabsearch(save, start, fwd, pat)
	int	save, start, fwd;
	char	*pat;
{
	char	*hptr;

	if ((start == 0 && fwd == 0) || (start >= hlast - 1 && fwd == 1))
		return -1;
	if ((hptr = findhist(start, fwd, pat)) == NULL) {
		/* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */
		if (start != 0 && fwd && strcmp(holdbuf, pat) >= 0) {
			restore_cbuf();
			return 0;
		} else
			return -1;
	} else if (hptr == (char *)-1) {
		return -1;
	}
	if (save)
		save_cbuf();
	es->linelen = strlen(hptr);
	memmove(es->cbuf, hptr, es->linelen);
	es->cursor = 0;
	return histN();
}

static
redraw_line()
{
	x_putc('\r');
	x_putc('\n');
	x_flush();
	pprompt(prompt);
	cur_col = pwidth;
	morec = ' ';
}

static
refresh(leftside)
	int		leftside;
{
	if (leftside < 0)
		leftside = lastref;
	else
		lastref = leftside;
	if (outofwin())
		rewindow();
	display(wbuf[1 - win], wbuf[win], leftside);
	win = 1 - win;
}

static int
outofwin()
{
	int	cur, col;

	if (es->cursor < es->winleft)
		return 1;
	col = 0;
	cur = es->winleft;
	while (cur < es->cursor)
		col = newcol(es->cbuf[cur++], col);
	if (col > winwidth)
		return 1;
	return 0;
}

static
rewindow()
{
	register int	tcur, tcol;
	int		holdcur1, holdcol1;
	int		holdcur2, holdcol2;

	holdcur1 = holdcur2 = tcur = 0;
	holdcol1 = holdcol2 = tcol = 0;
	while (tcur < es->cursor) {
		if (tcol - holdcol2 > winwidth / 2) {
			holdcur1 = holdcur2;
			holdcol1 = holdcol2;
			holdcur2 = tcur;
			holdcol2 = tcol;
		}
		tcol = newcol(es->cbuf[tcur++], tcol);
	}
	while (tcol - holdcol1 > winwidth / 2)
		holdcol1 = newcol(es->cbuf[holdcur1++], holdcol1);
	es->winleft = holdcur1;
}

static int
newcol(ch, col)
	int	ch, col;
{
	if (ch < ' ' || ch == 0x7f) {
		if (ch == '\t')
			return (col | 7) + 1;
		else
			return col + 2;
	} else
		return col + 1;
}

static
display(wb1, wb2, leftside)
	char	*wb1, *wb2;
	int	leftside;
{
	char	*twb1, *twb2, mc;
	int	cur, col, cnt;
	int	ncol = 0; /* set to 0 kludge for gcc -W */
	int	moreright;

	col = 0;
	cur = es->winleft;
	moreright = 0;
	twb1 = wb1;
	while (col < winwidth && cur < es->linelen) {
		if (cur == es->cursor && leftside)
			ncol = col + pwidth;
		if (es->cbuf[cur] < ' ' || es->cbuf[cur] == 0x7f) {
			if (es->cbuf[cur] == '\t') {
				do {
					*twb1++ = ' ';
				} while (++col < winwidth && (col & 7) != 0);
			} else {
				*twb1++ = '^';
				if (++col < winwidth) {
					*twb1++ = es->cbuf[cur] ^ '@';
					col++;
				}
			}
		} else {
			*twb1++ = es->cbuf[cur];
			col++;
		}
		if (cur == es->cursor && !leftside)
			ncol = col + pwidth - 1;
		cur++;
	}
	if (cur == es->cursor)
		ncol = col + pwidth;
	if (col < winwidth) {
		while (col < winwidth) {
			*twb1++ = ' ';
			col++;
		}
	} else
		moreright++;
	*twb1 = ' ';

	col = pwidth;
	cnt = winwidth;
	twb1 = wb1;
	twb2 = wb2;
	while (cnt--) {
		if (*twb1 != *twb2) {
			if (cur_col != col)
				ed_mov_opt(col, wb1);
			x_putc(*twb1);
			cur_col++;
		}
		twb1++;
		twb2++;
		col++;
	}
	if (es->winleft > 0 && moreright)
		mc = '+';
	else if (es->winleft > 0)
		mc = '<';
	else if (moreright)
		mc = '>';
	else
		mc = ' ';
	if (mc != morec) {
		ed_mov_opt(x_cols - 2, wb1);
		x_putc(mc);
		cur_col++;
		morec = mc;
	}
#if 0
	/*
	 * Hack to fix teh ^r redraw problem, but it redraws way too much.
	 * Probably unacceptable at low baudrates.  Someone please fix this
	 */
	else
	    {
	    ed_mov_opt(x_cols - 2, wb1);
	    }
#endif
	if (cur_col != ncol)
		ed_mov_opt(ncol, wb1);
}

static
ed_mov_opt(col, wb)
	int	col;
	char	*wb;
{
	if (col < cur_col) {
		if (col + 1 < cur_col - col) {
			x_putc('\r');
			x_flush();
			pprompt(prompt);
			cur_col = pwidth;
			while (cur_col++ < col)
				x_putc(*wb++);
		} else {
			while (cur_col-- > col)
				x_putc('\b');
		}
	} else {
		wb = &wb[cur_col - pwidth];
		while (cur_col++ < col)
			x_putc(*wb++);
	}
	cur_col = col;
}

int
x_vi(buf, len)
	char *buf;
	size_t len;
{
	int	c;

	vi_reset(buf, len > CMDLEN ? CMDLEN : len);
	x_flush();
	while ((c = getch()) != -1) {
		if (vi_hook(c))
			break;
		x_flush();
	}

	if (c == -1)
		return -1;

	if (es->cbuf != buf) {
		memmove(buf, es->cbuf, es->linelen);
		buf[es->linelen] = '\n';
	} else
		es->cbuf[es->linelen] = '\n';

	es->linelen++;
	return es->linelen;
}

getch()
{
	char	buf;

	if (read(ttyfd, &buf, 1) != 1)
		return -1;
	if ((buf & 0x7f) == Ctrl('c')) {
		/*
		 * If you hit ctrl-c, the buffer was left in a
		 * strange state; the next command typed was
		 * mucked up.  Doing all of this is probably
		 * overkill, but it works most of the time.
		 */
		memset(es->cbuf, 0, CMDLEN);
		es->winleft = 0;
		es->cbufsize = 0;
		es->linelen = 0;
		es->cursor = 0;

		memset(undo->cbuf, 0, CMDLEN);
		undo->winleft = 0;
		undo->cbufsize = 0;
		undo->linelen = 0;
		undo->cursor = 0;
		x_mode(FALSE);
		trapsig(SIGINT);
	} else if ((buf & 0x7f) == Ctrl('d'))
		return -1;
	return buf & 0x7f;
}


char **globstr(stuff)
char *stuff;
    {
    char *vecp[2];

    vecp[0] = stuff;
    vecp[1] = NULL;
    return(eval(vecp, DOBLANK|DOGLOB|DOTILDE));
    }
#endif /* VI */
./pdksh/sh/c_ksh.c   644    653   1762       26467  5302765310  11306 0ustar  hlu/*
 * built-in Korn commands: c_*
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include <unistd.h>
#include "sh.h"


int
c_hash(wp)
	register char **wp;
{
	register struct tbl *tp, **p;

	wp++;
	if (*wp == NULL) {
		for (p = tsort(&commands); (tp = *p++) != NULL; )
			if ((tp->flag&ISSET))
				printf("%s\n", tp->val.s);
		return 0;
	}

	if (strcmp(*wp, "-r") == 0)
		flushcom(1);
	while (*wp != NULL)
		findcom(*wp++, 1);
	return 0;
}

int
c_cd(wp)
	register char **wp;
{
	char path [PATH];
	char newd [PATH];
	register char *cp;
	register char *dir;
	register char *cdpath;
	register char *rep;
	register char *pwd = NULL, *oldpwd = NULL;
	register int done = 0;
	register int prt = 0;
	register struct tbl *v_pwd = NULL, *v_oldpwd = NULL;

	if ((dir = wp[1]) == NULL && (dir = strval(global("HOME"))) == NULL)
		errorf("no home directory");

	v_pwd = global("PWD");
	if ((pwd = strval(v_pwd)) == null) {
		setstr(v_pwd, getcwd(path, (size_t)PATH));
		pwd = strval(v_pwd);
	}

	if (wp[1] != NULL && (rep = wp[2]) != NULL) {
		/*
		 * Two arg version: cd pat rep
		 */
		if (strlen(pwd) - strlen(dir) + strlen(rep) >= PATH)
			errorf("substitution too long\n");
		cp = strstr(pwd, dir);
		if (cp == NULL)
			errorf("substitution failed\n");
		strncpy(path, pwd, cp - pwd);		/* first part */
		strcpy(path + (cp - pwd), rep);		/* replacement */
		strcat(path, cp + strlen(dir)); 	/* last part */
		dir = strsave(path, ATEMP);
		prt = 1;
	} else if (dir[0] == '-' && dir[1] == '\0') {
		/*
		 * Change to previous dir: cd -
		 */
		dir = strval(v_oldpwd = global("OLDPWD"));
		prt = 1;
	}
	if (dir[0] == '/' || (dir[0] == '.' && (dir[1] == '/' ||
	    (dir[1] == '.' && dir[2] == '/')))) {
		/*
		 * dir is an explicitly named path, so no CDPATH search
		 */
		cleanpath(pwd, dir, newd);
		if (chdir(newd) < 0)
			errorf("%s: bad directory\n", newd);
		else if (prt)
			shellf("%s\n", newd);
		flushcom(0);
	} else {
		/*
		 * search CDPATH for dir
		 */
		cdpath = strval(global("CDPATH"));
		while ( !done && cdpath != NULL ) {
			cp = path;
			while (*cdpath && *cdpath != ':')
				*cp++ = *cdpath++;
			if (*cdpath == '\0')
				cdpath = NULL;
			else
				cdpath++;
			if (prt = (cp > path)) {
				*cp++ = '/';
				(void) strcpy( cp, dir );
				cp = path;
			} else
				cp = dir;

			cleanpath(pwd, cp, newd);
			if (chdir(newd) == 0)
				done = 1;
		} while (!done && cdpath != NULL);
		if (!done)
			errorf("%s: bad directory\n", dir);
		if (prt)
			shellf("%s\n", newd);
		flushcom(0);
	}

	/*
	 * Keep track of OLDPWD and PWD
	 */
	oldpwd = pwd;
	pwd = newd;
	if (!v_oldpwd)
		v_oldpwd = global("OLDPWD");
	if (oldpwd && *oldpwd)
		setstr(v_oldpwd, oldpwd);
	else
		unset(v_oldpwd);
	if (*pwd)
		setstr(v_pwd, pwd);
	else
		unset(v_pwd);

	return 0;
}

int
c_print(wp)
	register char **wp;
{
	int nl = 1;
	int expand = 1;
	FILE *f = stdout;

	for (wp++; *wp != NULL && **wp == '-'; wp++) {
		register char *s = *wp + 1;
		if (*s == '\0') {
			wp++;
			break;
		}
		while (*s) switch (*s++) {
		  case 'n':
			nl = 0;
			break;
		  case 'e':
			expand = 1;
			break;
		  case 'r':
			expand = 0;
			break;
		  case 'u':
			if (!digit(*s) || (f = shf[*s++-'0']) == NULL)
				errorf("bad -u argument\n");
			break;
		}
	}

	while (*wp != NULL) {
		register char *s = *wp;
		register int c;
		while ((c = *s++) != '\0')
			if (expand && c == '\\') {
				switch ((c = *s++)) {
				case 'b': c = '\b'; break;
				case 'c': nl = 0; continue; /* AT&T brain damage */
				case 'f': c = '\f'; break;
				case 'n': c = '\n'; break;
				case 'r': c = '\r'; break;
				case 't': c = '\t'; break;
				case 'v': c = 0x0B; break;
				case '0': case '1': case '2': case '3':
				case '4': case '5': case '6': case '7':
					c = c - '0';
					if (*s >= '0' && *s <= '7')
						c = 8*c + *s++ - '0';
					if (*s >= '0' && *s <= '7')
						c = 8*c + *s++ - '0';
					break;
				case '\\': break;
				default:
					putc('\\', f);
				}
				putc(c, f);
			} else
				putc(c, f);
		if (*++wp != NULL)
			putc(' ', f);
	}
	if (nl)
		putc('\n', f);
	return 0;
}

/* todo: handle case where id is both lexical and command */
int
c_whence(wp)
	register char **wp;
{
	register struct tbl *tp;
	char *id;
	int vflag = 0;
	int ret = 0;

	for (wp++; (id = *wp) != NULL && *id == '-'; wp++)
		if (id[1] == 'v')
			vflag = 1;

	while ((id = *wp++) != NULL) {
		tp = tsearch(&lexicals, id, hash(id));
		if (tp == NULL)
			tp = findcom(id, 0);
		if (vflag)
			switch ((tp == NULL) ? CNONE : tp->type) {
			  case CNONE:
				printf("%s is unknown\n", id);
				ret = 1;
				break;
			  case CSHELL:
				printf("%s is a shell builtin\n", id);
				break;
			  case CFUNC:
				printf("%s is a function\n", id);
				fptreef(stdout, "function %s %T\n", id, tp->val.t);
				break;
			  case CEXEC:
				printf("%s is %s\n", id,
				       (tp->flag&ISSET) ? tp->val.s : "unknown");
				if (!(tp->flag&ISSET))
					ret = 1;
				break;
			  case CALIAS:
				printf("%s is the alias '%s'\n", id, tp->val.s);
				break;
			  case CKEYWD:
				printf("%s is a shell keyword\n", id);
				break;
			  default:
				printf("%s is *GOK*\n", id);
				break;
			}
		else
			switch ((tp == NULL) ? CNONE : tp->type) {
			  case CNONE:
				printf("\n");
				ret = 1;
				break;
			  case CSHELL:
				printf("builtin %s\n", id);
				break;
			  case CFUNC:
				printf("%s\n", id);
				break;
			  case CEXEC:
				printf("%s\n", (tp->flag&ISSET) ? tp->val.s : "");
				if (!(tp->flag&ISSET))
					ret = 1;
				break;
			  case CALIAS:
				printf("%s\n", tp->val.s);
				break;
			  case CKEYWD:
				printf("%s\n", id);
				break;
			  default:
				printf("*GOK*\n");
				break;
			}
	}
	return ret;
}

/* typeset, export, and readonly */
int
c_typeset(wp)
	register char **wp;
{
	register char *id;
	struct block *l = e.loc;
	register struct tbl *vp, **p;
	int fset = 0, fclr = 0;
	int thing = 0, func = 0, local = 0;

	switch (**wp) {
	  case 'e':		/* export */
		fset |= EXPORT;
		break;
	  case 'r':		/* readonly */
		fset |= RDONLY;
		break;
	  case 't':		/* typeset */
		local = 1;
		break;
	}

	for (wp++; (id = *wp) != NULL && (*id == '-' || *id == '+'); wp++) {
		int flag = 0;
		thing = *id;
		while (*++id != '\0') switch (*id) {
		  case 'f':
			flag |= FUNCT;
			func = 1;
			break;
		  case 'i':
			flag |= INTEGER;
			break;
		  case 'r':
			flag |= RDONLY;
			break;
		  case 'x':
			flag |= EXPORT;
			break;
		  case 't':
			flag |= TRACE;
			break;
		  default:
			errorf("unknown flag -%c\n", *id);
		}
		if (flag != 0) { /* + or - with options */
			if (thing == '-')
				fset |= flag;
			else
				fclr |= flag;
			thing = 0;
		}
	}

	/* list variables and attributes */
	if (*wp == NULL) {
		for (l = e.loc; l != NULL; l = l->next) {
		    for (p = tsort((func==0) ? &l->vars : &l->funs);
			 (vp = *p++) != NULL; )
			if ((vp->flag&ISSET))
			    if (thing == 0 && fclr == 0 && fset == 0) {
				printf("typeset ");
				if ((vp->flag&INTEGER))
					printf("-i ");
				if ((vp->flag&EXPORT))
					printf("-x ");
				if ((vp->flag&RDONLY))
					printf("-r ");
				if ((vp->flag&TRACE)) 
					printf("-t ");
				printf("%s\n", vp->name);
			    } else
			    if (thing == '+' ||
				(fclr && (vp->flag&fclr) == fclr)) {
				printf("%s\n", vp->name);
			    } else
			    if (thing == '-' ||
				(fset && (vp->flag&fset) == fset)) {
				if (fset&FUNCT)
				    printf("function %s\n", vp->name);
				else
				    printf("%s=%s\n", vp->name, strval(vp));
			    }
		}
		return (0);
	}

	if (local)
		fset |= LOCAL;
	for (; *wp != NULL; wp++)
#if 0
		if (func) {
		} else
#endif
		if (typeset(*wp, fset, fclr) == NULL)
			errorf("%s: not identifier\n", *wp);
	return 0;
}
	
int
c_alias(wp)
	register char **wp;
{
	register struct table *t = &lexicals;
	register struct tbl *ap, **p;
	int rv = 0;

	if (*++wp != NULL && strcmp(*wp, "-d") == 0) {
		t = &homedirs;
		wp++;
	}

	if (*wp == NULL)
		for (p = tsort(t); (ap = *p++) != NULL; )
			if (ap->type == CALIAS && (ap->flag&DEFINED))
				printf("%s='%s'\n", ap->name, ap->val.s);

	for (; *wp != NULL; wp++) {
		register char *id = *wp;
		register char *val = strchr(id, '=');

		if (val == NULL) {
			ap = tsearch(t, id, hash(id));
			if (ap != NULL && ap->type == CALIAS && (ap->flag&DEFINED))
				printf("%s='%s'\n", ap->name, ap->val.s);
			else
				rv = 1;
		} else {
			*val++ = '\0';
			ap = tenter(t, id, hash(id));
			if (ap->type == CKEYWD)
				errorf("cannot alias keyword\n");
			if ((ap->flag&ALLOC)) {
				afree((void*)ap->val.s, APERM);
				ap->flag &= ~(ALLOC|ISSET);
			}
			ap->type = CALIAS;
			ap->val.s = strsave(val, APERM);
			ap->flag |= DEFINED|ALLOC|ISSET;
		}
	}
	return rv;
}

int
c_unalias(wp)
	register char **wp;
{
	register struct table *t = &lexicals;
	register struct tbl *ap;

	if (*++wp != NULL && strcmp(*wp, "-d") == 0) {
		t = &homedirs;
		wp++;
	}

	for (; *wp != NULL; wp++) {
		ap = tsearch(t, *wp, hash(*wp));
		if (ap == NULL || ap->type != CALIAS)
			continue;
		if ((ap->flag&ALLOC))
			afree((void*)ap->val.s, APERM);
		ap->flag &= ~(DEFINED|ISSET|ALLOC);
	}
	return 0;
}

int
c_let(wp)
	char **wp;
{
	int rv = 1;

	for (wp++; *wp; wp++)
		rv = evaluate(*wp) == 0;
	return rv;
}

int
c_jobs(wp)
	char **wp;
{
	j_jobs();
	return 0;
}

#ifdef JOBS
int
c_fgbg(wp)
	register char **wp;
{
	int bg = strcmp(*wp, "bg") == 0;

	if (!flag[FMONITOR])
		errorf("Job control not enabled\n");
	wp++;
	j_resume(j_lookup((*wp == NULL) ? "%" : *wp), bg);
	return 0;
}
#endif

int
c_kill(wp)
	register char **wp;
{
	register char *cp;
	int sig = 15;		/* SIGTERM */
	int rv = 0;
	int n;
	int gotsig = FALSE;

	if (*++wp == NULL)
		errorf("Usage: kill [-l] [-signal] {pid|job} ...\n");
	if (strcmp(*wp, "-l") == 0) {
		register struct trap *p = sigtraps;
		for (sig = 0; sig < SIGNALS; sig++, p++)
			if (p->signal)
				printf("%2d %8s %s\n", p->signal, p->name, p->mess);
		return 0;
	}

	for (; (cp = *wp) != NULL; wp++)
		if (*cp == '-' && gotsig == FALSE && *(wp+1) != NULL) {
			struct trap *p;
			gotsig = FALSE;
			if (digit(*(cp+1))) {
				if ((n = atoi(cp+1)) < SIGNALS) {
					sig = n;
					gotsig = TRUE;
				} else if (kill(n, sig) < 0) {
					shellf("%s: %s\n", cp, strerror(errno));
					rv++;
				}
			} else {
				p = gettrap(cp+1);
				if (p == NULL)
					errorf("bad signal %s\n", cp+1);
				sig = p->signal;
				gotsig = TRUE;
			}
		} else {
			gotsig = FALSE;
			if (digit(*cp) || (*cp == '-' && digit(*(cp+1)))) {
				if (kill(atoi(cp), sig) < 0) {
					shellf("%s: %s\n", cp, strerror(errno));
					rv++;
				}
			} else
			if (*cp == '%')
				j_kill(j_lookup(cp), sig);
			else
				errorf("invalid argument\n");
		}
	return rv;
}

#ifdef EMACS
int
c_bind(wp)
	register char **wp;
{
	int macro = 0;
	register char *cp;

	for (wp++; (cp = *wp) != NULL && *cp == '-'; wp++)
		if (cp[1] == 'm')
			macro = 1;

	if (*wp == NULL)	/* list all */
		x_bind((char*)NULL, (char*)NULL, 0);

	for (; *wp != NULL; wp++) {
		cp = strchr(*wp, '=');
		if (cp != NULL)
			*cp++ = 0;
		x_bind(*wp, cp, macro);
	}

	return 0;
}
#endif

extern	c_fc();
extern	c_getopts();

const struct builtin kshbuiltins [] = {
	{"cd", c_cd},
	{"print", c_print},
	{"getopts", c_getopts},
	{"=typeset", c_typeset},
	{"=export", c_typeset},
	{"=readonly", c_typeset},
	{"whence", c_whence},
	{"=alias", c_alias},
	{"unalias", c_unalias},
	{"hash", c_hash},
	{"let", c_let},
	{"fc", c_fc},
	{"jobs", c_jobs},
	{"kill", c_kill},
#ifdef JOBS
	{"fg", c_fgbg},
	{"bg", c_fgbg},
#endif
#ifdef EMACS
	{"bind", c_bind},
#endif
	{NULL, NULL}
};

./pdksh/sh/eval.c   644    653   1762       45522  5302633257  11143 0ustar  hlu/*
 * Expansion - quoting, separation, substitution, globbing
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include <unistd.h>
#include <dirent.h>
#include <pwd.h>
#include "sh.h"
#include "expand.h"

/*
 * string expansion
 *
 * first pass: quoting, IFS separation, ${} and $() substitution.
 * second pass: filename expansion (*?[]~).
 */

/* expansion generator state */
typedef struct Expand {
	/* int  type; */	/* see expand() */
	char   *str;		/* string */
	union {
		char  **strv;	/* string[] */
		FILE   *file;	/* file */
	} u;			/* source */
	short	split;		/* split "$@"*/
} Expand;

#define	XBASE	0		/* scanning original */
#define	XSUB	1		/* expanding ${} string */
#define	XARGSEP	2		/* ifs0 between "$@" */
#define	XARG	3		/* expanding $*, $@ */
#define	XCOM	4		/* expanding $() */

static void     expand      ARGS((char *cp, XPtrV *wp, int f));
static int      varsub      ARGS((Expand *xp, char *sp, int stype));
static int      comsub      ARGS((Expand *xp, char *cp));
static char *   trimsub     ARGS((char *str, char *pat, int how));
static void     glob        ARGS((char *cp, XPtrV *wp));
static void     globit      ARGS((char *ds, char *dp, char *sp, XPtrV *wp, int check));
static char *   debunk      ARGS((char *cp));
static char *   tilde       ARGS((char *acp));
static char *   homedir     ARGS((char *name));
#ifdef ALTERNATIONS
static	int	alt_expand  ARGS((char *, XPtrV *, int));
static	int	alt_count   ARGS((char *));
static	int	alt_scan    ARGS((char **, char **, char, 	int));
#endif

int	ifs0 = ' ';		/* todo: first char of $IFS */

/* compile and expand word */
char *
substitute(cp, f)
	char const *cp;
	int f;
{
	struct source *s, *sold;

	sold = source;
	s = pushs(SWSTR);
	s->str = (char *) cp;
	source = s;
	if (yylex(ONEWORD) != LWORD)
		errorf("eval:substitute error\n");
	source = sold;
	return evalstr(yylval.cp, f);
}

/*
 * expand arg-list
 */
char **
eval(ap, f)
	register char **ap;
{
	XPtrV w;

	if (*ap == NULL)
		return ap;
	XPinit(w, 32);
	XPput(w, NULL);		/* space for shell name */
#ifdef	SHARPBANG
	XPput(w, NULL);		/* and space for one arg */
#endif
	while (*ap != NULL)
		expand(*ap++, &w, f);
	XPput(w, NULL);
#ifdef	SHARPBANG
	return (char **) XPclose(w) + 2;
#else
	return (char **) XPclose(w) + 1;
#endif
}

/*
 * expand string
 */
char *
evalstr(cp, f)
	register char *cp;
	int f;
{
	XPtrV w;

	XPinit(w, 1);
	expand(cp, &w, f);
	cp = (XPsize(w) == 0) ? "" : (char*) *XPptrv(w);
	XPfree(w);
	return cp;
}

/*
 * expand string - return only one component
 * used from iosetup to expand redirection files
 */
char *
evalonestr(cp, f)
	register char *cp;
	int f;
{
	XPtrV w;

	XPinit(w, 1);
	expand(cp, &w, f);
	switch (XPsize(w)) {
	case 0:
		cp = "";
		break;
	case 1:
		cp = (char*) *XPptrv(w);
		break;
	default:
		cp = evalstr(cp, f&~DOGLOB);
		break;
	}
	XPfree(w);
	return cp;
}

/* for nested substitution: ${var:=$var2} */
typedef struct SubType {
	short	type;		/* [=+-?%#] action after expanded word */
	short	base;		/* begin position of expanded word */
	char   *name;		/* name for ${var=word} */
} SubType;

static void
expand(cp, wp, f)
	char *cp;		/* input word */
	register XPtrV *wp;	/* output words */
	int f;			/* DO* flags */
{
	register int c;
	register int type = XBASE; /* expansion type */
	register int quote = 0;	/* quoted */
	int quotestack[11];	/* Keep this bigger than the subtype stack */
	register int *qst = quotestack + 11;	/* This too, of course */
	XString ds;		/* destination string */
	register char *dp, *sp;	/* dest., source */
	int fdo, word, combase;	/* second pass flags; have word */
	Expand x;		/* expansion variables */
	SubType subtype [10];	/* substitution type stack */
	register SubType *st = subtype + 10;
	int newlines;		/* For trailing newlines in COMSUB */
	int trimming = 0;	/* flag if expanding ${var#pat} or ${var%pat} */

	if (cp == NULL)
		errorf("eval:expand(NULL)\n");
	if (flag[FNOGLOB])
		f &= ~ DOGLOB;

#ifdef ALTERNATIONS
#define NOALT	BIT(8)		/* internal to this file */
				/* prevent endless recursion */
	/* look for '{' in the input word */
	if (((f & NOALT) == 0) && (f & DOGLOB) &&
	    (dp = strchr(cp, '{')) != NULL &&
	    (dp[-1] == CHAR) &&
    	    !(dp[1] == CHAR && dp[2] == '}')) {
		if (alt_expand(cp, wp, f))
			return;
	}
	f &= ~NOALT;
#endif

	Xinit(ds, dp, 128);	/* init dest. string */
	type = XBASE;
	sp = cp;
	fdo = 0;
	word = !(f&DOBLANK);

	while (1) {
		Xcheck(ds, dp);

		switch (type) {
		  case XBASE:	/* original prefixed string */
			c = *sp++;
			switch (c) {
			  case EOS:
				c = 0;
				break;
			  case CHAR:
				c = *sp++;
				break;
			  case QCHAR:
				quote |= 2; /* temporary quote */
				c = *sp++;
				break;
			  case OQUOTE:
				word = quote = 1;
				continue;
			  case CQUOTE:
				quote = 0;
				continue;
			  case COMSUB:
				type = comsub(&x, sp);
				sp = strchr(sp, 0) + 1;
				combase = Xsavepos(ds, dp);
				newlines = 0;
				continue;
			  case OSUBST: /* ${var{:}[=+-?]word} */
				cp = sp; 		/* variable */
				sp = strchr(sp, 0) + 1;	/* skip variable */
				c = (*sp == CSUBST) ? 0 : *sp++;
				if ((c&0x7F) == '#' || (c&0x7F) == '%') {
					if (flag[FNOUNSET] &&
					    strval(global(cp)) == null)
						errorf("%s: unset variable\n", cp);
					trimming++;
					type = XBASE;
					*--qst = quote;
					quote = 0;
				} else
					type = varsub(&x, cp, c);
				if (type == XBASE) {	/* expand? */
					if (st == subtype)
						errorf("ridiculous ${} nesting\n");
					--st;
					st->type = c;
					st->base = Xsavepos(ds, dp);
					st->name = cp;
				} else
					sp = wdscan(sp, CSUBST); /* skip word */
				continue;
			  case CSUBST: /* only get here if expanding word */
				*dp = 0;
				if (f&DOGLOB)
					f &= ~DOPAT;
				switch (st->type&0x7F) {
				  case '#':
				  case '%':
					*dp = 0;
					dp = Xrestpos(ds, dp, st->base);
					quote = *qst++;
					x.str = trimsub(strval(global(st->name)),
						dp, st->type);
					type = XSUB;
					trimming--;
					continue;
				  case '=':
#if 0
					if ((x.u.vp->flag&RDONLY))
						errorf("cannot set readonly %s\n", cp);
#endif
					setstr(global(st->name), Xrestpos(ds, dp, st->base));
					break;
				  case '?':
					if (dp == Xrestpos(ds, dp, st->base))
						errorf("missing value for %s\n", cp);
					else
						errorf("%s\n", Xrestpos(ds, dp, st->base));
				}
				st++;
				type = XBASE;
				continue;
			}
			break;

		  case XSUB:
			if ((c = *x.str++) == 0) {
				type = XBASE;
				continue;
			}
			break;

		  case XARGSEP:
			type = XARG;
			quote = 1;
		  case XARG:
			if ((c = *x.str++) == 0) {
				if ((x.str = *x.u.strv++) == NULL) {
					type = XBASE;
					continue;
				} else if (quote && x.split) {
					/* terminate word for "$@" */
					type = XARGSEP;
					quote = 0;
				}
				c = ifs0;
			}
			break;

		  case XCOM:
			if (newlines) {		/* Spit out saved nl's */
				c = '\n';
				--newlines;
			} else {
				while ((c = getc(x.u.file)) == '\n')
					newlines++;	/* Save newlines */
				if (newlines && c != EOF) {
					ungetc(c, x.u.file);
					c = '\n';
					--newlines;
				}
			}
			if (c == EOF) {
				cp = Xrestpos(ds, sp, combase);
				newlines = 0;
				fclose(x.u.file);
				if (x.split)
					waitlast();
				type = XBASE;
				continue;
			}
			break;
		}

		/* check for end of word or IFS separation */
		if (c == 0 || (!quote && (f&DOBLANK) && ctype(c, C_IFS))) {
			if (word) {
				*dp++ = 0;
				cp = Xclose(ds, dp);
				if (fdo&DOTILDE)
					cp = tilde(cp);
				if (fdo&DOGLOB)
					glob(cp, wp);
				else
					{XPput(*wp, cp);}
				fdo = word = 0;
				if (c != 0)
					Xinit(ds, dp, 128);
			} else
				; /* ignore IFS */
			if (c == 0)
				return;
		} else {
			/* mark any special second pass chars */
			if (!quote)
				switch (c) {
				  case '*':
				  case '?':
				  case '[':
					if (f&(DOPAT|DOGLOB) || trimming) {
						fdo |= (f&DOGLOB);
						*dp++ = MAGIC;
					}
					break;
				  case NOT:
					if ((f&(DOPAT|DOGLOB) || trimming) &&
					    dp[-1] == '[' && dp[-2] == MAGIC) {
						*dp++ = MAGIC;
					}
					break;
				  case '~':
					if (((f&DOTILDE) &&
					     dp == Xstring(ds, dp)) ||
					    (!(f&DOBLANK) && 
					    (dp[-1] == '=' || dp[-1] == ':'))) {
						fdo |= DOTILDE;
						*dp++ = MAGIC;
					}
					break;
				}
			else
				quote &= ~2; /* undo temporary */

			word = 1;
			*dp++ = c; /* save output char */
		}
	}
}

/*
 * Prepare to generate the string returned by ${} substitution.
 */
static int
varsub(xp, sp, stype)
	register Expand *xp;
	register char *sp;
	int stype;
{
	register int c;
	int type;

	/* ${#var}, string length or argc */
	if (sp[0] == '#' && (c = sp[1]) != 0) {
		c = (c == '*' || c == '@') ? e.loc->argc :
			strlen(strval(global(sp+1)));
		xp->str = strsave(ulton((unsigned long)c, 10), ATEMP);
		return XSUB;
	}

	c = sp[0];
	if (c == '*' || c == '@') {
		if (e.loc->argc == 0) {
			xp->str = null;
			type = XSUB;
		} else {
			xp->u.strv = e.loc->argv + 1;
			xp->str = *xp->u.strv++;
			xp->split = c == '@'; /* $@ */
			type = XARG;
		}
	} else {
		if ((xp->str = strval(global(sp))) == NULL)
		  xp->str = null;
		type = XSUB;
	}

	c = stype&0x7F;
	/* test the compiler's code generator */
	if (c == '%' || c == '#' ||
	    (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */
	     c == '=' || c == '-' || c == '?' : c == '+'))
		type = XBASE;	/* expand word instead of variable value */
	if (type != XBASE && flag[FNOUNSET] && xp->str == null && c != '+')
		errorf("%s: unset variable\n", sp);
	return type;
}

/*
 * Run the command in $(...) and read its output.
 */
static int
comsub(xp, cp)
	register Expand *xp;
	char *cp;
{
	Source *s;
	register struct op *t;
	FILE *fi;

	s = pushs(SSTRING);
	s->str = cp;
	t = compile(s);

	if (t != NULL && t->type == TCOM && /* $(<file) */
	    *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
		register struct ioword *io = *t->ioact;

		if ((io->flag&IOTYPE) != IOREAD)
			errorf("funny $() command\n");
		fi = fopen(evalstr(io->name, DOTILDE), "r");
		if (fi != NULL)
#ifdef linux
			setfileno (fi, savefd(fileno(fi)));
#else
			fileno(fi) = savefd(fileno(fi));
#endif
		xp->split = 0;	/* no waitlast() */
	} else {
		int ofd1, pv[2];
		openpipe(pv);
		fi = fdopen(pv[0], "r");
		ofd1 = savefd(1);
		dup2(pv[1], 1);
		close(pv[1]);
#if 0
		exchild(t, XXCOM|XPIPEO);
#else
		execute(t, XFORK|XXCOM|XPIPEO);
#endif
		dup2(ofd1, 1);
		close(ofd1);
		xp->split = 1;	/* waitlast() */
	}	

	if (fi == NULL)
		errorf("cannot open $() input\n");
	setvbuf(fi, (char *)NULL, _IOFBF, BUFSIZ);
	xp->u.file = fi;
	return XCOM;
}

/*
 * perform #pattern and %pattern substitution in ${}
 */

static char *
trimsub(str, pat, how)
	register char *str;
	char *pat;
	int how;
{
	register char *end = strchr(str, 0);
	register char *p, c, *match;

	switch (how&0xff) {	/* UCHAR_MAX maybe? */
	case '#':		/* shortest at begin */
		for (p = str; p <= end; p++) {
			c = *p; *p = '\0';
			if (gmatch(str, pat)) {
				*p = c;
				return p;
			}
			*p = c;
		}
		break;
	case '#'|0x80:		/* longest match at begin */
		for (p = end; p >= str; p--) {
			c = *p; *p = '\0';
			if (gmatch(str, pat)) {
				*p = c;
				return p;
			}
			*p = c;
		}
		break;
	case '%':		/* shortest match at end */
		for (p = end; p >= str; p--) {
			if (gmatch(p, pat)) {
				c = *p; *p = '\0';
				match = strsave( str, APERM );	/* APERM? */
				*p = c;
				return match;
			}
		}
		break;
	case '%'|0x80:	/* longest match at end */
		for (p = str; p <= end; p++) {
			if (gmatch(p, pat)) {
				c = *p; *p = '\0';
				match = strsave( str, ATEMP );	/* APERM? */
				*p = c;
				return match;
			}
		}
		break;
	}

	return str;		/* no match, return string */
}

#ifdef ALTERNATIONS
/*	([email protected])
 *	I have decided to `fudge' alternations by picking up
 *	the compiled command tree and working with it recursively
 *	to generate the set of arguments
 *	This has the advantage of making a single discrete change
 *	to the code
 *
 *	This routine calls itself recursively
 *	a)	scan forward looking for { building the output string
 *		if none found then call expand - and exit
 *	b)	When { found, scan forward finding the end }
 *	c)	add first alternate to output string
 *	d)	scan for the end of the string copying into output
 *	e)	call routine with new string
 *	Major complication is quoting
 */
static int
alt_expand(cp, wp, f)
	char *cp;		/* input word */
	register XPtrV *wp;	/* output words */
	int f;			/* DO* flags */
{
	char *srcp = cp;
	char *left;		/* destination string of left hand side */
	char *leftend;		/* end of left hand side */
	char *alt;		/* start of alterate section */
	char *altend;		/* end of alternate section */
	char *ap;		/* working pointer */
	char *right;		/* right hand side */
	char *rp;		/* used to copy right-hand side */
	int  maxlen;		/* max string length */

	leftend = left = alloc((maxlen = alt_count(cp)), ATEMP);
	
	if (alt_scan(&srcp, &leftend, '{', 0) == 0) {
		expand(cp, wp, f&NOALT);
		afree(left, ATEMP);
		return;
	}

	/*
	 *	we have a alternation section
	 */
	alt = altend = alloc(maxlen, ATEMP);

	srcp += 2;
	if (alt_scan(&srcp, &altend, '}', 1) == 0) {
		afree(left, ATEMP);
		afree(alt, ATEMP);
		errorf("Missing }.\n");
	}
	*altend++ = CHAR;
	*altend++ = ',';
	*altend = EOS;
	/*
	 *	finally we may have a right-hand side
	 */
	right = srcp + 2;

	/*
	 *	glue the bits together making a new string
	 */
	for (srcp = alt; *srcp != EOS;) {

		ap = leftend;

		if (alt_scan(&srcp, &ap, ',', -1) == 0) {
			afree(left, ATEMP);
			afree(alt, ATEMP);
			errorf("Missing comma.\n");
		}
		
		srcp += 2;

		rp = right;
		(void) alt_scan(&rp, &ap, EOS, 0);

		alt_expand(left, wp, f);
	}
	afree(left, ATEMP);
	afree(alt, ATEMP);
}

/*
 * see how much space we need to hold this tree
 */
static int
alt_count(cp)
	register char *cp;
{
	register int sum = 0;
	register char *sp;

	while (*cp != EOS) {
		switch(*cp) {
		  case CHAR:
		  case QCHAR:
			sum += 2;
			cp += 2;
			break;
		  case OQUOTE:
		  case CQUOTE:
		  case CSUBST:
			sum++;
			cp++;
			break;
		  case COMSUB:
		  case OSUBST:
			sp = cp;
			cp = strchr(sp, 0) + 1;
			sum += cp - sp;
			break;
		}
	}
	return ++sum;
}

#ifdef __STDC__
static int
alt_scan(
	char **cpp,		/* address of source pointer */
	char **dpp,		/* address of destination pointer */
	char endc,		/* last character we are looking for */
	int bal)
#else
static int
alt_scan(cpp, dpp, endc, bal)
	char **cpp;		/* address of source pointer */
	char **dpp;		/* address of destination pointer */
	char endc;		/* last character we are looking for */
	int bal;
#endif
{
	register char *cp, *dp;
	int quote = 0;
	int balance = 0;
	int usebalance = 0;

	if (bal)
	{	usebalance = 1;
		balance = (bal < 1) ? 0 : 1;
	}

	cp = *cpp;
	dp = *dpp;

	while (*cp != EOS) {
		switch (*cp) {
		  case CHAR:
			if (quote == 1) {
				if (cp[1] == ']')
					quote = 0;
			}
			else
			if (quote == 0) {
				if (cp[1] == '[')
					quote = 1;
				else {
					if (usebalance) {
						if (cp[1] == '{')
							balance++;
						if (cp[1] == '}')
							balance--;
						}
					if (cp[1] == endc && balance == 0) {
						*dp = EOS;
						*dpp = dp;
						*cpp = cp;
						return 1;
						}
				}
			}
		  case QCHAR:
			*dp++ = *cp++;
		  copy:
			*dp++ = *cp++;
			break;
			
		  case OQUOTE:
			quote = 1;
			goto copy;

		  case CQUOTE:
			quote = 0;
			goto copy;

		  case COMSUB:
		  case OSUBST:
			while (*dp++ = *cp++);
			break;
		}
	}
	*dp = EOS;
	*cpp = cp;
	*dpp = dp;
	return 0;
}
#endif	/* ALTERNATIONS */

/*
 * glob
 * Name derived from V6's /etc/glob, the program that expanded filenames.
 */

static	char   *debunk();

static void 
glob(cp, wp)
	char *cp;
	register XPtrV *wp;
{
	char path [PATH];
	register char *sp = cp;
	int oldsize;

	oldsize = XPsize(*wp);
	globit(path, path, sp, wp, 0);

	if (XPsize(*wp) == oldsize)
		{XPput(*wp, debunk(cp));}
	else
		qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize), xstrcmp);
}

static void
globit(ds, dp, sp, wp, check)
	char *ds;		/* dest path */
	char *dp;		/* dest end */
	char *sp;		/* source path */
	register XPtrV *wp;	/* output list */
	int check;		/* check dest existence */
{
	register char *np;	/* next source component */
	register char *tsp, *tdp;

	if (sp == NULL) {	/* end of source path */
		if (check && eaccess(ds, 0) < 0)
			return;
		XPput(*wp, strsave(ds, ATEMP));
		return;
	}

	if (dp > ds)
		*dp++ = '/';
	while (*sp == '/')
		*dp++ = *sp++;
	np = strchr(sp, '/');
	if (np != NULL)
		*np++ = 0;

	*dp = 0;
	if (strchr(sp, MAGIC) == NULL) { /* contains no pattern? */
		tdp = dp; tsp = sp;
		while ((*tdp++ = *tsp++) != 0)
			;
		--tdp;
		globit(ds, tdp, np, wp, check);
	} else {
		DIR *dirp;
		struct dirent *d;

		/* ToDo:
		 * should not attemp to open() special files: /dev/ttyd0/*
		 * opendir should do this check, but Doug Gwyn's does not.
		 */
		dirp = opendir((*ds == 0) ? "." : ds);
		if (dirp == NULL)
			goto Nodir;
		while ((d = readdir(dirp)) != NULL) {
			tsp = d->d_name;
			if (tsp[0] == '.' &&
			    (tsp[1] == 0 || (tsp[1] == '.' && tsp[2] == 0)))
				continue; /* always ignore . and .. */
			if ((*tsp == '.' && *sp != '.') || !gmatch(tsp, sp))
				continue;

			tdp = dp;
			while ((*tdp++ = *tsp++) != 0)
				;
			--tdp;
			globit(ds, tdp, np, wp, np != NULL);
		}
		closedir(dirp);
	  Nodir:;
	}

	if (np != NULL)
		*--np = '/';
}

/* remove MAGIC from string */
static char *
debunk(cp)
	char *cp;
{
	register char *dp, *sp;

	for (dp = sp = cp; *sp != 0; sp++)
		if (*sp != MAGIC)
			*dp++ = *sp;
	*dp = 0;
	return cp;
}

/*
 * tilde expansion
 *
 * based on a version by Arnold Robbins
 */

static char *homedir();

static char *
tilde(acp)
	char *acp;
{
	register int c;
	char path [PATH+1];
	register char *cp = acp, *wp = path, *dp;
	char userid [16+1];

  Again:
	while (1) {
		if ((c = *cp++) == 0) {
			*wp = 0;
			afree((void*)acp, ATEMP);
			return strsave(path, ATEMP);
		} else if (c == MAGIC && *cp == '~')
			break;
		else
			*wp++ = c;
	}

	dp = NULL;	/* no output substitution */
	if (cp[1] == 0 || cp[1] == '/' || cp[1] == ':') /* ~ or ~/ */
		dp = strval(global("HOME")), cp += 1;
	else if (cp[1] == '+' && (cp[2] == '/' || cp[2] == ':' || cp[2] == 0))
		dp = strval(global("PWD")), cp += 2;
	else if (cp[1] == '-' && (cp[2] == '/' || cp[2] == ':' || cp[2] == 0))
		dp = strval(global("OLDPWD")), cp += 2;
	else if (letter(cp[1])) {
		char *save = cp;
		for (dp = userid, cp++; letnum(*cp) && dp < userid+16; )
			*dp++ = *cp++;
		*dp = 0;
		dp = homedir(userid);
		if (dp == NULL)
			cp = save;
	}
	/* substitute */
	if (dp != NULL)
		while (*dp != 0)
			*wp++ = *dp++;
	goto Again;
}

/*
 * map userid to user's home directory.
 * todo: implement a cache with the "homedirs" table.
 * note that 4.3's getpw adds more than 6K to the shell,
 * and the YP version probably adds much more.
 * we might consider our own version of getpwnam() to keep the size down.
 */

static char *
homedir(name)
	char *name;
{
	register struct tbl *ap;
	register struct passwd *pw;
	extern struct passwd *getpwnam();

	ap = tsearch(&homedirs, name, hash(name));
	if ((ap != NULL && (ap->flag&ISSET)))
		return ap->val.s;
	pw = getpwnam(name);
	if (pw == NULL)
		return NULL;
	return pw->pw_dir;
}
./pdksh/sh/lex.c   644    653   1762       30712  5243743661  11004 0ustar  hlu/*
 * lexical analysis and source input
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include <unistd.h>
#include <assert.h>
#include "sh.h"
#include "expand.h"

	int	ttyfd = -1;		/* tty fd for edit and jobs */
#ifdef EASY_HISTORY
	char   *history[HISTORY];	/* saved commands */
	char  **histptr = history - 1;	/* last history item */
	int	histpush;		/* number of pushed fc commands */
#endif

/* we set s->str to NULLSTR instead of "", so that ungetsc() works */
static	char	nullstr [] = {0, 0};
#define	NULLSTR	(nullstr + 1)

static	int	expanding_alias;
static	int	alias;

static void     readhere    ARGS((struct ioword *iop));
static int      getsc_      ARGS((void));

/* optimized getsc_() */
#define	getsc()	((*source->str != 0) ? *source->str++ : getsc_())
#define	ungetsc() (source->str--)

/*
 * Lexical analyzer
 *
 * tokens are not regular expressions, they are LL(1).
 * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
 * hence the state stack.
 */

int
yylex(cf)
	int cf;
{
	register int c, state;
	char states [64], *statep = states;
	XString ws;		/* expandable output word */
	register char *wp;	/* output word pointer */
	register char *sp, *dp;
	int istate;
	int c2;
	static int rec_alias_cnt = 0;
	static struct tbl *rec_alias_table[20];


	if (expanding_alias) {
		expanding_alias = 0;
		while (rec_alias_cnt-- > 0)
			rec_alias_table[rec_alias_cnt]->flag &= ~EXPALIAS;
		rec_alias_cnt = 0;
	}
  Again:
	Xinit(ws, wp, 64);

	if (cf&ONEWORD)
		istate = SWORD;
	else if (cf&LETEXPR)
		istate = SDPAREN;
	else {			/* normal lexing */
		istate = SBASE;
		while ((c = getsc()) == ' ' || c == '\t')
			;
		if (c == '#')
			while ((c = getsc()) != 0 && c != '\n')
				;
		ungetsc();
	}
	if (alias) {			/* trailing ' ' in alias definition */
		alias = 0;
		cf |= ALIAS;
	}

	/* collect non-special or quoted characters to form word */
	for (*statep = state = istate;
	     !((c = getsc()) == 0 || (state == SBASE && ctype(c, C_LEX1))); ) {
		Xcheck(ws, wp);
		switch (state) {
		  case SBASE:
		  Sbase:
			switch (c) {
			  case '\\':
				c = getsc();
				if (c != '\n')
					*wp++ = QCHAR, *wp++ = c;
				else
					if (wp == Xstring(ws, wp))
						goto Again;
				break;
			  case '\'':
				*++statep = state = SSQUOTE;
				*wp++ = OQUOTE;
				break;
			  case '"':
				*++statep = state = SDQUOTE;
				*wp++ = OQUOTE;
				break;
			  default:
				goto Subst;
			}
			break;

		  Subst:
			switch (c) {
			  case '\\':
				c = getsc();
				switch (c) {
				  case '\n':
					break;
				  case '"': case '\\':
				  case '$': case '`':
					*wp++ = QCHAR, *wp++ = c;
					break;
				  default:
					Xcheck(ws, wp);
					*wp++ = CHAR, *wp++ = '\\';
					*wp++ = CHAR, *wp++ = c;
					break;
				}
				break;
			  case '$':
				c = getsc();
				if (c == '(') {
					*++statep = state = SPAREN;
					*wp++ = COMSUB;
				} else
				if (c == '{') {
					*++statep = state = SBRACE;
					*wp++ = OSUBST;
					c = getsc();
					do {
						Xcheck(ws, wp);
						*wp++ = c;
						c = getsc();
					} while (ctype(c, C_ALPHA|C_DIGIT));
					*wp++ = 0;
					/* todo: more compile-time checking */
					if (c == '}')
						ungetsc();
					else if (c == '#' || c == '%') {
						/* Korn pattern trimming */
						if (getsc() == c)
							c |= 0x80;
						else
							ungetsc();
						*wp++ = c;
					} else if (c == ':')
						*wp++ = 0x80|getsc();
					else
						*wp++ = c;
				} else if (ctype(c, C_ALPHA)) {
					*wp++ = OSUBST;
					do {
						Xcheck(ws, wp);
						*wp++ = c;
						c = getsc();
					} while (ctype(c, C_ALPHA|C_DIGIT));
					*wp++ = 0;
					*wp++ = CSUBST;
					ungetsc();
				} else if (ctype(c, C_DIGIT|C_VAR1)) {
					Xcheck(ws, wp);
					*wp++ = OSUBST;
					*wp++ = c;
					*wp++ = 0;
					*wp++ = CSUBST;
				} else {
					*wp++ = CHAR, *wp++ = '$';
					ungetsc();
				}
				break;
			  case '`':
				*++statep = state = SBQUOTE;
				*wp++ = COMSUB;
				break;
			  default:
				*wp++ = CHAR, *wp++ = c;
			}
			break;

		  case SSQUOTE:
			if (c == '\'') {
				state = *--statep;
				*wp++ = CQUOTE;
			} else
				*wp++ = QCHAR, *wp++ = c;
			break;

		  case SDQUOTE:
			if (c == '"') {
				state = *--statep;
				*wp++ = CQUOTE;
			} else
				goto Subst;
			break;

		  case SPAREN:
			if (c == '(')
				*++statep = state;
			else if (c == ')')
				state = *--statep;
			if (state == SPAREN)
				*wp++ = c;
			else
				*wp++ = 0; /* end of COMSUB */
			break;

		  case SBRACE:
			if (c == '}') {
				state = *--statep;
				*wp++ = CSUBST;
			} else
				goto Sbase;
			break;

		  case SBQUOTE:
			if (c == '`') {
				*wp++ = 0;
				state = *--statep;
			} else if (c == '\\') {
				switch (c = getsc()) {
				  case '\n':
					break;
				  case '\\':
				  case '$': case '`':
					*wp++ = c;
					break;
				  default:
					*wp++ = '\\';
					*wp++ = c;
					break;
				}
			} else
				*wp++ = c;
			break;

		  case SWORD:	/* ONEWORD */
			goto Subst;

		  case SDPAREN:	/* LETEXPR */
			if (c == ')') {
				if (getsc() == ')') {
					c = 0;
					goto Done;
				} else
					ungetsc();
			}
			goto Subst;
		}
	}
Done:
	Xcheck(ws, wp);
	if (state != istate)
		yyerror("no closing quote");

	if (c == '<' || c == '>') {
		char *cp = Xstring(ws, wp);
		if (wp > cp && cp[0] == CHAR && digit(cp[1])) {
			wp = cp; /* throw away word */
			c2/*unit*/ = cp[1] - '0';
		} else
			c2/*unit*/ = c == '>'; /* 0 for <, 1 for > */
	}

	if (wp == Xstring(ws, wp) && state == SBASE) {
		Xfree(ws, sp);	/* free word */
		/* no word, process LEX1 character */
		switch (c) {
		  default:
			return c;

		  case '|':
		  case '&':
		  case ';':
			if (getsc() == c)
				c = (c == ';') ? BREAK :
				    (c == '|') ? LOGOR :
				    (c == '&') ? LOGAND :
				    YYERRCODE;
			else
				ungetsc();
			return c;

		  case '>':
		  case '<': {
			register struct ioword *iop;

			iop = (struct ioword *) alloc(sizeof(*iop), ATEMP);
			iop->unit = c2/*unit*/;

			c2 = getsc();
			if (c2 == '>' || c2 == '<') {
				iop->flag = c != c2 ? IORDWR : c == '>' ? IOCAT : IOHERE;
				c2 = getsc();
			} else
				iop->flag = c == '>' ? IOWRITE : IOREAD;

			if (iop->flag == IOHERE)
				if (c2 == '-')
					iop->flag |= IOSKIP;
				else
					ungetsc();
			else
				if (c2 == '&')
					iop->flag = IODUP;
				else if (c2 == '!' && iop->flag == IOWRITE)
					iop->flag |= IOCLOB;
				else
					ungetsc();
			yylval.iop = iop;
			return REDIR;
		    }
		  case '\n':
			gethere();
			if (cf & CONTIN)
				goto Again;
			return c;

		  case '(':
			c2 = getsc();
			if (c2 == ')')
				c = MPAREN;
			else if (c2 == '(')
				c = MDPAREN;
			else
				ungetsc();
		  case ')':
			return c;
		}
	}

	*wp++ = EOS;		/* terminate word */
	yylval.cp = Xclose(ws, wp);
	if (state == SWORD || state == SDPAREN)	/* ONEWORD? */
		return LWORD;
	ungetsc();		/* unget terminator */

	/* copy word to unprefixed string ident */
	for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
		*dp++ = *sp++;
	/* Make sure the ident array stays '\0' padded */
	while (dp <= ident+IDENT)
		*dp++ = '\0';
#if 0
	if (*ident == '~' || (dp = strchr(ident, '=')) != NULL && dp[1] == '~')
		"Tilde expansion";
#endif
	if (c != EOS)
		*ident = 0;	/* word is not unquoted */

	if (*ident != 0 && (cf&(KEYWORD|ALIAS))) {
		register struct tbl *p;

		p = tsearch(&lexicals, ident, hash(ident));
		if (p != NULL && (p->flag&ISSET))
			if (p->type == CKEYWD && (cf&KEYWORD)) {
				afree(yylval.cp, ATEMP);
				return p->val.i;
			} else if (p->type == CALIAS && (cf&ALIAS) &&
				   !(p->flag&EXPALIAS)) {
				register Source *s;

				if (rec_alias_cnt == sizeof(rec_alias_table)/sizeof(rec_alias_table[0]))
					yyerror("excessive recusrsive aliasing");
				else
					rec_alias_table[rec_alias_cnt++] = p;
				p->flag |= EXPALIAS;
				/* check for recursive aliasing */
				for (s = source; s->type == SALIAS; s = s->next)
					if (s->u.tblp == p)
						return LWORD;
				afree(yylval.cp, ATEMP);

				/* push alias expansion */
				s = pushs(SALIAS);
				s->str = p->val.s;
				s->u.tblp = p;
				s->next = source;
				source = s;
				goto Again;
			} 
	}

	return LWORD;
}

static void readhere();

gethere()
{
	register struct ioword **p;

	for (p = heres; p < herep; p++)
		readhere(*p);
	herep = heres;
}

/*
 * read "<<word" text into temp file
 * todo: set up E_ERR to fclose(f) on unwind
 */

static void
readhere(iop)
	register struct ioword *iop;
{
	register FILE *f;
	struct temp *h;
	register int c;
	char *eof;
	register char *cp;
	char line [LINE+1];

	eof = evalstr(iop->name, 0);

	h = maketemp(ATEMP);
	h->next = e.temps; e.temps = h;
	iop->name = h->name;
	f = fopen(h->name, "w");
	if (f == NULL)
		errorf("Cannot create temporary file\n");
	setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);

	for (;;) {
		cp = line;
		while ((c = getsc()) != '\n') {
			if (c == 0)
				errorf("here document `%s' unclosed\n", eof);
			if (cp >= line+LINE)
				break;
			*cp++ = c;
		}
		ungetsc();
		*cp = 0;
		for (cp = line; iop->flag&IOSKIP && *cp == '\t'; cp++)
			;
		if (strcmp(eof, cp) == 0 || c == 0)
			break;
		while ((c = *cp++) != '\0')
			putc(c, f);
		while ((c = getsc()) != '\n') {
			if (c == 0)
				errorf("here document `%s' unclosed\n", eof);
			putc(c, f);
		}
		putc(c, f);
	}
	fclose(f);
}

void
yyerror(msg)
	const char *msg;
{
	yynerrs++;
	while (source->type == SALIAS) /* pop aliases */
		source = source->next;
	if (source->file != NULL)
		shellf("%s[%d]: ", source->file, source->line);
	source->str = NULLSTR;	/* zap pending input */
	errorf("%s\n", msg);
}

/*
 * input for yylex with alias expansion
 */

Source *
pushs(type)
	int type;
{
	register Source *s;

	s = (Source *) alloc(sizeof(Source), ATEMP);
	s->type = type;
	s->str = NULLSTR;
	s->line = 0;
	s->file = NULL;
	s->echo = 0;
	s->next = NULL;
	return s;
}

static int
getsc_()
{
	register Source *s = source;
	register int c;
	extern void	mprint();
	
	while ((c = *s->str++) == 0) {
		s->str = NULL;		/* return 0 for EOF by default */
		switch (s->type) {
		  case SEOF:
			s->str = NULLSTR;
			return 0;

		  case STTY:
			if (histpush < 0) {	/* commands pushed by dofc */
				s->type = SHIST;
				s->str = NULLSTR;
				continue;
			}
			s->line++;
			s->str = line;
			line[0] = '\0';
			mprint();
			pprompt(prompt);
			flushshf(1);	flushshf(2);
			/*
			 * This allows the arival of a SIGCHLD 
			 * to not disturb us until we are ready. 
			 * BSD and other systems that 
			 * automatically rety a read after an 
			 * interrupt don't need this but it 
			 * doesn't do any harm either.
			 */
		      retry:
#ifdef EDIT
#ifdef EMACS
			if (flag[FEMACS])
				c = x_read(ttyfd, line, LINE);
			else
#endif
#ifdef VI
			if (flag[FVI])
				c = x_read(ttyfd, line, LINE);
			else
#endif
#endif
				c = read(ttyfd, line, LINE);
			if (c < 0 && sigchld_caught)
			{
			  goto retry;
			}
			if (c < 0)	/* read error */
				c = 0;
			line[c] = '\0';
			prompt = strval(global("PS2"));
			if (c == 0) { /* EOF */
				s->str = NULL;
				s->line--;
			} else {
				c = 0;
				while(line[c] && ctype(line[c], C_IFS))
					c++;
				if (!line[c]) {
					s->str = &line[c - 1];
					s->line--;
				} else {
					s->str = &line[c];
#ifdef EASY_HISTORY
					histsave(s->str);
#else
					histsave(s->line, s->str, 1);
#endif
				}
			}
			break;

		  case SHIST:
			if (histpush == 0) {
				s->type = STTY;
				s->str = NULLSTR;
				continue;
			}
			s->line++;
			s->str = histptr[++histpush];
#if 0
			pprompt("!< ");	/* todo: PS9 */
#endif
			shellf("%s\n", s->str);
			strcpy(line, s->str);
			s->str = strchr(line, 0);
			*s->str++ = '\n';
			*s->str = 0;
			s->str = line;
			break;

		  case SFILE:
			s->line++;
			s->str = fgets(line, LINE, s->u.file);
			if (s->str == NULL)
				if (s->u.file != stdin)
					fclose(s->u.file);
			break;

		  case SWSTR:
			break;

		  case SSTRING:
			s->str = "\n";
			s->type = SEOF;
			break;

		  case SWORDS:
			s->str = *s->u.strv++;
			s->type = SWORDSEP;
			break;

		  case SWORDSEP:
			if (*s->u.strv == NULL) {
				s->str = "\n";
				s->type = SEOF;
			} else {
				s->str = " ";
				s->type = SWORDS;
			}
			break;

		  case SALIAS:
			s->str = s->u.tblp->val.s;
			if (s->str[0] != 0) {
				c = strchr(s->str, 0)[-1];
				if (c == ' ' || c == '\t')
					alias = 1;	/* trailing ' ' */
			}
			source = s = s->next;
			expanding_alias = 1;
			continue;
		}
		if (s->str == NULL) {
			s->type = SEOF;
			s->str = NULLSTR;
			return 0;
		}
		if (s->echo)
			fputs(s->str, shlout);
	}
	return c;
}

pprompt(cp)
	register char *cp;
{
	while (*cp != 0)
		if (*cp != '!')
			putc(*cp++, shlout);
		else
			if (*++cp == '!')
				putc(*cp++, shlout);
			else
				shellf("%d", source->line);
	fflush(shlout);
}
./pdksh/sh/syn.c   644    653   1762       23636  5243743665  11040 0ustar  hlu/*
 * shell parser (C version)
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include "sh.h"
#include "expand.h"

static struct op *pipeline  ARGS((int cf));
static struct op *andor     ARGS((void));
static struct op *c_list    ARGS((void));
static struct ioword *synio ARGS((int cf));
static void     musthave    ARGS((int c, int cf));
static struct op *nested    ARGS((int type, int mark));
static struct op *command   ARGS((int cf));
static struct op *dogroup   ARGS((int onlydone));
static struct op *thenpart  ARGS((void));
static struct op *elsepart  ARGS((void));
static struct op *caselist  ARGS((void));
static struct op *casepart  ARGS((void));
static char **  wordlist    ARGS((void));
static struct op *block     ARGS((int type, struct op *t1, struct op *t2, char **wp));
static struct op *newtp     ARGS((int type));
static void     zzerr       ARGS((void));

static	struct	op	*outtree; /* yyparse output */

static	int	reject;		/* token(cf) gets symbol again */
static	int	symbol;		/* yylex value */

#define	REJECT	(reject = 1)
#define	ACCEPT	(reject = 0)
#define	token(cf) \
	((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
#define	tpeek(cf) \
	((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))

int
yyparse()
{
	ACCEPT;
	yynerrs = 0;
	if ((tpeek(KEYWORD|ALIAS)) == 0) { /* EOF */
		outtree = newtp(TEOF);
		return 0;
	}
	outtree = c_list();
	musthave('\n', 0);
	return (yynerrs != 0);
}

static struct op *
pipeline(cf)
	int cf;
{
	register struct op *t, *p, *tl = NULL;
	register int c;

	t = command(cf);
	if (t != NULL) {
		while ((c = token(0)) == '|') {
			if ((p = command(CONTIN)) == NULL)
				SYNTAXERR;
			if (tl == NULL)
				t = tl = block(TPIPE, t, p, NOWORDS);
			else
				tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
			/*t = block(TPIPE, t, p, NOWORDS);*/
		}
		REJECT;
	}
	return (t);
}

static struct op *
andor()
{
	register struct op *t, *p;
	register int c;

	t = pipeline(0);
	if (t != NULL) {
		while ((c = token(0)) == LOGAND || c == LOGOR) {
			if ((p = pipeline(CONTIN)) == NULL)
				SYNTAXERR;
			t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
		}
		REJECT;
	}
	return (t);
}

static struct op *
c_list()
{
	register struct op *t, *p, *tl = NULL;
	register int c;

	t = andor();
	if (t != NULL) {
		while ((c = token(0)) == ';' || c == '&' ||
		       ((multiline || source->type == SSTRING
		        || (source->type == SALIAS)) && c == '\n')) {
			if (c == '&') {
				if (tl)
					tl->right = block(TASYNC, tl->right, NOBLOCK, NOWORDS);
				else
					t = block(TASYNC, t, NOBLOCK, NOWORDS);
			}
			if ((p = andor()) == NULL)
				return (t);
			if (tl == NULL)
				t = tl = block(TLIST, t, p, NOWORDS);
			else
				tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
		}
		REJECT;
	}
	return (t);
}

static struct ioword *
synio(cf)
	int cf;
{
	register struct ioword *iop;

	if (tpeek(cf) != REDIR)
		return NULL;
	ACCEPT;
	iop = yylval.iop;
	musthave(LWORD, 0);
	iop->name = yylval.cp;
	if ((iop->flag&IOTYPE) == IOHERE) {
		if (*ident != 0) /* unquoted */
			iop->flag |= IOEVAL;
		if (herep >= &heres[HERES])
			errorf("too many <<'s\n");
		*herep++ = iop;
	}
	return iop;
}

static void
musthave(c, cf)
	int c, cf;
{
	if ((token(cf)) != c)
		SYNTAXERR;
}

static struct op *
nested(type, mark)
	int type, mark;
{
	register struct op *t;

	multiline++;
	t = c_list();
	musthave(mark, KEYWORD);
	multiline--;
	return (block(type, t, NOBLOCK, NOWORDS));
}

static struct op *
command(cf)
	int cf;
{
	register struct op *t;
	register int c, iopn = 0;
	struct ioword *iop, **iops;
	XPtrV args, vars;

	iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1), ATEMP);
	XPinit(args, 16);
	XPinit(vars, 16);

	if (multiline)
		cf = CONTIN;
	cf |= KEYWORD|ALIAS;

	while ((iop = synio(cf)) != NULL) {
		if (iopn >= NUFILE)
			yyerror("too many redirections");
		iops[iopn++] = iop;
		cf &=~ CONTIN;
	}

	switch (c = token(cf)) {
	  case 0:
		yyerror("unexpected EOF");
		return NULL;

	  default:
		REJECT;
		if (iopn == 0)
			return NULL; /* empty line */
		t = newtp(TCOM);
		break;

	  case LWORD:
	  case MDPAREN:
		REJECT;
		t = newtp(TCOM);
		if (c == MDPAREN) {
			ACCEPT;
			XPput(args,"let");
			musthave(LWORD,LETEXPR);
			XPput(args,yylval.cp);
		}
		while (1)
			switch (tpeek(0)) {
			  case REDIR:
				if (iopn >= NUFILE)
					yyerror("too many redirections");
				iops[iopn++] = synio(0);
				break;

			  case LWORD:
				ACCEPT;
				if ((XPsize(args) == 0 || flag[FKEYWORD])
				    && strchr(ident+1, '='))
					{XPput(vars, yylval.cp);}
				else
					{XPput(args, yylval.cp);}
				break;

			  case MPAREN:
				ACCEPT;
				if (XPsize(args) != 1)
					SYNTAXERR;
				if (*ident == 0)
					yyerror("invalid function name\n");
				t = newtp(TFUNCT);
				t->str = strsave(ident, ATEMP);
				musthave('{', CONTIN|KEYWORD);
				t->left = nested(TBRACE, '}');
				return t;

			  default:
				goto Leave;
			}
	  Leave:
		break;

	  case '(':
		t = nested(TPAREN, ')');
		break;

	  case '{':
		t = nested(TBRACE, '}');
		break;

	  case FOR:
	  case SELECT:
		t = newtp((c == FOR) ? TFOR: TSELECT);
		musthave(LWORD, 0);
		t->str = strsave(ident, ATEMP);
		multiline++;
		t->vars = wordlist();
		t->left = dogroup(0);
		multiline--;
		break;

	  case WHILE:
	  case UNTIL:
		multiline++;
		t = newtp((c == WHILE) ? TWHILE: TUNTIL);
		t->left = c_list();
		t->right = dogroup(1);
		multiline--;
		break;

	  case CASE:
		t = newtp(TCASE);
		musthave(LWORD, 0);
		t->str = yylval.cp;
		multiline++;
		musthave(IN, KEYWORD|CONTIN);
		t->left = caselist();
		musthave(ESAC, KEYWORD);
		multiline--;
		break;

	  case IF:
		multiline++;
		t = newtp(TIF);
		t->left = c_list();
		t->right = thenpart();
		musthave(FI, KEYWORD);
		multiline--;
		break;

	  case TIME:
		t = pipeline(CONTIN);
		t = block(TTIME, t, NOBLOCK, NOWORDS);
		break;

	  case FUNCTION:
		t = newtp(TFUNCT);
		musthave(LWORD, 0);
		t->str = strsave(ident, ATEMP);
		musthave('{', CONTIN|KEYWORD);
		t->left = nested(TBRACE, '}');
		break;

#if 0
	  case MDPAREN:
		t = newtp(TCOM);
		XPput(args, "let");
		musthave(LWORD, LETEXPR);
		XPput(args, yylval.cp);
		while (tpeek(0) == REDIR) {
			if (iopn >= NUFILE)
				yyerror("too many redirections");
			iops[iopn++] = synio(0);
		}
		break;
#endif
	}

	while ((iop = synio(0)) != NULL) {
		if (iopn >= NUFILE)
			yyerror("too many redirections");
		iops[iopn++] = iop;
	}

	if (iopn == 0) {
		afree((void*) iops, ATEMP);
		t->ioact = NULL;
	} else {
		iops[iopn++] = NULL;
		aresize((void*) iops, sizeofN(struct ioword *, iopn), ATEMP);
		t->ioact = iops;
	}

	if (t->type == TCOM) {
		XPput(args, NULL);
		t->args = (char **) XPclose(args);
		XPput(vars, NULL);
		t->vars = (char **) XPclose(vars);
	} else {
		XPfree(args);
		XPfree(vars);
	}

	return t;
}

static struct op *
dogroup(onlydone)
	int onlydone;
{
	register int c;
	register struct op *list;

	c = token(CONTIN|KEYWORD);
	if (c == DONE && onlydone)
		return NULL;
	if (c != DO)
		SYNTAXERR;
	list = c_list();
	musthave(DONE, KEYWORD);
	return list;
}

static struct op *
thenpart()
{
	register int c;
	register struct op *t;

	if ((c = token(0)) != THEN) {
		REJECT;
		return NULL;
	}
	t = newtp(0);
	t->left = c_list();
	if (t->left == NULL)
		SYNTAXERR;
	t->right = elsepart();
	return (t);
}

static struct op *
elsepart()
{
	register int c;
	register struct op *t;

	switch (c = token(0)) {
	  case ELSE:
		if ((t = c_list()) == NULL)
			SYNTAXERR;
		return (t);

	  case ELIF:
		t = newtp(TELIF);
		t->left = c_list();
		t->right = thenpart();
		return (t);

	  default:
		REJECT;
		return NULL;
	}
}

static struct op *
caselist()
{
	register struct op *t, *tl;

	t = tl = NULL;
	while ((tpeek(CONTIN|KEYWORD)) != ESAC) {
		struct op *tc = casepart();
		if (tl == NULL)
			t = tl = tc, tl->right = NULL;
		else
			tl->right = tc, tl = tc;
	}
	return (t);
}

static struct op *
casepart()
{
	register struct op *t;
	register int c, cf;
	XPtrV ptns;

	XPinit(ptns, 16);
	t = newtp(TPAT);
	cf = CONTIN|KEYWORD;
	c = token(cf);
	if (c != '(')
		REJECT;
	else
		cf = 0;
	do {
		musthave(LWORD, cf);
		XPput(ptns, yylval.cp);
		cf = 0;
	} while ((c = token(0)) == '|');
	REJECT;
	XPput(ptns, NULL);
	t->vars = (char **) XPclose(ptns);
	musthave(')', 0);

	t->left = c_list();
	if ((tpeek(CONTIN|KEYWORD)) != ESAC)
		musthave(BREAK, CONTIN|KEYWORD);
	return (t);
}

static char **
wordlist()
{
	register int c;
	XPtrV args;

	XPinit(args, 16);
	if ((c = token(CONTIN|KEYWORD)) != IN) {
		REJECT;
		return NULL;
	}
	while ((c = token(0)) == LWORD)
		XPput(args, yylval.cp);
	if (c != '\n' && c != ';')
		SYNTAXERR;
	if (XPsize(args) == 0) {
		XPfree(args);
		return NULL;
	} else {
		XPput(args, NULL);
		return (char **) XPclose(args);
	}
}

/*
 * supporting functions
 */

static struct op *
block(type, t1, t2, wp)
	struct op *t1, *t2;
	char **wp;
{
	register struct op *t;

	t = newtp(type);
	t->left = t1;
	t->right = t2;
	t->vars = wp;
	return (t);
}

const	struct res {
	char	*name;
	int	val;
} restab[] = {
	"for",		FOR,
	"select",	SELECT,
	"case",		CASE,
	"esac",		ESAC,
	"while",	WHILE,
	"do",		DO,
	"done",		DONE,
	"if",		IF,
	"in",		IN,
	"then",		THEN,
	"else",		ELSE,
	"elif",		ELIF,
	"until",	UNTIL,
	"fi",		FI,
	"function",	FUNCTION,
	"time",		TIME,
	"{",		'{',
	"}",		'}',
	0
};

keywords()
{
	register struct res const *rp;
	register struct tbl *p;

	for (rp = restab; rp->name; rp++) {
		p = tenter(&lexicals, rp->name, hash(rp->name));
		p->flag |= DEFINED|ISSET;
		p->type = CKEYWD;
		p->val.i = rp->val;
	}
}

static struct op *
newtp(type)
	int type;
{
	register struct op *t;

	t = (struct op *) alloc(sizeof(*t), ATEMP);
	t->type = type;
	t->args = t->vars = NULL;
	t->ioact = NULL;
	t->left = t->right = NULL;
	t->str = NULL;
	return (t);
}

static void
zzerr()
{
	yyerror("syntax error");
}

struct op *
compile(s)
	Source *s;
{
	yynerrs = 0;
	multiline = 0;
	herep = heres;
	source = s;
	if (yyparse())
		unwind();
	if (s->type == STTY || s->type == SFILE || s->type == SHIST)
		s->str = null;	/* line is not preserved */
	return outtree;
}

./pdksh/sh/c_sh.c   644    653   1762       21073  5302766212  11121 0ustar  hlu/*
 * built-in Bourne commands
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>		/* getcwd */
#include <sys/times.h>
#ifdef linux
#include <sys/stat.h>
#endif
#include "sh.h"

static char *   clocktos    ARGS((clock_t t));

#ifndef CLK_TCK
#define CLK_TCK 60			/* 60HZ */
#endif

int
c_label(wp)
	char **wp;
{
	return 0;
}

int
c_shift(wp)
	register char **wp;
{
	register struct block *l = e.loc;
	register int n;

	n = wp[1] ? evaluate(wp[1]) : 1;
	if (l->argc < n) {
		errorf("nothing to shift\n");
		return (1);
	}
	l->argv[n] = l->argv[0];
	l->argv += n;
	l->argc -= n;
	return 0;
}

int
c_umask(wp)
	register char **wp;
{
	register int i;
	register char *cp;

	if ((cp = wp[1]) == NULL) {
		i = umask(0);
		umask(i);
		printf("%#3.3o\n", i);	/* should this be shell output? */
	} else {
		for (i = 0; *cp>='0' && *cp<='7'; cp++)
			i = i*8 + (*cp-'0');
		umask(i);
	}
	return 0;
}

int
c_dot(wp)
	char **wp;
{
	char *file, *cp;

	if ((cp = wp[1]) == NULL)
		return 0;
	file = search(cp, path, 0);
	if (file == NULL)
		errorf("%s: not found\n", cp);
	if (include(file))
		return exstat;
	return -1;
}

int
c_wait(wp)
	char **wp;
{
	register char *cp;

	wp++;
	cp = *wp;
	if (cp == NULL) cp = "%";
	/* todo: print status ? */
	return waitfor(j_lookup(cp));
}

int
c_read(wp)
	register char **wp;
{
	register int c = 0;
	FILE *f = stdin;
	int expand = 1;
	register char *cp;

	for (wp++; (cp = *wp) != NULL && *cp++ == '-'; wp++) {
		while (*cp) switch (*cp++) {
		  case 'e':
			expand = 1;
			break;
		  case 'r':
			expand = 0;
			break;
		  case 'u':
			if (!digit(*cp) || (f = shf[*cp++-'0']) == NULL)
				errorf("bad -u argument\n");
			break;
		}
	}

	if (*wp == NULL)
		errorf("missing name\n");
	if ((cp = strchr(*wp, '?')) != NULL) {
		*cp = 0;
		if (flag[FTALKING]) {
			shellf("%s ", cp+1);
			fflush(shlout);
		}
	}

	for (; *wp != NULL; wp++) {
		for (cp = line; cp <= line+LINE; ) {
			if (c == '\n')
				break;
			c = getc(f);
			if (c == EOF)
				return 1;
			if (expand && c == '\\') {
				c = getc(f);
				if (c == '\n')
					c = 0;
				else
					*cp++ = c;
				continue;
			}
			if (c == '\n' || (wp[1] && ctype(c, C_IFS)))
				break;
			*cp++ = c;
		}
		*cp = 0;
		setstr(global(*wp), line);
	}
	return 0;
}

int
c_eval(wp)
	register char **wp;
{
	register struct source *s;

	s = pushs(SWORDS);
	s->u.strv = wp+1;
	return shell(s);
}

void setsig ARGS((struct trap *p, handler_t f));

int
c_trap(wp)
	register char **wp;
{
	int i;
	char *s;
	register struct trap *p;

	wp++;
	if (*wp == NULL) {
		for (p = sigtraps, i = SIGNALS; --i >= 0; p++) {
			if (p->trap != NULL)
				shellf("%s: %s\n", p->name, p->trap);
		}
		return 0;
	}

	s = (gettrap(*wp) == NULL) ? *wp++ : NULL; /* get command */
	if (s != NULL && s[0] == '-' && s[1] == '\0')
		s = NULL;

	/* set/clear traps */
	while (*wp != NULL) {
		p = gettrap(*wp++);
		if (p == NULL)
			errorf("trap: bad signal %s\n", wp[-1]);
		if (p->trap != NULL)
			afree((void*)p->trap, APERM);
		p->trap = NULL;
		if (s != NULL) {
			if (strlen(s) != 0) {
				p->trap = strsave(s, APERM);
				setsig(p, trapsig);
			} else
				setsig(p, (handler_t)SIG_IGN);
		} else
			/* todo: restore to orginal value */
		    setsig(p,
		       (p->signal==SIGINT || p->signal==SIGQUIT) && flag[FTALKING]
			   ? (handler_t)SIG_IGN : (handler_t)SIG_DFL);
	}
	return 0;
}

void
setsig(p, f)
	register struct trap *p;
	void (*f)();
{
  if (p->signal == 0)
    return;
#ifdef USE_SIGACT
  sigaction(p->signal, &Sigact_ign, &Sigact);
  if (Sigact.sa_handler != SIG_IGN || p->ourtrap)
  {
    p->ourtrap = 1;
    Sigact.sa_handler = f;
    sigaction(p->signal, &Sigact, NULL);
    sigemptyset(&Sigact.sa_mask);
    Sigact.sa_flags = 0;
  }
#else
  if (signal(p->signal, SIG_IGN) != SIG_IGN || p->ourtrap)
  {
    p->ourtrap = 1;
    signal(p->signal, f);
  }
#endif
}

int
c_return(wp)
	char **wp;
{
	wp++;
	if (*wp != NULL)
		exstat = getn(*wp);
	quitenv();		/* pop E_TCOM */
	while (e.type == E_LOOP || e.type == E_EXEC)
		quitenv();
	if (e.type == E_FUNC)
		longjmp(e.jbuf, 1);
	leave(exstat);
}

int
c_brkcont(wp)
	register char **wp;
{
	int quit;

	quit = wp[1] == NULL ? 1 : getn(wp[1]);
	quitenv();		/* pop E_TCOM */
	while (e.type == E_LOOP || e.type == E_EXEC) {
		if (e.type == E_LOOP && --quit <= 0)
			longjmp(e.jbuf, (*wp[0] == 'b') ? LBREAK : LCONTIN);
		quitenv();
	}
	errorf("cannot %s\n", wp[0]);
}


/* 91-05-27 <sjg>
 * we are supposed to not exit first try
 * if there are stopped jobs.
 */
int
c_exit(wp)
	char **wp;
{
	register char *cp;
	static int extry = 0;
	
#ifdef JOBS
	if (extry++ == 0)
	{
	  if (flag[FMONITOR] && j_stopped()) /* todo: only once */
	  {
	    errorf("There are stopped jobs\n");
	    return 1;
	  }
	}
#endif
	e.oenv = NULL;
	if ((cp = wp[1]) != NULL)
		exstat = getn(cp);
	leave(exstat);
}

int
c_set(wp)
	register char **wp;
{
	struct block *l = e.loc;
	register char **owp = wp;
	register char *cp;
	int old_fmonitor = flag[FMONITOR];

	if ((cp = *++wp) == NULL) {
		static char * const args [] = {"set", "-", NULL};
		extern int c_typeset ARGS((char **args));
		return c_typeset(args);
	}
	
	for (; (cp = *wp) != NULL && (*cp == '-' || *cp == '+');) {
		int i, n = *cp++ == '-'; /* set or clear flag */
		wp++;
		if (*cp == '\0') {
			if (n)
				flag[FXTRACE] = flag[FVERBOSE] = 0;
			break;
		}
		if (*cp == '-')
			goto setargs;
		for (; *cp != '\0'; cp++)
			if (*cp == 'o') {
				if (*wp == NULL) {
					printoptions();
					return 0;
				}
				i = option(*wp++);
				if (i == 0)
					shellf("%s: unknown option\n", *--wp);
				flag[i] = n;
				if (i == FEMACS && n)
					flag[FVI] = 0;
				else if (i == FVI && n)
					flag[FEMACS] = 0;
			} else if (*cp>='a' && *cp<='z')
				flag[FLAG(*cp)] = n;
			else
				errorf("%c: bad flag\n", *cp);
		if (flag[FTALKING])
			flag[FERREXIT] = 0;
	}

#ifdef JOBS
	if (old_fmonitor != flag[FMONITOR])
		j_change();
#endif

	/* set $# and $* */
	if (*wp != NULL) {
	  setargs:
		owp = --wp;
		wp[0] = l->argv[0]; /* save $0 */
		while (*++wp != NULL)
			*wp = strsave(*wp, &l->area);
		l->argc = wp - owp - 1;
		l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
		for (wp = l->argv; (*wp++ = *owp++) != NULL; )
			;
		resetopts();
	}
	return 0;
}

int
c_unset(wp)
	register char **wp;
{
	register char *id;
	int flagf = 0;

	for (wp++; (id = *wp) != NULL && *id == '-'; wp++)
		if (*++id == 'f')
			flagf++;
	for (; (id = *wp) != NULL; wp++)
		if (!flagf) {	/* unset variable */
			unset(global(id));
		} else {	/* unset function */
			define(id, (struct op *)NULL);
		}
	return 0;
}

int
c_ulimit(wp)
	register char **wp;
{
	extern int do_ulimit();

	return do_ulimit(wp[1], wp[2]);
}

int
c_times(wp)
	char **wp;
{
	struct tms all;

	(void) times(&all);
	printf("Shell: ");
	printf("%8s user ", clocktos(all.tms_utime));
	printf("%8s system\n", clocktos(all.tms_stime));
	printf("Kids:  ");
	printf("%8s user ", clocktos(all.tms_cutime));
	printf("%8s system\n", clocktos(all.tms_cstime));

	return 0;
}

/*
 * time pipeline (really a statement, not a built-in comman)
 */
int
timex(t, f)
	struct op *t;
	int f;
{
	int rv;
	struct tms t0, t1;
	clock_t t0t, t1t;
	extern clock_t j_utime, j_stime; /* computed by j_wait */

	j_utime = j_stime = 0;
	t0t = times(&t0);
	rv = execute(t->left, f);
	t1t = times(&t1);

	shellf("%8s real ", clocktos(t1t - t0t));
	shellf("%8s user ",
	       clocktos(t1.tms_utime - t0.tms_utime + j_utime));
	shellf("%8s system ",
	       clocktos(t1.tms_stime - t0.tms_stime + j_stime));
	shellf("\n");

	return rv;
}

static char *
clocktos(t)
	clock_t t;
{
	static char temp[20];
	register int i;
	register char *cp = temp + sizeof(temp);

#if CLK_TCK != 100		/* convert to 1/100'ths */
	t = (t < 1000000000/CLK_TCK) ?
		(t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
#endif

	*--cp = '\0';
	*--cp = 's';
	for (i = -2; i <= 0 || t > 0; i++) {
		if (i == 0)
			*--cp = '.';
		*--cp = '0' + (char)(t%10);
		t /= 10;
	}
	return cp;
}

/* dummy function, special case in comexec() */
int
c_exec(wp)
	char ** wp;
{
	return 0;
}

/* dummy function, special case in comexec() */
int
c_builtin(wp)
	char ** wp;
{
	return 0;
}

extern	int c_test();		/* in test.c */

const struct builtin shbuiltins [] = {
	{"=:", c_label},
	{"=.", c_dot},
	{"[", c_test},
	{"=builtin", c_builtin},
	{"=exec", c_exec},
	{"=shift", c_shift},
	{"=wait", c_wait},
	{"read", c_read},
	{"=eval", c_eval},
	{"=trap", c_trap},
	{"=break", c_brkcont},
	{"=continue", c_brkcont},
	{"=exit", c_exit},
	{"=return", c_return},
	{"=set", c_set},
	{"unset", c_unset},
	{"umask", c_umask},
	{"test", c_test},
	{"=times", c_times},
	{"ulimit", c_ulimit},
	{NULL, NULL}
};

./pdksh/sh/c_test.c   644    653   1762       16156  5302766312  11475 0ustar  hlu/*
 * test(1); version 7-like  --  author Erik Baalbergen
 * modified by Eric Gisin to be used as built-in.
 * modified by Arnold Robbins to add SVR3 compatibility
 * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <unistd.h>
#include <sys/stat.h>
#include "sh.h"

/* test(1) accepts the following grammar:
	oexpr	::= aexpr | aexpr "-o" oexpr ;
	aexpr	::= nexpr | nexpr "-a" aexpr ;
	nexpr	::= primary ! "!" primary
	primary	::= unary-operator operand
		| operand binary-operator operand
		| operand
		| "(" oexpr ")"
		;
	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";

	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
			"-nt"|"-ot"|"-ef";
	operand ::= <any legal UNIX file name>
*/

#define EOI	0
#define FILRD	1
#define FILWR	2
#define FILREG	3
#define FILID	4
#define FILGZ	5
#define FILTT	6
#define STZER	7
#define STNZE	8
#define STEQL	9
#define STNEQ	10
#define INTEQ	11
#define INTNE	12
#define INTGE	13
#define INTGT	14
#define INTLE	15
#define INTLT	16
#define UNOT	17
#define BAND	18
#define BOR	19
#define LPAREN	20
#define RPAREN	21
#define OPERAND	22
#define FILEX	23
#define FILCDEV	24
#define FILBDEV	25
#define FILFIFO	26
#define FILSETU	27
#define FILSETG	28
#define FILSTCK	29
#define FILSYM	30
#define FILNT	31
#define FILOT	32
#define FILEQ	33
#define FILSOCK	34
#define	FILUID	35
#define	FILGID	36
#define	OPTION	37

#define UNOP	1
#define BINOP	2
#define BUNOP	3
#define BBINOP	4
#define PAREN	5

struct t_op {
	char *op_text;
	short op_num, op_type;
} const ops [] = {
	{"-r",	FILRD,	UNOP},
	{"-w",	FILWR,	UNOP},
	{"-x",	FILEX,	UNOP},
	{"-f",	FILREG,	UNOP},
	{"-d",	FILID,	UNOP},
	{"-c",	FILCDEV,UNOP},
	{"-b",	FILBDEV,UNOP},
	{"-p",	FILFIFO,UNOP},
	{"-u",	FILSETU,UNOP},
	{"-g",	FILSETG,UNOP},
	{"-k",	FILSTCK,UNOP},
	{"-s",	FILGZ,	UNOP},
	{"-t",	FILTT,	UNOP},
	{"-z",	STZER,	UNOP},
	{"-n",	STNZE,	UNOP},
#if 0				/* conficts with binary -o */
	{"-o",	OPTION,	UNOP},
#endif
	{"-U",	FILUID,	UNOP},
	{"-G",	FILGID,	UNOP},
	{"-L",	FILSYM,	UNOP},
	{"-S",	FILSOCK,UNOP},
	{"=",	STEQL,	BINOP},
	{"!=",	STNEQ,	BINOP},
	{"-eq",	INTEQ,	BINOP},
	{"-ne",	INTNE,	BINOP},
	{"-ge",	INTGE,	BINOP},
	{"-gt",	INTGT,	BINOP},
	{"-le",	INTLE,	BINOP},
	{"-lt",	INTLT,	BINOP},
	{"-nt",	FILNT,	BINOP},
	{"-ot",	FILOT,	BINOP},
	{"-ef",	FILEQ,	BINOP},
	{"!",	UNOT,	BUNOP},
	{"-a",	BAND,	BBINOP},
	{"-o",	BOR,	BBINOP},
	{"(",	LPAREN,	PAREN},
	{")",	RPAREN,	PAREN},
	{0,	0,	0}
};

char **t_wp;
struct t_op const *t_wp_op;

static void syntax();

int
c_test(wp)
	char **wp;
{
	int	res;

	t_wp = wp+1;
	if (strcmp(wp[0], "[") == 0) {
		while (*wp != NULL)
			wp++;
		if (strcmp(*--wp, "]") != 0)
			errorf("[: missing ]\n");
		*wp = NULL;
	}
	res = *t_wp == NULL || !oexpr(t_lex(*t_wp));

	if (*t_wp != NULL && *++t_wp != NULL)
		syntax(*t_wp, "unknown operand");

	return res;
}

static void
syntax(op, msg)
	char	*op;
	char	*msg;
{
	if (op && *op)
		errorf("test: %s: %s\n", op, msg);
	else
		errorf("test: %s\n", msg);
}

oexpr(n)
{
	int res;

	res = aexpr(n);
	if (t_lex(*++t_wp) == BOR)
		return oexpr(t_lex(*++t_wp)) || res;
	t_wp--;
	return res;
}

aexpr(n)
{
	int res;

	res = nexpr(n);
	if (t_lex(*++t_wp) == BAND)
		return aexpr(t_lex(*++t_wp)) && res;
	t_wp--;
	return res;
}

nexpr(n)
	int n;			/* token */
{
	if (n == UNOT)
		return !nexpr(t_lex(*++t_wp));
	return primary(n);
}

primary(n)
	int n;			/* token */
{
	register char *opnd1, *opnd2;
	int res;

	if (n == EOI)
		syntax(NULL, "argument expected");
	if (n == LPAREN) {
		res = oexpr(t_lex(*++t_wp));
		if (t_lex(*++t_wp) != RPAREN)
			syntax(NULL, "closing paren expected");
		return res;
	}
	if (t_wp_op && t_wp_op->op_type == UNOP) {
		/* unary expression */
		if (*++t_wp == NULL && n != FILTT)
			syntax(t_wp_op->op_text, "argument expected");
		switch (n) {
		  case OPTION:
			return flag[option(*t_wp)];
		  case STZER:
			return strlen(*t_wp) == 0;
		  case STNZE:
			return strlen(*t_wp) != 0;
		  case FILTT:
			if (!digit(**t_wp))
				return filstat("0", n);
		  default:	/* all other FIL* */
			return filstat(*t_wp, n);
		}
	}
	opnd1 = *t_wp;
	(void) t_lex(*++t_wp);
	if (t_wp_op && t_wp_op->op_type == BINOP) {
		struct t_op const *op = t_wp_op;

		if ((opnd2 = *++t_wp) == (char *)0)
			syntax(op->op_text, "argument expected");
		
		switch (op->op_num) {
		case STEQL:
			return strcmp(opnd1, opnd2) == 0;
		case STNEQ:
			return strcmp(opnd1, opnd2) != 0;
		case INTEQ:
			return evaluate(opnd1) == evaluate(opnd2);
		case INTNE:
			return evaluate(opnd1) != evaluate(opnd2);
		case INTGE:
			return evaluate(opnd1) >= evaluate(opnd2);
		case INTGT:
			return evaluate(opnd1) > evaluate(opnd2);
		case INTLE:
			return evaluate(opnd1) <= evaluate(opnd2);
		case INTLT:
			return evaluate(opnd1) < evaluate(opnd2);
		case FILNT:
			return newerf (opnd1, opnd2);
		case FILOT:
			return olderf (opnd1, opnd2);
		case FILEQ:
			return equalf (opnd1, opnd2);
		}
	}
	t_wp--;
	return strlen(opnd1) > 0;
}

filstat(nm, mode)
	char *nm;
{
	struct stat s;
	
	switch (mode) {
	case FILRD:
		return eaccess(nm, 4) == 0;
	case FILWR:
		return eaccess(nm, 2) == 0;
	case FILEX:
		return eaccess(nm, 1) == 0;
	case FILREG:
		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG;
	case FILID:
		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFDIR;
	case FILCDEV:
		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFCHR;
	case FILBDEV:
		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFBLK;
	case FILFIFO:
#ifdef S_IFIFO
		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFIFO;
#else
		return 0;
#endif
	case FILSETU:
		return stat(nm, &s) == 0 && (s.st_mode & S_ISUID) == S_ISUID;
	case FILSETG:
		return stat(nm, &s) == 0 && (s.st_mode & S_ISGID) == S_ISGID;
	case FILSTCK:
		return stat(nm, &s) == 0 && (s.st_mode & S_ISVTX) == S_ISVTX;
	case FILGZ:
		return stat(nm, &s) == 0 && s.st_size > 0L;
	case FILTT:
		return isatty(getn(nm));
	  case FILUID:
		return stat(nm, &s) == 0 && s.st_uid == geteuid();
	  case FILGID:
		return stat(nm, &s) == 0 && s.st_gid == getegid();
#ifdef S_IFLNK
	case FILSYM:
		return lstat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFLNK;
#endif
#ifdef S_IFSOCK
	case FILSOCK:
		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK;
#endif
	  default:
		return 1;
	}
}

int
t_lex(s)
	register char *s;
{
	register struct t_op const *op = ops;

	if (s == 0) {
		t_wp_op = (struct t_op *)0;
		return EOI;
	}
	while (op->op_text) {
		if (strcmp(s, op->op_text) == 0) {
			t_wp_op = op;
			return op->op_num;
		}
		op++;
	}
	t_wp_op = (struct t_op *)0;
	return OPERAND;
}

newerf (f1, f2)
char *f1, *f2;
{
	struct stat b1, b2;

	return (stat (f1, &b1) == 0 &&
		stat (f2, &b2) == 0 &&
		b1.st_mtime > b2.st_mtime);
}

olderf (f1, f2)
char *f1, *f2;
{
	struct stat b1, b2;

	return (stat (f1, &b1) == 0 &&
		stat (f2, &b2) == 0 &&
		b1.st_mtime < b2.st_mtime);
}

equalf (f1, f2)
char *f1, *f2;
{
	struct stat b1, b2;

	return (stat (f1, &b1) == 0 &&
		stat (f2, &b2) == 0 &&
		b1.st_dev == b2.st_dev &&
		b1.st_ino == b2.st_ino);
}

./pdksh/sh/edit.c   644    653   1762       22023  5243743652  11135 0ustar  hlu/*
 * Command line editing - common code
 *
 */

#include "config.h"
#if defined(EMACS) || defined(VI)

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <setjmp.h>
#ifndef NOSTDHDRS
# include <string.h>
#endif
#include "sh.h"
#include "tty.h"
#define EXTERN
#include "edit.h"
#undef EXTERN

#ifdef _CRAY2
extern unsigned	sleep();
#endif


static int	x_noecho = 0;

/*
 * read an edited command line
 */
int
x_read(fd, buf, len)
	int fd;			/* not used */
	char *buf;
	size_t len;
{
  static int setup_done = 0;
	int	i;

  if (setup_done != 42)
  {
    setup_done = 42;		/* these get done once only */
    x_do_init = 1;
    x_col = 0;
    ed_erase = -1, ed_kill = -1, ed_werase = -1, ed_intr = -1, ed_quit = -1;
    x_adj_ok = 1;
    x_adj_done = 0;
  }
	if (x_do_init)
		x_init();

	if (x_noecho)
		return(read(ttyfd, buf, len));

	(void)x_mode(TRUE);
#ifdef EMACS
	if (flag[FEMACS])
		i = x_emacs(buf, len);
	else
#endif
#ifdef VI
	if (flag[FVI])
		i = x_vi(buf, len);
	else
#endif
		i = -1;		/* internal error */
	(void) x_mode(FALSE);
	if (i > 4 && strstr(buf, "stty"))
		x_do_init = 1;
	if (i < 0 && errno == EINTR)
		trapsig(SIGINT);
	return i;
}

/* tty I/O */

int
x_getc()
{
  char c;

  /*
   * This allows the arival of a SIGCHLD to not disturb us until 
   * we are ready. 
   * BSD and other systems that automatically rety a read after 
   * an interrupt don't need this but it doesn't do any harm 
   * either. 
   */
 retry:
	if (read(ttyfd, &c, 1) != 1)
	{
	  if (sigchld_caught)		/* just a SIGCHLD ? */
	  {
	    goto retry;
	  }
	  return -1;
	}
	return c & 0x7F;
}

void
x_flush()
{
	fflush(stdout);
}


/* NAME:
 *      x_adjust - redraw the line adjusting starting point etc.
 *
 * DESCRIPTION:
 *      This function is called when we have exceeded the bounds 
 *      of the edit window.  It increments x_adj_done so that 
 *      functions like x_ins and x_delete know that we have been 
 *      called and can skip the x_bs() stuff which has already 
 *      been done by x_redraw.
 *
 * RETURN VALUE:
 *      None
 */

void
x_adjust()
{
  x_adj_done++;			/* flag the fact that we were called. */
#ifdef EMACS
  /*
   * we had a promblem if the prompt length > x_cols / 2
   */
  if ((xbp = xcp - (x_displen / 2)) < xbuf)
    xbp = xbuf;
  xlp_valid = FALSE;
  x_redraw(x_cols);
#endif
  x_flush();
}

void
x_putc(c)
	int c;
{
  if (c == '\r' || c == '\n')
    x_col = 0;
  if (x_col < x_cols)
  {
    putc(c, stdout);
    switch(c)
    {
    case BEL:
      break;
    case '\r':
    case '\n':
    break;
    case '\b':
      x_col--;
      break;
    default:
      x_col++;
      break;
    }
  }
  if (x_adj_ok && (x_col < 0 || x_col >= (x_cols - 2)))
  {
    x_adjust();
  }
}

#ifdef DEBUG
int
x_debug_info()
{
  x_flush();
  printf("\nksh debug:\n");
  printf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
	 x_col, x_cols, x_displen);
  printf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
  printf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
  printf("\txlp == 0x%lx\n", (long) xlp);
  printf("\txlp == 0x%lx\n", (long) x_lastcp());
  printf("\n");
  x_redraw(-1);
  return 0;
}
#endif

void
x_puts(s)
	register char *s;
{
  register int	adj = x_adj_done;

  while (*s && adj == x_adj_done)
    x_putc(*s++);
}

#ifdef _BSD
static	struct sgttyb cb, cborig;
#ifdef TIOCGATC
static struct ttychars lchars, lcharsorig;
#else
static struct tchars tchars, tcharsorig;
#ifdef TIOCGLTC
static struct ltchars ltchars, ltcharsorig;
#endif
#endif
#else
#ifdef _POSIX_TERM
static	struct termios cb, cborig;
#else
static	struct termio cb, cborig;
#endif
#endif

/* initialize editing mode */
void
x_init()
{
	x_do_init = 0;
#ifdef _BSD
	(void)ioctl(ttyfd, TIOCGETP, &cborig);
	if ((cborig.sg_flags & ECHO) == 0)
		x_noecho = 1;
	cb = cborig;
	ed_erase = cb.sg_erase;
	ed_kill = cb.sg_kill;
	cb.sg_flags &= ~ECHO;
	cb.sg_flags |= CBREAK;
#ifdef TIOCGATC
	(void)ioctl(ttyfd, TIOCGATC, &lcharsorig);
	lchars = lcharsorig;
	ed_werase = lchars.tc_werasc;
	lchars.tc_suspc = -1;
	lchars.tc_dsuspc = -1;
	lchars.tc_lnextc = -1;
	lchars.tc_statc = -1;
	lchars.tc_intrc = -1;
	lchars.tc_quitc = -1;
	lchars.tc_rprntc = -1;
#else
	(void)ioctl(ttyfd, TIOCGETC, &tcharsorig);
#ifdef TIOCGLTC
	(void)ioctl(ttyfd, TIOCGLTC, &ltcharsorig);
#endif
	tchars = tcharsorig;
#ifdef TIOCGLTC
	ltchars = ltcharsorig;
	ed_werase = ltchars.t_werasc;
	ltchars = ltcharsorig;
	ltchars.t_suspc = -1;
	ltchars.t_dsuspc = -1;
	ltchars.t_lnextc = -1;
#endif
	tchars.t_intrc = -1;
	tchars.t_quitc = -1;
#ifdef TIOCGLTC
	ltchars.t_rprntc = -1;
#endif
#endif
#else /* !_BSD */
#ifdef _POSIX_TERM
	(void) tcgetattr(ttyfd, &cborig);
#else
	(void)ioctl(ttyfd, TCGETA, &cborig);
#endif
	if ((cborig.c_lflag & ECHO) == 0)
		x_noecho = 1;
	cb = cborig;
	ed_erase = cb.c_cc[VERASE]; /* TODO */
	ed_kill = cb.c_cc[VKILL]; /* TODO */
	ed_intr = cb.c_cc[VINTR];
	ed_quit = cb.c_cc[VQUIT];
#ifdef _CRAY2		/* brain-damaged terminal handler */
	cb.c_lflag &= ~(ICANON|ECHO);
	/* rely on print routine to map '\n' to CR,LF */
#else
	cb.c_iflag &= ~(INLCR|ICRNL);
#ifdef _BSD_SYSV	/* need to force CBREAK instead of RAW (need CRMOD on output) */
	cb.c_lflag &= ~(ICANON|ECHO);
#else
#ifdef SWTCH	/* need CBREAK to handle swtch char */
	cb.c_lflag &= ~(ICANON|ECHO);
	cb.c_lflag |= ISIG;
	cb.c_cc[VINTR] = 0377;
	cb.c_cc[VQUIT] = 0377;
#else
	cb.c_lflag &= ~(ISIG|ICANON|ECHO);
#endif
#endif
	cb.c_cc[VTIME] = 0;
	cb.c_cc[VMIN] = 1;
#endif	/* _CRAY2 */
#endif
#ifdef EMACS
	x_emacs_keys(ed_erase, ed_kill, ed_werase, ed_intr, ed_quit);
#endif
}

static	bool_t	x_cur_mode = FALSE;

/* set/clear tty cbreak mode */

#ifdef _BSD
bool_t
x_mode(onoff)
	bool_t	onoff;
{
	bool_t	prev;

	if (x_cur_mode == onoff) return x_cur_mode;
	prev = x_cur_mode;
	x_cur_mode = onoff;
	if (onoff)  {
		(void)ioctl(ttyfd, TIOCSETN, &cb);
#ifdef TIOCGATC
		(void)ioctl(ttyfd, TIOCSATC, &lchars);
#else
		(void)ioctl(ttyfd, TIOCSETC, &tchars);
#ifdef TIOCGLTC
		(void)ioctl(ttyfd, TIOCSLTC, &ltchars);
#endif
#endif
	}
	else {
		(void)ioctl(ttyfd, TIOCSETN, &cborig);
#ifdef TIOCGATC
		(void)ioctl(ttyfd, TIOCSATC, &lcharsorig);
#else
		(void)ioctl(ttyfd, TIOCSETC, &tcharsorig);
#ifdef TIOCGLTC
		(void)ioctl(ttyfd, TIOCSLTC, &ltcharsorig);
#endif
#endif
	}
	return prev;
}

#else	/* !_BSD */

bool_t
x_mode(onoff)
bool_t	onoff;
{
	bool_t	prev;

	if (x_cur_mode == onoff) return x_cur_mode;
	prev = x_cur_mode;
	x_cur_mode = onoff;

	if (onoff)  {
#ifdef _POSIX_TERM
		(void) tcsetattr(ttyfd, TCSADRAIN, &cb);
#else
#ifndef TCSETAW				/* e.g. Cray-2 */
		/* first wait for output to drain */
#ifdef TCSBRK
		(void)ioctl(ttyfd, TCSBRK, 1);
#else	/* the following kludge is minimally intrusive, but sometimes fails */
		(void)sleep((unsigned)1);	/* fake it */
#endif
#endif
#if defined(_BSD_SYSV) || !defined(TCSETAW)
/* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
		(void)ioctl(ttyfd, TCSETA, &cb);
#else
		(void)ioctl(ttyfd, TCSETAW, &cb);
#endif
#endif
	}
	else {
#ifdef _POSIX_TERM
		(void) tcsetattr(ttyfd, TCSADRAIN, &cborig);
#else
#ifndef TCSETAW				/* e.g. Cray-2 */
		/* first wait for output to drain */
#ifdef TCSBRK
		(void)ioctl(ttyfd, TCSBRK, 1);
#else
/* doesn't seem to be necessary when leaving xmode */
/*		(void)sleep((unsigned)1);	/* fake it */
#endif
#endif
#if defined(_BSD_SYSV) || !defined(TCSETAW)
/* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
		(void)ioctl(ttyfd, TCSETA, &cborig);
#else
		(void)ioctl(ttyfd, TCSETAW, &cborig);
#endif
#endif
	}
	return prev;
}
#endif	/* _BSD */


/* NAME:
 *      promptlen - calculate the length of PS1 etc.
 *
 * DESCRIPTION:
 *      This function is based on a fix from [email protected]
 *      It fixes a bug in that if PS1 contains '!', the length 
 *      given by strlen() is probably wrong.
 *
 * RETURN VALUE:
 *      length
 */
 
int
promptlen(cp)
  register char  *cp;
{
  register int count = 0;

  while (*cp)
  {
    if ( *cp++ != '!' )
      count++;
    else
      if ( *cp == '!' )
      {
	cp++;
	count++;
      }
      else
      {
	register int i = source->line;

	do
	{
	  count ++;
	}
	while( ( i /= 10 ) > 0 );
      }
  }
  return count;
}


/*
 * this function check the environment
 * for FCEDIT,EDITOR or VISUAL
 * as a hint to what edit mode is desired.
 */
init_editmode()
{
  static char *ev[] = { "FCEDIT", "EDITOR", "VISUAL", NULL };
  register int i;
  register char *rcp;

  for (i = 0; ev[i]; i++)
  {
#ifdef DEBUG
    (void) fprintf(stderr, "check %s\n", ev[i]);
#endif
    if ((rcp = strval(global(ev[i]))) && *rcp)
      break;
  }
  if (ev[i] && rcp)
  {
    set_editmode(rcp);
  }
  return 0;
}

void
set_editmode(ed)
  char *ed;
{
  register char *rcp;
  
#ifdef DEBUG
  (void) fprintf(stderr, "set_editmode(%s)\n", ed);
#endif
  if (rcp = strrchr(ed, '/'))
    ed = ++rcp;
#ifdef EMACS
  if (strstr(ed, "emacs"))
  {
    flag[FVI] = 0;
    flag[FEMACS] = 1;
  }
#endif
#if defined(EMACS) && defined(VI)
  else
#endif
#ifdef VI
    if (strstr(ed, "vi"))
    {
      flag[FVI] = 1;
      flag[FEMACS] = 0;
    }
#endif
}
#endif
./pdksh/sh/history.c   644    653   1762       43137  5243743676  11730 0ustar  hlu/*
 * command history
 *
 * only implements in-memory history.
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif
/*
 *	This file contains
 *	a)	the original in-memory history  mechanism
 *	b)	a simple file saving history mechanism done by  sjg@zen
 *		define EASY_HISTORY to get this
 *	c)	a more complicated mechanism done by  [email protected]
 *		that more closely follows the real ksh way of doing
 *		things. You need to have the mmap system call for this
 *		to work on your system
 */

#include "config.h"
#include "stdh.h"

#ifdef EASY_HISTORY

#include <errno.h>
#include <setjmp.h>
#include "sh.h"

static FILE *hist_fh = NULL;
static FILE *hist_open ARGS((char *mode));
#ifndef HISTFILE
# define HISTFILE ".pdksh_hist"
#endif

#else
/*	Defines and includes for the complicated case */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <errno.h>
#include <setjmp.h>
#include "sh.h"

/*
 *	variables for handling the data file
 */
static char	*hname;
static int	histfd;
static int	hsize;
static int	hstarted;

static int hist_count_lines ARGS((unsigned char *, int));
static int hist_shrink ARGS((unsigned char *, int));
static unsigned char *hist_skip_back ARGS((unsigned char *,int *,int));
static void histload ARGS((Source *, unsigned char *, int));
static void histinsert ARGS((Source *, int, unsigned char *));
static void writehistfile ARGS((int, char *));
static int sprinkle ARGS((int));

#ifdef MAP_FILE
#define	MAP_FLAGS	MAP_FILE|MAP_PRIVATE
#else
#define	MAP_FLAGS	MAP_PRIVATE
#endif

#endif	/* of EASY_HISTORY */

  
char   *histrpl();
char  **current;
int	curpos;

c_fc(wp)
	register char **wp;
{
	register char *id;
	FILE *f;
	struct temp *tf;
	register char **hp;
	char **hbeg, **hend;
	char *p, *cmd = NULL;
	int lflag = 0, nflag = 0, sflag = 0, rflag = 0, gflag = 0;
	int done = 0;
	void histbackup();

	for (wp++; (id = *wp) != NULL && *id++ == '-' && !done; wp++)
		while (*id && !done) {
			switch (*id++) {
			  case 'l':
				lflag++;
				break;
			  case 'n':
				nflag++;
				break;
			  case 'r':
				rflag++;
				break;
			  case 'g':
				gflag++;
				break;
			  case 'e':
				if (++wp && (p = *wp)) {
					if (p[0] == '-' && !p[1]) {
						sflag++;
					} else {
						cmd = alloc((size_t)(strlen(p)+4),ATEMP);
						strcpy(cmd, p);
						strcat(cmd, " $_");
					}
				} else
					errorf("argument expected\n");
				id = "";
				break;
			  default:
				wp--;
				done++;
				break;
			}
		}

	if (sflag) {
		char *pat = NULL, *rep = NULL;

		hp = histptr - 1;
		while ((id = *wp++) != NULL) {
			/* todo: multiple substitutions */
			if ((p = strchr(id, '=')) != NULL) {
				pat = id;
				rep = p;
				*rep++ = '\0';
			} else
				hp = histget(id);
		}

		if (hp == NULL || hp < history)
			errorf("cannot find history\n");
		if (pat == NULL)
			strcpy(line, *hp);
		else
			histrpl(*hp, pat, rep, gflag);
		histbackup();
#ifdef EASY_HISTORY
		histsave(line); 
#else
		histsave(source->line+1, line, 1);
#endif
		histpush--; 
		line[0] = '\0';
		return 0;
	}

	if (*wp != NULL) {
		hbeg = histget(*wp++); /* first */
		if (*wp != NULL)
			hend = histget(*wp++); /* last */
		else if (lflag)
			hend = histptr;
		else
			hend = hbeg;
	} else {
		if (lflag)
			hbeg = histptr - 16, hend = histptr;
		else
			hbeg = hend = histptr - 1;
		if (hbeg < history)
			hbeg = history;
	}
	if (hbeg == NULL || hend == NULL)
		errorf("can't find history\n");

	if (lflag)
		f = stdout;
	else {
		nflag++;
		tf = maketemp(ATEMP);
		tf->next = e.temps; e.temps = tf;
		f = fopen(tf->name, "w");
		if (f == NULL)
			errorf("cannot create temp file %s", tf->name);
		setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
	}

	for (hp = (rflag ? hend : hbeg); rflag ? (hp >= hbeg) : (hp <= hend);
	      rflag ? hp-- : hp++) {
		if (!nflag)
			fprintf(f, "%3d: ", source->line - (int)(histptr-hp));
		fprintf(f, "%s\n", *hp);
	}

	if (lflag)
		return 0;
	else
		fclose(f);

	setstr(local("_"), tf->name);
	if (cmd) {
		command(cmd); /* edit temp file */
		afree(cmd, ATEMP);
	} else
		command("${FCEDIT:-/bin/ed} $_");

	f = fopen(tf->name, "r");
	if (f == NULL)
		errorf("cannot open temp file %s\n", tf->name);
	setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
	/* we push the editted lines onto the history list */
	while (fgets(line, sizeof(line), f) != NULL) {
#ifdef EASY_HISTORY
		histsave(line); 
#else
		histsave(source->line, line, 1); 
#endif
		histpush--; 
	}
	line[0] = '\0';
	fclose(f);

	return 0;
}

/******************************/
/* Back up over last histsave */
/******************************/
void
histbackup()
{
	static int last_line = -1;

	if (histptr > history && last_line != source->line) { 
		source->line--;
		afree((void*)*histptr, APERM);
		histptr--;
		last_line = source->line;
	}
}

/*
 * get pointer to history given pattern
 * pattern is a number or string
 */
char **
histget(str)
	char *str;
{
	register char **hp = NULL;

	if (*str == '-')
		hp = histptr + getn(str);
	else
	if (digit(*str))
		hp = histptr + (getn(str) - source->line);
	else 
	if (*str == '?') {	/* unanchored match */
		for (hp = histptr-1; hp >= history; hp--)
			if (strstr(*hp, str+1) != NULL)
				break;
	} else {		/* anchored match */
		for (hp = histptr; hp >= history; hp--)
			if (strncmp(*hp, str, strlen(str)) == 0)
				break;
	}

	return (history <= hp && hp <= histptr) ? hp : NULL;
}

char *
histrpl(s, pat, rep, global)
	char *s;
	char *pat, *rep;
	int global;
{
	char *s1, *p, *last = NULL;
	int len = strlen(pat);

	if (strlen(s) - strlen(pat) + strlen(rep) >= LINE)
		errorf("substitution too long\n");
	line[0] = '\0';
	p = line;
	while (s1 = strstr(s, pat)) {
		strncpy(p, s, s1 - s);		/* first part */
		strcpy(p + (s1 - s), rep);	/* replacement */
		s = s1 + len;
		last = s1;
		p = strchr(p, 0);
		if (!global)
			s = "";
	}
	if (last)
		strcpy(p, last + len);		/* last part */
	else
		errorf("substitution failed\n");
	return line;
}

/*
 * Return the current position.
 */
char **
histpos()
{
	return current;
}

int
histN()
{
	return curpos;
}

int
histnum(n)
{
	int	last = histptr - history;

	if (n < 0 || n >= last) {
		current = histptr;
		curpos = last;
		return last;
	}  else {
		current = &history[n];
		curpos = n;
		return n;
	}
}

/*
 * This will become unecessary if histget is modified to allow
 * searching from positions other than the end, and in either 
 * direction.
 */
char *
findhist(start, fwd, str)
	int	start;
	int	fwd;
	char 	*str;
{
	int	 pos = start;
	char	 *line, *last;

	/* XXX check that we are valid after this */
	if (fwd)
		pos++;
	else
		pos--;
	histnum(pos);
	line = *histpos();
	do {
		last = line;
		if (strstr(line, str) != 0) {
			/* keep position current */
			return (line);
		}
		if (fwd)
			pos++;
		else
			pos--;
		histnum(pos);
		line = *histpos();
	} while (line && *line && line != last && pos>0);

	histnum(start);
	if (pos <= 0)
		return (char*)-1; /* TODO */
	return NULL;
}

#ifdef EASY_HISTORY
/*
 * save command in history
 */
void
histsave(cmd)
	char *cmd;
{
	register char **hp = histptr;
	char *cp;

	if (++hp >= history + HISTORY) { /* remove oldest command */
		afree((void*)*history, APERM);
		for (hp = history; hp < history + HISTORY - 1; hp++)
			hp[0] = hp[1];
	}
	*hp = strsave(cmd, APERM);
	if ((cp = strchr(*hp, '\n')) != NULL)
		*cp = '\0';
	histptr = hp;
}

/*
 * 92-04-25 <sjg@zen>
 * A simple history file implementation.
 * At present we only save the history when we exit.
 * This can cause problems when there are multiple shells are 
 * running under the same user-id.  The last shell to exit gets 
 * to save its history.
 */
void
hist_init(s)
  Source *s;
{
  static int once = 0;
  FILE *fh;
  
  if (once++)
    return;

  if (fh = hist_open("r"))
  {
    while (fgets(line, sizeof(line), fh) != NULL)
    {
      histsave(line); 
      s->line++;
    }
    line[0] = '\0';
    fclose(fh);
#if 0	/* this might be a good idea? */
    hist_fh = hist_open("a");
#endif
  }
  
}

void
init_histvec()
{	;	}

/*
 * save our history.
 * We check that we do not have more than we are allowed.
 * If the history file is read-only we do nothing.
 * Handy for having all shells start with a useful history set.
 */

void
hist_finish()
{
  static int once = 0;
  FILE *fh;
  register int i, mx;
  register char **hp, *mode = "w";
  
  if (once++)
    return;
  if ((mx = atoi(strval(global("HISTSIZE")))) > HISTORY || mx <= 0)
    mx = HISTORY;
  /* check how many we have */
  i = histptr - history;
  if (i >= mx)
  {
    hp = &histptr[-mx];
  }
  else
  {
    hp = history;
  }
  if (fh = hist_open(mode))
  {
    for (i = 0; i < mx && hp[i]; i++)
      fprintf(fh, "%s\n", hp[i]);
    fclose(fh);
  }
}


/*
 * simply grab the nominated history file.
 */
static FILE *
hist_open(mode)
  char *mode;
{
  register char *rcp;
  FILE *fh;
  char name[128];
  
  if ((rcp = strval(global("HISTFILE"))) == NULL || *rcp == '\0')
  {
    (void) sprintf(name, "%s/%s", strval(global("HOME")), HISTFILE);
    rcp = name;
  }
  return fopen(rcp, mode);
}

#else /* EASY_HISTORY */

/*
 *	Routines added by Peter Collinson BSDI(Europe)/Hillside Systems to
 *	a) permit HISTSIZE to control number of lines of history stored
 *	b) maintain a physical history file
 *
 *	It turns out that there is a lot of ghastly hackery here
 */


/*
 * save command in history
 */
void
histsave(lno, cmd, dowrite)
	int lno;
	char *cmd;
	int dowrite;
{
	register char **hp;
	char *cp;

	cmd = strsave(cmd, APERM);
	if ((cp = strchr(cmd, '\n')) != NULL)
		*cp = '\0';

	if (histfd && dowrite)
		writehistfile(lno, cmd);

	hp = histptr;
		
	if (++hp >= history + histsize) { /* remove oldest command */
		afree((void*)*history, APERM);
		for (hp = history; hp < history + histsize - 1; hp++)
			hp[0] = hp[1];
	}
	*hp = cmd;
	histptr = hp;
}

/*
 *	set history
 *	this means reallocating the dataspace
 */
void
sethistsize(n)
	int n;
{
	int	offset;
	
	if (n != histsize) {
		offset = histptr - history;
		history = (char **)aresize(history, n*sizeof(char *), APERM);

		if (n < histsize && offset > histsize)
			offset = histsize;

		histsize = n;
		histptr = history + offset;
	}
}

/*
 *	set history file
 *	This can mean reloading/resetting/starting history file
 *	maintenance
 */
void
sethistfile(name)
	char *name;
{
	/* if not started then nothing to do */
	if (hstarted == 0)
		return;

	/* if the name is the same as the name we have */
	if (hname && strcmp(hname, name) == 0)
		return;

	/*
	 * its a new name - possibly
	 */
	if (histfd) {
		/* yes the file is open */
		(void) close(histfd);
		histfd = 0;
		hsize = 0;
		afree(hname, APERM);
		hname = NULL;
		/* let's reset the history */
		histptr = history - 1;
		source->line = 0;
	}

	hist_init(source);
}

/*
 *	initialise the history vector
 */
void
init_histvec()
{
	if (history == (char **)NULL) {
		history = (char **)alloc(histsize*sizeof (char *), APERM);
		histptr = history-1;
	}
}
	
/*
 *	Write history data to a file nominated by HISTFILE
 *	if HISTFILE is unset then history still happens, but
 *	the data is not written to a file
 *	All copies of ksh looking at the file will maintain the
 *	same history. This is ksh behaviour.
 *
 *	This stuff uses mmap()
 *	if your system ain't got it - then you'll have to undef HISTORYFILE
 */
	
/*
 *	Open a history file
 *	Format is:
 *	Bytes 1, 2: HMAGIC - just to check that we are dealing with
 *		    the correct object
 *	Then follows a number of stored commands
 *	Each command is
 *	<command byte><command number(4 bytes)><bytes><null>
 */
#define HMAGIC1		0xab
#define HMAGIC2		0xcd
#define COMMAND		0xff

void
hist_init(s)
	Source *s;
{
	unsigned char	*base;
	int	lines;
	int	bytes;
	
	hstarted = 1;
	
	if (flag[FTALKING] == 0)
		return;

	hname = strval(global("HISTFILE"));
	if (hname == NULL)
		return;
	hname = strsave(hname, APERM);

  retry:
	/* we have a file and are interactive */
	if ((histfd = open(hname, O_RDWR|O_CREAT|O_APPEND, 0600)) < 0)
		return;

	histfd = fcntl(histfd, F_DUPFD, FDBASE);
	
	(void) fcntl(histfd, F_SETFD, 1); /* close on exec */
	
	(void) flock(histfd, LOCK_EX);

	hsize = lseek(histfd, 0L, L_XTND);

	if (hsize == 0) {
		/* add magic */
		if (sprinkle(histfd)) {
			hist_finish();
			return;
		}
	}
	else if (hsize > 0) {
		/*
		 * we have some data
		 */
		base = (unsigned char *)mmap(0, hsize, PROT_READ, MAP_FLAGS, histfd, 0);
		/*
		 * check on its validity
		 */
		if ((int)base == -1 || *base != HMAGIC1 || base[1] != HMAGIC2) {
			if ((int)base !=  -1)
				munmap((caddr_t)base, hsize);
			hist_finish();
			unlink(hname);
			goto retry;
		}
		if (hsize > 2) {
			lines = hist_count_lines(base+2, hsize-2);
			if (lines > histsize) {
				/* we need to make the file smaller */
				if (hist_shrink(base, hsize))
					unlink(hname);
				munmap((caddr_t)base, hsize);
				hist_finish();
				goto retry;
			}
		}
		histload(s, base+2, hsize-2);
		munmap((caddr_t)base, hsize);
	}
	(void) flock(histfd, LOCK_UN);
	hsize = lseek(histfd, 0L, L_XTND);
}

typedef enum state {
	shdr,		/* expecting a header */
	sline,		/* looking for a null byte to end the line */
	sn1,		/* bytes 1 to 4 of a line no */
	sn2, sn3, sn4,
} State;

static int
hist_count_lines(base, bytes)
	register unsigned char *base;
	register int bytes;
{
	State state = shdr;
	register lines = 0;
	
	while (bytes--) {
		switch (state)
		{
		case shdr:
			if (*base == COMMAND)
				state = sn1;
			break;
		case sn1:
			state = sn2; break;
		case sn2:
			state = sn3; break;
		case sn3:
			state = sn4; break;
		case sn4:
			state = sline; break;
		case sline:
			if (*base == '\0')
				lines++, state = shdr;
		}
		base++;
	}
	return lines;
}

/*
 *	Shrink the history file to histsize lines
 */
static int
hist_shrink(oldbase, oldbytes)
	unsigned char *oldbase;
	int oldbytes;
{
	int fd;
	char	nfile[1024];
	struct	stat statb;
	unsigned char *nbase = oldbase;
	int nbytes = oldbytes;

	nbase = hist_skip_back(nbase, &nbytes, histsize);
	if (nbase == NULL)
		return 1;
	if (nbase == oldbase)
		return 0;
	
	/*
	 *	create temp file
	 */
	(void) sprintf(nfile, "%s.%d", hname, getpid());
	if ((fd = creat(nfile, 0600)) < 0)
		return 1;

	if (sprinkle(fd)) {
		close(fd);
		unlink(nfile);
		return 1;
	}
	if (write(fd, nbase, nbytes) != nbytes) {
		close(fd);
		unlink(nfile);
		return 1;
	}
	/*
	 *	worry about who owns this file
	 */
	if (fstat(histfd, &statb) >= 0)
		fchown(fd, statb.st_uid, statb.st_gid);
	close(fd);
	
	/*
	 *	rename
	 */
	if (rename(nfile, hname) < 0)
		return 1;
	return 0;
}
	

/*
 *	find a pointer to the data `no' back from the end of the file
 *	return the pointer and the number of bytes left
 */
static unsigned char *
hist_skip_back(base, bytes, no)
	unsigned char *base;
	int *bytes;
	int no;
{
	register int lines = 0;
	register unsigned char *ep;

	

	for (ep = base + *bytes; ep > base; ep--)
	{
		while (*ep != COMMAND) {
			if (--ep == base)
				break;
		}
		if (++lines == no) {
			*bytes = *bytes - ((char *)ep - (char *)base);
			return ep;
		}
	}
	if (ep > base)
		return base;
	return NULL;
}

/*
 *	load the history structure from the stored data
 */
static void
histload(s, base, bytes)
	Source *s;
	register unsigned char *base;
	register int bytes;
{
	State state;
	int	lno;
	unsigned char	*line;
	
	for (state = shdr; bytes-- > 0; base++) {
		switch (state) {
		case shdr:
			if (*base == COMMAND)
				state = sn1;
			break;
		case sn1:
			lno = (((*base)&0xff)<<24);
			state = sn2;
			break;
		case sn2:
			lno |= (((*base)&0xff)<<16);
			state = sn3;
			break;
		case sn3:
			lno |= (((*base)&0xff)<<8);
			state = sn4;
			break;
		case sn4:
			lno |= (*base)&0xff;
			line = base+1;
			state = sline;
			break;
		case sline:
			if (*base == '\0') {
				/* worry about line numbers */
				if (histptr >= history && lno-1 != s->line) {
					/* a replacement ? */
					histinsert(s, lno, line);
				}
				else {
					s->line = lno;
					histsave(lno, (char *)line, 0);
				}
				state = shdr;
			}
		}
	}
}
				
/*
 *	Insert a line into the history at a specified number
 */
static void
histinsert(s, lno, line)
	Source *s;
	int lno;
	unsigned char *line;
{
	register char **hp;
	
	if (lno >= s->line-(histptr-history) && lno <= s->line) {
		hp = &histptr[lno-s->line];
		if (*hp)
			afree((void*)*hp, APERM);
		*hp = strsave((char *)line, APERM);
	}
}

/*
 *	write a command to the end of the history file
 *	This *MAY* seem easy but it's also necessary to check
 *	that the history file has not changed in size.
 *	If it has - then some other shell has written to it
 *	and we should read those commands to update our history
 */
static void
writehistfile(lno, cmd)
	int lno;
	char *cmd;
{
	int	sizenow;
	unsigned char	*base;
	unsigned char	*new;
	int	bytes;
	char	hdr[5];
	
	(void) flock(histfd, LOCK_EX);
	sizenow = lseek(histfd, 0L, L_XTND);
	if (sizenow != hsize) {
		/*
		 *	Things have changed
		 */
		if (sizenow > hsize) {
			/* someone has added some lines */
			bytes = sizenow - hsize;
			base = (unsigned char *)mmap(0, sizenow, PROT_READ, MAP_FLAGS, histfd, 0);
			if ((int)base == -1)
				goto bad;
			new = base + hsize;
			if (*new != COMMAND) {
				munmap((caddr_t)base, sizenow);
				goto bad;
			}
			source->line--;
			histload(source, new, bytes);
			source->line++;
			lno = source->line;
			munmap((caddr_t)base, sizenow);
			hsize = sizenow;
		} else {
			/* it has shrunk */
			/* but to what? */
			/* we'll give up for now */
			goto bad;
		}
	}
	/*
	 *	we can write our bit now
	 */
	hdr[0] = COMMAND;
	hdr[1] = (lno>>24)&0xff;
	hdr[2] = (lno>>16)&0xff;
	hdr[3] = (lno>>8)&0xff;
	hdr[4] = lno&0xff;
	(void) write(histfd, hdr, 5);
	(void) write(histfd, cmd, strlen(cmd)+1);
	hsize = lseek(histfd, 0L, L_XTND);
	(void) flock(histfd, LOCK_UN);
	return;
bad:
	hist_finish();
}

void
hist_finish()
{
	(void) flock(histfd, LOCK_UN);
	(void) close(histfd);
	histfd = 0;
}

/*
 *	add magic to the history file
 */
static int
sprinkle(fd)
	int fd;
{
	static char mag[] = { HMAGIC1, HMAGIC2 };

	return(write(fd, mag, 2) != 2);
}

#endif
./pdksh/sh/main.c   644    653   1762       23020  5302634017  11120 0ustar  hlu/*
 * startup, main loop, enviroments and error handling
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#define	EXTERN				/* define EXTERNs in sh.h */

#include "stdh.h"
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <time.h>
#include "sh.h"

#if !defined(HAVE_REMOVE) && !defined(remove)
#define remove(x)	unlink(x)
#endif

/*
 * global data
 */

Area	aperm;

static	void	reclaim ARGS((void));

/*
 * shell initialization
 */

static	char	initifs [] = "IFS= \t\n"; /* must be R/W */

static	const	char   initsubs [] = 
#ifdef sun				/* sun's don't have a real /bin */
  "${SHELL:=/bin/sh} ${PATH:=/usr/bin:/usr/ucb:.} ${HOME:=/} ${PS1:=$ } ${PS2:=> } ${PS3:=#? } ${MAILCHECK:=600}";
#else
  "${SHELL:=/bin/sh} ${PATH:=/bin:/usr/bin:.} ${HOME:=/} ${PS1:=$ } ${PS2:=> } ${PS3:=#? } ${MAILCHECK:=600}";
#endif

static	const	char *initcoms [] = {
	"cd", ".", NULL,		/* set up $PWD */
	"typeset", "-x", "SHELL", "PATH", "HOME", NULL,
	"typeset", "-r", "PWD", "OLDPWD", NULL,
	"typeset", "-i", "SECONDS=0", "OPTIND=1", NULL,
	"alias",
	  "integer=typeset -i", "pwd=print -r \"$PWD\"",
	  "history=fc -l", "r=fc -e -", "nohup=nohup ",
	  "login=exec login", "newgrp=exec newgrp",
	  "type=whence -v", "functions=typeset -f",
	  "echo=print", "true=:", "false=let", "[=\\[",
#ifdef JOBS
	  "suspend=kill -STOP $$",
#endif
	  NULL,

	
	NULL
};

#ifdef USE_TRACE
/*
 * use SIGUSR1 to bump up Trace_level
 * use SIGUSR2 to clear Trace_level
 */
void
set_TraceLev(sig)
  int sig;
{
  switch(sig)
  {
  case SIGUSR1:
    Trace_level++;
    break;
  case SIGUSR2:
    Trace_level = 0;
    break;
  }
#if defined(_SYSV) && !defined(USE_SIGACT)
  if (sig > 0)
    (void) signal(sig, set_TraceLev);
#endif
  return;
}
#endif

main(argc, argv, envp)
	int argc;
	register char **argv;
	char **envp;
{
	register int i;
	register char *arg;
	int cflag = 0, qflag = 0, fflag = 0;
	int argi;
	char *name;
	register Source *s;
	register struct block *l = &globals;
	register char **wp0, **wp;
	extern char ksh_version [];
	extern time_t time();

#ifdef USE_SIGACT
	sigemptyset(&Sigact.sa_mask);
	sigemptyset(&Sigact_dfl.sa_mask);
	sigemptyset(&Sigact_ign.sa_mask);
	sigemptyset(&Sigact_trap.sa_mask);
	Sigact.sa_flags = 0;
	Sigact_dfl.sa_flags = 0;
	Sigact_ign.sa_flags = 0;
	Sigact_trap.sa_flags = 0;
	Sigact_dfl.sa_handler = SIG_DFL;
	Sigact_ign.sa_handler = SIG_IGN;
	Sigact_trap.sa_handler = trapsig;
#endif
	ainit(&aperm);		/* initialize permanent Area */

#ifndef F_SETFD
  init_clexec();
#endif
	/* set up base enviroment */
	e.type = E_NONE;
	ainit(&e.area);
	e.loc = l;
	e.savefd = NULL;
	e.oenv = NULL;

	initctypes();

	/* open file streams for fd's 0,1,2 */
	fopenshf(0);	fopenshf(1);	fopenshf(2);

	/* set up variable and command dictionaries */
	newblock();		/* set up global l->vars and l->funs */
	tinit(&commands, APERM);
	tinit(&builtins, APERM);
	tinit(&lexicals, APERM);
	tinit(&homedirs, APERM);

	init_histvec();
	
	/* import enviroment */
	if (envp != NULL)
		for (wp = envp; *wp != NULL; wp++)
			import(*wp);

	kshpid = getpid();
	typeset(initifs, 0, 0);	/* for security */
	typeset(ksh_version, 0, 0); /* RDONLY */

#ifdef USE_TRACE
#ifdef USE_SIGACT
	Sigact.sa_handler = set_TraceLev;
	sigaction(SIGUSR1, &Sigact, NULL);
	sigaction(SIGUSR2, &Sigact, NULL);
#else
	(void) signal(SIGUSR1, set_TraceLev);
	(void) signal(SIGUSR2, set_TraceLev);
#endif
	_TRACE(0, ("Traces enabled.")); /* allow _TRACE to setup */
#endif

	/* define shell keywords */
	keywords();

	/* define built-in commands */
	for (i = 0; shbuiltins[i].name != NULL; i++)
		builtin(shbuiltins[i].name, shbuiltins[i].func);
	for (i = 0; kshbuiltins[i].name != NULL; i++)
		builtin(kshbuiltins[i].name, kshbuiltins[i].func);

	/* assign default shell variable values */
	substitute(initsubs, 0);
	setint(typeset("PPID", INTEGER, 0), (long) getppid());
	typeset("PPID", RDONLY, 0);
	setint(typeset("RANDOM", INTEGER, 0), (long) time((time_t *)0));
	/* execute initialization statements */
	for (wp0 = (char**) initcoms; *wp0 != NULL; wp0 = wp+1) {
		/* copy because the alias initializers are readonly */
		for (wp = wp0; *wp != NULL; wp++)
			*wp = strsave(*wp, ATEMP);
		shcomexec(wp0);
	}
	afreeall(ATEMP);

	if (geteuid() == 0)
		setstr(global("PS1"), "# ");

	s = pushs(SFILE);
	s->u.file = stdin;
	cflag = 0;
	name = *argv;

	/* what a bloody mess */
	if ((argi = 1) < argc) {
		if (argv[argi][0] == '-' && argv[argi][1] != '\0') {
			for (arg = argv[argi++]+1; *arg; arg++) {
				switch (*arg) {
				  case 'c':
					cflag = 1;
					if (argi < argc) {
						s->type = SSTRING;
						s->str = argv[argi++];
					}
					break;
	
				  case 'q':
					qflag = 1;
					break;

				  default:
					if (*arg>='a' && *arg<='z')
						flag[FLAG(*arg)]++;
				}
			}
		}
		if (s->type == SFILE && argi < argc && !flag[FSTDIN]) {
			s->file = name = argv[argi++];
			if ((s->u.file = fopen(name, "r")) == NULL)
				errorf("%s: cannot open\n", name);
			fflag = 1;
#ifdef linux
			setfileno (s->u.file, savefd(fileno(s->u.file)));
#else
			fileno(s->u.file) = savefd(fileno(s->u.file));
#endif
			setvbuf(s->u.file, (char *)NULL, _IOFBF, BUFSIZ);
		}
	}

	if (s->type == SFILE) {
		if (fileno(s->u.file) == 0)
			flag[FSTDIN] = 1;
		if (isatty(0) && isatty(1) && !cflag && !fflag)
			flag[FTALKING] = 1;
		if (flag[FTALKING] && flag[FSTDIN])
			s->type = STTY;
	}
	if (s->type == STTY) {
		ttyfd = fcntl(0, F_DUPFD, FDBASE);
#ifdef F_SETFD
		(void) fcntl(ttyfd, F_SETFD, 1);
#else
		(void) fd_clexec(ttyfd);
#endif
#ifdef EMACS
	  	x_init_emacs();
#endif
	}

	/* initialize job control */
	j_init();

	if (!qflag)
		ignoresig(SIGQUIT);

	l->argv = &argv[argi];
	l->argc = argc - argi;
	l->argv[0] = name;
	resetopts();

	if (name[0] == '-') {
		flag[FTALKING] = 1;
		(void) include("/etc/profile");
		(void) include(".profile");
	}

	/* include $ENV */
	arg = substitute(strval(global("ENV")), DOTILDE);
	if (*arg != '\0')
		(void) include(arg);

	if (flag[FTALKING])
	{
#ifdef USE_SIGACT
	  sigaction(SIGTERM, &Sigact_trap, NULL);
#else
	  signal(SIGTERM, trapsig);
#endif
	  ignoresig(SIGINT);
#if defined(EMACS) || defined(VI)
	  init_editmode();
#endif
	} else
	  flag[FHASHALL] = 1;

#ifdef JOBS			/* todo: could go before includes? */
	if (s->type == STTY) {
		flag[FMONITOR] = 1;
		j_change();
	}
#endif
	if (flag[FTALKING])
	{
	  hist_init(s);
	}
	argc = shell(s);
	leave(argc);
	return 0;
}

int
include(name)
	register char *name;
{
	register FILE *f;
	register Source *s;

	if (strcmp(name, "-") != 0) {
		f = fopen(name, "r");
		if (f == NULL)
			return 0;
		/* todo: the savefd doesn't get popped */
#ifdef linux
		setfileno (f, savefd(fileno(f))); /* questionable */
#else
		fileno(f) = savefd(fileno(f)); /* questionable */
#endif
		setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
	} else
		f = stdin;
	s = pushs(SFILE);
	s->u.file = f;
	s->file = name;
	/*return*/ shell(s);
	if (f != stdin)
		fclose(f);
	return 1;
}

int
command(comm)
	register char *comm;
{
	register Source *s;

	s = pushs(SSTRING);
	s->str = comm;
	return shell(s);
}

/*
 * run the commands from the input source, returning status.
 */
int
shell(s)
	Source *s;		/* input source */
{
	struct op *t;
	volatile int attempts = 13;
	volatile int wastty;
	volatile int reading = 0;
	extern void mcheck();

	newenv(E_PARSE);
	e.interactive = 1;
	exstat = 0;
	if (setjmp(e.jbuf)) {
		/*shellf("<unwind>");*/
		if (trap)	/* pending SIGINT */
			shellf("\n");
		if (reading && s->type == STTY && s->line)
			s->line--;
		sigtraps[SIGINT].set = 0;
	}

	while (1) {
		if (trap)
			runtraps();
		if (flag[FTALKING])
		{
#ifdef USE_SIGACT
		  sigaction(SIGINT, &Sigact_trap, NULL);
#else
		  signal(SIGINT, trapsig);
#endif
		}

		if (s->next == NULL)
			s->echo = flag[FVERBOSE];

		j_notify();

		if ((wastty = (s->type == STTY)) || s->type == SHIST) {
			prompt = substitute(strval(global("PS1")), 0);
			mcheck();
		}

		reading = 1;
		t = compile(s);
		reading = 0;
		j_reap();
		if (t != NULL && t->type == TEOF)
			if (wastty && flag[FIGNEOF] && --attempts > 0) {
				shellf("Use `exit'\n");
				s->type = STTY;
				continue;
			}
			else
				break;
		flushshf(2);	/* flush -v output */

		if (!flag[FNOEXEC] || s->type == STTY)
			execute(t, 0);

		reclaim();
	}
	/* Error: */
	quitenv();
	return exstat;
}

void
leave(rv)
	int rv;
{
	if (e.type == E_TCOM && e.oenv != NULL)	/* exec'd command */
		unwind();
	runtrap(&sigtraps[0]);
	if (flag[FTALKING])
	{
	  hist_finish();
	}
	j_exit();
	exit(rv);
	/* NOTREACHED */
}

error()
{
	if (flag[FERREXIT] || !flag[FTALKING])
		leave(1);
	unwind();
}

/* return to closest error handler or shell(), exit if none found */
unwind()
{
	while (1)
		switch (e.type) {
		  case E_NONE:
			leave(1);
			/* NOTREACHED */
		  case E_PARSE:
			longjmp(e.jbuf, 1);
			/* NOTREACHED */
		  case E_ERRH:
			longjmp(e.jbuf, 1);
			/* NOTREACHED */
		  default:
			quitenv();
			break;
		}
}

newenv(type)
{
	register struct env *ep;

	ep = (struct env *) alloc(sizeof(*ep), ATEMP);
	*ep = e;
	ainit(&e.area);
	e.type = type;
	e.oenv = ep;
	e.savefd = NULL;
	e.temps = NULL;
}

quitenv()
{
	register struct env *ep;
	register int fd;

	if ((ep = e.oenv) == NULL)
		exit(exstat);	/* exit child */
	if (e.loc != ep->loc)
		popblock();
	if (e.savefd != NULL)
		for (fd = 0; fd < NUFILE; fd++)
			restfd(fd, e.savefd[fd]);
	reclaim();
	e = *ep;
	afree(ep, ATEMP);
}

/* remove temp files and free ATEMP Area */
static void
reclaim()
{
	register struct temp *tp;

	for (tp = e.temps; tp != NULL; tp = tp->next)
		remove(tp->name);
	e.temps = NULL;
	afreeall(&e.area);
}

void
aerror(ap, msg)
	Area *ap;
	const char *msg;
{
	errorf("alloc internal error: %s\n", msg);
}

./pdksh/sh/tree.c   644    653   1762       22721  5243743617  11155 0ustar  hlu/*
 * command tree climbing
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>

#ifdef __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "sh.h"

#define	FSTRING	(FILE*)NULL

static int      tputc       ARGS((int c, FILE *f));
static void     tputC       ARGS((int c, FILE *f));
static void     tputS       ARGS((char *wp, FILE *f));
static struct ioword **iocopy ARGS((struct ioword **iow, Area *ap));
static void     iofree      ARGS((struct ioword **iow, Area *ap));

/*
 * print a command tree
 */

void
ptree(t, f)
	register struct op *t;
	register FILE *f;
{
	register char **w;
	struct ioword **ioact;
	struct op *t1;

 Chain:
	if (t == NULL)
		return;
	switch (t->type) {
	  case TCOM:
		for (w = t->vars; *w != NULL; )
			fptreef(f, "%S ", *w++);
		for (w = t->args; *w != NULL; )
			fptreef(f, "%S ", *w++);
		break;
	  case TEXEC:
		t = t->left;
		goto Chain;
	  case TPAREN:
		fptreef(f, "(%T)", t->left);
		break;
	  case TPIPE:
		fptreef(f, "%T| ", t->left);
		t = t->right;
		goto Chain;
	  case TLIST:
		fptreef(f, "%T", t->left);
		fptreef(f, "%;");
		t = t->right;
		goto Chain;
	  case TOR:
	  case TAND:
		fptreef(f, "%T", t->left);
		fptreef(f, "%s %T", (t->type==TOR) ? "||" : "&&", t->right);
		break;
	  case TFOR:
		fptreef(f, "for %s ", t->str);
		if (t->vars != NULL) {
			fptreef(f, "in ");
			for (w = t->vars; *w; )
				fptreef(f, "%S ", *w++);
			fptreef(f, "%;");
		}
		fptreef(f, "do %T", t->left);
		fptreef(f, "%;done ");
		break;
	  case TCASE:
		fptreef(f, "case %S in%;", t->str);
		for (t1 = t->left; t1 != NULL; t1 = t1->right) {
			fptreef(f, "(");
			for (w = t1->vars; *w != NULL; w++) {
				fptreef(f, "%S", *w);
				fptreef(f, "%c", (w[1] != NULL) ? '|' : ')');
			}
			fptreef(f, " %T;;%;", t1->left);
		}
		fptreef(f, "esac ");
		break;
	  case TIF:
		fptreef(f, "if %T", t->left);
		fptreef(f, "%;");
		t = t->right;
		if (t->left != NULL) {
			fptreef(f, "then %T", t->left);
			fptreef(f, "%;");
		}
		if (t->right != NULL) {
			fptreef(f, "else %T", t->right);
			fptreef(f, "%;");
		}
		fptreef(f, "fi ");
		break;
	  case TWHILE:
	  case TUNTIL:
		fptreef(f, "%s %T",
			(t->type==TWHILE) ? "while" : "until",
			t->left);
		fptreef(f, "%;do %T", t->right);
		fptreef(f, "%;done ");
		break;
	  case TBRACE:
		fptreef(f, "{%;%T", t->left);
		fptreef(f, "%;} ");
		break;
	  case TASYNC:
		fptreef(f, "%T&", t->left);
		break;
	  case TFUNCT:
		fptreef(f, "function %s %T", t->str, t->left);
		break;
	  case TTIME:
		fptreef(f, "time %T", t->left);
		break;
	  default:
		fptreef(f, "<botch>");
		break;
	}
	if ((ioact = t->ioact) != NULL)
		while (*ioact != NULL)
			pioact(f, *ioact++);
}

pioact(f, iop)
	register FILE *f;
	register struct ioword *iop;
{
	register int flag = iop->flag;
	if (iop->unit > 1)
		fptreef(f, "%c", '0' + iop->unit );

	switch(flag&IOTYPE) {
	case IOREAD:
		fptreef(f, "< ");
		break;
	case IOHERE:
		if (flag&IOSKIP)
			fptreef(f, "<<- ");
		else
			fptreef(f, "<< ");
		if (!(flag&IOEVAL))
			fptreef(f, "'");
		break;
	case IOCAT:
		fptreef(f, ">> ");
		break;
	case IOWRITE:
		if (flag&IOCLOB)
			fptreef(f, ">! ");
		else
			fptreef(f, "> ");
		break;
	case IODUP:			/* Needs help */
		if (iop->unit == 0)
			fptreef(f, "<&");
		else
			fptreef(f, ">&");
		break;
	}

	if ((flag&IOTYPE) == IOHERE) {
		if (flag&IOEVAL)
			fptreef(f, "%s ", iop->name);
		else
			fptreef(f, "%s' ", iop->name);
	} else {
		fptreef(f, "%S ", iop->name);
	}
}


/*
 * variants of fputc, fputs for ptreef and snptreef
 */

static	char   *snpf_s;		/* snptreef string */
static	int	snpf_n;		/* snptreef length */

static int
tputc(c, f)
	int c;
	register FILE *f;
{
	if (f != NULL)
		putc(c, f);
	else
		if (--snpf_n >= 0)
			*snpf_s++ = c;
	return c;
}

static void
tputC(c, f)
	register int c;
	register FILE *f;
{
	if ((c&0x60) == 0) {		/* C0|C1 */
		tputc((c&0x80) ? '$' : '^', f);
		tputc(((c&0x7F)|0x40), f);
	} else if ((c&0x7F) == 0x7F) {	/* DEL */
		tputc((c&0x80) ? '$' : '^', f);
		tputc('?', f);
	} else
		tputc(c, f);
}

static void
tputS(wp, f)
	register char *wp;
	register FILE *f;
{
	register int c, quoted=0;

	while (1)
		switch ((c = *wp++)) {
		  case EOS:
			return;
		  case CHAR:
			tputC(*wp++, f);
			break;
		  case QCHAR:
			if (!quoted)
				tputc('\\', f);
			tputC(*wp++, f);
			break;
		  case OQUOTE:
		  	quoted = 1;
			tputc('"', f);
			break;
		  case CQUOTE:
			quoted = 0;
			tputc('"', f);
			break;
		  case OSUBST:
			tputc('$', f);
			tputc('{', f);
			while ((c = *wp++) != 0)
				tputc(c, f);
			if (*wp != CSUBST)
				tputC(*wp++, f);
			break;
		  case CSUBST:
			tputc('}', f);
			break;
		  case COMSUB:
			tputc('$', f);
			tputc('(', f);
			while (*wp != 0)
				tputC(*wp++, f);
			tputc(')', f);
			break;
		}
}

/*
 * this is the _only_ way to reliably handle
 * variable args with an ANSI compiler
 */
#ifdef __STDC__
/* VARARGS */ int
fptreef(FILE *f, char *fmt, ...)
{
#else
fptreef(va_alist) 
  va_dcl
{
  FILE *f;
  char *fmt;
#endif
  va_list	va;

#ifdef __STDC__
  va_start(va, fmt);
#else
  va_start(va);
  f = va_arg(va, FILE *);
  fmt = va_arg(va, char *);
#endif
  
  vfptreef(f, fmt, va);
  va_end(va);
  return 0;
}

/* VARARGS */ int
#ifdef __STDC__
snptreef(char *s, int n, char *fmt, ...)
{
#else
snptreef(va_alist)
  va_dcl
{
  char *s;
  int n;
  char *fmt;
#endif
  va_list va;

#ifdef __STDC__
  va_start(va, fmt);
#else
  va_start(va);
  s = va_arg(va, char *);
  n = va_arg(va, int);
  fmt = va_arg(va, char *);
#endif

  snpf_s = s;
  snpf_n = n;
  vfptreef(FSTRING, fmt, va);
  tputc('\0', FSTRING);
  va_end(va);
  return 0;
}


vfptreef(f, fmt, va)
	register FILE *f;
	register char *fmt;
	register va_list va;
{
	register int c;

	while ((c = *fmt++))
	    if (c == '%') {
		register long n;
		register char *p;
		int neg;

		switch ((c = *fmt++)) {
		  case 'c':
			tputc(va_arg(va, int), f);
			break;
		  case 's':
			p = va_arg(va, char *);
			while (*p)
				tputc(*p++, f);
			break;
		  case 'S':	/* word */
			p = va_arg(va, char *);
			tputS(p, f);
			break;
		  case 'd': case 'u': /* decimal */
			n = (c == 'd') ? va_arg(va, int) : va_arg(va, unsigned int);
			neg = c=='d' && n<0;
			p = ulton((neg) ? -n : n, 10);
			if (neg)
				*--p = '-';
			while (*p)
				tputc(*p++, f);
			break;
		  case 'T':	/* format tree */
			ptree(va_arg(va, struct op *), f);
			break;
		  case ';':	/* newline or ; */
			p = (f == FSTRING) ? "; " : "\n";
			while (*p)
				tputc(*p++, f);
			break;
		  default:
			tputc(c, f);
			break;
		}
	    } else
		tputc(c, f);
}

/*
 * copy tree (for function definition)
 */

static	struct ioword **iocopy();

struct op *
tcopy(t, ap)
	register struct op *t;
	Area *ap;
{
	register struct op *r;
	register char **tw, **rw;

	if (t == NULL)
		return NULL;

	r = (struct op *) alloc(sizeof(struct op), ap);

	r->type = t->type;

	/* this will copy function and for identifiers quite accidently */
	r->str = (t->str == NULL) ? NULL : wdcopy(t->str, ap);

	if (t->vars == NULL)
		r->vars = NULL;
	else {
		for (tw = t->vars; *tw++ != NULL; )
			;
		rw = r->vars = (char **)
			alloc((int)(tw - t->vars) * sizeof(*tw), ap);
		for (tw = t->vars; *tw != NULL; )
			*rw++ = wdcopy(*tw++, ap);
		*rw = NULL;
	}

	if (t->args == NULL)
		r->args = NULL;
	else {
		for (tw = t->args; *tw++ != NULL; )
			;
		rw = r->args = (char **)
			alloc((int)(tw - t->args) * sizeof(*tw), ap);
		for (tw = t->args; *tw != NULL; )
			*rw++ = wdcopy(*tw++, ap);
		*rw = NULL;
	}

	r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);

	r->left = tcopy(t->left, ap);
	r->right = tcopy(t->right, ap);

	return r;
}

char *
wdcopy(wp, ap)
	char *wp;
	Area *ap;
{
	size_t len = wdscan(wp, EOS) - wp;
	return memcpy(alloc(len, ap), wp, len);
}

/* return the position of prefix c in wp plus 1 */
char *
wdscan(wp, c)
	register char *wp;
	register int c;
{
	register int nest = 0;

	while (1)
		switch (*wp++) {
		  case EOS:
			return wp;
		  case CHAR:
		  case QCHAR:
			wp++;
			break;
		  case OQUOTE:
		  case CQUOTE:
			break;
		  case OSUBST:
			nest++;
			while (*wp++ != 0)
				;
			if (*wp != CSUBST)
				wp++;
			break;
		  case CSUBST:
			if (c == CSUBST && nest == 0)
				return wp;
			nest--;
			break;
		  case COMSUB:
			while (*wp++ != 0)
				;
			break;
		}
}

static	struct ioword **
iocopy(iow, ap)
	register struct ioword **iow;
	Area *ap;
{
	register struct ioword **ior;
	register int i;

	for (ior = iow; *ior++ != NULL; )
		;
	ior = (struct ioword **) alloc((int)(ior - iow) * sizeof(*ior), ap);

	for (i = 0; iow[i] != NULL; i++) {
		register struct ioword *p, *q;

		p = iow[i];
		q = (struct ioword *) alloc(sizeof(*p), ap);
		ior[i] = q;
		*q = *p;
		if (p->name != NULL)
			q->name = wdcopy(p->name, ap);
	}
	ior[i] = NULL;

	return ior;
}

/*
 * free tree (for function definition)
 */

static	void iofree();

void
tfree(t, ap)
	register struct op *t;
	Area *ap;
{
	register char **w;

	if (t == NULL)
		return;

	if (t->str != NULL)
		afree((void*)t->str, ap);

	if (t->vars != NULL) {
		for (w = t->vars; *w != NULL; w++)
			afree((void*)*w, ap);
		afree((void*)t->vars, ap);
	}

	if (t->args != NULL) {
		for (w = t->args; *w != NULL; w++)
			afree((void*)*w, ap);
		afree((void*)t->args, ap);
	}

	if (t->ioact != NULL)
		iofree(t->ioact, ap);

	tfree(t->left, ap);
	tfree(t->right, ap);

	afree((void*)t, ap);
}

static	void
iofree(iow, ap)
	struct ioword **iow;
	Area *ap;
{
	register struct ioword **iop;
	register struct ioword *p;

	for (iop = iow; (p = *iop++) != NULL; ) {
		if (p->name != NULL)
			afree((void*)p->name, ap);
		afree((void*)p, ap);
	}
}

./pdksh/sh/ChangeLog   644    653   1762       23617  5243743674  11634 0ustar  hluThu Aug 13 00:00:42 1992  Simon J. Gerraty  (sjg@zen)

	* setstr(), varsub(): be robust when given dud args.

Wed Aug 12 23:56:29 1992  Simon J. Gerraty  (sjg@zen)

	* Fixed build problem when COMPLEX_HISTORY is not defined.
	* don't make COMPLETE_LIST the default, add 
		bind '^[^['=complete-list
	in .kshrc if desired.


Mon Aug  3 22:41:17 1992  Simon J. Gerraty  (sjg@zen)

	* emacs.c: correctly bind <ESC><erase>.
	* var.c: treat COLUMNS and FCEDIT as special.

Sat Aug  1 17:17:02 1992  Simon J. Gerraty  (sjg@zen)

	* Incorporated massive contribution from Peter Collinson
	includes new features (refer to ../Changes.pc) and support for
	BSDI's BSD/386.

	* emacs.c: new command complete-list provided by
	[email protected] this nicer than the standard ksh
	file completion.  Define COMPLETE_LIST to bind this to <ESC><ESC>
	by default.

Sat May 30 15:44:56 1992  Simon J. Gerraty  (sjg@zen)

	* added flag XXWHL in tree.h, used by execute() when calling
	exchild() to indicate that stdin should not be invalidated.  This
	corrects handling of:  
		 ls | while read f; do ls -l $f; done

	Thanks to Bruce Momjian for tracking down the fault.

Tue May 12 19:23:17 1992  Simon J. Gerraty  (sjg@zen)

	* Fix bug in init_editmode() if EMACS and VI are not both defined.

Sun May  3 17:47:54 1992  Simon J. Gerraty  (sjg@zen)

	* sigact.c:  allow force build if USE_* defined.
	* main.c: call init_editmode() _after_ processing /etc/profile.
	* jobs.c: ensure SA_RESTART is defined.

Sat Apr 25 00:20:51 1992  Simon J. Gerraty  (sjg@zen)

	* Implemented a simple history file.
	The default file is "$HOME/.pdksh_hist" but can be changed by
	setting HISTFILE in any of /etc/profile,.profile or .kshrc.
	The format is trivial - one line per history item.  
	You can creat a set history file, by making it read-only.
	History is only saved during wrap-up and only if the file is
	writeable.  NOTE: if writeable the file is OVERWRITTEN.

Fri Apr 24 22:22:04 1992  Simon J Gerraty  (sjg@zen)

	* sigact.c: New file.
	An implementation of sigaction() and freinds, which simply
	interfaces to BSD's setsigmask() et al, BSD4.1's setsig() or plain
	old signal(2).  It attempts to use the most useful available.
	If it thinks the system really has sigaction() it compiles to
	noting, and its header sigact.h does nothing.
	At present all use of sigaction is bounded by USE_SIGACT, if/when
	this approach appears to work, the alternatives will be withdrawn.

Fri Apr 24 10:42:40 1992  Simon J Gerraty  (sjg@taureau)

	* Added support for sigaction and friends!, turns out sigset() 
	et al just don't handle job control.  Define USE_SIGACT if you
	have sigaction().  Job control now works on this System V machine
	(Bull DPX/2).

	* getsc_(lex.c), x_getc(edit.c):  Added goto's! to allow the
	read() calls to be retried (on systems that don't do it
	automatically) if the read() was interrupted by a SIGCHLD
	(sigchld_caught > 0).  This was the cause of the problem with an
	async child terminating the shell on System V.

Wed Apr 22 14:57:01 1992  Simon J Gerraty  (sjg@taureau)

	* exchild(jobs.c): block SIGCHLD when fork()ing, until safe to
	receive.

	* Added support? for sigset() and friends.  Allow JOBS to work on
	System V machines.  This does NOT work right yet.
	With JOBS defined, an async process terminates the shell when it
	(the child) exits, and ^Z does nothing!  

Tue Apr 21 15:18:08 1992  Simon J. Gerraty  (sjg@sun0)

	* removed const qualifyer from setctypes() 1st arg, as gcc-2.1
	generates incorrect code for this function.  This is a temperary
	hack until gcc is fixed.

	* do not install std/stdc/stdarg.h in std/h, any compiler that
	will use stdarg.h should have one.

Sun Apr 19 20:16:32 1992  Simon J. Gerraty  (sjg@zen)

	* added support of stdargs to tree.c and _fixed_ the use of
	varargs. 

Sat Apr 18 16:35:48 1992  Simon J. Gerraty  (sjg@zen)

	* x_read(edit.c): added logic to check $EDITOR etc.


Fri, 10 Jan 92 13:13:52	  Bullseye Software  (sumax!polari!bullseye)

	* alloc.c:afreeall() references memory it has already deallocated.

Wed, 1 Jan 92 20:03:55	Bert Gijsbers ([email protected])

	* expand(eval.c):  PS1='${PWD##/*/}[!]% ' prints also characters
	with ascii = 128 

	* main(main.c): Testing whether the first letter of argv[0] is a
	'-' does not work when ksh reads .kshrc.

Sun, 29 Dec 91 20:05:02  Bert Gijsbers ([email protected])

	* Support for Minix.

Wed, 11 Dec 91 12:41:31	Kees J. Bot ([email protected])

	* fixes for sun3 with 4.1.1

Wed, 4 Dec 91 15:53:43  Reg Quinton ([email protected])

	* fixes for SGI

Mon Nov 25 12:36:42 1991  Simon J. Gerraty  (sjg at zen)

	* stdh.h:  make sure FD_CLEXEC is defined if we support F_SETFD.
	
	* emacs.c: Attempt to make alloc() of x_tab acceptible to more
	compilers.  Not 100% yet.
	
Sat Nov 23 14:31:44 1991  Simon J. Gerraty  (sjg at zen)

	* Improved fd_clexec handling for systems that don't have
	an F_SETFD fcntl().  The new arrangement will not blow up if an
	attempt is made to fd_clexec a fd above MAXFD (64 by default).
	main.c:main()  and io.c:savefd() now simply call
	exec.c:fd_clexec(). 

Fri Nov 22 11:24:57 1991  Simon J. Gerraty  (sjg at zen)

	* Since many people had problems using the headers and libraries
	in std/*, modified sh/* so that they can be compiled in the
	absence of std/*.  This requires putting in some fixes that I had
	left out from my 3.2 version.  Particularly, catering for systems
	that do not have F_SETFD.

	* exec.c:
	Added fd_clexec array for tracking fd's to close in child after
	fork().  This is avoid wasting fd's on systems that don't have
	F_SETFD.

	* jobs.c:
	Allow Sun's and perhaps other BSD systems to define WAIT_T to be
	union wait and thus use their native status handling for children.

	* The file sh/MACHINES now tracks systems the shell has been
	compiled on.


Sat Nov  9 14:57:30 1991  Simon J. Gerraty  (sjg at zen)

	* Release version 4.1 as a new base line.

Thu Nov  7 23:11:25 1991  Simon J. Gerraty  (sjg at zen)

	* John R MacMillan suppied a fix for a bug in yylex() that was the
	cause of several odd problems such as:
		$ foo=echo
		$ $foo bar
		bar: not found
		$ pwd
		$ /local/src/pdksh
		$ $foo bar
		bar
		$

Sun Sep 15 23:19:27 1991  Simon J. Gerraty  (sjg at zen)

	* emacs.c:
	Added function x_lastcp() which returns a pointer to that char in
	the edit buffer that will be the last displayed on the screen.
	Thus:

          cp = x_lastcp();
	  while (cp > xcp)
            x_bs(*--cp);
	
	Will correctly position the cursor on the screen (regardless of
	TABs etc in the buffer).  The previous method got out of sync if
	there were any TABs to display.

Wed Aug  7 11:26:55 1991  Simon J. Gerraty  (sjg at sun0)

	* jobs.c:
	The Sun SPARCstation 2 was proving extremely unreliable using ksh.
	After puting traces in jobs.c, it turns out the problem was
	multiple SIGCHLD events happening too quickly causing the handler
	to be interupted and thus not recognise the job that it had just
	reaped was one of its own.  Having done the waitpid(), but not
	adjusted the job table entry, j_waitj() would loop forever waiting
	for a job to finnish (that had already done so!)
	Solution was to have the SIGCHLD handler simply record the events
	by inrcrementing sigchld_caught.  The actual reaping is now done
	in a new funtion j_reapchld(), which does what the old signal
	handler did but blocks SIGCHLD while scanning the job table.
	j_waitj() calls j_reapchld() when sigchld_caught is non-zero.
	The SS2 is now much more reliable...

	* trace.c:
	Added my simple _TRACE facility (used to track the j_waitj
	problem).  Simply -DUSE_TRACE for it to have effect.  If USE_TRACE
	is undefined, calls to _TRACE() expand to while(0) which an
	optimizer will usually remove.  sh.h now includes trace.h

Mon Jun 10 10:27:14 1991  Simon J. Gerraty  (sjg at zen)

	* emacs.c:
	A couple of assignments (xbp = xbuf) were not migrated from the
	3.2 version.  Caused an anoying bug when retrieving history
	commands. 

Mon May 27 12:50:20 1991  Simon J. Gerraty  (sjg at sun0)

	* added fixes supplied by Mike Jetzer:
	These relate mainly to vi mode.  See Changes.mlj

	* c_sh.c c_exit():
	Modified behavior to not imediately exit if there are stopped
	jobs.  A subsequent exit will kill any jobs left and terminate the
	shell. 

Fri May 24 15:20:10 1991  Simon J. Gerraty  (sjg at sun0)

	* edit.h:
	Cleaned up prototypes.  Built shell on sun3.
	While gcc-1.39 builds the ksh ok on the 386i, on the sun3 jobs
	don't work correctly - any non-builtin command gets stopped and
	put into the background.  Had same problem with 3.2, using
	/usr/bin/cc works fine.

Thu May 23 13:45:20 1991  Simon J. Gerraty  (sjg at sun0)

	* migrated my 3.2 edit.c changes to the new shell.
	Affects edit.c, emacs.c
	Added edit.h which is now included by edit.c,emacs.c and vi.c
	
	* vi.c:
	Fixed handling of '!' in prompt by using pprompt() as in emacs.c

	* std/stdc/vprintf.c:
	Fixed bug in output of left '0' padded unsigned numbers was
	always padding with ' ' which left a space in ksh's temp file
	names.  This prevented fc -l from working.

Here is my 3.2 ChangeLog:
Fri Mar 22 16:50:14 1991  Simon J. Gerraty  (sjg at sun0)

	* edit.c:
	Added x_set_arg() and x_prev_histword().
	x_set_arg() handles 'ESC''0-9' type args which are used by word
	related commands.
	x_prev_histword() recovers the last (default) or sepcified arg
	word from the previous command line.  Bound to ESC. and ESC_ to be
	compatible with real ksh.

Tue Feb 26 14:16:17 1991 Simon J. Gerraty  (sjg at zen)

	* edit.c:
	Changes to handle editing of command lines longer than $COLUMNS in
	a manner compatible with real ksh.

Mon Feb 25 12:20:36 1991 Simon J. Gerraty  (sjg at sun0)

	* var.c,table.h:
	Implemented $RANDOM
	Some scripts use [ "$RANDOM" != "$RANDOM" ] to check for ksh. 

Wed Feb 20 12:20:36 1991 Simon J. Gerraty  (sjg at sun0)

	Changes so that shell will compile on sun386i.

	* exec.c,main.c,io.c:
	Handle the case where FD_CLEXEC isn't defined.

	* jobs.c:
	SunOS has its own ideas about job status etc.

	* tree.c:
	Fixed conflict between varargs and stdarg.




./pdksh/sh/alloc.c   644    653   1762       11333  5243743566  11310 0ustar  hlu/*
 * area-based allocation built on malloc/free
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <setjmp.h>
#include "sh.h"

#define	ICELLS	100		/* number of Cells in small Block */

typedef union Cell Cell;
typedef struct Block Block;

/*
 * The Cells in a Block are organized as a set of objects.
 * Each object (pointed to by dp) begins with a size in (dp-1)->size,
 * followed with "size" data Cells.  Free objects are
 * linked together via dp->next.
 */

union Cell {
	size_t	size;
	union Cell   *next;
	struct {int _;} junk;	/* alignment */
};

struct Block {
	struct Block  *next;		/* list of Blocks in Area */
	union Cell   *free;		/* object free list */
	union Cell   *last;		/* &b.cell[size] */
	union Cell	cell [1];	/* [size] Cells for allocation */
};

Block aempty = {&aempty, aempty.cell, aempty.cell};

/* create empty Area */
Area *
ainit(ap)
	register Area *ap;
{
	ap->free = &aempty;
	return ap;
}

/* free all object in Area */
void
afreeall(ap)
	register Area *ap;
{
	register Block *bp;
	register Block *tmp;

	bp = ap->free;
	if (bp != NULL && bp != &aempty) {
		do {
			tmp = bp->next;
			free((void*)bp);
			bp = tmp;
		} while (bp != ap->free);
		ap->free = &aempty;
	}
}

/* allocate object from Area */
void *
alloc(size, ap)
	size_t size;
	register Area *ap;
{
	int cells, split;
	register Block *bp;
	register Cell *dp, *fp, *fpp;

	if (size <= 0) {
		aerror(ap, "allocate bad size");
		return NULL;
	}
	cells = (unsigned)(size - 1) / sizeof(Cell) + 1;

	/* find Cell large enough */
	for (bp = ap->free; ; bp = bp->next) {
		for (fpp = NULL, fp = bp->free;
		     fp != bp->last; fpp = fp, fp = fpp->next)
			if ((fp-1)->size >= cells)
				goto Found;

		/* wrapped around Block list, create new Block */
		if (bp->next == ap->free) {
			bp = (Block*) malloc(offsetof(Block, cell[ICELLS + cells]));
			if (bp == NULL) {
				aerror(ap, "cannot allocate");
				return NULL;
			}
			if (ap->free == &aempty)
				bp->next = bp;
			else {
				bp->next = ap->free->next;
				ap->free->next = bp;
			}
			bp->last = bp->cell + ICELLS + cells;
			fp = bp->free = bp->cell + 1; /* initial free list */
			(fp-1)->size = ICELLS + cells - 1;
			fp->next = bp->last;
			fpp = NULL;
			break;
		}
	}
  Found:
	ap->free = bp;
	dp = fp;		/* allocated object */
	split = (dp-1)->size - cells;
	if (split < 0)
		aerror(ap, "allocated object too small");
	if (--split <= 0) {	/* allocate all */
		fp = fp->next;
	} else {		/* allocate head, free tail */
		(fp-1)->size = cells;
		fp += cells + 1;
		(fp-1)->size = split;
		fp->next = dp->next;
	}
	if (fpp == NULL)
		bp->free = fp;
	else
		fpp->next = fp;
	return (void*) dp;
}

/* change size of object -- like realloc */
void *
aresize(ptr, size, ap)
	register void *ptr;
	size_t size;
	Area *ap;
{
	int cells;
	register Cell *dp = (Cell*) ptr;

	if (size <= 0) {
		aerror(ap, "allocate bad size");
		return NULL;
	}
	cells = (unsigned)(size - 1) / sizeof(Cell) + 1;

	if (dp == NULL || (dp-1)->size < cells) { /* enlarge object */
		register Cell *np;
		register int i;
		void *optr = ptr;

		ptr = alloc(size, ap);
		np = (Cell*) ptr;
		if (dp != NULL)
			for (i = (dp-1)->size; i--; )
				*np++ = *dp++;
		afree(optr, ap);
	} else {		/* shrink object */
		int split;

		split = (dp-1)->size - cells;
		if (--split <= 0) /* cannot split */
			;
		else {		/* shrink head, free tail */
			(dp-1)->size = cells;
			dp += cells + 1;
			(dp-1)->size = split;
			afree((void*)dp, ap);
		}
	}
	return (void*) ptr;
}

void
afree(ptr, ap)
	void *ptr;
	register Area *ap;
{
	register Block *bp;
	register Cell *fp, *fpp;
	register Cell *dp = (Cell*)ptr;

	/* find Block containing Cell */
	for (bp = ap->free; ; bp = bp->next) {
		if (bp->cell <= dp && dp < bp->last)
			break;
		if (bp->next == ap->free) {
			aerror(ap, "freeing with invalid area");
			return;
		}
	}

	/* find position in free list */
	for (fpp = NULL, fp = bp->free; fp < dp; fpp = fp, fp = fpp->next)
		;

	if (fp == dp) {
		aerror(ap, "freeing free object");
		return;
	}

	/* join object with next */
	if (dp + (dp-1)->size == fp-1) { /* adjacent */
		(dp-1)->size += (fp-1)->size + 1;
		dp->next = fp->next;
	} else			/* non-adjacent */
		dp->next = fp;

	/* join previous with object */
	if (fpp == NULL)
		bp->free = dp;
	else if (fpp + (fpp-1)->size == dp-1) { /* adjacent */
		(fpp-1)->size += (dp-1)->size + 1;
		fpp->next = dp->next;
	} else			/* non-adjacent */
		fpp->next = dp;
}


#if TEST_ALLOC

Area a;

main(int argc, char **argv) {
	int i;
	char *p [9];

	ainit(&a);
	for (i = 0; i < 9; i++) {
		p[i] = alloc(124, &a);
		printf("alloc: %x\n", p[i]);
	}
	for (i = 1; i < argc; i++)
		afree(p[atoi(argv[i])], &a);
	afreeall(&a);
	return 0;
}

void aerror(Area *ap, const char *msg) {
	abort();
}

#endif

./pdksh/sh/expr.c   644    653   1762       11336  5243743574  11176 0ustar  hlu/*
 * Korn expression evaluation
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include "sh.h"

#define	ef	else if		/* fashion statement */

#define	VAR	0x01
#define	LIT	0x02
#define	LEQ	0x03
#define	LNE	0x04
#define	LLE	0x05
#define	LGE	0x06

static const char *expression;	/* expression being evaluated */
static const char *tokp;	/* lexical position */
static int tok;			/* token from token() */
static struct tbl *val;		/* value from token() */

static struct tbl *asn      ARGS((void));
static struct tbl *e6       ARGS((void));
static struct tbl *e5       ARGS((void));
static struct tbl *e3       ARGS((void));
static struct tbl *e2       ARGS((void));
static struct tbl *e0       ARGS((void));
static void     token       ARGS((void));
static struct tbl *tempvar  ARGS((void));
static struct tbl *intvar   ARGS((struct tbl *vp));

/*
 * parse and evalute expression
 */
void
evalerr(err)
	char *err;
{
	errorf("%s: %s\n", expression, err);
}

long
evaluate(expr)
	const char *expr;
{
	struct tbl *v;

	expression = tokp = expr;
	token();
	v = intvar(asn());
	if (!(tok == 0))
		evalerr("bad expression");
	return v->val.i;
}

static struct tbl *
asn()
{
	register struct tbl *vl, *vr;

	vr = vl = e6();
	if ((tok == '=')) {
		Area * olastarea = lastarea;
		token();
		if ((vl->flag&RDONLY)) /* assign to rvalue */
			evalerr("bad assignment");
		vr = intvar(asn());
		lastarea = olastarea;
		setint(vl, vr->val.i);
		if ((vl->flag&INTEGER) && vl->type == 0) /* default base? */
			vl->type = vr->type;
	}
	return vr;
}

static struct tbl *
e6()
{
	register struct tbl *vl, *vr;

	vl = e5();
	while ((tok == LEQ) || (tok == LNE)) {
		int op = tok;
		token();
		vl = intvar(vl);
		vr = intvar(e5());
		vl->val.i = vl->val.i == vr->val.i;
		if (op == LNE)
			vl->val.i = ! vl->val.i;
	}
	return vl;
}

static struct tbl *
e5()
{
	register struct tbl *vl, *vr;

	vl = e3();
	while ((tok == LLE) || (tok == '<') || (tok == '>') || (tok == LGE)) {
		int op = tok;
		token();
		vl = intvar(vl);
		vr = intvar(e3());
		if (op == LLE)
			vl->val.i = vl->val.i <= vr->val.i;
		ef (op == '<')
			vl->val.i = vl->val.i < vr->val.i;
		ef (op == LGE)
			vl->val.i = vl->val.i >= vr->val.i;
		ef (op == '>')
			vl->val.i = vl->val.i > vr->val.i;
	}
	return vl;
}

static struct tbl *
e3()
{
	register struct tbl *vl, *vr;

	vl = e2();
	while ((tok == '+') || (tok == '-')) {
		int op = tok;
		token();
		vl = intvar(vl);
		vr = intvar(e2());
		if (op == '+')
			vl->val.i += vr->val.i;
		ef (op == '-')
			vl->val.i -= vr->val.i;
	}
	return vl;
}

static struct tbl *
e2()
{
	register struct tbl *vl, *vr;

	vl = e0();
	while ((tok == '*') || (tok == '/') || (tok == '%')) {
		int op = tok;
		token();
		vl = intvar(vl);
		vr = intvar(e0());
		if (op != '*' && vr->val.i == 0)
			evalerr("zero divisor");
		if (op == '*')
			vl->val.i *= vr->val.i;
		ef (op == '/')
			vl->val.i /= vr->val.i;
		ef (op == '%')
			vl->val.i %= vr->val.i;
	}
	return vl;
}

static struct tbl *
e0()
{
	register struct tbl *v;

	if ((tok == '!') || (tok == '-')) {
		int op = tok;
		token();
		v = intvar(e0());
		if (op == '!')
			v->val.i = !v->val.i;
		ef (op == '-')
			v->val.i = -v->val.i;
	} else
	if ((tok == '(')) {
		token();
		v = asn();
		if (!(tok == ')'))
			evalerr("missing )");
		token();
	} else
	if ((tok == VAR) || (tok == LIT)) {
		v = val;
		token();
	} else
		evalerr("bad expression");
	return v;
}

static void
token()
{
	register char *cp = (char *) tokp;
	register int c, c2;

	/* skip white space */
	do c = *cp++;	while (c != '\0' && (c == ' ' || c == '\t'));
	tokp = cp-1;

	if (letter(c)) {
		for (; letnum(c); c = *cp++)
			;
		c = *--cp;
		*cp = 0;
		val = global(tokp);
		*cp = c;
		tok = VAR;
	} else
	if (digit(c)) {
		for (; letnum(c) || c == '#'; c = *cp++)
			;
		c = *--cp;
		*cp = 0;
		val = tempvar();
		setstr(val, tokp);
		val->flag |= RDONLY;
		*cp = c;
		tok = LIT;
	} else {
		c2 = *cp++;
		if (c == '=' && c2 == '=')
			c = LEQ;
		ef (c == '!' && c2 == '=')
			c = LNE;
		ef (c == '<' && c2 == '=')
				c = LLE;
		ef (c == '>' && c2 == '=')
				c = LGE;
		else
			cp--;
		tok = c;
	}
	tokp = cp;
}

static struct tbl *
tempvar()
{
	register struct tbl *vp;

	vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP);
	lastarea = ATEMP;
	vp->flag = ISSET|INTEGER;
	vp->type = 0;
	vp->name[0] = '\0';
	return vp;
}

/* cast (string) variable to temporary integer variable */
static struct tbl *
intvar(vp)
	register struct tbl *vp;
{
	register struct tbl *vq;

	vq = tempvar();
	vq->type = 10;
	if (strint(vq, vp) == NULL) {
		if ((vp->flag&ISSET) && vp->val.s && *(vp->val.s)) {
			evalerr("bad number");
		} else {
			vq->flag |= (ISSET|INTEGER);
			vq->type = 10;
			vq->val.i = 0;
		}
	}
	return vq;
}

./pdksh/sh/mail.c   644    653   1762       10267  5302766411  11133 0ustar  hlu/*
 * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
 * John R. MacMillan
 */
#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "sh.h"

#define MBMESSAGE	"you have mail in $_"

typedef struct mbox {
	struct mbox    *mb_next;	/* next mbox in list */
	char	       *mb_path;	/* path to mail file */
	char	       *mb_msg;		/* to announce arrival of new mail */
	unsigned int	mb_size;	/* size of mail file (bytes) */
} mbox_t;

struct mailmsg {
	char		*msg;		/* Text of message */
	struct mailmsg	*next;		/* Next message */
};

/*
 * $MAILPATH is a linked list of mboxes.  $MAIL is a treated as a
 * special case of $MAILPATH, where the list has only one node.  The
 * same list is used for both since they are exclusive.
 */

static mbox_t  *mplist = NULL;
static mbox_t  mbox = { NULL, NULL, NULL, 0 };
static long	mlastchkd = 0;	/* when mail was last checked */
static struct mailmsg *mmsgs = NULL;	/* Messages to be printed */
#if 0
static void	munset();		/* free mlist and mval */
static mbox_t  *mballoc();		/* allocate a new mbox */
static void	maddmsg();
#endif
static void     munset      ARGS((mbox_t *mlist));
static mbox_t * mballoc     ARGS((char *p, char *m));
static void     maddmsg     ARGS((mbox_t *mbp));

void
mcheck()
{
	register mbox_t	*mbp;
	long		 now;
	struct tbl	*vp, mailcheck;
	struct stat	 stbuf;

	vp = global("MAILCHECK");
	if (!(vp->flag & ISSET) || strint(&mailcheck, vp) == NULL)
		return;

	if (mlastchkd == 0)
		mlastchkd = time((long *)0);

	if ((now=time((long *)0)) - mlastchkd >= mailcheck.val.i) {
		mlastchkd = now;
		
		vp = global("MAILPATH");
		if (vp && (vp->flag & ISSET))
			mbp = mplist;
		else if ((vp = global("MAIL")) && (vp->flag & ISSET))
			mbp = &mbox;
		else
			mbp = NULL;

		while (mbp) {
			if (stat(mbp->mb_path, &stbuf) == 0 &&
			    (stbuf.st_mode & S_IFMT) == S_IFREG) {
				if (mbp->mb_size < stbuf.st_size)
					maddmsg( mbp );
				mbp->mb_size = stbuf.st_size;
			} else {
				/*
				 * Some mail readers remove the mail
				 * file if all mail is read.  If file
				 * does not exist, assume this is the
				 * case and set size to zero.
				 */
				mbp->mb_size = 0;
			}
			mbp = mbp->mb_next;
		}
	}
}

void
mbset(p)
	register char	*p;
{
	struct stat	stbuf;

	if (mbox.mb_msg)
		afree((void *)mbox.mb_msg, APERM);
	mbox.mb_path = p;
	mbox.mb_msg = NULL;
	if (stat(p,&stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFREG)
		mbox.mb_size = stbuf.st_size;
	else
		mbox.mb_size = 0;
}

void
mpset(mptoparse)
	register char	*mptoparse;
{
	register mbox_t	*mbp;
	register char	*mpath, *mmsg, *mval;

	munset( mplist );
	mplist = NULL;
	mval = strsave(mptoparse, APERM);
	while (mval) {
		mpath = mval;
		if ((mval = strchr(mval, ':')) != NULL) {
			*mval ='\0', mval++;
		}
		if ((mmsg = strchr(mpath, '?')) != NULL) {
			*mmsg = '\0', mmsg++;
		}
		mbp = mballoc(mpath, mmsg);
		mbp->mb_next = mplist;
		mplist = mbp;
	}
}

static void
munset(mlist)
register mbox_t	*mlist;
{
	register mbox_t	*mbp;

	while (mlist != NULL) {
		mbp = mlist;
		mlist = mbp->mb_next;
		if (!mlist)
			afree((void *)mbp->mb_path, APERM);
		afree((void *)mbp, APERM);
	}
}

static mbox_t *
mballoc(p, m)
	char	*p;
	char	*m;
{
	struct stat	stbuf;
	register mbox_t	*mbp;

	mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
	mbp->mb_next = NULL;
	mbp->mb_path = p;
	mbp->mb_msg = m;
	if (stat(mbp->mb_path, &stbuf) == 0 &&
	   (stbuf.st_mode & S_IFMT) == S_IFREG) {
		mbp->mb_size = stbuf.st_size;
	} else {
		mbp->mb_size = 0;
	}
	return(mbp);
}

void
mprint()
{
	struct mailmsg *mm;

	while ((mm = mmsgs) != NULL) {
		shellf( "%s\n", mm->msg );
		fflush(shlout);
		afree((void *)mm->msg, APERM);
		mmsgs = mm->next;
		afree((void *)mm, APERM);
	}
}

static void
maddmsg( mbp )
mbox_t	*mbp;
{
	struct mailmsg	*message;
	struct tbl	*vp;

	message = (struct mailmsg *)alloc(sizeof(struct mailmsg), APERM);
	setstr((vp = typeset("_", LOCAL, 0)), mbp->mb_path);

	if (mbp->mb_msg)
		message->msg = strsave(substitute(mbp->mb_msg,0),APERM);
	else
		message->msg = strsave(substitute(MBMESSAGE,0),APERM);

	unset(vp);
	message->next = mmsgs;
	mmsgs = message;
}
./pdksh/sh/misc.c   644    653   1762       15541  5302637123  11141 0ustar  hlu/*
 * Miscellaneous functions
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include "sh.h"
#include "expand.h"
#ifndef NOSTDHDRS
# include <limits.h>
#else
# define UCHAR_MAX	0xFF
#endif

char ctypes [UCHAR_MAX+1];	/* type bits for unsigned char */

static char *   cclass      ARGS((char *p, int sub));

/*
 * Fast character classes
 */
void
setctypes(s, t)
	register /* const */ char *s;
	register int t;
{
	register int i;

	if ((t&C_IFS)) {
		for (i = 0; i < UCHAR_MAX+1; i++)
			ctypes[i] &=~ C_IFS;
		ctypes[0] |= C_IFS; /* include \0 in C_IFS */
	}
	ctypes[(unsigned char) *s++] |= t;	/* allow leading \0 in string */
	while (*s != 0)
		ctypes[(unsigned char) *s++] |= t;
}

void
initctypes()
{
	register int c;

	for (c = 'a'; c <= 'z'; c++)
		ctypes[c] |= C_ALPHA;
	for (c = 'A'; c <= 'Z'; c++)
		ctypes[c] |= C_ALPHA;
	ctypes['_'] |= C_ALPHA;
	setctypes("0123456789", C_DIGIT);
	setctypes("\0 \t\n|&;<>()", C_LEX1);
	setctypes("*@#!$-?", C_VAR1);
	setctypes("=-+?#%", C_SUBOP);
}

/* convert unsigned long to base N string */

char *
ulton(n, base)
	register unsigned long n;
	int base;
{
	register char *p;
	static char buf [20];

	p = &buf[sizeof(buf)];
	*--p = '\0';
	do {
		*--p = "0123456789ABCDEF"[n%base];
		n /= base;
	} while (n != 0);
	return p;
}

char *
strsave(s, ap)
	register char *s;
	Area *ap;
{
  return s ? strcpy((char*) alloc((size_t)strlen(s)+1, ap), s) : NULL;
}

static struct option {
	char *name;
	int flag;
} options[] = {
	{"allexport",	FEXPORT},
	{"bgnice",	FBGNICE},
#if defined(EDIT) && defined(EMACS)
	{"emacs",	FEMACS},
#endif
	{"errexit",	FERREXIT},
	{"hashall",	FHASHALL},
	{"ignoreeof",	FIGNEOF},
	{"interactive",	FTALKING},
	{"keyword",	FKEYWORD},
	{"markdirs",	FMARKDIRS},
	{"monitor",	FMONITOR},
	{"noexec",	FNOEXEC},
	{"noglob",	FNOGLOB},
	{"nounset",	FNOUNSET},
	{"privileged",	FPRIVILEGED},
	{"stdin",	FSTDIN},
	{"trackall",	FHASHALL},
	{"verbose",	FVERBOSE},
#if defined(EDIT) && defined(VI)
	{"vi",		FVI},
#endif
	{"xtrace",	FXTRACE},
	{NULL,		0}
};	

/*
 * translate -o option into F* constant
 */
int
option(n)
	const char *n;
{
	register struct option *op;

	for (op = options; op->name != NULL; op++)
		if (strcmp(op->name, n) == 0)
			return op->flag;
	return 0;
}

char *
getoptions()
{
	register int c;
	char m [26+1];
	register char *cp = m;

	for (c = 'a'; c <= 'z'; c++)
		if (flag[FLAG(c)])
			*cp++ = (char) c;
	*cp = 0;
	return strsave(m, ATEMP);
}

void
printoptions()
{
	register struct option *op;

	for (op = options; op->name != NULL; op++)
		if (flag[op->flag])
			shellf("%s ", op->name);
	shellf("\n");
}
	
/* atoi with error detection */

getn(as)
	char *as;
{
	register char *s;
	register int n;

	s = as;
	if (*s == '-')
		s++;
	for (n = 0; digit(*s); s++)
		n = (n*10) + (*s-'0');
	if (*s)
		errorf("%s: bad number\n", as);
	return (*as == '-') ? -n : n;
}

#ifndef linux
/*
 * stripped down strerror for kill and exec
 */
char *
strerror(i)
	int i;
{
	switch (i) {
	  case EINVAL:
		return "Invalid argument";
	  case EACCES:
		return "Permission denied";
	  case ESRCH:
		return "No such process";
	  case EPERM:
		return "Not owner";
	  case ENOENT:
		return "No such file or directory";
	  case ENOTDIR:
		return "Not a directory";
	  case ENOEXEC:
		return "Exec format error";
	  case ENOMEM:
		return "Not enough memory";
	  case E2BIG:
		return "Argument list too long";
	  default:
		return "Unknown system error";
	}
}

#endif

/* -------- gmatch.c -------- */

/*
 * int gmatch(string, pattern)
 * char *string, *pattern;
 *
 * Match a pattern as in sh(1).
 * pattern character are prefixed with MAGIC by expand.
 */

static	char	*cclass ARGS((char *, int c));

int
gmatch(s, p)
	register char *s, *p;
{
	register int sc, pc;

	if (s == NULL || p == NULL)
		return 0;
	while ((pc = *p++) != 0) {
		sc = *s++;
		if (pc ==  MAGIC)
			switch (*p++) {
			  case '[':
				if (sc == 0 || (p = cclass(p, sc)) == NULL)
					return (0);
				break;

			  case '?':
				if (sc == 0)
					return (0);
				break;

			  case '*':
				s--;
				do {
					if (*p == '\0' || gmatch(s, p))
						return (1);
				} while (*s++ != '\0');
				return (0);

			  default:
				if (sc != p[-1])
					return 0;
				break;
			}
		else
			if (sc != pc)
				return 0;
	}
	return (*s == 0);
}

static char *
cclass(p, sub)
	register char *p;
	register int sub;
{
	register int c, d, not, found = 0;

	if ((not = (*p == MAGIC && *++p == NOT)))
		p++;
	do {
		if (*p == MAGIC)
			p++;
		if (*p == '\0')
			return NULL;
		c = *p;
		if (p[1] == '-' && p[2] != ']') {
			d = p[2];
			p++;
		} else
			d = c;
		if (c == sub || (c <= sub && sub <= d))
			found = 1;
	} while (*++p != ']');

	return (found != not) ? p+1 : NULL;
}

/* -------- qsort.c -------- */

/*
 * quick sort of array of generic pointers to objects.
 */

void
qsortp(base, n, f)
	void **base;		/* base address */
	size_t n;		/* elements */
	int (*f)();		/* compare function */
{
	qsort1(base, base + n, f);
}

#define	swap2(a, b)	{\
	register void *t; t = *(a); *(a) = *(b); *(b) = t;\
}
#define	swap3(a, b, c)	{\
	register void *t; t = *(a); *(a) = *(c); *(c) = *(b); *(b) = t;\
}

qsort1(base, lim, f)
	void **base, **lim;
	int (*f)();
{
	register void **i, **j;
	register void **lptr, **hptr;
	size_t n;
	int c;

  top:
	n = (lim - base) / 2;
	if (n == 0)
		return;
	hptr = lptr = base+n;
	i = base;
	j = lim - 1;

	for (;;) {
		if (i < lptr) {
			if ((c = (*f)(*i, *lptr)) == 0) {
				lptr --;
				swap2(i, lptr);
				continue;
			}
			if (c < 0) {
				i += 1;
				continue;
			}
		}

	  begin:
		if (j > hptr) {
			if ((c = (*f)(*hptr, *j)) == 0) {
				hptr ++;
				swap2(hptr, j);
				goto begin;
			}
			if (c > 0) {
				if (i == lptr) {
					hptr ++;
					swap3(i, hptr, j);
					i = lptr += 1;
					goto begin;
				}
				swap2(i, j);
				j -= 1;
				i += 1;
				continue;
			}
			j -= 1;
			goto begin;
		}

		if (i == lptr) {
			if (lptr-base >= lim-hptr) {
				qsort1(hptr+1, lim, f);
				lim = lptr;
			} else {
				qsort1(base, lptr, f);
				base = hptr+1;
			}
			goto top;
		}

		lptr -= 1;
		swap3(j, lptr, i);
		j = hptr -= 1;
	}
}

int
xstrcmp(p1, p2)
	void *p1, *p2;
{
	return (strcmp((char *)p1, (char *)p2));
}

void
cleanpath(pwd, dir, clean)
	char *pwd, *dir, *clean;
{
	register char  *s, *d, *p;
	char *slash = "/";
	register int inslash = 0;

	d = clean;
	if (*dir != '/') {
		s = pwd;
		while (*d++ = *s++)
			;
		if (d >= clean + 2 && *(d - 2) == '/')
			d--;
		else
			*(d - 1) = '/';
	}

	s = dir;
	while (*s) {
		if ((*d++ = *s++) == '/' && d > clean + 1) {
			if (*(p = d - 2) == '/') {
				--d;
			} else if (*p == '.') {
				if (*--p == '/') {
					d -= 2;
				} else if (*p == '.' && *--p == '/') {
					while (p > clean && *--p != '/')
						;
					d = p + 1;
				}
			}
		}
		if (!*s && !inslash && *(s - 1) != '/') {
			inslash = 1;
			s = slash;
		}
	}

	if (*(d - 1) == '/' && (d - 1) > clean)
		d--;
	*d = '\0';
}
./pdksh/sh/sh.h   644    653   1762       16566  5302634513  10635 0ustar  hlu/*
 * Public Domain Bourne/Korn shell
 */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include "config.h"

/* some useful #defines */
#ifdef EXTERN
# define _I_(i) = i
#else
# define _I_(i)
# define EXTERN extern
# define EXTERN_DEFINED
#endif

#ifndef SHELL
#define	SHELL	"/bin/sh"	/* shell to exec scripts */
#endif

#ifdef _BSD
#define memmove(dst, src, n)	bcopy((src), (dst), (n))
#endif

/* some people object to this use of __STDC__ */
#ifdef __STDC__
#define	ARGS(args)	args	/* prototype declaration */
#else
#define	ARGS(args)	()	/* K&R declaration */
#ifdef VOID
#define	void	VOID
#endif
#define	const	
#define	volatile 
#endif

#ifdef _ULTRIX			/* Ultrix 2.x gets dup2 wrong */
int dup2 ARGS ((int, int));
/* assumes we don't want dup2 return value */
#define	dup2(ofd, nfd) \
		(void) ((dup2)(ofd, nfd), fcntl(nfd, F_SETFD, 0))
#endif

#if defined(EMACS) || defined(VI)
#define	EDIT
#endif

typedef int bool_t;
#define	FALSE	0
#define	TRUE	1

#define	sizeofN(type, n) (sizeof(type) * (n))
#define	BIT(i)	(1<<(i))	/* define bit in flag */

#define	NUFILE	10		/* Number of user-accessible files */
#define	FDBASE	10		/* First file usable by Shell */

/* you're not going to run setuid shell scripts, are you? */
#define	eaccess(path, mode)	access(path, mode)

#define	MAGIC	(char)0x80	/* prefix for ~*?[ during expand */
#define	NOT	'!'	/* might use ^ */

#define	LINE	256		/* input line size */
#define	PATH	256		/* pathname size */

EXTERN	int	kshpid;		/* $$, shell pid */
EXTERN	int	exstat;		/* exit status */
EXTERN	int	async;		/* $!, last &'d pid */
EXTERN	volatile int sigchld_caught;	/* count of dead children */


/*
 * Area-based allocation built on malloc/free
 */

typedef struct Area {
	struct Block *free;	/* free list */
} Area;

extern	Area	aperm;		/* permanent object space */
#define	APERM	&aperm
#define	ATEMP	&e.area

/*
 * parsing & execution environment
 */
EXTERN	struct	env {
	int	type;			/* enviroment type - see below */
	Area	area;			/* temporary allocation area */
	struct	block *loc;		/* local variables and functions */
	short  *savefd;			/* original redirected fd's */
	struct	env *oenv;		/* link to previous enviroment */
	jmp_buf	jbuf;			/* long jump back to env creator */
	int	interactive;		/* fd's 0,1,2 are tty */
	struct temp *temps;		/* temp files */
} e;

#define	E_NONE	0		/* dummy enviroment */
#define	E_PARSE	1		/* parsing command # */
#define	E_EXEC	2		/* executing command tree */
#define	E_LOOP	3		/* executing for/while # */
#define	E_TCOM	5		/* executing simple command */
#define	E_FUNC	6		/* executing function */
#define	E_ERRH	7		/* general error handler # */
/* # indicates env has valid jbuf */

/*
 * flags
 */
#define	FEXPORT	FLAG('a')	/* -a: allexport */
#define	FERREXIT FLAG('e')	/* -e: errexit (quit on error) */
#define	FBGNICE	29		/* bgnice */
#define	FEMACS 30		/* emacs command editing */
#define	FIGNEOF	27		/* ignoreeof (eof does not exit) */
#define	FHASHALL FLAG('h')	/* -h: trackall, hashall */
#define	FTALKING FLAG('i')	/* -i: interactive (talking type wireless) */
#define	FKEYWORD FLAG('k')	/* -k: keyword (name=value anywhere) */
#define	FMARKDIRS 28		/* markdirs */
#define	FMONITOR FLAG('m')	/* -m: monitor */
#define	FNOEXEC	FLAG('n')	/* -n: noexec */
#define	FNOGLOB	FLAG('f')	/* -f: noglob */
#define	FPRIVILEGED FLAG('p')	/* -p: privileged */
#define	FSTDIN	FLAG('s')	/* -s (invocation): parse stdin */
#define	FNOUNSET FLAG('u')	/* -u: nounset (unset vars is error) */
#define	FVERBOSE FLAG('v')	/* -v: verbose (echo input) */
#define	FVI 31			/* vi command editing */
#define	FXTRACE	FLAG('x')	/* -x: (execute) xtrace */

#define	FLAG(c)	(1 + c - 'a')	/* map char to flags index */
#define	FLAGS	32
EXTERN	char flag [FLAGS];
int	option ARGS((const char *name));
char   *getoptions ARGS((void));
void	printoptions ARGS((void));

extern	char	null [];	/* null value for variable */

/*
 * other functions
 */
char * substitute ARGS((char const *, int));
char   *search();
struct tbl *findcom();
char   *strsave ARGS((char *, Area *));
char   *ulton ARGS((unsigned long n, int base));
int	xstrcmp();
void	qsortp ARGS((void **base, size_t n, int (*compare)(void *, void *)));
long	evaluate ARGS((const char *expr));
void	resetopts();
void	histsave();
void	histlist();
int	pr_menu ARGS((char **, int));

void	j_init ARGS((void));
void	j_exit ARGS((void));
void	j_notify ARGS((void));
void	j_kill ARGS((int job, int sig));
#ifdef JOBS
void	j_change ARGS((void));
int	j_resume ARGS((int job, int bg));
#endif

/*
 * error handling
 */
void	leave();	/* abort shell (or fail in subshell) */

/*
 * library functions
 */
typedef	void (*handler_t)();	/* signal handler */

/* temp/here files. the file is removed when the struct is freed */
struct	temp {
	struct	temp * next;
	char   *name;
};
struct temp *maketemp ARGS((Area *ap));

/*
 * stdio and our IO routines
 */

#ifdef	BUFSIZ			/* <stdio.h> included? */
extern	FILE *	shf [NUFILE];	/* map shell fd to FILE */
#endif
void	fopenshf();
void	flushshf();

#undef	stdin
#undef	stdout

#define	stdin	shf[0]		/* standard input */
#define	stdout	shf[1]		/* standard output */
#define	shlout	shf[2]		/* shell output */

int	shellf ARGS((const char *fmt, ...)); /* fprintf(shlout, ); */
int	errorf ARGS((const char *fmt, ...)); /* fprintf(shlout, ); error(); */

/*
 * IO control
 */
extern	int ttyfd;		/* tty fd (original fd 0) */

int	savefd ARGS((int fd));	/* save user fd */
void	restfd ARGS((int fd, int ofd));
void	openpipe ARGS((int [2]));
void	closepipe ARGS((int [2]));

/*
 * trap handlers
 */
typedef struct trap {
	int	signal;		/* signal number */
	char   *name;		/* short name */
	char   *mess;		/* descriptive name */
	char   *trap;		/* trap command */
	int	volatile set;	/* trap pending */
	int	ourtrap;	/* not ignored (?) */
	int	sig_dfl;	/* originally SIG_DFL */
} Trap;

#ifndef	SIGKILL
#include <signal.h>
#endif	/* SIGKILL */
#ifdef	NSIG
#define	SIGNALS	NSIG
#else
#ifdef	_MINIX
#define	SIGNALS	(_NSIG+1)	/* _NSIG is # of signals used, excluding 0. */
#else
#define	SIGNALS	32
#endif	/* _MINIX */
#endif	/* NSIG */

#ifdef USE_SIGACT			/* always use it? */
#ifndef  SA_NOCLDSTOP
# include "sigact.h"			/* use sjg's fake sigaction() */
#endif
EXTERN struct sigaction Sigact, Sigact_dfl, Sigact_ign, Sigact_trap;
#endif

EXTERN	int volatile trap;	/* traps pending? */
extern	Trap	sigtraps[SIGNALS];
Trap    *gettrap ARGS((char *)); /* search for struct trap by number or name */
void	trapsig ARGS((int sig)); /* trap signal handler */

/*
 * fast character classes
 */
#define	C_ALPHA	0x01		/* a-z_A-Z */
#define	C_DIGIT	0x02		/* 0-9 */
#define	C_LEX1	0x04		/* \0 \t\n|&;<>() */
#define	C_VAR1	0x08		/* *@#!$-? */
#define	C_SUBOP	0x40		/* "=-+?#%" */
#define	C_IFS	0x80		/* $IFS */

extern	char ctypes [];
#if 0
void	initctypes ARGS((void));
void	setctypes ARGS((const char*, int type));
#endif
#define	ctype(c, t)	!!(ctypes[(unsigned char)(c)]&(t))
#define	letter(c)	ctype(c, C_ALPHA)
#define	digit(c)	ctype(c, C_DIGIT)
#define	letnum(c)	ctype(c, C_ALPHA|C_DIGIT)

#include "table.h"
#include "tree.h"
#include "lex.h"
#include "proto.h"
  
/*
 * 91-07-06 <sjg@sun0>
 * use my simple debug tracing... 
 */
#include "trace.h"

#ifdef linux
#include <stdio.h>
#else
#ifndef fileno
/* This is quite outrageous. H.J. */
#define fileno(p)	((p)->_file)
#endif
#endif

/* be sure not to interfere with anyone else's idea about EXTERN */
#ifdef EXTERN_DEFINED
# undef EXTERN_DEFINED
# undef EXTERN
#endif
#undef _I_
/*
 * Local Variables:
 * version-control:t
 * comment-column:40
 * End:
 */
./pdksh/sh/table.c   644    653   1762        7360  5243743614  11264 0ustar  hlu#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

/*
 * dynamic hashed associative table for commands and variables
 */

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include "sh.h"

#define	INIT_TBLS	8	/* initial table size (power of 2) */

static struct tstate {
	int left;
	struct tbl **next;
} tstate;

static void     texpand     ARGS((struct table *tp, int nsize));
static int      tnamecmp    ARGS((void *p1, void *p2));


unsigned int
hash(n)
	register char * n;
{
	register unsigned int h = 0;

	while (*n != '\0')
		h = 2*h + *n++;
	return h * 32821;	/* scatter bits */
}

#if 0
phash(s) char *s; {
	printf("%2d: %s\n", hash(s)%32, s);
}
#endif

void
tinit(tp, ap)
	register struct table *tp;
	register Area *ap;
{
	tp->areap = ap;
	tp->size = tp->free = 0;
	tp->tbls = NULL;
}

static void
texpand(tp, nsize)
	register struct table *tp;
	int nsize;
{
	register int i;
	register struct tbl *tblp, **p;
	register struct tbl **ntblp, **otblp = tp->tbls;
	int osize = tp->size;

	ntblp = (struct tbl**) alloc(sizeofN(struct tbl *, nsize), tp->areap);
	for (i = 0; i < nsize; i++)
		ntblp[i] = NULL;
	tp->size = nsize;
	tp->free = 8*nsize/10;	/* table can get 80% full */
	tp->tbls = ntblp;
	if (otblp == NULL)
		return;
	for (i = 0; i < osize; i++)
		if ((tblp = otblp[i]) != NULL)
			if ((tblp->flag&DEFINED)) {
				for (p = &ntblp[hash(tblp->name) &
						(tp->size-1)];
				     *p != NULL; p--)
					if (p == ntblp) /* wrap */
						p += tp->size;
				*p = tblp;
				tp->free--;
			} else {
				afree((void*)tblp, tp->areap);
			}
	afree((void*)otblp, tp->areap);
}

struct tbl *
tsearch(tp, n, h)
	register struct table *tp;	/* table */
	register char *n;		/* name to enter */
	unsigned int h;			/* hash(n) */
{
	register struct tbl **pp, *p;

	if (tp->size == 0)
		return NULL;

	/* search for name in hashed table */
	for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
		if (*p->name == *n && strcmp(p->name, n) == 0
		    && (p->flag&DEFINED))
			return p;
		if (pp == tp->tbls) /* wrap */
			pp += tp->size;
	}

	return NULL;
}

struct tbl *
tenter(tp, n, h)
	register struct table *tp;	/* table */
	register char *n;		/* name to enter */
	unsigned int h;			/* hash(n) */
{
	register struct tbl **pp, *p;
	register char *cp;

	if (tp->size == 0)
		texpand(tp, INIT_TBLS);
  Search:
	/* search for name in hashed table */
	for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
		if (*p->name == *n && strcmp(p->name, n) == 0)
			return p; 	/* found */
		if (pp == tp->tbls) /* wrap */
			pp += tp->size;
	}

	if (tp->free <= 0) {	/* too full */
		texpand(tp, 2*tp->size);
		goto Search;
	}

	/* create new tbl entry */
	for (cp = n; *cp != '\0'; cp++)
		;
	p = (struct tbl *) alloc(offsetof(struct tbl, name[(cp-n)+1]), tp->areap);
	p->flag = 0;
	p->type = 0;
	for (cp = p->name; *n != '\0';)
		*cp++ = *n++;
	*cp = '\0';

	/* enter in tp->tbls */
	tp->free--;
	*pp = p;
	return p;
}

void
tdelete(p)
	register struct tbl *p;
{
	p->flag = 0;
}

void
twalk(tp)
	register struct table *tp;
{
	tstate.left = tp->size;
	tstate.next = tp->tbls;
}

struct tbl *
tnext()
{
	while (--tstate.left >= 0) {
		struct tbl *p = *tstate.next++;
		if (p != NULL && (p->flag&DEFINED))
			return p;
	}
	return NULL;
}

static int
tnamecmp(p1, p2)
	void *p1, *p2;
{
	return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name);
}

struct tbl **
tsort(tp)
	register struct table *tp;
{
	register int i;
	register struct tbl **p, **sp, **dp;

	p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP);
	sp = tp->tbls;		/* source */
	dp = p;			/* dest */
	for (i = 0; i < tp->size; i++)
		if ((*dp = *sp++) != NULL && ((*dp)->flag&DEFINED))
			dp++;
	i = dp - p;
	qsortp((void**)p, (size_t)i, tnamecmp);
	p[i] = NULL;
	return p;
}

./pdksh/sh/Makefile   644    653   1762       12705  5303002252  11467 0ustar  hlu# PD Bourne/Korn Shell
# $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $

SHELL = /bin/sh
MAKE  = make

LN    = ln -s

# You _can_ build this shell without the ../std tree if your
# system provides a sufficiently POSIX environment, or if your
# BSD system is a Sun or close.  If not try ../std.

# gcc is good value on most mc68k's and sun386's if nothing else.
# if you don't have gcc cc should do
# CC=gcc -pipe
CC=gcc -pipe 
CC=/usr/local/bin/gcc

# The following are the defintions used (or thereabouts) 
# to build ksh without ../std
#
# sun386 SunOS 4.0.2, sun3 SunOS 4.0.3
# CONFIG=-D_BSD
# XOPTS=-DNOSTDHDRS
# copy these from ../std/stdc or ensure they are in libstdc.a
# XOBJS = memmove.o strstr.o 
#
# sun3  SunOS 4.1.1
# CONFIG=-D_BSD
# XOPTS=-DNOSTDHDRS
# copy these from ../std/stdc or ensure they are in libstdc.a
# XOBJS = memmove.o
#
# sun4c (sparc) SunOS 4.1.1
# CC=cc -pipe	# don't use gcc
# CONFIG=-D_BSD
# XOPTS=-DNOSTDHDRS
# copy these from ../std/stdc or ensure they are in libstdc.a
# XOBJS = memmove.o
#
# Bull DPX/2 B.O.S. 2.00.45
# CC=gcc -ansi
# CONFIG=-D_POSIX_SOURCE
# XOPTS=
# XOBJS=
#
# Minix-386 1.5.10 with estdio
# CONFIG= -D_BSD -D_MINIX -D_POSIX_SOURCE
# XOPTS=
# XOBJS=
#
# BSD/386
# CONFIG= -D_BSDI -D_POSIX_TERM -D_POSIX_SOURCE
# XOPTS=
# XOBJS=

#CONFIG= -D_SYSV
#CONFIG= -D_BSD -DHAVE_SYS_STDTYPES
CONFIG= -D_BSD -DCOMPLEX_HISTORY


STD=../std
INCL=$(STD)/h
XINCL=-I$(INCL)
LDOPTS=-L$(STD)
XOBJS=

# use -O if you trust it :-)
DBG=-g -O
DBG=-O
CFLAGS = $(DBG) $(CONFIG) $(XINCL) $(XOPTS)

LDFLAGS = $(DBG) $(LDOPTS)

#COMPATLIBS = -lstdc -lposix
#XLIBS = -lc_s
#XLIBS = -ldirent
LDLIBS = $(COMPATLIBS) $(XLIBS)

HDRS =	sh.h table.h expand.h lex.h tree.h tty.h trace.h
SRCS1 =	version.c main.c misc.c trap.c alloc.c io.c \
	syn.c lex.c edit.c emacs.c vi.c history.c tree.c 
SRCS2 =	exec.c jobs.c \
	c_sh.c c_ksh.c c_test.c getopts.c do_ulimit.c \
	var.c table.c eval.c expr.c mail.c sigact.c trace.c
SRCS =	Makefile $(HDRS) $(SRCS1) $(SRCS2) 

OBJS =	version.o main.o misc.o \
	syn.o lex.o edit.o emacs.o vi.o tree.o \
	exec.o jobs.o trap.o \
	c_sh.o c_ksh.o c_test.o \
	do_ulimit.o getopts.o expr.o history.o \
	var.o table.o alloc.o io.o eval.o mail.o sigact.o trace.o $(XOBJS)

ksh: $(OBJS) 
	$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

clean:
	rm -f *.o *.out core

clobber: clean
	rm -f ksh

link:
	($(SHELL) ../std/mklinks ../std/h stdh.h)
	

depend:
	makedepend $(CFLAGS) $(SRCS1) $(SRCS2)

install:
	@echo "Try:"
	@echo "cp ksh /bin"
	@echo "strip /bin/ksh"
	@echo "chmod 555 /bin/ksh"

.c.s:
	$(CC) $(CFLAGS) -S -o $@ $<

asms: $(OBJS:.o=.s)


# DO NOT DELETE THIS LINE -- make depend depends on it.
# If this runs make out of memory, delete /usr/include lines.
alloc.o: alloc.c
alloc.o: config.h
alloc.o: sh.h
alloc.o: stdh.h
alloc.o: trace.h
c_ksh.o: c_ksh.c
c_ksh.o: config.h
c_ksh.o: sh.h
c_ksh.o: stdh.h
c_ksh.o: table.h
c_ksh.o: trace.h
c_sh.o: c_sh.c
c_sh.o: config.h
c_sh.o: lex.h
c_sh.o: sh.h
c_sh.o: stdh.h
c_sh.o: table.h
c_sh.o: trace.h
c_sh.o: tree.h
c_test.o: c_test.c
c_test.o: config.h
c_test.o: sh.h
c_test.o: stdh.h
c_test.o: trace.h
edit.o: config.h
edit.o: edit.c
edit.o: edit.h
edit.o: lex.h
edit.o: sh.h
edit.o: stdh.h
edit.o: trace.h
edit.o: tty.h
emacs.o: config.h
emacs.o: edit.h
emacs.o: emacs.c
emacs.o: expand.h
emacs.o: lex.h
emacs.o: sh.h
emacs.o: stdh.h
emacs.o: table.h
emacs.o: trace.h
emacs.o: tree.h
eval.o: config.h
eval.o: eval.c
eval.o: expand.h
eval.o: lex.h
eval.o: sh.h
eval.o: stdh.h
eval.o: table.h
eval.o: trace.h
eval.o: tree.h
exec.o: config.h
exec.o: exec.c
exec.o: lex.h
exec.o: sh.h
exec.o: stdh.h
exec.o: table.h
exec.o: trace.h
exec.o: tree.h
expr.o: config.h
expr.o: expr.c
expr.o: sh.h
expr.o: stdh.h
expr.o: table.h
expr.o: trace.h
getopts.o: config.h
getopts.o: getopts.c
getopts.o: sh.h
getopts.o: stdh.h
getopts.o: table.h
getopts.o: trace.h
history.o: config.h
history.o: history.c
history.o: lex.h
history.o: sh.h
history.o: stdh.h
history.o: trace.h
io.o: config.h
io.o: io.c
io.o: sh.h
io.o: stdh.h
io.o: trace.h
jobs.o: config.h
jobs.o: jobs.c
jobs.o: sh.h
jobs.o: stdh.h
jobs.o: trace.h
jobs.o: tree.h
lex.o: config.h
lex.o: expand.h
lex.o: lex.c
lex.o: lex.h
lex.o: sh.h
lex.o: stdh.h
lex.o: table.h
lex.o: trace.h
lex.o: tree.h
mail.o: config.h
mail.o: mail.c
mail.o: sh.h
mail.o: stdh.h
mail.o: table.h
mail.o: trace.h
main.o: config.h
main.o: lex.h
main.o: main.c
main.o: sh.h
main.o: stdh.h
main.o: table.h
main.o: trace.h
main.o: tree.h
memmove.o: memmove.c
memmove.o: stdh.h
misc.o: config.h
misc.o: expand.h
misc.o: misc.c
misc.o: sh.h
misc.o: stdh.h
misc.o: trace.h
strstr.o: stdh.h
strstr.o: strstr.c
syn.o: config.h
syn.o: expand.h
syn.o: lex.h
syn.o: sh.h
syn.o: stdh.h
syn.o: syn.c
syn.o: table.h
syn.o: trace.h
syn.o: tree.h
sigact.o: sigact.h sigact.c
table.o: config.h
table.o: sh.h
table.o: stdh.h
table.o: table.c
table.o: table.h
table.o: trace.h
times.o: times.c
trace.o: trace.c
trap.o: config.h
trap.o: sh.h
trap.o: stdh.h
trap.o: trace.h
trap.o: trap.c
tree.o: config.h
tree.o: sh.h
tree.o: stdh.h
tree.o: trace.h
tree.o: tree.c
tree.o: tree.h
do_ulimit.o: config.h
do_ulimit.o: sh.h
do_ulimit.o: stdh.h
do_ulimit.o: trace.h
do_ulimit.o: do_ulimit.c
var.o: config.h
var.o: expand.h
var.o: sh.h
var.o: stdh.h
var.o: table.h
var.o: trace.h
var.o: var.c
version.o: config.h
version.o: sh.h
version.o: stdh.h
version.o: trace.h
version.o: version.c
vi.o: config.h
vi.o: edit.h
vi.o: expand.h
vi.o: lex.h
vi.o: sh.h
vi.o: stdh.h
vi.o: table.h
vi.o: trace.h
vi.o: tree.h
vi.o: vi.c
# WARNING: Put nothing here or make depend will gobble it up!
./pdksh/sh/ReadMe   644    653   1762        3104  5243742756  11107 0ustar  hlu		Public Domain KornShell

	Quick installation notes for PD KornShell

PD KornShell can be installed on 4.2+ BSD systems, System V, and
POSIX-compatable systems.  The makefiles all define _BSD, change
this to _SYSV, or _POSIX.  The makefiles also contain CC=gcc,
delete this if you don't have GNU C.  The ksh makefile also
contains some options, including JOBS (BSD/POSIX job control)
and EDIT (emacs command editing).

PD KornShell assumes you have standard C (ANSI) and POSIX header
files and functions. Since you probably don't, they are provided
in the "std" directory.

The Alpha test version will probably come as two tar files.
std.tar contains standard C and POSIX emulation and must be
extracted into a directory called std.  ksh.tar contains the ksh
source and should be extracted into a directory called src or
ksh.

See std/ReadMe and install it. Only then can you make ksh in the
"src" directory.

To clear up questions about the origin of this shell, this shell
is NOT based on the "Minix shell".  It is based on Charles
Forsyth's public domain V7 shell, which he later contributed to
Minix.

I have permission directly from Charles Forsyth to use his shell.

	Eric Gisin, [email protected] (or Waterloo.EDU)

	Things to do
- add sxt-based job control (see Brown's contribution on the Usenix 87 tape).
- add arrays and variable attributes.
- add MAILPATH and CDPATH.
- add vi editing mode (apparently someone has a PD version).
- add new features described in Korn's book.

	Machines ported to
VAX, 68000, 80386

	OS's ported to
BSD 4.2, BSD 4.3 (with and without YP and NFS
Sys V.3
./pdksh/sh/alloc.h   644    653   1762         172  5243743566  11254 0ustar  hlu/*
 * area-based allocation built on malloc/free
 */

typedef struct Area {
	struct Block *free;	/* free list */
} Area;

./pdksh/sh/edit.h   644    653   1762        4134  5243743674  11131 0ustar  hlu/* NAME:
 *      edit.h - globals for edit modes
 *
 * DESCRIPTION:
 *      This header defines various global edit objects.
 *
 * SEE ALSO:
 *      
 *
 * RCSid:
 *      $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
 *
 */

/* some useful #defines */
#ifdef EXTERN
# define _I_(i) = i
#else
# define _I_(i)
# define EXTERN extern
# define EXTERN_DEFINED
#endif

#define	BEL		0x07

/*
 * The following are used for my horizontal scrolling stuff
 */
EXTERN	char   *xbuf;		/* beg input buffer */
EXTERN	char   *xend;		/* end input buffer */
EXTERN char    *xcp;		/* current position */
EXTERN char    *xep;		/* current end */
EXTERN char    *xbp;		/* start of visible portion of input buffer */
EXTERN char    *xlp;		/* last char visible on screen */
EXTERN int	x_adj_ok;
/*
 * we use x_adj_done so that functions can tell 
 * whether x_adjust() has been called while they are active.
 */
EXTERN int	x_adj_done;

EXTERN int	x_cols _I_(80);	/* default to 80 cols */
EXTERN int	x_col;
EXTERN int	x_displen;
EXTERN int	x_arg;		/* general purpose arg */

EXTERN int	x_do_init;		/* set up tty modes */
EXTERN int	ed_erase, ed_kill, ed_werase, ed_intr, ed_quit;

#ifdef DEBUG
# define _D_(x) x
#else
# define _D_(x)
#endif

/****  edit.c  ****/
int             x_read      ARGS((int fd, char *buf, size_t len));
int             x_getc      ARGS((void));
void            x_flush     ARGS((void));
void            x_adjust    ARGS((void));
void            x_putc      ARGS((int c));
int             x_debug_info ARGS((void));
void            x_puts      ARGS((char *s));
void            x_init      ARGS((void));
bool_t          x_mode      ARGS((bool_t onoff));
bool_t          x_mode      ARGS((bool_t onoff));
int             promptlen   ARGS((char *cp));

/****  emacs.c  ****/
void            x_redraw    ARGS((int limit));
char*		x_lastcp    ARGS((void));
EXTERN int xlp_valid _I_(0);
  
/* This lot goes at the END */
/* be sure not to interfere with anyone else's idea about EXTERN */
#ifdef EXTERN_DEFINED
# undef EXTERN_DEFINED
# undef EXTERN
#endif
#undef _I_
/*
 * Local Variables:
 * version-control:t
 * comment-column:40
 * End:
 */
./pdksh/sh/expand.h   644    653   1762        4250  5243743574  11461 0ustar  hlu/*
 * Expanding strings
 */

#if 0				/* Usage */
	XString xs;
	char *xp;

	Xinit(xs, xp, 128);	/* allocate initial string */
	while ((c = generate()) {
		Xcheck(xs, xp);	/* expand string if neccessary */
		Xput(xs, xp, c); /* add character */
	}
	return Xclose(xs, xp);	/* resize string */
#endif

typedef struct XString {
	char   *end, *beg;	/* end, begin of string */
#if 1
	char   *oth, *old;	/* togo, adjust */
#endif
	size_t	len;		/* length */
} XString;

typedef char * XStringP;

/* initialize expandable string */
#define	Xinit(xs, xp, length) { \
			(xs).len = length; \
			(xs).beg = alloc((xs).len + 8, ATEMP); \
			(xs).end = (xs).beg + (xs).len; \
			xp = (xs).beg; \
		}

/* stuff char into string */
#define	Xput(xs, xp, c)	*xp++ = (c)

/* check for overflow, expand string */
#define	Xcheck(xs, xp) if (xp >= (xs).end) { \
			char *old_beg = (xs).beg; \
			(xs).len += (xs).len; /* double size */ \
			(xs).beg = aresize((xs).beg, (xs).len + 8, ATEMP); \
			(xs).end = (xs).beg + (xs).len; \
			xp = (xs).beg + (xp - old_beg); /* adjust pointer */ \
		}

/* free string */
#define	Xfree(xs, xp)	afree((void*) (xs).beg, ATEMP)

/* close, return string */
#define	Xclose(xs, xp)	(char*) aresize((void*)(xs).beg, \
					(size_t)(xp - (xs).beg), ATEMP)
/* begin of string */
#define	Xstring(xs, xp)	((xs).beg)

#define	Xsavepos(xs, xp) (xp - (xs).beg)
#define	Xrestpos(xs, xp, n) ((xs).beg + (n))

/*
 * expandable vector of generic pointers
 */

typedef struct XPtrV {
	void  **cur;		/* next avail pointer */
	void  **beg, **end;	/* begin, end of vector */
} XPtrV;

#define	XPinit(x, n) { \
			register void **vp; \
			vp = (void**) alloc(sizeofN(void*, n), ATEMP); \
			(x).cur = (x).beg = vp; \
			(x).end = vp + n; \
			}

#define	XPput(x, p) { \
			if ((x).cur >= (x).end) { \
				int n = XPsize(x); \
				(x).beg = (void**) aresize((void*) (x).beg, \
						   sizeofN(void*, n*2), ATEMP); \
				(x).cur = (x).beg + n; \
				(x).end = (x).cur + n; \
			} \
			*(x).cur++ = (p); \
			}

#define	XPptrv(x)	((x).beg)
#define	XPsize(x)	((x).cur - (x).beg)

#define	XPclose(x)	(void**) aresize((void*)(x).beg, \
					 sizeofN(void*, XPsize(x)), ATEMP)

#define	XPfree(x)	afree((void*) (x).beg, ATEMP)

./pdksh/sh/getopts.c   644    653   1762        6760  5243743656  11673 0ustar  hlu/*
 * Reimplementation of SysVr3 sh builtin command "getopts" for S5R2 shell.
 *
 * created by Arnold Robbins
 * modified by Doug Gwyn
 * modified for PD ksh by Eric Gisin
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <setjmp.h>
#include "sh.h"

#ifdef _BSDI
/* internal getopt conflicts with system getopt prototype */
# define getopt	local_getopt
#endif

/*
 * The following is derived from getopt() source placed into the public
 * domain by AT&T (the only time they're known to have done that).
 *
 * It has been modified somewhat to fit into the context of the shell.
 *
 * -D"FASCIST" if you really want to strictly enforce ALL the
 * Command Syntax Standard rules (not recommended).
 */

#define GETOPTEOF	(-1)
#define ERR(S, C)	shellf("%s%c\n", (S), (C))

static	int	optind;
static char    *optarg;
static int	sp;

static int
getopt(argc, argv, opts)
	int argc;
	register char **argv, *opts;
{
	register int c;
	register char *cp;

	if (sp == 1)
		if (optind >= argc ||
		   argv[optind][0] != '-' || argv[optind][1] == '\0')
			return(GETOPTEOF);
		else if (strcmp(argv[optind], "--") == 0) {
			optind++;
			return(GETOPTEOF);
		}
	c = argv[optind][sp];
	if (c == ':' || (cp=strchr(opts, c)) == NULL) {
		ERR("illegal option -- ", c);
		if (argv[optind][++sp] == '\0') {
			optind++;
			sp = 1;
		}
		optarg = NULL;
		return('?');
	}
	if (*++cp == ':') {
#ifdef FASCIST
		if (sp != 1) {
			ERR("option must not be grouped -- ", c );
			optind++;
			sp = 1;
			optarg = NULL;
			return('?');
		} else
#endif
		if (argv[optind][sp+1] != '\0') {
#ifdef FASCIST
			ERR("option must be followed by whitespace -- ", c );
			optind++;
			sp = 1;
			optarg = NULL;
			return('?');
#else
			optarg = &argv[optind++][sp+1];
#endif
		} else if (++optind >= argc) {
			ERR("option requires an argument -- ", c);
			sp = 1;
			optarg = NULL;
			return('?');
		} else
			optarg = argv[optind++];
		sp = 1;
	} else {
		if (argv[optind][++sp] == '\0') {
			sp = 1;
			optind++;
		}
		optarg = NULL;
	}
	return(c);
}

/*
 * The following were created by Arnold Robbins.
 */

/* resetopts --- magic code for when OPTIND is reset to 1 */

void
resetopts ()
{
	optind = 1;
	sp = 1;
}

int
c_getopts(wp)
	char **wp;
{
	int ret;
	register int argc;
	char temp[2];
	char *optstr;			/* list of options */
	char *name;			/* variable to get flag val */
	char **argv;

	if ((optstr = *++wp) == NULL || (name = *++wp) == NULL)
		errorf("missing arguments\n");

	for (argc = 1; wp[argc] != NULL; argc++)
		;

	if (argc > 1)
		ret = getopt(argc, wp, optstr);
	else {
		if (**(e.loc->argv) == '\0') {
			/*
			 * When c_getopts gets called from comexec() it
			 * doesn't set up argc/argv in the local block.
			 * Maybe this should be done in newblock() but
			 * I'm not sure about the implications, and this
			 * is the only place I've been bitten so far...
			 * JRM
			 */
			argc = e.loc->next->argc;
			argv = e.loc->next->argv;
		} else {
			argc = e.loc->argc;
			argv = e.loc->argv;
		}
		ret = getopt(argc+1, argv, optstr);

	}

	/*
	 * set the OPTIND variable in any case, to handle "--" skipping
	 * unless it's 1, which would trigger a reset
	 */

	if (optind != 1)
		setint(global("OPTIND"), (long)optind);

	if (ret == GETOPTEOF)		/* end of args */
		return (1);

	/*
	 * else, got an arg, set the various shell variables
	 */

	if (optarg != NULL)
		setstr(global("OPTARG"), optarg);

	temp[0] = (char) ret;
	temp[1] = '\0';
	setstr(global(name), temp);

	return (0);
}
./pdksh/sh/io.c   644    653   1762        6537  5303016706  10601 0ustar  hlu/*
 * shell buffered IO and formatted output
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <setjmp.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "sh.h"

#if 0
/* fputc with ^ escaping */
static void
fzotc(c, f)
	register int c;
	register FILE *f;
{
	if ((c&0x60) == 0) {		/* C0|C1 */
		putc((c&0x80) ? '$' : '^', f);
		putc((c&0x7F|0x40), f);
	} else if ((c&0x7F) == 0x7F) {	/* DEL */
		putc((c&0x80) ? '$' : '^', f);
		putc('?', f);
	} else
		putc(c, f);
}
#endif

/*
 * formatted output functions
 */

/* shellf(...); error() */
int
#ifdef __STDC__
errorf(const char *fmt, ...) {
#else
errorf(va_alist) va_dcl
{
	char *fmt;
#endif
	va_list va;

#ifdef __STDC__
	va_start(va, fmt);
#else
	va_start(va);
	fmt = va_arg(va, char *);
#endif
	vfprintf(shlout, fmt, va);
	va_end(va);
	/*fflush(shlout);*/
	error();
}

/* printf to shlout (stderr) */
int
#ifdef __STDC__
shellf(const char *fmt, ...) {
#else
shellf(va_alist) va_dcl
{
	char *fmt;
#endif
	va_list va;

#ifdef __STDC__
	va_start(va, fmt);
#else
	va_start(va);
	fmt = va_arg(va, char *);
#endif
	vfprintf(shlout, fmt, va);
	va_end(va);
	return 0;
}

/*
 * We have a stdio stream for any open shell file descriptors (0-9)
 */
FILE *	shf [NUFILE];		/* map shell fd to FILE * */

/* open stream for shell fd */
void
fopenshf(fd)
	int fd;
{
	if (shf[fd] != NULL)
		return;
#if !defined(_MINIX) && !defined(linux)
	if (fd <= 2)
#ifndef _BSDI
		_iob[fd]._flag = 0; /* re-use stdin, stdout, stderr */
#else
		/* Chris Torek's stdio replacement */
		__sF[fd]._flags = 0;
#endif
#endif
	shf[fd] = fdopen(fd, "r+");
	if (shf[fd] == NULL)
		return;
	setvbuf(shf[fd], (char*)NULL, _IOFBF, (size_t)BUFSIZ);
}

/* flush stream assoc with fd */
/* this must invalidate input and output buffers */
void
flushshf(fd)
	int fd;
{
	if (shf[fd] != NULL) {
#ifndef _BSDI
		/* Chris Torek's stdio replacement */
		fseek(shf[fd], 0L, 1); /* V7 derived */
#endif
		fflush(shf[fd]);	/* standard C */
	}
}

/*
 * move fd from user space (0<=fd<10) to shell space (fd>=10)
 */
int
savefd(fd)
	int fd;
{
	int nfd;

	if (fd < FDBASE) {
		flushshf(fd);
		nfd = fcntl(fd, F_DUPFD, FDBASE);
		if (nfd < 0)
			if (errno == EBADF)
				return -1;
			else
				errorf("too many files open in shell\n");
#ifdef F_SETFD
		(void) fcntl(nfd, F_SETFD, 1);
#else
		(void) fd_clexec(ttyfd);
#endif
		close(fd);
	} else
		nfd = fd;
	return nfd;
}

void
restfd(fd, ofd)
	int fd, ofd;
{
	if (ofd == 0)		/* not saved (e.savefd) */
		return;
	flushshf(fd);
	close(fd);
	if (ofd < 0)		/* original fd closed */
		return;
	(void) fcntl(ofd, F_DUPFD, fd);
	close(ofd);
}

void
openpipe(pv)
	register int *pv;
{
	if (pipe(pv) < 0)
		errorf("can't create pipe - try again\n");
	pv[0] = savefd(pv[0]);
	pv[1] = savefd(pv[1]);
}

void
closepipe(pv)
	register int *pv;
{
	close(pv[0]);
	close(pv[1]);
}

/*
 * temporary files
 */

struct temp *
maketemp(ap)
	Area *ap;
{
	register struct temp *tp;
	static unsigned int inc = 0;
	char path [PATH];

	sprintf(path, "/tmp/sh%05u%02u", (unsigned)getpid(), inc++);
#if defined(_SYSV) || defined(_BSD)
	close(creat(path, 0600));	/* to get appropriate permissions */
#endif
	tp = (struct temp *) alloc(sizeof(struct temp), ap);
	tp->next = NULL;
	tp->name = strsave(path, ap);
	return tp;
}
./pdksh/sh/lex.h   644    653   1762        7106  5243743702  10766 0ustar  hlu/*
 * Source input, lexer and parser
 */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#define	IDENT	64

typedef struct source Source;
struct source {
	char   *str;		/* input pointer */
	int	type;		/* input type */
	union {
		char  **strv;	/* string [] */
		FILE   *file;	/* file */
		struct tbl *tblp; /* alias */
	} u;
	int	line;		/* line number */
	char   *file;		/* input file name */
	int	echo;		/* echo input to shlout */
	Source *next;		/* stacked source */
};

/* Source.type values */
#define	SEOF	0		/* input EOF */
#define	STTY	1		/* terminal input */
#define	SFILE	2		/* file input */
#define	SSTRING	4		/* string */
#define	SWSTR	3		/* string without \n */
#define	SWORDS	5		/* string[] */
#define	SWORDSEP 8		/* string[] seperator */
#define	SALIAS	6		/* alias expansion */
#define	SHIST	7		/* history expansion */

Source *pushs ARGS((int stype)); 	/* push Source */
struct op *compile ARGS((Source *s));	/* compile tree */

/*
 * states while lexing word
 */
#define	SBASE	0		/* outside any lexical constructs */
#define	SWORD	6		/* implicit quoting for substitute() */
#define	SDPAREN	7		/* inside (( )), implicit quoting */
#define	SSQUOTE	1		/* inside '' */
#define	SDQUOTE	2		/* inside "" */
#define	SBRACE	3		/* inside ${} */
#define	SPAREN	4		/* inside $() */
#define	SBQUOTE	5		/* inside `` */

EXTERN	int	multiline;	/* \n changed to ; */

typedef union {
	int	i;
	char   *cp;
	char  **wp;
	struct op *o;
	struct ioword *iop;
} YYSTYPE;

#define	LWORD	256
#define	LOGAND	257
#define	LOGOR	258
#define	BREAK	259
#define	IF	260
#define	THEN	261
#define	ELSE	262
#define	ELIF	263
#define	FI	264
#define	CASE	265
#define	ESAC	266
#define	FOR	267
#define	WHILE	268
#define	UNTIL	269
#define	DO	270
#define	DONE	271
#define	IN	272
#define	FUNCTION 273
#define	TIME	274
#define	REDIR	275
#define	MPAREN	276		/* () */
#define	MDPAREN	277		/* (( )) */
#define SELECT	278		/* ksh */
#define	YYERRCODE 300

/* flags to yylex */
#define	CONTIN	BIT(0)		/* skip new lines to complete command */
#define	ONEWORD	BIT(1)		/* single word for substitute() */
#define	ALIAS	BIT(2)		/* recognize alias */
#define	KEYWORD	BIT(3)		/* recognize keywords */
#define	LETEXPR	BIT(4)		/* get expression inside (( )) */

#define	SYNTAXERR	zzerr()
#define	HERES	10		/* max << in line */

EXTERN	char	line [LINE+1];	/* input line */
EXTERN	Source *source;		/* yyparse/yylex source */
EXTERN	YYSTYPE	yylval;		/* result from yylex */
EXTERN	int	yynerrs;
EXTERN	struct ioword *heres [HERES], **herep;
EXTERN	char	ident [IDENT+1];

extern	int	yylex ARGS((int flags));
extern	void	yyerror ARGS((const char *msg));

#define	HISTORY	100		/* size of saved history */

#ifdef EASY_HISTORY
EXTERN	char   *history [HISTORY];	/* saved commands */
#else
EXTERN  char   **history;		/* saved commands */
EXTERN	int	histsize _I_(HISTORY);	/* history size */
EXTERN	char  **history;	/* saved commands */
#endif
EXTERN	char  **histptr;	/* last history item */
EXTERN	int	histpush;	/* number of pushed fc commands */

extern	char	**histget();
extern  char	**histpos();
extern	int	histnum();
extern	char	*findhist();
extern	int	histN();

#ifdef EDIT

extern	void	x_init ARGS ((void));	/* setup tty modes */
extern	void	x_init_emacs ARGS ((void));
extern	void	x_emacs_keys ();
extern	void	x_bind();

extern	int	x_read ARGS ((int fd, char *buf, size_t len));
extern	int	x_emacs ARGS ((char *buf, size_t len));
extern	int	x_vi ARGS ((char *buf, size_t len));

extern	bool_t	x_mode ARGS ((bool_t));	/* set/clear cbreak mode */
extern	int	x_getc();		/* get tty char */
extern	void	x_flush(), x_putc(), x_puts(); /* put tty char */

extern	int	x_cols;		/* tty columns */

#endif
./pdksh/sh/table.h   644    653   1762        7125  5243743701  11265 0ustar  hlu/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * generic hashed associative table for commands and variables.
 */

struct table {
	Area   *areap;		/* area to allocate entries */
	int	size, free;	/* hash size (always 2^^n), free entries */
	struct	tbl **tbls;	/* hashed table items */
};

struct tbl {			/* table item */
	int	flag;		/* flags */
	int	type;		/* command type or base, see below */
	union {
		char *s;	/* string */
		long i;		/* integer */
		int (*f) ARGS ((char**)); /* int function */
		struct op *t;	/* "function" tree */
	} val;			/* value */
	char	name[4];	/* name -- variable length */
};

/* flag bits */
#define	ALLOC	BIT(0)		/* val.s has been allocated */
#define	DEFINED	BIT(1)		/* is defined in block */
#define	ISSET	BIT(2)		/* has value, vp->val.[si] */
#define	SPECIAL	BIT(3)		/* PATH, IFS, SECONDS, etc */
#define	INTEGER	BIT(4)		/* val.i contains integer value */
#define	RDONLY	BIT(8)		/* read-only variable */
#define	EXPORT	BIT(9)		/* exported variable */
#define	LOCAL	BIT(10)		/* for local typeset() */
#define	TRACE	BIT(11)		/* trace (-t) */
#define	FUNCT	BIT(12)		/* function */
#define	EXPALIAS BIT(13)	/* expanding this alias */

/* command types */
#define	CNONE	0		/* undefined */
#define	CSHELL	1		/* built-in */
#define	CFUNC	2		/* function */
#define	CEXEC	4		/* executable command */
#define	CALIAS	5		/* alias */
#define	CKEYWD	6		/* keyword */

void tinit ARGS((struct table *, Area *)); /* initialize table */
unsigned int hash();		/* name hash function */
struct tbl *tsearch();		/* table lookup primative */
struct tbl *tenter();		/* table lookup/enter primative */
void tdelete();			/* mark tbl entry for deletion */
void twalk();			/* initialize walk of table */
struct tbl *tnext();		/* walk table returning table time */
struct tbl **tsort();		/* sort table entries by name */

/*
 * activation record for function blocks
 */
struct block {
	Area	area;		/* area to allocate things */
	int	argc;		/* current $# */
	char **	argv;		/* current $* */
	struct	table vars;	/* local variables */
	struct	table funs;	/* local functions */
#if 1
	char *	error;		/* error handler */
	char *	exit;		/* exit handler */
#else
	struct	trap error, exit;
#endif
	struct	block *next;	/* enclosing block */
};

EXTERN	struct block globals;	/* global variables and functions */
EXTERN	struct table commands;	/* hashed commands */
EXTERN	struct table builtins;	/* built-in commands */
EXTERN	struct table lexicals;	/* keywords and aliases */
EXTERN	struct table homedirs;	/* homedir() cache */

struct builtin {
	char   *name;
	int  (*func)();
};

/* these really are externs! Look in table.c for them */

extern const struct builtin shbuiltins [], kshbuiltins [];

/* var spec values */
#define	V_NONE	0
#define	V_PATH	1
#define	V_IFS	2
#define	V_SECONDS 3
#define	V_OPTIND 4
#define	V_MAIL	5
#define	V_MAILPATH 6
#define	V_RANDOM 7
#ifndef EASY_HISTORY
#define V_HISTSIZE 8
#define V_HISTFILE 9
#endif
#define V_FCEDIT 10
#define V_COLUMNS 11

EXTERN	Area   *lastarea;	/* area of last variable/function looked up */
EXTERN	char   *path;		/* PATH value */
EXTERN	char   *prompt;		/* PS1 or PS2 */

void	newblock();
void	popblock();
struct tbl *global(/* char *s */);
struct tbl *local(/* char *s */);
struct tbl *typeset(/* char *var; int set, clr */);
struct tbl *setvar(/* struct tbl *vdst, *vsrc */);
struct tbl *strint(/* struct tbl *vdst, *vsrc */);
long	intval(/* struct tbl *vp */);
void	setint(/* struct tbl *vp; long n */);
char   *strval(/* struct tbl *vp */);
void	setstr(/* struct tbl *vp; char *s */);
void	unset(/* struct tbl *vp */);
int	import(/* char *s */);
char  **makenv();
int	isassign(/* char *s */);

./pdksh/sh/trace.h   644    653   1762        4160  5243743615  11274 0ustar  hlu/* NAME:
 *      trace.h - definitions for a simple trace facility
 *
 * SYNOPSIS:
 *      #include "trace.h"
 *
 * DESCRIPTION:
 *      Defines the macro _TRACE().
 *      Also declares Trace_log and Trace_level.
 *
 * SEE ALSO:
 *      
 *
 * AMENDED:
 *      91/11/22  22:53:58  (sjg)
 *
 * RELEASED:
 *      91/11/22  22:54:18  v1.2
 *
 * SCCSID:
 *      @(#)trace.h  1.2  91/11/22  22:53:58  (sjg)
 *
 *      @(#)Copyright (c) 1990 Simon J. Gerraty.
 */

/* some useful #defines */
#ifndef EXTERN
# define EXTERN extern
# define EXTERN_DEFINED
#endif

#ifndef TRUE
# define TRUE  1
# define FALSE 0
#endif
#ifndef ARGS
# if defined(__STDC__) || defined(PROTO)
#   define ARGS(p) p
# else
#   define ARGS(p) ()
# endif
#endif

/*
 * this garbage is sometimes needed when mixing
 * langauges or calling conventions under DOS.
 */
#ifndef _CDECL
# if defined(MSDOS) || defined(MSC)
#   ifndef NO_EXT_KEYS
#     define _CDECL  cdecl
#     define _NEAR   near
#   else
#     define _CDECL
#     define _NEAR
#   endif
# else /* not DrOS */
#   define _CDECL
#   define _NEAR
# endif /* DOS */
#endif /* _CDECL */

/* manifest constants */

/* struct / union */

/* macros */


#ifdef USE_TRACE
EXTERN char * _CDECL	Trace_log;
EXTERN int _CDECL 	Trace_level;

void _CDECL checkpoint	ARGS((char *fmt, ...));

/*
 * This macro takes a variabel number of args. 
 * examples:
 * 	_TRACE(5, ("The current Debug level is %d\n", Debug));
 * Note that if more than two args are provided, all but the 
 * first (which should be an integer indicating the Trace-level 
 * required for this message to be printed) must be enclosed in 
 * parenthesis. 
 */
# define _TRACE(lev, args) if (Trace_level >= lev) checkpoint args
#else 	/* don't USE_TRACE */
  /*
   * this macro evaluates to a harmless no entry
   * loop that most optimizers will remove all together.
   */
# define _TRACE(l, args) while (0)
#endif 	/* USE_TRACE */


/* This lot goes at the END */
/* be sure not to interfere with anyone else's idea about EXTERN */
#ifdef EXTERN_DEFINED
# undef EXTERN_DEFINED
# undef EXTERN
#endif
/*
 * Local Variables:
 * version-control:t
 * comment-column:40
 * End:
 */
./pdksh/sh/trap.c   644    653   1762       11410  5302761055  11145 0ustar  hlu/*
 * signal handling
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include "sh.h"

Trap sigtraps [SIGNALS] = {
	{0,	"EXIT", "Signal 0"}, /* todo: belongs in e.loc->exit */
	{SIGHUP, "HUP", "Hangup"},
	{SIGINT, "INT", "Interrupt"},
	{SIGQUIT, "QUIT", "Quit"},
	{SIGILL, "ILL", "Illegal instruction"},
	{SIGTRAP, "TRAP", "Trace trap"},
#ifdef	SIGABRT
	{SIGIOT, "ABRT", "Abort"},
#else
	{SIGIOT, "IOT", "IOT instruction"},
#endif
#ifdef	linux
	{SIGUNUSED, "UNUSED", "Unused signal"},
#else
	{SIGEMT, "EMT", "EMT trap"},
#endif
	{SIGFPE, "FPE", "Floating exception"},
	{SIGKILL, "KILL", "Killed"},
#if defined(_MINIX) || defined(linux)
	{SIGUSR1, "USR1", "User defined signal 1"},
	{SIGSEGV, "SEGV", "Memory fault"},
	{SIGUSR2, "USR2", "User defined signal 2"},
#else
	{SIGBUS, "BUS", "Bus error"},
	{SIGSEGV, "SEGV", "Memory fault"},
	{SIGSYS, "SYS", "Bad system call"},
#endif
	{SIGPIPE, "PIPE", "Broken pipe"},
	{SIGALRM, "ALRM", "Alarm clock"},
	{SIGTERM, "TERM", "Terminated"},
#if defined(_MINIX) || defined(linux)
	{SIGSTKFLT, "STKFLT", "Stack fault"},
#endif
#ifdef linux
	{SIGCHLD, "CHLD", "Child exited"},
	{SIGCONT, "CONT", "Continue"},
	{SIGSTOP, "STOP", "Stop (signal)"},
	{SIGTSTP, "TSTP", "Stop"},
	{SIGTTIN, "TTIN", "Stop (tty input)"},
	{SIGTTOU, "TTOU", "Stop (tty output)"},
	{SIGIO,	"IO", "Possible I/O"},
	{SIGXCPU, "XCPU", "CPU time limit exceeded"},
	{SIGXFSZ, "XFSZ", "File size limit exceeded"},
	{SIGVTALRM, "VTALRM", "Virtual time alarm"},
	{SIGPROF, "PROF", "Profile signal"},
	{SIGWINCH, "WINCH", "Window size changed"},
#ifdef SIGLOST
	{SIGLOST, "LOST", "File lock lost"},
#endif
#else
#ifdef _SYSV
	{SIGUSR1, "USR1", "User defined signal 1"},
	{SIGUSR2, "USR2", "User defined signal 2"},
	{SIGCLD, "CLD", "Death of a child"},
	{SIGPWR, "PWR", "Power-fail restart"},
#ifdef JOBS			/* todo: need to be more portable */
	{SIGTSTP, "TSTP", "Stop"},
	{SIGTTIN, "TTIN", "Stop (tty input)"},
#ifdef SIGPOLL
	{SIGPOLL, "POLL", "Pollable event occured"},
#endif
	{SIGSTOP, "STOP", "Stop (signal)"},
	{SIGTTOU, "TTOU", "Stop (tty output)"},
	{SIGCONT, "CONT", "Continue"},
#endif
#else	/* _SYSV */
#ifdef JOBS			/* todo: need to be more portable */
	{SIGURG, "URG", "Urgent condition"}, /* BSDism */
	{SIGSTOP, "STOP", "Stop (signal)"},
	{SIGTSTP, "TSTP", "Stop"},
	{SIGCONT, "CONT", "Continue"},
	{SIGCHLD, "CHLD", "Waiting children"},
	{SIGTTIN, "TTIN", "Stop (tty input)"},
	{SIGTTOU, "TTOU", "Stop (tty output)"},
#endif
#endif /* _SYSV */
#endif /* linux */
};

Trap *
gettrap(name)
	char *name;
{
	int i;
	register Trap *p;

	if (digit(*name)) {
		i = getn(name);
		return (0 <= i && i < SIGNALS) ? &sigtraps[getn(name)] : NULL;
	}
#if 0
	if (strcmp("ERR", name) == 0)
		return &e.loc->err;
	if (strcmp("EXIT", name) == 0)
		return &e.loc->exit;
#endif
	for (p = sigtraps, i = SIGNALS; --i >= 0; p++)
		if (p->name != NULL && strcmp(p->name, name) == 0)
			return p;
	return NULL;
}

/*
 * trap signal handler
 */
void
trapsig(i)
	int i;
{
	trap = sigtraps[i].set = 1;
	if (i == SIGINT && (e.type == E_PARSE || e.type == E_LOOP))
		/* dangerous but necessary to deal with BSD silly signals */
		longjmp(e.jbuf, 1);
#ifdef USE_SIGACT
	sigaction(i, &Sigact_trap, NULL);
#else
	(void) signal(i, trapsig);
#endif
}

/*
 * run any pending traps
 */
runtraps()
{
	int i;
	register Trap *p;

	for (p = sigtraps, i = SIGNALS; --i >= 0; p++)
		if (p->set)
			runtrap(p);
	trap = 0;
}

runtrap(p)
	Trap *p;
{
	char *trapstr;

	p->set = 0;
	if ((trapstr = p->trap) == NULL)
		if (p->signal == SIGINT)
			unwind();	/* return to shell() */
		else
			return;
	if (p->signal == 0)	/* ??? */
		p->trap = 0;
	command(trapstr);
}
 
/* restore signals for children */
cleartraps()
{
	int i;
	register Trap *p;

	if ((p = sigtraps)->trap != NULL) {	/* Maybe put in exchild() */
		afree((void *)p->trap,APERM);	/* Necessary? */
		p->trap = NULL;
	}
	for (i = SIGNALS, p = sigtraps; --i >= 0; p++) {
		p->set = 0;
#ifdef USE_SIGACT
		if (p->ourtrap)
		{
		  sigaction(p->signal, &Sigact_ign, &Sigact);
		  if (Sigact.sa_handler != SIG_IGN)
		    sigaction(p->signal, &Sigact_dfl, NULL);
		}
#else
		if (p->ourtrap && signal(p->signal, SIG_IGN) != SIG_IGN)
			(void) signal(p->signal, SIG_DFL);
#endif
	}
}

ignoresig(i)
	int i;
{
#ifdef USE_SIGACT
  sigaction(i, &Sigact_ign, &Sigact);
  sigemptyset(&Sigact.sa_mask);
  Sigact.sa_flags = 0;

  if (Sigact.sa_handler != SIG_IGN)
    sigtraps[i].sig_dfl = 1;
#else
  if (signal(i, SIG_IGN) != SIG_IGN)
    sigtraps[i].sig_dfl = 1;
#endif
}

restoresigs()
{
	int i;
	register Trap *p;

	for (p = sigtraps, i = SIGNALS; --i >= 0; p++)
		if (p->sig_dfl) {
			p->sig_dfl = 0;
#ifdef USE_SIGACT
			sigaction(p->signal, &Sigact_dfl, NULL);
#else
			(void) signal(p->signal, SIG_DFL);
#endif
		}
}

./pdksh/sh/tree.h   644    653   1762        7130  5243743666  11143 0ustar  hlu/*
 * command trees for compile/execute
 */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#define	NOBLOCK	((struct op *)NULL)
#define	NOWORD	((char *)NULL)
#define	NOWORDS	((char **)NULL)

/*
 * Description of a command or an operation on commands.
 */
struct op {
	int	type;			/* operation type, see below */
	char  **args;			/* arguments to a command */
	char  **vars;			/* variable assignments */
	struct ioword	**ioact;	/* IO actions (eg, < > >>) */
	struct op *left, *right; 	/* descendents */
	char   *str;		/* identifier for case and for (use vars[0]) */
};

/* Tree.type values */
#define	TEOF	0
#define	TCOM	1		/* command */
#define	TPAREN	2		/* (c-list) */
#define	TPIPE	3		/* a | b */
#define	TLIST	4		/* a [&;] b */
#define	TOR	5		/* || */
#define	TAND	6		/* && */
#define	TFOR	7
#define	TCASE	9
#define	TIF	10
#define	TWHILE	11
#define	TUNTIL	12
#define	TELIF	13
#define	TPAT	14		/* pattern in case */
#define	TBRACE	15		/* {c-list} */
#define	TASYNC	16		/* c & */
#define	TFUNCT	17		/* function name { command; } */
#define	TTIME	18		/* time pipeline */
#define	TEXEC	19		/* fork/exec eval'd TCOM */
#define TSELECT	20		/* select */

/*
 * prefix codes for words in command tree
 */
#define	EOS	0		/* end of string */
#define	CHAR	1		/* unquoted character */
#define	QCHAR	2		/* quoted character */
#define	COMSUB	3		/* $() substitution (0 terminated) */
#define	OQUOTE	4		/* opening " or ' */
#define	CQUOTE	5		/* closing " or ' */
#define	OSUBST	6		/* opening ${ substitution */
#define	CSUBST	7		/* closing } of above */

/*
 * IO redirection
 */
struct ioword {
	int	unit;	/* unit affected */
	int	flag;	/* action (below) */
	char   *name;	/* file name */
};

/* ioword.flag - type of redirection */
#define	IOTYPE	0xF		/* type: bits 0:3 */
#define	IOREAD	0x1		/* < */
#define	IOWRITE	0x2		/* > */
#define	IORDWR	0x3		/* <>: todo */
#define	IOHERE	0x4		/* << (here file) */
#define	IOCAT	0x5		/* >> */
#define	IODUP	0x6		/* <&/>& */
#define	IOEVAL	BIT(4)		/* expand in << */
#define	IOSKIP	BIT(5)		/* <<-, skip ^\t* */
#define	IOCLOB	BIT(6)		/* >!, override -o noclob */

/* values for E_LOOP longjmp */
#define	LBREAK	1
#define	LCONTIN	2

/* execute/exchild flags */
#define	XEXEC	BIT(0)		/* execute without forking */
#define	XFORK	BIT(5)		/* fork before executing */
#define	XBGND	BIT(1)		/* command & */
#define	XPIPEI	BIT(2)		/* input is pipe */
#define	XPIPEO	BIT(3)		/* output is pipe */
#define	XPIPE	(XPIPEI|XPIPEO)	/* member of pipe */
#define	XXCOM	BIT(4)		/* dup2 xcomfd to 1 */
#define XXWHL	BIT(6)		/* don't flush stdin before fork */

/*
 * flags to control expansion of words
 */
#define	DOBLANK	BIT(1)		/* perform blank interpretation */
#define	DOGLOB	BIT(2)		/* expand [?* */
#define	DOPAT	BIT(3)		/* quote *?[ */
#define	DOTILDE	BIT(5)		/* expand ~ */

#if 0
/* job.c: job control primatives */
int	execute ARGS((struct op *, int flags));	/* execute tree */
int	exchild ARGS((struct op *, int flags));	/* execute tree as child */
int	waitfor ARGS((int job)); 		/* wait for job completion */
int	waitlast ARGS((void));			/* wait for last job */

/* eval.c: word expansion */
char  **eval ARGS((char **wv, int flag)); 	/* expand words */
char   *evalstr ARGS((char *wp, int flags));	/* expand word */
char   *substitute ARGS((const char *s, int flags)); /* compile and expand string */

/* tree.c: command trees */
void	ptree ARGS((struct op *t, FILE *f));	/* print tree */
char   *wdscan ARGS((char *wp, int c));		/* scan word for prefix */
char   *wdcopy ARGS((char *wp, Area *));	/* copy word */
struct op *tcopy ARGS((struct op *t, Area *));	/* copy tree */
void	tfree ARGS((struct op *t, Area *));	/* free tree */
#endif
./pdksh/sh/Changes   644    653   1762        1124  5243742770  11316 0ustar  hluFix echo $$ | cat
#if and config option cleanup
Fix let evaluation of null/unset vars
alloc improvement
Fix accidental SCCS keywords
Fix Xstring overwriting in lex.c
Print here doc temp file when printing I/O actions
Add more slack on end of Xstrings
Fix up test(1) parsing
Run shell scripts with EXECSHELL
Make temp files 0600
Make unset -f work
Make trailing blank or tab in alias work
Fix command completion bug
--------------------------------------------------
Fix "cd / foo"
Fix getopts accidentally resetting itself
--------------------------------------------------
Fix whence exit codes
./pdksh/sh/config.h   644    653   1762        4140  5302767335  11442 0ustar  hlu/*
 * Configuration file for the PD ksh
 *
 * RCSid: $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
 */

#ifndef	_CONFIG_H
#define	_CONFIG_H

/*
 * Builtin edit modes
 */

#define	EMACS				/* EMACS-like mode */
#define	VI				/* vi-like mode */
#define	JOBS				/* job control */

#ifndef SIGINT
#include <signal.h>
#endif

/*
 * leave USE_SIGACT defined.
 * if you don't have sigaction(2) and the
 * implementation in sigact.c doesn't work for your system,
 * fix it.
 * 
 * Of course if your system has a real sigaction() 
 * implementation that is faulty! undef JOBS and add USE_SIGNAL
 * or whatever does work.  You may find it necessary to undef
 * USE_SIGACT, if so please report it.
 */
#define USE_SIGACT			/* POSIX signal handling */
/* 
 * These control how sigact.c implements sigaction()
 * If you don't define any of them it will try and work it out 
 * for itself.  The are listed in order of preference (usefulness).
 */
#if 0
#define USE_SIGMASK			/* BSD4.2 ? signal handling */
#define USE_SIGSET			/* BSD4.1 ? signal handling */
#define USE_SIGNAL			/* plain old signal(2) */
#endif

#if defined(JOBS) && (!defined(SIGCONT) || (defined(_SYSV) && defined(USE_SIGNAL)))
#undef JOBS
#endif

#if 0
#define	FASCIST			/* Fascist getopts */
#endif
#define	SHARPBANG			/* Hack to handle #! */
#if 0
#define	SILLY			/* Game of life in EMACS mode */
#define	SWTCH			/* Handle SWTCH for shl(1) */
#endif

/*
 * better to leave this one out, and let users that
 * like it add
 *   bind '^[^['=complete-list
 * to their .kshrc
 */
#if 0
#define COMPLETE_LIST			/* default to Emacs style completion */
#endif
/*
 * ALTERNATIONS is csh not ksh, but it is such a nice feature...
 */
#define ALTERNATIONS			/* csh {a,b,c} arg expansion */

#if 0
#define COMPLEX_HISTORY			/* Peter Collinson's history */
#endif
/*
 * if you don't have mmap() you can't use Peter Collinson's history
 * mechanism.  If that is the case, then define EASY_HISTORY
 */
#if !defined(COMPLEX_HISTORY) || defined(NO_MMAP)
# undef COMPLEX_HISTORY
# ifndef EASY_HISTORY
#  define EASY_HISTORY			/* sjg's trivial history file */
# endif
#endif
  
#endif	/* _CONFIG_H */
./pdksh/sh/tty.h   644    653   1762        1321  5243743667  11021 0ustar  hlu/*
	tty.h -- centralized definitions for a variety of terminal interfaces

	created by DPK, Oct. 1986

	last edit:	30-Jul-1987	D A Gwyn
*/

#if _BSD_SYSV			/* BRL UNIX System V emulation */
#include <termio.h>	/* includes <sys/_ioctl.h> */
#ifndef NTTYDISC
#define	TIOCGETD	_IOR( 't', 0, int )
#define	TIOCSETD	_IOW( 't', 1, int )
#define	NTTYDISC	2
#endif
#ifndef TIOCSTI
#define	TIOCSTI		_IOW( 't', 114, char )
#endif
#ifndef TIOCSPGRP
#define	TIOCSPGRP	_IOW( 't', 118, int )
#endif
#else	/* !_BSD_SYSV */
#if _BSD
#ifdef _MINIX
#include <sgtty.h>
#define TIOCSETN	TIOCSETP
#else
#include <sys/ioctl.h>
#endif
#else
#ifdef	_POSIX_TERM
#include <termios.h>
#else
#include <termio.h>
#endif
#endif
#endif	/* _BSD_SYSV */
./pdksh/sh/version.c   644    653   1762        2302  5243743701  11646 0ustar  hlu/*
 * value of $KSH_VERSION
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <setjmp.h>
#include "sh.h"
#include "patchlevel.h"

char ksh_version [] =
	"KSH_VERSION=@(#)PD KSH v4.7 92/08/12";

/***
$Log: ksh4.7.tar,v $
Revision 1.1.1.1  2019/05/29 04:56:40  root
coherent

 * Revision 1.6  1992/08/12  14:15:53  sjg
 * Patch07: fix some build problems,
 * and avoid core dump from arg processing bug.
 *
 * Revision 1.5  1992/08/10  12:03:29  sjg
 * Update for patch06.
 * Contributions from Peter Collinson, Neil Smithline and sjg
 *
 * Revision 1.4  1992/05/12  09:30:37  sjg
 * see ChangeLog
 *
 * Revision 1.3  1992/05/03  08:29:20  sjg
 * Update for Patch05
 *
 * Revision 1.2  1992/04/25  08:33:28  sjg
 * Added RCS key.
 *
 * Revision 1.1  1992/04/18  05:51:48  sjg
 * Initial revision
 *
Version  4.0  91/11/09  sjg
distribution
Revision 3.3  89/03/27  15:52:29  egisin
distribution

Revision 3.2  88/12/14  20:10:41  egisin
many fixes

Revision 3.1  88/11/03  09:18:36  egisin
alpha distribution

Revision 1.3  88/10/20  17:34:03  egisin
added @(#) to ksh_version

Revision 1.2  88/09/27  19:01:58  egisin
fix version.c

Revision 1.1  88/09/27  18:59:06  egisin
Initial revision
***/

./pdksh/sh/stdh.h   644    653   1762        3543  5302634075  11137 0ustar  hlu/* NAME:
 *      stdh.h - standard headers
 *
 * SYNOPSIS:
 *      #include "stdh.h"
 *
 * DESCRIPTION:
 *      We use this header to encapsulate all the stddef et al 
 *      inclusion so that most of the source can ignore the 
 *      problems that their lack might cause.
 *
 * SEE ALSO:
 *      
 *
 * AMENDED:
 *      91/11/25  13:33:12  (sjg)
 *
 * RELEASED:
 *      91/11/25  13:33:17  v1.3
 *
 * SCCSID:
 *      @(#)stdh.h  1.3  91/11/25  13:33:12  (sjg)
 *
 */

#ifndef ARGS
# ifdef __STDC__
#   define ARGS(args) args
# else
#   define ARGS(args) ()
#   ifdef VOID
#     define void VOID
#   endif
#   define const
#   define volatile
# endif
#endif

#include <stdio.h>
/* if we have std headers then include them here
 * otherwise make allowances
 */
#ifdef linux
extern void setfileno ARGS ((FILE *__fp, int __fd));
#endif

#ifndef NOSTDHDRS
# include <stddef.h>
# include <stdlib.h>
# include <string.h>
# include <memory.h>
# include <sys/types.h>
#else
# ifdef HAVE_SYS_STDTYPES
#   include <sys/stdtypes.h>
# else
#   include <sys/types.h>
/* just in case they have sys/stdtypes and don't know it
 */
#   ifndef	__sys_stdtypes_h
#define _PID_T
#define _CLOCK_T
typedef int pid_t;
typedef long clock_t;
#   endif
# endif
# ifdef _SYSV
#   include <string.h>
# else
#   include <strings.h>
#   define strchr index
#   define strrchr rindex
# endif
/* just a useful subset of what stdlib.h would have
 */
extern char * getenv  ARGS((const char *));
extern void * malloc  ARGS((size_t));
extern int    free    ARGS((void *));
extern int    exit    ARGS((int));

/* these _should_ match ANSI */
extern char * strstr  ARGS((const char *, const char *));
extern void * memmove ARGS((void *, const void *, size_t));
extern void * memcpy  ARGS((void *, const void *, size_t));
#endif /* NOSTDHDRS */
  

#ifndef offsetof
#define	offsetof(type,id) ((size_t)&((type*)NULL)->id)
#endif

./pdksh/sh/do_ulimit.c   644    653   1762        5523  5302641624  12153 0ustar  hlu/*
	ulimit -- handle "ulimit" builtin

	Eric Gisin, September 1988
	Adapted to PD KornShell. Removed AT&T code.

	last edit:	06-Jun-1987	D A Gwyn

	This started out as the BRL UNIX System V system call emulation
	for 4.nBSD, and was later extended by Doug Kingston to handle
	the extended 4.nBSD resource limits.  It now includes the code
	that was originally under case SYSULIMIT in source file "xec.c".
*/

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#if defined(_BSDI) || defined(linux)
#define _BSD	1
#endif

#include "stdh.h"
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#if defined(_BSD) || defined(_BSD_SYSV)
#include <sys/time.h>
#include <sys/resource.h>
#else
#define	RLIMIT_FSIZE	2
#endif
#include "sh.h"

#ifndef _BSD
extern	long ulimit();
#endif

int
do_ulimit(a1, a2)
	char	*a1, *a2;
{
	register int	c;
	long		i;
#if defined(_BSD) || defined(_BSD_SYSV)
	struct rlimit	limit;		/* data being gotten/set */
	int		softonly = 0;	/* set => soft limit, clear => hard limit */
	int		factor = 1024;	/* unit scaling (1K or 1) */
#endif
	int	command = RLIMIT_FSIZE;

	if (a1 && (*a1 == '-'))		/* DAG -- Gould added first test */
	{	c = *++a1;		/* DAG */
#if defined(_BSD) || defined(_BSD_SYSV)
		if (c >= 'A' && c <= 'Z')
		{
			++softonly;
			c += 'a' - 'A';	/* DAG -- map to lower-case */
		}
#endif
		switch(c)
		{
#if defined(_BSD) || defined(_BSD_SYSV)
			case 'c':
				command = RLIMIT_CORE;
				break;
			case 'd':
				command = RLIMIT_DATA;
				break;
			case 'm':
				command = RLIMIT_RSS;
				break;
			case 's':
				command = RLIMIT_STACK;
				break;
			case 't':
				factor = 1;
				command = RLIMIT_CPU;
				break;
#endif	/* _BSD || _BSD_SYSV */
			case 'f':
				command = RLIMIT_FSIZE;
#if _BSD_SYSV
				factor = 512;
#endif
				break;
			default:
#if _BSD
				errorf("Usage: %s [-cdmstf] [limit]\n", "ulimit");
#else
				errorf("Usage: %s [-f] [limit]\n", "ulimit");
#endif
		}
		a1 = a2;
	}
	if (a1)
	{
		i = 0;
		while ((c = *a1++) >= '0' && c <= '9')
		{
			i = (i * 10) + (long)(c - '0');
			if (i < 0)
				goto Error;
		}
		if (c || i < 0)
			goto Error;
	}
#if !(defined(_BSD) || defined(_BSD_SYSV))
	else
	{
		i = -1;
		command--;
	}

	if ((i = ulimit(command, i)) < 0L)
		goto Error;

	if (command != RLIMIT_FSIZE)
		shellf("%ld\n", i);
#else					/* DPK -- generalized for 4.nBSD: */
	if (getrlimit(command, &limit))
		goto Error;	/* errno is already set */

	if (a1)
	{
		limit.rlim_cur = i * factor;

		if (!softonly)
			limit.rlim_max = limit.rlim_cur;

		if (setrlimit(command, &limit))
			goto Error;
	}
	else
	{
		i = softonly ? limit.rlim_cur : limit.rlim_max;
#if _BSD			/* DAG -- System V always prints an integer */
		if (i == RLIM_INFINITY)
			shellf("unlimited\n");
		else
#endif
			shellf("%ld\n", i/factor);
	}
#endif	/* _BSD || _BSD_SYSV */
	return 0;

  Error:
	errorf("bad ulimit\n");
}

./pdksh/sh/patchlevel.h   644    653   1762         162  5243743700  12276 0ustar  hlu/*
 * PD KSH
 * $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
 */
#define VERSION		4
#define PATCHLEVEL	7
./pdksh/sh/proto.h   644    653   1762       20022  5243743663  11357 0ustar  hlu/*
 * prototypes for PD-KSH
 * originally generated using "cproto.c 3.5 92/04/11 19:28:01 cthuang "
 * $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
 */
#ifndef ARGS
#if defined(__STDC__) || defined(__cplusplus)
#define ARGS(s) s
#else
#define ARGS(s) ()
#endif
#endif

/* alloc.c */
Area *	ainit		 ARGS((Area *ap));
void 	afreeall	 ARGS((Area *ap));
void *	alloc		 ARGS((size_t size, Area *ap));
void *	aresize		 ARGS((void *ptr, size_t size, Area *ap));
void 	afree		 ARGS((void *ptr, Area *ap));
/* c_ksh.c */
int 	c_hash		 ARGS((char **wp));
int 	c_cd		 ARGS((char **wp));
int 	c_print		 ARGS((char **wp));
int 	c_whence	 ARGS((char **wp));
int 	c_typeset	 ARGS((char **wp));
int 	c_alias		 ARGS((char **wp));
int 	c_unalias	 ARGS((char **wp));
int 	c_let		 ARGS((char **wp));
int 	c_jobs		 ARGS((char **wp));
int 	c_fgbg		 ARGS((char **wp));
int 	c_kill		 ARGS((char **wp));
int 	c_bind		 ARGS((char **wp));
/* c_sh.c */
int 	c_label		 ARGS((char **wp));
int 	c_shift		 ARGS((char **wp));
int 	c_umask		 ARGS((char **wp));
int 	c_dot		 ARGS((char **wp));
int 	c_wait		 ARGS((char **wp));
int 	c_read		 ARGS((char **wp));
int 	c_eval		 ARGS((char **wp));
int 	c_trap		 ARGS((char **wp));
void 	setsig		 ARGS((struct trap *p, void (*f)()));
int 	c_return	 ARGS((char **wp));
int 	c_brkcont	 ARGS((char **wp));
int 	c_exit		 ARGS((char **wp));
int 	c_set		 ARGS((char **wp));
int 	c_unset		 ARGS((char **wp));
int 	c_ulimit	 ARGS((char **wp));
int 	c_times		 ARGS((char **wp));
int 	timex		 ARGS((struct op *t, int f));
int 	c_exec		 ARGS((char **wp));
int 	c_builtin	 ARGS((char **wp));
/* c_test.c */
int 	c_test		 ARGS((char **wp));
int 	oexpr		 ARGS((int n));
int 	aexpr		 ARGS((int n));
int 	nexpr		 ARGS((int n));
int 	primary		 ARGS((int n));
int 	filstat		 ARGS((char *nm, int mode));
int 	t_lex		 ARGS((char *s));
int 	newerf		 ARGS((char *f1, char *f2));
int 	olderf		 ARGS((char *f1, char *f2));
int 	equalf		 ARGS((char *f1, char *f2));
/* do_ulimit.c */
int 	do_ulimit	 ARGS((char *a1, char *a2));
/* edit.c */
int 	x_read		 ARGS((int fd, char *buf, size_t len));
int 	x_getc		 ARGS((void));
void 	x_flush		 ARGS((void));
void 	x_adjust	 ARGS((void));
void 	x_putc		 ARGS((int c));
void 	x_puts		 ARGS((char *s));
void 	x_init		 ARGS((void));
bool_t 	x_mode		 ARGS((bool_t onoff));
int 	promptlen	 ARGS((char *cp));
int 	init_editmode	 ARGS((void));
void 	set_editmode	 ARGS((char *ed));
/* emacs.c */
int 	x_emacs		 ARGS((char *buf, size_t len));
void 	x_redraw	 ARGS((int limit));
void 	x_bind		 ARGS((char *a1, char *a2, int macro));
void 	x_init_emacs	 ARGS((void));
void 	x_emacs_keys	 ARGS((int erase, int kill, int werase, int intr, int quit));
char *	x_lastcp	 ARGS((void));
/* eval.c */
char *	substitute	 ARGS((char const *cp, int f));
char **	eval		 ARGS((char **ap, int f));
char *	evalstr		 ARGS((char *cp, int f));
char *	evalonestr	 ARGS((char *cp, int f));
/* exec.c */
int 	execute		 ARGS((struct op *t, volatile int flags));
int 	shcomexec	 ARGS((char **wp));
int 	define		 ARGS((char *name, struct op *t));
int 	builtin		 ARGS((char *name, int (*func)()));
struct tbl *	findcom	 ARGS((char *name, int insert));
int 	flushcom	 ARGS((int all));
char *	search		 ARGS((char *name, char *path, int mode));
int	pr_menu		 ARGS((char **ap, int usestored));
/* expr.c */
void 	evalerr		 ARGS((char *err));
long 	evaluate	 ARGS((const char *expr));
/* getopts.c */
void 	resetopts	 ARGS((void));
int 	c_getopts	 ARGS((char **wp));
/* history.c */
int 	c_fc	 	 ARGS((register char **wp));
void 	histbackup	 ARGS((void));
#ifdef EASY_HISTORY
void 	histsave	 ARGS((char *cmd));
#else
void	sethistsize	 ARGS((int n));
void	sethistfile	 ARGS((char *name));
void	histsave	 ARGS((int lno, char *cmd, int dowrite));
#endif
char **	histget	 	 ARGS((char *str));
char *	histrpl	 	 ARGS((char *s, char *pat, char *rep, int global));
void 	hist_init	 ARGS((Source *s));
void 	hist_finish	 ARGS((void));
char **	histpos	 	 ARGS((void));
int 	histN	 	 ARGS((void));
int 	histnum	 	 ARGS((int n));
char *	findhist	 ARGS((int start, int fwd, char *str));
/* io.c */
int 	errorf		 ARGS((const char *fmt, ...));
int 	shellf		 ARGS((const char *fmt, ...));
void 	fopenshf	 ARGS((int fd));
void 	flushshf	 ARGS((int fd));
int 	savefd		 ARGS((int fd));
void 	restfd		 ARGS((int fd, int ofd));
void 	openpipe	 ARGS((int *pv));
void 	closepipe	 ARGS((int *pv));
struct temp *	maketemp ARGS((Area *ap));
/* jobs.c */
void 	j_init		 ARGS((void));
void 	j_exit		 ARGS((void));
void 	j_change	 ARGS((void));
int 	exchild		 ARGS((struct op *t, int flags));
int 	waitlast	 ARGS((void));
int 	j_reapchld	 ARGS((void));
int 	j_reap		 ARGS((void));
int 	waitfor		 ARGS((int job));
void 	j_kill		 ARGS((int job, int sig));
int 	j_resume	 ARGS((int job, int bg));
void 	j_jobs		 ARGS((void));
void 	j_notify	 ARGS((void));
int 	j_lookup	 ARGS((char *cp));
int 	j_stopped	 ARGS((void));
/* lex.c */
int 	yylex		 ARGS((int cf));
int 	gethere		 ARGS((void));
void 	yyerror		 ARGS((const char *msg));
Source * pushs		 ARGS((int type));
int 	pprompt		 ARGS((char *cp));
/* mail.c */
void 	mcheck		 ARGS((void));
void 	mbset		 ARGS((char *p));
void 	mpset		 ARGS((char *mptoparse));
void 	mprint		 ARGS((void));
/* main.c */
int 	main		 ARGS((int argc, char **argv, char **envp));
int 	include		 ARGS((char *name));
#if 0
int 	command		 ARGS((char *comm));
#endif
int 	shell		 ARGS((Source *s));
void 	leave		 ARGS((int rv));
int 	error		 ARGS((void));
int 	unwind		 ARGS((void));
int 	newenv		 ARGS((int type));
int 	quitenv		 ARGS((void));
void 	aerror		 ARGS((Area *ap, const char *msg));
/* misc.c */
void 	setctypes	 ARGS((/* const */ char *s, int t));
void 	initctypes	 ARGS((void));
char *	ulton		 ARGS((unsigned long n, int base));
char *	strsave		 ARGS((char *s, Area *ap));
int 	option		 ARGS((const char *n));
char *	getoptions	 ARGS((void));
void 	printoptions	 ARGS((void));
int 	getn		 ARGS((char *as));
char *	strerror	 ARGS((int i));
int 	gmatch		 ARGS((char *s, char *p));
void 	qsortp		 ARGS((void **base, size_t n, int (*f)()));
int 	qsort1		 ARGS((void **base, void **lim, int (*f)()));
int 	xstrcmp		 ARGS((void *p1, void *p2));
void 	cleanpath	 ARGS((char *pwd, char *dir, char *clean));
/* syn.c */
int 	yyparse		 ARGS((void));
int 	keywords	 ARGS((void));
struct op * compile	 ARGS((Source *s));
/* table.c */
unsigned int 	hash	 ARGS((char *n));
void 	tinit		 ARGS((struct table *tp, Area *ap));
struct tbl *	tsearch	 ARGS((struct table *tp, char *n, unsigned int h));
struct tbl *	tenter	 ARGS((struct table *tp, char *n, unsigned int h));
void 	tdelete		 ARGS((struct tbl *p));
void 	twalk		 ARGS((struct table *tp));
struct tbl *	tnext	 ARGS((void));
struct tbl **	tsort	 ARGS((struct table *tp));
/* trace.c */
/* trap.c */
Trap *	gettrap		 ARGS((char *name));
void 	trapsig		 ARGS((int i));
int 	runtraps	 ARGS((void));
int 	runtrap		 ARGS((Trap *p));
int 	cleartraps	 ARGS((void));
int 	ignoresig	 ARGS((int i));
int 	restoresigs	 ARGS((void));
/* tree.c */
void 	ptree		 ARGS((struct op *t, FILE *f));
int 	pioact		 ARGS((FILE *f, struct ioword *iop));
int 	fptreef		 ARGS((FILE *f, char *fmt, ...));
int 	snptreef	 ARGS((char *s, int n, char *fmt, ...));
struct op *	tcopy	 ARGS((struct op *t, Area *ap));
char *	wdcopy		 ARGS((char *wp, Area *ap));
char *	wdscan		 ARGS((char *wp, int c));
void 	tfree		 ARGS((struct op *t, Area *ap));
/* var.c */
void 	newblock	 ARGS((void));
void 	popblock	 ARGS((void));
struct tbl *	global	 ARGS((char *n));
struct tbl *	local	 ARGS((char *n));
char *	strval		 ARGS((struct tbl *vp));
long 	intval		 ARGS((struct tbl *vp));
void 	setstr		 ARGS((struct tbl *vq, char *s));
struct tbl *	strint	 ARGS((struct tbl *vq, struct tbl *vp));
void 	setint		 ARGS((struct tbl *vq, long n));
int 	import		 ARGS((char *thing));
struct tbl *	typeset	 ARGS((char *var, int set, int clr));
void 	unset		 ARGS((struct tbl *vp));
int 	isassign	 ARGS((char *s));
char **	makenv		 ARGS((void));
/* version.c */
/* vi.c */
void 	vi_reset	 ARGS((char *buf, int len));
int 	vi_hook		 ARGS((int ch));
int 	save_cbuf	 ARGS((void));
int 	restore_cbuf	 ARGS((void));
int 	x_vi		 ARGS((char *buf, size_t len));
int 	getch		 ARGS((void));
char **	globstr		 ARGS((char *stuff));


./pdksh/sh/sigact.h   644    653   1762        3662  5243743611  11452 0ustar  hlu/* NAME:
 *      sigact.h - sigaction et al
 *
 * SYNOPSIS:
 *      #include <signal.h>
 *      #ifndef  SA_NOCLDSTOP
 *      # include "sigact.h"
 *      #endif
 *
 * DESCRIPTION:
 *      This header is the interface to a fake sigaction(2) implementation.  
 *      Do NOT include this header unless your system does not 
 *      have a real sigaction(2) implementation.
 */
/*
 * $Log: ksh4.7.tar,v $
 * Revision 1.1.1.1  2019/05/29 04:56:40  root
 * coherent
 *
 * Revision 1.2  1992/04/24  15:04:11  sjg
 * now compiles with cc
 *
 * Revision 1.1  1992/04/24  12:01:38  sjg
 * Initial revision
 *
 */

#ifndef _SIGACT_H
#define _SIGACT_H

#ifndef ARGS
# if defined(__STDC__)
#   define ARGS(p) p
# else
#   define ARGS(p) ()
# endif
#endif
#ifndef __STDC__
# define volatile			/* can change without warning */
# define const				/* read only */
#endif

#ifndef SIGKILL
# include <signal.h>
#endif
#ifndef SA_NOCLDSTOP
/* sa_flags */
#define	SA_NOCLDSTOP	0x0001		/* don't send SIGCHLD on child stop */
#define SA_RESTART	0x0002		/* re-start I/O */

/* sigprocmask flags */
#define	SIG_BLOCK	0x0001
#define	SIG_UNBLOCK	0x0002
#define	SIG_SETMASK	0x0004

#ifndef __sys_stdtypes_h
typedef int sigset_t;
#endif

struct sigaction
{
  void		(*sa_handler)();
  sigset_t	sa_mask;
  int		sa_flags;
};


int	sigaction	ARGS(( int sig, struct sigaction *act, struct sigaction *oact ));
int	sigaddset	ARGS(( sigset_t *mask, int sig ));
int	sigdelset	ARGS(( sigset_t *mask, int sig ));
int	sigemptyset	ARGS(( sigset_t *mask ));
int	sigfillset	ARGS(( sigset_t *mask ));
int	sigismember	ARGS(( sigset_t *mask, int sig ));
int	sigpending	ARGS(( sigset_t *set ));
int	sigprocmask	ARGS(( int how, sigset_t *set, sigset_t *oldset ));
int	sigsuspend	ARGS(( sigset_t *mask ));

#ifndef sigmask
#define sigmask(m)	(1<<((m)-1))	/* convert SIGnum to mask */
#endif
#if !defined(NSIG) && defined(_NSIG)
# define NSIG _NSIG
#endif
#endif /* ! SA_NOCLDSTOP */
#endif /* _SIGACT_H */
/*
 * Local Variables:
 * version-control:t
 * comment-column:40
 * End:
 */
./pdksh/sh/sigact.c   644    653   1762       13042  5243743636  11465 0ustar  hlu/* NAME:
 *      sigact.c - fake sigaction(2)
 *
 * SYNOPSIS:
 *      #include <signal.h>
 *      #ifndef  SA_NOCLDSTOP
 *      # include "sigact.h"
 *      #endif
 * 
 *      int sigaction(int sig, struct sigaction *act, 
 *                      struct sigaction *oact);
 *      int sigaddset(sigset_t *mask, int sig);
 *      int sigdelset(sigset_t *mask, int sig);
 *      int sigemptyset(sigset_t *mask);
 *      int sigfillset(sigset_t *mask);
 *      int sigismember(sigset_t *mask, int sig);
 *      int sigpending(sigset_t *set);
 *      int sigprocmask(int how, sigset_t *set, sigset_t *oldset);
 *      int sigsuspend(sigset_t *mask);
 *
 * DESCRIPTION:
 *      This is a fake sigaction implementation.  It uses 
 *      sigset(2) if available, otherwise it just uses 
 *      signal(2).  If it thinks sigaction(2) really exists it 
 *      compiles to almost nothing.
 *      
 *      The need for all this is the problems caused by mixing 
 *      signal handling routines in the one process.  This 
 *      module allows for a consistent POSIX compliant interface 
 *      to whatever is available.
 *
 * RETURN VALUE:
 *      0==success, -1==failure
 *
 * FILES:
 *      None.
 *
 * SEE ALSO:
 *      
 *
 * BUGS:
 *      Since we fake most of this, don't expect fancy usage to 
 *      work.
 *      
 * COPYRIGHT:
 *      @(#)Copyright (c) 1992 Simon J. Gerraty
 *
 *      This is free software.  It comes with NO WARRANTY.
 *      Permission to use, modify and distribute this source code 
 *      is granted subject to the following conditions.
 *      1/ that that the above copyright notice and this notice 
 *      are preserved in all copies and that due credit be given 
 *      to the author.  
 *      2/ that any changes to this code are clearly commented 
 *      as such so that the author does get blamed for bugs 
 *      other than his own.
 *      
 *      Please send copies of changes and bug-fixes to:
 *      [email protected]
 *
 */
#ifndef lint
static char  *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif
/*
 * $Log: ksh4.7.tar,v $
 * Revision 1.1.1.1  2019/05/29 04:56:40  root
 * coherent
 *
 * Revision 1.5  1992/05/03  08:29:10  sjg
 * Update for Patch05
 *
 * Revision 1.4  1992/04/29  06:29:13  sjg
 * avoid use of #pragma
 *
 * Revision 1.3  1992/04/26  11:24:43  sjg
 * USE_SIGSET corrected in sigsuspend().
 *
 * Revision 1.2  1992/04/24  15:04:11  sjg
 * now compiles with cc
 *
 * Revision 1.1  1992/04/24  12:03:58  sjg
 * Initial revision
 *
 */

#include <signal.h>

/*
 * some systems have a faulty sigaction() implementation!
 * Allow us to bypass it.
 */
#if !defined(SA_NOCLDSTOP) || defined(USE_SIGNAL) || defined(USE_SIGSET) || defined(USE_SIGMASK)

/*
 * if we haven't been told,
 * try and guess what we should implement with.
 */
#if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL)
# if defined(sigmask) || defined(BSD) || defined(_BSD) && !defined(BSD41)
#   define USE_SIGMASK
# else
#   ifndef NO_SIGSET
#     define USE_SIGSET
#   else
#     define USE_SIGNAL
#   endif
# endif
#endif
/*
 * if we still don't know, we're in trouble
 */
#if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL)
error must know what to implement with
#endif

#include "sigact.h"



int
sigaction(sig, act, oact)
  int sig;
  struct sigaction *act, *oact;
{
  void (*oldh)();

  if (act)
  {
#ifdef USE_SIGSET
    oldh = sigset(sig, act->sa_handler);
#else
    oldh = signal(sig, act->sa_handler);
#endif
  }
  else
  {
    if (oact)
    {      
#ifdef USE_SIGSET
      oldh = sigset(sig, SIG_IGN);
#else
      oldh = signal(sig, SIG_IGN);
#endif
      if (oldh != SIG_IGN)
      {
#ifdef USE_SIGSET
	(void) sigset(sig, oldh);
#else
	(void) signal(sig, oldh);
#endif
      }
    }
  }
  if (oact)
  {
    oact->sa_handler = oldh;
  }
  return 0;				/* hey we're faking it */
}

int
sigaddset(mask, sig)
  sigset_t *mask;
  int sig;
{
  *mask |= sigmask(sig);
  return 0;
}


int
sigdelset(mask, sig)
  sigset_t *mask;
  int sig;
{
  *mask &= ~(sigmask(sig));
  return 0;
}


int
sigemptyset(mask)
  sigset_t *mask;
{
  *mask = 0;
  return 0;
}


int
sigfillset(mask)
  sigset_t *mask;
{
  *mask = ~0;
  return 0;
}


int
sigismember(mask, sig)
  sigset_t *mask;
  int sig;
{
  return ((*mask) & sigmask(sig));
}


int
sigpending(set)
  sigset_t *set;
{
  return 0;
}


int
sigprocmask(how, set, oldset)
  int how;
  sigset_t *set, *oldset;
{
#ifdef USE_SIGSET
  register int i;
#endif
  sigset_t sm;

#ifdef USE_SIGMASK
  sm = sigblock(0);
#else
  sm = 0;
#endif
  
  if (oldset)
    *oldset = sm;	/* dangerous ? */
  if (set)
  {
    switch (how)
    {
    case SIG_BLOCK:
      sm |= *set;
      break;
    case SIG_UNBLOCK:
      sm &= ~(*set);
      break;
    case SIG_SETMASK:
      sm = *set;
      break;
    }
#ifdef USE_SIGMASK
    (void) sigsetmask(sm);
#else
# ifdef USE_SIGSET
    for (i = 1; i < NSIG; i++)
    {
      if (how == SIG_UNBLOCK)
      {
	if (*set & sigmask(i))
	  sigrelse(i);
      }
      else
	if (sm & sigmask(i))
	{
	  sighold(i);
	}
    }
# endif
#endif
  }
  return 0;
}


int
sigsuspend(mask)
  sigset_t *mask;
{
#ifdef USE_SIGSET
  int sig = SIGCHLD;			/* our default */
  
  /*
   * add as many tests as you think sensible, but
   * SIGALRM, and SIGCHLD are probably the most
   * common.
   */
  if (*mask & sigmask(SIGALRM))
    sig = SIGALRM;
  else
    if (*mask & sigmask(SIGPIPE))
      sig = SIGPIPE;
  sigpause(sig);
#else
# ifdef USE_SIGMASK
  sigpause(mask);
# else
  pause();
# endif
#endif
  return 0;
}

#endif /* ! SA_NOCLDSTOP */


/* This lot (for GNU-Emacs) goes at the end of the file. */
/* 
 * Local Variables:
 * version-control:t
 * comment-column:40
 * End:
 */
./pdksh/sh/trap.c.new   644    653   1762        7771  5302640172  11730 0ustar  hlu/*
 * signal handling
 */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include "sh.h"

Trap sigtraps [SIGNALS] = {
	{0,	"EXIT", "Signal 0"}, /* todo: belongs in e.loc->exit */
	{SIGHUP, "HUP", "Hangup"},
	{SIGINT, "INT", "Interrupt"},
	{SIGQUIT, "QUIT", "Quit"},
	{SIGILL, "ILL", "Illegal instruction"},
	{SIGTRAP, "TRAP", "Trace trap"},
#ifdef	SIGABRT
	{SIGIOT, "ABRT", "Abort"},
#else
	{SIGIOT, "IOT", "IOT instruction"},
#endif
#ifdef SIGEMT
	{SIGEMT, "EMT", "EMT trap"},
#endif
	{SIGFPE, "FPE", "Floating exception"},
	{SIGKILL, "KILL", "Killed"},
#ifdef SIGUSR1
	{SIGUSR1, "USR1", "User defined signal 1"},
#endif
	{SIGSEGV, "SEGV", "Memory fault"},
#ifdef SIGUSR2
	{SIGUSR2, "USR2", "User defined signal 2"},
#endif
#ifdef SIGBUS
	{SIGBUS, "BUS", "Bus error"},
#endif
#ifdef SIGSYS
	{SIGSYS, "SYS", "Bad system call"},
#endif
	{SIGPIPE, "PIPE", "Broken pipe"},
	{SIGALRM, "ALRM", "Alarm clock"},
	{SIGTERM, "TERM", "Terminated"},
#ifdef SIGSTKFLT
	{SIGSTKFLT, "STKFLT", "Stack fault"},
#endif
#ifdef SIGCHLD
	{SIGCHLD, "CHLD", "Waiting children"},
#else
	{SIGCLD, "CLD", "Death of a child"},
#endif
#ifdef SIGPWR
	{SIGPWR, "PWR", "Power-fail restart"},
#endif
#ifdef SIGTSTP /* todo: need to be more portable */
	{SIGTSTP, "TSTP", "Stop"},
#endif
	{SIGTTIN, "TTIN", "Stop (tty input)"},
#ifdef SIGPOLL
	{SIGPOLL, "POLL", "Pollable event occured"},
#endif
#ifdef SIGSTOP
	{SIGSTOP, "STOP", "Stop (signal)"},
#endif
#ifdef SIGTTOU
	{SIGTTOU, "TTOU", "Stop (tty output)"},
#endif
#ifdef SIGCONT
	{SIGCONT, "CONT", "Continue"},
#endif
#if defined(SIGURG) && (SIGURG != SIGPOLL)
	{SIGURG, "URG", "Urgent condition"}, /* BSDism */
#endif
#ifdef SIGWINCH
	{SIGWINCH, "WINCH", "Window changed"},
#endif
};

Trap *
gettrap(name)
	char *name;
{
	int i;
	register Trap *p;

	if (digit(*name)) {
		i = getn(name);
		return (0 <= i && i < SIGNALS) ? &sigtraps[getn(name)] : NULL;
	}
#if 0
	if (strcmp("ERR", name) == 0)
		return &e.loc->err;
	if (strcmp("EXIT", name) == 0)
		return &e.loc->exit;
#endif
	for (p = sigtraps, i = SIGNALS; --i >= 0; p++)
		if (p->name != NULL && strcmp(p->name, name) == 0)
			return p;
	return NULL;
}

/*
 * trap signal handler
 */
void
trapsig(i)
	int i;
{
	trap = sigtraps[i].set = 1;
	if (i == SIGINT && (e.type == E_PARSE || e.type == E_LOOP))
		/* dangerous but necessary to deal with BSD silly signals */
		longjmp(e.jbuf, 1);
#ifdef USE_SIGACT
	sigaction(i, &Sigact_trap, NULL);
#else
	(void) signal(i, trapsig);
#endif
}

/*
 * run any pending traps
 */
runtraps()
{
	int i;
	register Trap *p;

	for (p = sigtraps, i = SIGNALS; --i >= 0; p++)
		if (p->set)
			runtrap(p);
	trap = 0;
}

runtrap(p)
	Trap *p;
{
	char *trapstr;

	p->set = 0;
	if ((trapstr = p->trap) == NULL)
		if (p->signal == SIGINT)
			unwind();	/* return to shell() */
		else
			return;
	if (p->signal == 0)	/* ??? */
		p->trap = 0;
	command(trapstr);
}
 
/* restore signals for children */
cleartraps()
{
	int i;
	register Trap *p;

	if ((p = sigtraps)->trap != NULL) {	/* Maybe put in exchild() */
		afree((void *)p->trap,APERM);	/* Necessary? */
		p->trap = NULL;
	}
	for (i = SIGNALS, p = sigtraps; --i >= 0; p++) {
		p->set = 0;
#ifdef USE_SIGACT
		if (p->ourtrap)
		{
		  sigaction(p->signal, &Sigact_ign, &Sigact);
		  if (Sigact.sa_handler != SIG_IGN)
		    sigaction(p->signal, &Sigact_dfl, NULL);
		}
#else
		if (p->ourtrap && signal(p->signal, SIG_IGN) != SIG_IGN)
			(void) signal(p->signal, SIG_DFL);
#endif
	}
}

ignoresig(i)
	int i;
{
#ifdef USE_SIGACT
  sigaction(i, &Sigact_ign, &Sigact);
  sigemptyset(&Sigact.sa_mask);
  Sigact.sa_flags = 0;

  if (Sigact.sa_handler != SIG_IGN)
    sigtraps[i].sig_dfl = 1;
#else
  if (signal(i, SIG_IGN) != SIG_IGN)
    sigtraps[i].sig_dfl = 1;
#endif
}

restoresigs()
{
	int i;
	register Trap *p;

	for (p = sigtraps, i = SIGNALS; --i >= 0; p++)
		if (p->sig_dfl) {
			p->sig_dfl = 0;
#ifdef USE_SIGACT
			sigaction(p->signal, &Sigact_dfl, NULL);
#else
			(void) signal(p->signal, SIG_DFL);
#endif
		}
}

./pdksh/sh/makefile.linux   644    653   1762       13043  5302764171  12677 0ustar  hlu# PD Bourne/Korn Shell
# $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $

SHELL = /bin/sh
MAKE  = make

LN    = ln -s

# You _can_ build this shell without the ../std tree if your
# system provides a sufficiently POSIX environment, or if your
# BSD system is a Sun or close.  If not try ../std.

# gcc is good value on most mc68k's and sun386's if nothing else.
# if you don't have gcc cc should do
# CC=gcc -pipe
CC=gcc -V ss-921113 -b i386-linux

# The following are the defintions used (or thereabouts) 
# to build ksh without ../std
#
# sun386 SunOS 4.0.2, sun3 SunOS 4.0.3
# CONFIG=-D_BSD
# XOPTS=-DNOSTDHDRS
# copy these from ../std/stdc or ensure they are in libstdc.a
# XOBJS = memmove.o strstr.o 
#
# sun3  SunOS 4.1.1
# CONFIG=-D_BSD
# XOPTS=-DNOSTDHDRS
# copy these from ../std/stdc or ensure they are in libstdc.a
# XOBJS = memmove.o
#
# sun4c (sparc) SunOS 4.1.1
# CC=cc -pipe	# don't use gcc
# CONFIG=-D_BSD
# XOPTS=-DNOSTDHDRS
# copy these from ../std/stdc or ensure they are in libstdc.a
# XOBJS = memmove.o
#
# Bull DPX/2 B.O.S. 2.00.45
# CC=gcc -ansi
# CONFIG=-D_POSIX_SOURCE
# XOPTS=
# XOBJS=
#
# Minix-386 1.5.10 with estdio
# CONFIG= -D_BSD -D_MINIX -D_POSIX_SOURCE
# XOPTS=
# XOBJS=
#
# BSD/386
# CONFIG= -D_BSDI -D_POSIX_TERM -D_POSIX_SOURCE
# XOPTS=
# XOBJS=

# Linux, mmap () is not complete.
CONFIG= -D_SYSV -D_POSIX_TERM -DNO_MMAP
#CONFIG= -D_SYSV
#CONFIG= -D_BSD -DHAVE_SYS_STDTYPES
#CONFIG= -D_BSD -DCOMPLEX_HISTORY


STD=../std
INCL=$(STD)/h
XINCL=-I$(INCL)
LDOPTS=-L$(STD)
XOBJS=

# use -O if you trust it :-)
DBG=-Wall -O2 -fomit-frame-pointer -s
CFLAGS = $(DBG) $(CONFIG) $(XINCL) $(XOPTS)

LDFLAGS = $(DBG) $(LDOPTS)

#COMPATLIBS = -lstdc -lposix
#XLIBS = -lc_s
#XLIBS = -ldirent
LDLIBS = $(COMPATLIBS) $(XLIBS)

HDRS =	sh.h table.h expand.h lex.h tree.h tty.h trace.h
SRCS1 =	version.c main.c misc.c trap.c alloc.c io.c \
	syn.c lex.c edit.c emacs.c vi.c history.c tree.c 
SRCS2 =	exec.c jobs.c \
	c_sh.c c_ksh.c c_test.c getopts.c do_ulimit.c \
	var.c table.c eval.c expr.c mail.c sigact.c trace.c
SRCS =	Makefile $(HDRS) $(SRCS1) $(SRCS2) 

OBJS =	version.o main.o misc.o \
	syn.o lex.o edit.o emacs.o vi.o tree.o \
	exec.o jobs.o trap.o \
	c_sh.o c_ksh.o c_test.o \
	do_ulimit.o getopts.o expr.o history.o \
	var.o table.o alloc.o io.o eval.o mail.o sigact.o trace.o $(XOBJS)

ksh: $(OBJS) 
	$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

clean:
	rm -f *.o *.out core

clobber: clean
	rm -f ksh

link:
	($(SHELL) ../std/mklinks ../std/h stdh.h)
	

depend:
	makedepend $(CFLAGS) $(SRCS1) $(SRCS2)

install:
	@echo "Try:"
	@echo "cp ksh /bin"
	@echo "strip /bin/ksh"
	@echo "chmod 555 /bin/ksh"

.c.s:
	$(CC) $(CFLAGS) -S -o $@ $<

asms: $(OBJS:.o=.s)


# DO NOT DELETE THIS LINE -- make depend depends on it.
# If this runs make out of memory, delete /usr/include lines.
alloc.o: alloc.c
alloc.o: config.h
alloc.o: sh.h
alloc.o: stdh.h
alloc.o: trace.h
c_ksh.o: c_ksh.c
c_ksh.o: config.h
c_ksh.o: sh.h
c_ksh.o: stdh.h
c_ksh.o: table.h
c_ksh.o: trace.h
c_sh.o: c_sh.c
c_sh.o: config.h
c_sh.o: lex.h
c_sh.o: sh.h
c_sh.o: stdh.h
c_sh.o: table.h
c_sh.o: trace.h
c_sh.o: tree.h
c_test.o: c_test.c
c_test.o: config.h
c_test.o: sh.h
c_test.o: stdh.h
c_test.o: trace.h
edit.o: config.h
edit.o: edit.c
edit.o: edit.h
edit.o: lex.h
edit.o: sh.h
edit.o: stdh.h
edit.o: trace.h
edit.o: tty.h
emacs.o: config.h
emacs.o: edit.h
emacs.o: emacs.c
emacs.o: expand.h
emacs.o: lex.h
emacs.o: sh.h
emacs.o: stdh.h
emacs.o: table.h
emacs.o: trace.h
emacs.o: tree.h
eval.o: config.h
eval.o: eval.c
eval.o: expand.h
eval.o: lex.h
eval.o: sh.h
eval.o: stdh.h
eval.o: table.h
eval.o: trace.h
eval.o: tree.h
exec.o: config.h
exec.o: exec.c
exec.o: lex.h
exec.o: sh.h
exec.o: stdh.h
exec.o: table.h
exec.o: trace.h
exec.o: tree.h
expr.o: config.h
expr.o: expr.c
expr.o: sh.h
expr.o: stdh.h
expr.o: table.h
expr.o: trace.h
getopts.o: config.h
getopts.o: getopts.c
getopts.o: sh.h
getopts.o: stdh.h
getopts.o: table.h
getopts.o: trace.h
history.o: config.h
history.o: history.c
history.o: lex.h
history.o: sh.h
history.o: stdh.h
history.o: trace.h
io.o: config.h
io.o: io.c
io.o: sh.h
io.o: stdh.h
io.o: trace.h
jobs.o: config.h
jobs.o: jobs.c
jobs.o: sh.h
jobs.o: stdh.h
jobs.o: trace.h
jobs.o: tree.h
lex.o: config.h
lex.o: expand.h
lex.o: lex.c
lex.o: lex.h
lex.o: sh.h
lex.o: stdh.h
lex.o: table.h
lex.o: trace.h
lex.o: tree.h
mail.o: config.h
mail.o: mail.c
mail.o: sh.h
mail.o: stdh.h
mail.o: table.h
mail.o: trace.h
main.o: config.h
main.o: lex.h
main.o: main.c
main.o: sh.h
main.o: stdh.h
main.o: table.h
main.o: trace.h
main.o: tree.h
memmove.o: memmove.c
memmove.o: stdh.h
misc.o: config.h
misc.o: expand.h
misc.o: misc.c
misc.o: sh.h
misc.o: stdh.h
misc.o: trace.h
strstr.o: stdh.h
strstr.o: strstr.c
syn.o: config.h
syn.o: expand.h
syn.o: lex.h
syn.o: sh.h
syn.o: stdh.h
syn.o: syn.c
syn.o: table.h
syn.o: trace.h
syn.o: tree.h
sigact.o: sigact.h sigact.c
table.o: config.h
table.o: sh.h
table.o: stdh.h
table.o: table.c
table.o: table.h
table.o: trace.h
times.o: times.c
trace.o: trace.c
trap.o: config.h
trap.o: sh.h
trap.o: stdh.h
trap.o: trace.h
trap.o: trap.c
tree.o: config.h
tree.o: sh.h
tree.o: stdh.h
tree.o: trace.h
tree.o: tree.c
tree.o: tree.h
do_ulimit.o: config.h
do_ulimit.o: sh.h
do_ulimit.o: stdh.h
do_ulimit.o: trace.h
do_ulimit.o: do_ulimit.c
var.o: config.h
var.o: expand.h
var.o: sh.h
var.o: stdh.h
var.o: table.h
var.o: trace.h
var.o: var.c
version.o: config.h
version.o: sh.h
version.o: stdh.h
version.o: trace.h
version.o: version.c
vi.o: config.h
vi.o: edit.h
vi.o: expand.h
vi.o: lex.h
vi.o: sh.h
vi.o: stdh.h
vi.o: table.h
vi.o: trace.h
vi.o: tree.h
vi.o: vi.c
# WARNING: Put nothing here or make depend will gobble it up!
./pdksh/std/  2755    653   1762           0  5302550313  10131 5ustar  hlu./pdksh/std/posix/  2755    653   1762           0  5302550303  11272 5ustar  hlu./pdksh/std/posix/io.h   644    653   1762        3017  5243743535  12130 0ustar  hlu/* POSIX IO functions */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * the incomplete type "struct stat"
 * will get warnings from GCC,
 * errors from Turbo C. Too bad.
 */

/* include <unistd.h> to get this */

#if ! _IO_H
#define	_IO_H	1

#include <unistd.h>

#if _ST				/* dLibs hack */
#define	unlink	remove
#endif

struct stat;			/* create global incompletely-typed structure */

int chdir ARGS ((const char *path));
#ifndef sparc
int umask ARGS ((int mode));
#endif

int open ARGS ((const char *path, int flags, ... /*mode*/));
int creat ARGS ((const char *path, int mode));
int pipe ARGS ((int pv[2]));
int close ARGS ((int fd));

int fcntl ARGS ((int fd, int cmd, int arg));
int dup ARGS ((int fd));
int dup2 ARGS ((int ofd, int nfd));

int link ARGS ((const char *opath, const char *npath));
int unlink ARGS ((const char *path));
int rename ARGS ((const char *opath, const char *npath));
int mkdir ARGS ((const char *path, int mode));

long lseek ARGS ((int fd, long off, int how));
int read ARGS ((int fd, char *buf, unsigned len));
int write ARGS ((int fd, char *buf, unsigned len));

int access ARGS ((const char *path, int mode));
int stat ARGS ((const char *path, struct stat *sp));
int fstat ARGS ((int fd, struct stat *sp));

int chmod ARGS ((const char *path, int mode));
int chown ARGS ((const char *path, int uid));
int chgrp ARGS ((const char *path, int gid));
int utime ARGS ((const char *path, long tv[2]));

#if _BSD || _V7
int ioctl ARGS ((int fd, int cmd, void *argp)); /* BSD is "uns long cmd" */
#endif

#endif
./pdksh/std/posix/Makefile   644    653   1762        1760  5243743532  13010 0ustar  hlu# POSIX P1003.1 compatability
# $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $

SHELL = /bin/sh
MAKE  = make

#CONFIG = -D_SYSV
CONFIG = -D_BSD

LN = ln
RANLIB = ranlib		# For BSD systems
#RANLIB = echo Updated

LIB = ../libposix.a
INCL = ../h

CFLAGS = $(CCOPTS) -I$(INCL) $(CONFIG)

MISC =	Makefile 
HDRS =	io.h unistd.h fcntl.h dirent.h 
SYSHDRS = wait.h time.h times.h

SRCS =	unistd.c fcntl.c times.c dup2.c
OBJS =	$(LIB)(unistd.o) \
	$(LIB)(fcntl.o) \
	$(LIB)(times.o) \
	$(LIB)(dup2.o)

all:	$(LIB)

link:	$(HDRS)
	[ -d $(INCL) ] || mkdir $(INCL)
	[ -d $(INCL)/sys ] || mkdir $(INCL)/sys
	($(SHELL) ../mklinks $(INCL) $(HDRS))
	($(SHELL) ../mklinks $(INCL)/sys $(SYSHDRS))
	-if [ -r /usr/include/unistd.h ]; then $(RM) $(INCL)/unistd.h; fi 

$(LIB):	$(OBJS)
# if you make doesn't know how to put objects in libraries
# then simply make all the .o's and use the following line
#	ar r $@ $?
	$(RANLIB) $@

clean:
	-rm -f *.o *.out

clobber: clean
	-rm -f $(LIB)

fcntl.o: fcntl.h 

times.o: times.h 
./pdksh/std/posix/dirent.C   644    653   1762        2105  5243743532  12733 0ustar  hlu/*
 * simple implementation of directory(3) routines for V7 and Minix.
 * completly untested. not designed to be efficient.
 * missing telldir and seekdir.
 */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <sys/types.h>
#include <dirent.h>

char	*malloc();

#define	DIRSIZ	14
struct	direct_v7
{
	unsigned short	d_ino;
	char	d_name[DIRSIZ];
};

DIR *opendir(filename)
	char *filename;
{
	DIR *dirp;

	dirp = (DIR *) malloc(sizeof(DIR));
	if (dirp == NULL)
		return NULL;
	dirp->fd = open(filename, 0);
	if (dirp->fd < 0) {
		free((char *) dirp);
		return NULL;
	}
	return dirp;
}

struct dirent *readdir(dirp)
	register DIR *dirp;
{
	static	struct direct_v7 ent;

	while (read(dirp->fd, (char *)&ent, (int)sizeof(ent)) == sizeof(ent))
		if (ent.d_ino != 0)
			goto found;
	return (struct dirent *) NULL;
 found:
	dirp->ent.d_ino = ent.d_ino;
	strncpy(dirp->ent.d_name, ent.d_name, DIRSIZ);
	return &dirp->ent;
}

void rewinddir(dirp)
	DIR *dirp;
{
	lseek(dirp->fd, 0L, 0);
}

closedir(dirp)
	DIR *dirp;
{
	close(dirp->fd);
	dirp->fd = -1;
	free((char *) dirp);
	return 0;
}
./pdksh/std/posix/dirent.H   644    653   1762        1650  5243743533  12745 0ustar  hlu/*
	<sys/dirent.h> -- file system independent directory entry (SVR3)

	last edit:	25-Apr-1987	D A Gwyn
	last hack:	14-Aug-1987	Eric Gisin

	prerequisite:	<sys/types.h>
*/
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#define	MAXNAMLEN	16		/* maximum filename length */

struct dirent				/* data from getdents()/readdir() */
	{
	long		d_ino;		/* inode number of entry */
	off_t		d_off;		/* offset of disk directory entry */
	unsigned short	d_reclen;	/* length of this record */
	char	d_name[MAXNAMLEN];	/* name of file */
};

#ifndef NAME_MAX
#define	NAME_MAX	(MAXNAMLEN - 1)	/* DAG -- added for POSIX */
#endif

typedef struct {			/* returned by opendir() */
	int	fd;
	struct dirent ent;
} DIR;

extern DIR		*opendir();
extern struct dirent	*readdir();
extern off_t		telldir();
extern void		seekdir();
extern void		rewinddir();
extern int		closedir();

#ifndef NULL
#define	NULL	0			/* DAG -- added for convenience */
#endif
./pdksh/std/posix/fcntl.c   644    653   1762         745  5243743534  12606 0ustar  hlu/* fcntl emulation */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#if _V7

#include <sgtty.h>

int
fcntl(fd, cmd, arg)
	int fd, cmd, arg;
{
	switch (cmd) {
	  case F_SETFD:		/* set fd flags */
		ioctl(fd, (arg&FD_CLEXEC) ? FIOCLEX : FIONCLEX, (char *)NULL);
		break;
	  case F_DUPFD:		/* dup fd */
		/* this one is fun. find an unused fd >= arg and dup2 */
		break;
	}
	return 0;
}

#endif

./pdksh/std/posix/fcntl.h   644    653   1762         753  5243743534  12612 0ustar  hlu/* P1003.1 fcntl/open definitions */
/* Based on a version by Terrence W. Holm */
/*  for fcntl(2)  */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#define	F_DUPFD		0
#define	F_GETFD		1
#define	F_SETFD		2
#define	F_GETFL		3
#define	F_SETFL		4

#define	FD_CLEXEC	1		/* fcntl F_SETFD close on exec mode */

/*  for open(2)  */

#define	O_RDONLY	0
#define	O_WRONLY	1
#define	O_RDWR		2

#if _BSD
#undef	O_RDONLY
#undef	O_WRONLY
#undef	O_RDWR
#include "/./usr/include/fcntl.h"
#endif

./pdksh/std/posix/fixincludes   644    653   1762        1437  5243742777  13623 0ustar  hlu# Install modified versions of certain ANSI-incompatible system header files
# which are fixed to work correctly with ANSI C
# and placed in a directory that GNU C will search.
# This works properly on a Sun in system version 3.4;
# for other versions, you had better check.

mkdir /usr/local/lib/gcc-include
mkdir /usr/local/lib/gcc-include/sys
cp /usr/include/sys/ioctl.h /usr/local/lib/gcc-include/sys/ioctl.h
chmod +w /usr/local/lib/gcc-include/sys/ioctl.h
ex /usr/local/lib/gcc-include/sys/ioctl.h <<\EOF
g/_IO/s/(\(.\),/('\1',/
g/#define._IO/s/'x'/x/g
wq
EOF

cp /usr/include/sys/ttychars.h /usr/local/lib/gcc-include/sys/ttychars.h
chmod +w /usr/local/lib/gcc-include/sys/ttychars.h
ex /usr/local/lib/gcc-include/sys/ttychars.h <<\EOF
g/CTRL/s/(\(.\))/('\1')/
g/#define.CTRL/s/'c'/c/g
wq
EOF
./pdksh/std/posix/times.c   644    653   1762        2235  5243743536  12637 0ustar  hlu/* P1003.1 times emulation */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <sys/times.h>

#if _BSD

#include <sys/time.h>
#include <sys/resource.h>

static	long base_tv_sec = 0;

clock_t
times(tmsp)
	register struct tms *tmsp;
{
	struct timeval tv;
	struct rusage ru;

	getrusage(RUSAGE_SELF, &ru);
	tmsp->tms_utime = ru.ru_utime.tv_sec*CLK_TCK
		+ (long)ru.ru_utime.tv_usec*CLK_TCK/1000000;
	tmsp->tms_stime = ru.ru_stime.tv_sec*CLK_TCK
		+ (long)ru.ru_stime.tv_usec*CLK_TCK/1000000;
	getrusage(RUSAGE_CHILDREN, &ru);
	tmsp->tms_cutime = ru.ru_utime.tv_sec*CLK_TCK
		+ (long)ru.ru_utime.tv_usec*CLK_TCK/1000000;
	tmsp->tms_cstime = ru.ru_stime.tv_sec*CLK_TCK
		+ (long)ru.ru_stime.tv_usec*CLK_TCK/1000000;

	gettimeofday(&tv, (struct timezone *)NULL);
	if (base_tv_sec == 0)
		base_tv_sec = tv.tv_sec;
	tv.tv_sec -= base_tv_sec; /*  prevent clock_t overflow */
	return tv.tv_sec*CLK_TCK + (long)tv.tv_usec*CLK_TCK/1000000;
}

#endif

#if _V7

clock_t
times(tmsp)
	struct tms *tmsp;
{
	struct timeb tb;

#undef times			/* access real times() */
	times(tmsp);
#define times times_
	ftime(&tb);
	return tb.time*CLK_TCK + (long)tb.millitm*CLK_TCK/1000;
}

#endif

./pdksh/std/posix/times.h   644    653   1762         632  5243743536  12623 0ustar  hlu/*
 * sys/times.h: POSIX times()
 */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#if ! _TIMES_H
#define	_TIMES_H 1

#include <time.h>		/* defines CLK_TCK */

#if __STDC__
#define	ARGS(args)	args
#else
#define	ARGS(args)	()
#endif

struct tms {
	clock_t	tms_utime, tms_stime;
	clock_t	tms_cutime, tms_cstime;
};

#if _V7
#define times times_
#endif

clock_t	times ARGS((struct tms *tmsp));

#endif

./pdksh/std/posix/unistd.c   644    653   1762        1032  5243743537  13017 0ustar  hlu/* misc. POSIX emulation */

#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

#if _V7 || _BSD

char *
getcwd(buf, len)
	char *buf;
	size_t len;
{
	char cwd [1024];
	extern char *getwd();
	if (getwd(cwd) == NULL)
		return NULL;
	if (strlen(cwd)+1 >= len) {
		errno = ERANGE;
		return NULL;
	}
	return strcpy(buf, cwd);
}

#endif

#if _V7

long
ulimit(cmd, limit)
	int cmd;
	long limit;
{
	return 0;
}

#endif

./pdksh/std/posix/unistd.h   644    653   1762        1506  5243743537  13032 0ustar  hlu/* unistd.h: misc. P1003.1 definitions */
/* Based on a version by Terrence W. Holm */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#if ! _UNISTD_H
#define	_UNISTD_H 1

#include <stddef.h>

/* doesn't really belong here, but the library function need it */
/* todo: use _ARGS, _void, _const */
#if __STDC__
#define	ARGS(args)	args
#define void	void
#define	const	const
#else
#define	ARGS(args)	()
#define	void	char
#define	const
#endif

#include <io.h>			/* POSIX IO functions */

/*  for access(2)  */

#define	R_OK	4
#define	W_OK	2
#define	X_OK	1
#define	F_OK	0

/*  for lockf(2)  */

#define	F_ULOCK	0
#define	F_LOCK	1
#define	F_TLOCK	2
#define	F_TEST	3

/*  for lseek(2)  */

#define	SEEK_SET	0
#define	SEEK_CUR	1
#define	SEEK_END	2

#define	IN_PATH	"/usr/include"

char   *getcwd ARGS ((char *buf, size_t len));

#endif

./pdksh/std/posix/wait.h   644    653   1762        2231  5243743540  12456 0ustar  hlu/*
 * POSIX <sys/wait.h>
 */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */
#if __STDC__
#define	ARGS(args)	args
#else
#define	ARGS(args)	()
#endif

#ifdef HAVE_SYS_STDTYPES
# include <sys/stdtypes.h>
#else
# ifndef _PID_T
#   define _PID_T
typedef int pid_t;		/* belong in sys/types.h */
# endif
#endif

#ifdef sun
# include "/./usr/include/sys/wait.h"
#else

#define WAIT_T int

/* waitpid options */
#define WNOHANG		1	/* don't hang in wait */
#define WUNTRACED	2	/* tell about stopped, untraced children */

#define	WSTOPPED	0x7F	/* process is stopped */

#define WIFSTOPPED(x)	(((x)&0xFF) == 0x7F)
#define WIFSIGNALED(x)	(((x)&0xFF) != 0x7F && ((x)&0x7F) != 0)
#define WIFEXITED(x)	(((x)&0xFF) != 0x7F && ((x)&0x7F) == 0)
#define	WIFCORED(x)	(!!((x)&0x80)) /* non-standard */
#define	WEXITSTATUS(x)	((x)>>8&0xFF)
#define	WTERMSIG(x)	((x)&0x7F)
#define	WSTOPSIG(x)	((x)>>8&0xFF)

pid_t wait ARGS((int *statp));
#if _BSD
pid_t wait3 ARGS((int *statp, int options, void *));
/* todo: does not emulate pid argument */
#define	waitpid(pid, sp, opts)	wait3(sp, opts, (void*)NULL)
#else
pid_t waitpid ARGS((pid_t pid, int *statp, int options));
#endif

#endif /* sparc */
./pdksh/std/posix/dirent.h   644    653   1762         127  5243743024  12756 0ustar  hlu/* <dirent.h> based on BSD <sys/dir.h> */

#include <sys/dir.h>
#define dirent direct

./pdksh/std/posix/dup2.c   644    653   1762         514  5243743533  12343 0ustar  hlu/*
 * Cheap imitation of BSD dup2()
 */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <fcntl.h>

#if _SYSV
int
dup2( oldd, newd )
int	oldd, newd;
{
	int	fd;

	if (fcntl( oldd, F_GETFL, 0 ) < 0)
		return( -1 );

	(void) close( newd );
	fd = fcntl( oldd, F_DUPFD, newd );

	return( (fd > newd) ? -1 : fd );
}
#endif
./pdksh/std/posix/time.h   644    653   1762         510  5243743536  12433 0ustar  hlu/*
 * Replacement for BSD <sys/time.h>
 * because Ultrix screws it up.
 */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

struct timeval {
	long tv_sec;		/* time_t */
	long tv_usec;		/* microsex */
};

struct timezone {
	int tz_minuteswest;	/* of Greenwinch */
	int tz_dsttime;		/* type of dst correction to apply */
};
./pdksh/std/posix/ChangeLog   644    653   1762         305  5243743531  13073 0ustar  hluSat Apr 25 14:51:33 1992  Simon J. Gerraty  (sjg@zen)

	* Added RCS keys to sources.

Mon Nov 25 13:17:04 1991  Simon J. Gerraty  (sjg at zen)

	* wait.h: use "/./usr/include/sys/wait.h for sun's

./pdksh/std/stdc/  2755    653   1762           0  5302550312  11065 5ustar  hlu./pdksh/std/stdc/stdio.c   644    653   1762         616  5243743550  12410 0ustar  hlu/*
 * Emulation of misc. ANSI C stdio functions
 */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <stdio.h>

#ifndef __STDC__
#define const
#define volatile
#endif

#if 1
int
remove(name)
	const char *name;
{
	return unlink(name);
}
#endif

#if _V7
int
rename(oname, nname)
	const char *oname, *nname;
{
	return link(oname, nname) == 0 && unlink(oname) == 0 ? 0 : -1;
}
#endif

./pdksh/std/stdc/vprintf.c   644    653   1762       12004  5243743642  13012 0ustar  hlu#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <stdio.h>

#define	BUF	40		/* buffer for int -> string conversion */

int
#ifdef __STDC__
vprintf(const char *fmt, va_list va) {
#else
vprintf(fmt, va) char *fmt; va_list va; {
#endif
	return vfprintf(stdout, fmt, va);
}

int
#ifdef __STDC__
vfprintf(register FILE *f, register const char *fmt, register va_list va) {
#else
vfprintf(f, fmt, va) register FILE *f; register char *fmt; register va_list va; {
#endif
	register int c;
	int pos = 0;			/* todo: implement */

	while ((c = *fmt++))
	    if (c == '%') {
		long n;
		register unsigned long u;
		char buf [BUF+1];
		register char *p = buf + BUF;
		register enum {
			FF_ALT = 0x01, /* #, alternate format */
			FF_SHORT = 0x02, /* h, short arg */
			FF_LONG = 0x04,	/* l, long arg */
			FF_ZERO = 0x08,	/* 0, zero fill */
			FF_LEFT = 0x10,	/* -, left adjust */
			FF_PREC = 0x20,	/* .*, precision */
			FF_NEG = 0x40,	/* signed arg */
			FF_PUTS = 0x80,	/* fputs(p, f) */
			FF_DEFAULT = 0
		} flags = FF_DEFAULT;
		int sign = '-';	/* sign: [ +-] */
		int width = 0, prec = 0; /* width, precision */

		*p = 0;

		/* scan flag characters */
		for (c = *fmt++; ; c = *fmt++) switch (c) {
		  case '0':
			flags |= FF_ZERO;
			break;

		  case '#':		/* alternate format */
			flags |= FF_ALT;
			break;

		  case ' ':		/* blank sign */
			sign = ' ';
			break;
		  case '+':		/* +/- sign */
			sign = '+';
			break;

		  case '-':		/* left just. */
			flags |= FF_LEFT;
			break;

		  default:
			goto Frogs;
		}
	  Frogs:

		/* scan width */
	  	if (c == '*') {		/* width from arg list */
			width = va_arg(va, int);
			c = *fmt++;
		} else
			while ('0' <= c && c <= '9') {
				width = width*10 + (c-'0');
				c = *fmt++;
			}

		if (c == '.') {		/* scan precision */
			flags |= FF_PREC;
			c = *fmt++;
			if (c == '*') {	/* precision from arg list */
				prec = va_arg(va, int);
				c = *fmt++;
			} else
				while ('0' <= c && c <= '9') {
					prec = prec*10 + (c-'0');
					c = *fmt++;
				}
		}

		/* length modifiers */
		if (c == 'h') {
			flags |= FF_SHORT;
			c = *fmt++;
		} else if (c == 'l') {
			flags |= FF_LONG;
			c = *fmt++;
		}

		/* do conversion */
		switch (c) {
		  case '%':		/* %% -> % */
			putc(c, f);
			pos ++;
			break;

		  case 'p':		/* pointer */
			*--p = '}';
			u = (unsigned long) va_arg(va, void*);
			do {
				*--p = "0123456789ABCDEF"[u%16];
				u /= 16;
			} while (u != 0);
			*--p = '{';
			flags |= FF_PUTS;
			break;

		  case 'n':		/* save position */
			*va_arg(va, int*) = pos;
			break;

		  case 'c':		/* character */
			u = (flags&FF_SHORT) ? va_arg(va, unsigned short)
			  : (flags&&FF_LONG) ? va_arg(va, unsigned long)
			  : va_arg(va, unsigned int);
			*--p = u;
			flags |= FF_PUTS;
			break;

		  case 's':		/* string */
			if ((p = va_arg(va, char *)) == NULL)
			  p = "";
			if ((flags&FF_PREC) && strlen(p) > prec) {
				pos += prec;
				while (--prec >= 0)
				{
				  c = *p++;
				  putc(c, f);
				}
				break;
			}
			flags |= FF_PUTS;
			break;

		  case 'i': case 'd': case 'u': /* decimal */
			if (c != 'u') {	/* signed */
				n = (flags&FF_SHORT) ? va_arg(va, short)
				  : (flags&&FF_LONG) ? va_arg(va, long)
				  : va_arg(va, int);
				if (n < 0)
					flags |= FF_NEG;
				u = (n < 0) ? -n : n;
			} else
				u = (flags&FF_SHORT) ? va_arg(va, unsigned short)
				  : (flags&&FF_LONG) ? va_arg(va, unsigned long)
				  : va_arg(va, unsigned int);
			do {
				*--p = '0' + u%10;
				u /= 10;
			} while (u != 0);
			prec -= buf+BUF - p;
			while (--prec >= 0)
				*--p = '0';
			if (flags&FF_NEG)
				*--p = '-';
			else
				if (sign != '-')
					*--p = (sign == '+') ? '+' : ' ';
			flags |= FF_PUTS;
			break;

		  case 'x': case 'X':	/* hex, Hex */
			u = (flags&FF_SHORT) ? va_arg(va, unsigned short)
			  : (flags&&FF_LONG) ? va_arg(va, unsigned long)
			  : va_arg(va, unsigned int);
			do {
				*--p = "0123456789ABCDEF"[u%16];
				u /= 16;
			} while (u != 0);
			prec -= buf+BUF - p;
			while (--prec >= 0)
				*--p = '0';
			if (flags&&FF_ALT)
				*--p = 'x', *--p = '0';
			flags |= FF_PUTS;
			break;

		  case 'o':		/* octal */
			u = (flags&FF_SHORT) ? va_arg(va, unsigned short)
			  : (flags&&FF_LONG) ? va_arg(va, unsigned long)
			  : va_arg(va, unsigned int);
			do {
				*--p = '0' + u%8;
				u /= 8;
			} while (u != 0);
			prec -= buf+BUF - p;
			while (--prec >= 0)
				*--p = '0';
			if (flags&&FF_ALT && *p != '0')
				*--p = '0';
			flags |= FF_PUTS;
			break;

		  default:		/* todo: error */
			putc('%', f);
			putc(c, f);
			pos += 2;
			break;
		}

		/* copy adjusted string "p" to output */
		if (flags&FF_PUTS) {
			int len = strlen(p);
			int pad = width - len;
			if (!(flags&FF_LEFT))
				while (--pad >= 0)
					putc((flags&FF_ZERO) ? '0' : ' ', f);
			while (c = *p++)
				putc(c, f);
			if ((flags&FF_LEFT))
				while (--pad >= 0)
					putc(' ', f);
			pos += (len < width) ? width : len;
		}
	    } else {			/* ordinary character */
		putc(c, f);
		pos ++;
	    }
	return pos;
}

./pdksh/std/stdc/stdio.h_std   644    653   1762        4356  5243743642  13316 0ustar  hlu/*
 * ANSI stream IO
 *
 * Heavily dependent on /usr/include/stdio.h being AT&T derived.
 * todo: needs L_* constants.
 */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#if ! _STDIO_H
#define	_STDIO_H 1

#include <stddef.h>

/* system stdio.h goes here ... %%% */
/* ... end system stdio.h */
#line 15 "stdio.h"

#ifndef _IOFBF
#define	_IOFBF	00000
#endif
#ifndef _IOLBF
#define	_IOLBF	00000		/* same as _IOFBF */
#endif

#define	SEEK_SET	0
#define	SEEK_CUR	1
#define	SEEK_END	2

#if _SYSV
#define	_EXTERN	extern
#else
#define	_EXTERN	
#endif

_EXTERN	int	remove ARGS((const char *name));
_EXTERN	int	rename ARGS((const char *oname, const char *nname));
_EXTERN	FILE   *tmpfile ARGS((void));
_EXTERN	char   *tmpnam ARGS((char *s));

_EXTERN	FILE   *fopen ARGS((const char *name, const char *mode));
_EXTERN	FILE   *freopen ARGS((const char *name, const char *mode, FILE *f));
_EXTERN	FILE   *fdopen ARGS((int fd, const char *mode));
_EXTERN	int	fflush ARGS((FILE *f));
_EXTERN	int	fclose ARGS((FILE *f));
_EXTERN	void	setbuf ARGS((FILE *f, char *buf));
_EXTERN	int	setvbuf ARGS((FILE *f, char *buf, int flags, size_t len));

_EXTERN	int	fseek ARGS((FILE *f, long off, int how));
_EXTERN	long	ftell ARGS((FILE *f));
_EXTERN	void	rewind ARGS((FILE *f));

_EXTERN	int	printf ARGS((const char *fmt, ...));
_EXTERN	int	fprintf ARGS((FILE *f, const char *fmt, ...));
_EXTERN	int	sprintf ARGS((char *s, const char *fmt, ...));
/* we do not include <stdarg.h> to prevent <varargs.h> conflicts */
_EXTERN	int	vprintf ARGS((const char *fmt, Void *va));
_EXTERN	int	vfprintf ARGS((FILE *f, const char *fmt, Void *va));
_EXTERN	int	vsprintf ARGS((char *s, const char *fmt, Void *va));
_EXTERN	int	scanf ARGS((const char *fmt, ...));
_EXTERN	int	fscanf ARGS((FILE *f, const char *fmt, ...));
_EXTERN	int	sscanf ARGS((const char *s, const char *fmt, ...));

_EXTERN	size_t	fread ARGS((void *ptr, size_t size, size_t n, FILE *f));
_EXTERN	size_t	frwrite ARGS((const void *ptr, size_t size, size_t n, FILE *f));
_EXTERN	int	fgetc ARGS((FILE *f));
_EXTERN	int	fputc ARGS((int c, FILE *f));
_EXTERN	char   *fgets ARGS((char *s, int len, FILE *f));
_EXTERN	int	fputs ARGS((const char *s, FILE *f));
_EXTERN	char   *gets ARGS((char *s));
_EXTERN	int     puts ARGS((const char *s));

#endif

./pdksh/std/stdc/Makefile   644    653   1762        4401  5243743640  12576 0ustar  hlu# Standard C (ANSI) compatabilaty
# $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $

# edit this makefile such that only the functions that
# your systems doesn't have are provided.

SHELL = /bin/sh
MAKE  = make

#CONFIG = -D_SYSV
CONFIG = -D_BSD

LN = ln
RANLIB = ranlib		# For BSD systems
#RANLIB = echo Updated

LIB = ../libstdc.a
INCL = ../h

CFLAGS = $(CCOPTS) -I$(INCL) $(CONFIG)

MISC =	Makefile #stdio.h_std
HDRS =	limits.h stddef.h stdlib.h string.h time.h #stdarg.h 
SYSHDRS = types.h

SRCS =	strstr.c memmove.c stdio.c clock.c fprintf.c memchr.c \
	memcmp.c memcpy.c memset.c setvbuf.c sprintf.c \
	stdio.c strcat.c strchr.c strcmp.c strcpy.c strcspn.c \
	strerror.c strlen.c strncat.c strncmp.c strncpy.c \
	strpbrk.c strrchr.c strspn.c strtok.c vprintf.c

# only add to this list the modules that you _need_
# some of these are untested!
OBJS =	$(LIB)(strstr.o) \
	$(LIB)(memmove.o) \
	$(LIB)(clock.o) \
#	$(LIB)(vprintf.o) \
#	$(LIB)(fprintf.o) \
#	$(LIB)(sprintf.o) \
#	$(LIB)(strtok.o) \
#	$(LIB)(memchr.o) \
#	$(LIB)(memcmp.o) \
#	$(LIB)(memcpy.o) \
#	$(LIB)(memset.o) \
#	$(LIB)(setvbuf.o) \
#	$(LIB)(strcat.o) \
#	$(LIB)(strchr.o) \
#	$(LIB)(strcmp.o) \
#	$(LIB)(strcpy.o) \
#	$(LIB)(strcspn.o) \
#	$(LIB)(strerror.o) \
#	$(LIB)(strlen.o) \
#	$(LIB)(strncat.o) \
#	$(LIB)(strncmp.o) \
#	$(LIB)(strncpy.o) \
#	$(LIB)(strpbrk.o) \
#	$(LIB)(strrchr.o) \
#	$(LIB)(strspn.o) \
#	$(LIB)(stdio.o) 
#



all:	$(LIB)

link:	$(HDRS) #stdio.h 
	[ -d $(INCL) ] || mkdir $(INCL)
	[ -d $(INCL)/sys ] || mkdir $(INCL)/sys
	($(SHELL) ../mklinks $(INCL) $(HDRS))
	($(SHELL) ../mklinks $(INCL)/sys $(SYSHDRS))
#	($(SHELL) ../mklinks $(INCL) stdio.h)

$(LIB):	$(OBJS)
# if you make doesn't know how to put objects in libraries
# then simply make all the .o's and use the following line
#	ar r $@ $?
	$(RANLIB) $@

stdio.h: stdio.h_std stdio.sed /usr/include/stdio.h 
	sed -f stdio.sed </usr/include/stdio.h >stdio.hacked
	sed <stdio.h_std >stdio.h -e '/%%%/ r stdio.hacked'
	rm stdio.hacked

clean:
	-rm -f *.o *.out stdio.hacked

clobber: clean
	-rm -f $(LIB) stdio.h

string.h: stddef.h

stdlib.h: stddef.h

stdio.h: stddef.h 

time.h: stddef.h

stdio.o: stdio.h

setvbuf.o: stdlib.h stdio.h

fprintf.o: stdarg.h stdio.h

sprintf.o: stdarg.h stdio.h

vprintf.o: stdarg.h stdio.h

strstr.o: string.h 

./pdksh/std/stdc/clock.c   644    653   1762        1337  5243743003  12373 0ustar  hlu/* clock() */

#include <time.h>

#if _BSD

#include <sys/time.h>
#include <sys/resource.h>

clock_t
clock()
{
	struct timeval tv;
	struct rusage ru;

	getrusage(RUSAGE_SELF, &ru);
	tv.tv_sec = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
	tv.tv_usec = ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
	return tv.tv_sec*CLK_TCK + (long)tv.tv_usec*CLK_TCK/1000000;
}

#endif

#if _V7 || _SYSV

#include <sys/times.h>

clock_t
clock()
{
	struct tms tms;

	(void) times(&tms);
	return tms.tms_utime + tms.tms_stime;
}

#endif

#if _ST

#include <osbind.h>

clock_t
clock()
{
	long save;
	clock_t c;

	/* access the ST's 200 HZ system clock in protected memory */
	save = Super(0L);
	c = *((long *)0x04BA);
	(void)Super(save);
	return c;
}

#endif

./pdksh/std/stdc/fprintf.c   644    653   1762        1426  5243743640  12756 0ustar  hlu/*
 * printf and fprintf
 */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <stdio.h>

#if _V7 || _BSD

/* printf to stdout */
int
#ifdef __STDC__
printf(const char *fmt, ...) {
#else
printf(va_alist) va_dcl
{
	char *fmt;
#endif
	va_list va;

#ifdef __STDC__
	va_start(va, fmt);
#else
	va_start(va);
	fmt = va_arg(va, char *);
#endif
	vfprintf(stdout, fmt, va);
	va_end(va);
	return 0;
}

int
#ifdef __STDC__
fprintf(FILE *f, const char *fmt, ...) {
#else
fprintf(va_alist) va_dcl
{
	FILE *f;
	char *fmt;
#endif
	va_list va;

#ifdef __STDC__
	va_start(va, fmt);
#else
	va_start(va);
	f = va_arg(va, FILE *);
	fmt = va_arg(va, char *);
#endif
	vfprintf(f, fmt, va);
	va_end(va);
	return 0;
}

#endif
./pdksh/std/stdc/limits.h   644    653   1762        1727  5243743004  12612 0ustar  hlu/* Implementation-defined limits */

#if __STDC__
#define	Signed	signed
#else
#define	Signed	
#endif

#define	CHAR_BIT	8

#define	_S_MIN(type)	(-(Signed type)((unsigned type) ~0 >> 1) - 1)
#define	_S_MAX(type)	((Signed type)((unsigned type) ~0 >> 1))

#define	UCHAR_MIN	((unsigned char) 0)
#define	UCHAR_MAX	((unsigned char) ~0)
#define	SCHAR_MIN	_S_MIN(char)
#define	SCHAR_MAX	_S_MAX(char)

/* some PCC compilers don't like the "elegant" definition of _UCHAR */
/* let the poor user provide -D_UCHAR=0 or 1 */
#ifndef _UCHAR
#define	_UCHAR		((char) ~0 == (unsigned char) ~0)
#endif
#define	CHAR_MIN	(_UCHAR ? UCHAR_MIN : SCHAR_MIN)
#define	CHAR_MAX	(_UCHAR ? UCHAR_MAX : SCHAR_MAX)

#define	USHRT_MAX	((unsigned short) ~0)
#define	SHRT_MIN	_S_MIN(short)
#define	SHRT_MAX	_S_MAX(short)

#define	UINT_MAX	((unsigned int) ~0)
#define	INT_MIN		_S_MIN(int)
#define	INT_MAX		_S_MAX(int)

#define	ULONG_MAX	((unsigned long) ~0)
#define	LONG_MIN	_S_MIN(long)
#define	LONG_MAX	_S_MAX(long)

./pdksh/std/stdc/memcmp.c   644    653   1762         617  5243743544  12550 0ustar  hlu/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <string.h>

int
memcmp(dap, sap, n)
	const void *dap;
	const void *sap;
	register size_t n;
{
	register const unsigned char *dp = (unsigned char const *) dap;
	register const unsigned char *sp = (unsigned char const *) sap;

	if (n++ > 0)
		while (--n > 0)
			if (*dp++ != *sp++)
				return *--dp - *--sp; /* (int)? */
	return 0;
}

./pdksh/std/stdc/memmove.c   644    653   1762         570  5243743545  12736 0ustar  hlu/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include "stdh.h"

void *
memmove(dap, sap, n)
	void *dap;
	const void *sap;
	register size_t n;
{
	register char *dp = dap, *sp = (void*) sap;

	if (n <= 0)
		;
	else if (dp < sp)
		do *dp++ = *sp++; while (--n > 0);
	else if (dp > sp) {
		dp += n;
		sp += n;
		do *--dp = *--sp; while (--n > 0);
	}
	return dap;
}


./pdksh/std/stdc/setvbuf.c   644    653   1762        2077  5243743546  12774 0ustar  hlu/*
 * PD ksh needs an ANSI-compatible setvbuf.
 * if (buf == NULL) it must also allocate a buffer
 * and arrange for fclose to deallocate it.
 * the reason for doing setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ)
 * in the shell is to avoid 4/8K buffers on BSD like systems.
 */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <stdlib.h>
#include <stdio.h>

#if _BSD || _SYSV
int
setvbuf(f, buf, type, size)
	register FILE *f;
	char *buf;
	int type;
	size_t size;
{
	if ((f->_flag&_IOMYBUF) && f->_base != NULL)
		free(f->_base);
	f->_flag &= ~(_IOMYBUF|_IONBF|_IOFBF|_IOLBF);
	switch (type) {
	  case _IONBF:
		size = 0;
		buf = NULL;
		break;
	  case _IOLBF:
	  case _IOFBF:
		if (size == 0)
			size = BUFSIZ;
#if _V7
		else if (size != BUFSIZ)
			return -1;
#endif
		if (buf == NULL) {
			buf = malloc(size);
			if (buf == NULL)
				return -1;
			f->_flag |= _IOMYBUF;
		}
		break;
	  default:
		return -1;
	}
	f->_flag |= type;
	f->_base = f->_ptr = buf;
	f->_cnt = 0;
#if _BSD
	f->_bufsiz = size;
#endif
#if _SYSV
	_bufend(f) = buf + size;
#endif
	return 0;
}
#endif

./pdksh/std/stdc/sprintf.c   644    653   1762        1522  5243743641  12771 0ustar  hlu/*
 * sprintf and vsprintf
 */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <stdio.h>

#if _V7 || _BSD

int
#ifdef __STDC__
sprintf(char *s, const char *fmt, ...) {
#else
sprintf(va_alist) va_dcl
{
	char *s;
	char *fmt;
#endif
	register va_list va;
	int n;

#ifdef __STDC__
	va_start(va, fmt);
#else
	va_start(va);
	s = va_arg(va, char *);
	fmt = va_arg(va, char *);
#endif
	n = vsprintf(s, fmt, va);
	va_end(va);
	return n;
}

int
#ifdef __STDC__
vsprintf(char *s, const char *fmt, va_list va) {
#else
vsprintf(s, fmt, va)
	char *s;
	char *fmt;
	va_list va;
{
#endif
	int n;
	static FILE siob;

	siob._flag = _IOWRT;
	siob._base = siob._ptr = s;
	siob._cnt = BUFSIZ;
	siob._file = -1;

	n = vfprintf(&siob, fmt, va);
	*siob._ptr = 0;
	return n;
}

#endif

./pdksh/std/stdc/stdarg.h   644    653   1762        1331  5243743547  12600 0ustar  hlu/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */
/* DON'T USE THIS IF YOUR COMPILER HAS ITS OWN!!! */

#ifndef _STDARG_H
#define _STDARG_H

typedef char *va_list;

/* Amount of space required in an argument list for an arg of type TYPE.
   TYPE may alternatively be an expression whose type is used.  */

#define __va_rounded_size(TYPE)  \
  (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

#define va_start(AP, LASTARG) 						\
 (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))

void va_end (va_list);		/* Defined in gnulib */
#define va_end(AP)

#define va_arg(AP, TYPE)						\
 (AP += __va_rounded_size (TYPE),					\
  *((TYPE *) (AP - __va_rounded_size (TYPE))))

#endif /* _STDARG_H */
./pdksh/std/stdc/stddef.h   644    653   1762        1347  5243743547  12574 0ustar  hlu/* ANSI common definitions */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#ifndef NULL
#if __STDC__
#define	NULL	(void*)0
#else
#define	NULL	0
#endif
#endif

#ifndef _STDDEF_H
#define	_STDDEF_H

/* doesn't really belong here, but the library function need it */
#ifndef ARGS
# ifdef  __STDC__
#   define ARGS(args) args
# else
#   define ARGS(args) ()
#   ifdef VOID
#     define void VOID
#   endif
#   define const
#   define volatile
# endif
#endif

#ifdef HAVE_SYS_STDTYPES
# include <sys/stdtypes.h>
#else
typedef unsigned size_t;		/* may need long */
typedef int ptrdiff_t;
#endif /* HAVE_SYS_STDTYPES */
#define	offsetof(type,id) ((size_t)&((type*)NULL)->id)

extern	int errno;		/* really belongs in <errno.h> */

#endif

./pdksh/std/stdc/stdio.sed   644    653   1762        1324  5243743011  12746 0ustar  hlu/^#[ 	]*include/d
/^#[ 	]*define[ 	]*NULL/d
/remove[ 	]*([ 	]*)/d
/rename[ 	]*([ 	]*)/d
/tmpfile[ 	]*([ 	]*)/d
/tmpnam[ 	]*([ 	]*)/d
/fopen[ 	]*([ 	]*)/d
/freopen[ 	]*([ 	]*)/d
/fdopen[ 	]*([ 	]*)/d
/fflush[ 	]*([ 	]*)/d
/fclose[ 	]*([ 	]*)/d
/setbuf[ 	]*([ 	]*)/d
/setvbuf[ 	]*([ 	]*)/d
/fseek[ 	]*([ 	]*)/d
/ftell[ 	]*([ 	]*)/d
/rewind[ 	]*([ 	]*)/d
/printf[ 	]*([ 	]*)/d
/fprintf[ 	]*([ 	]*)/d
/sprintf[ 	]*([ 	]*)/d
/vprintf[ 	]*([ 	]*)/d
/vfprintf[ 	]*([ 	]*)/d
/vsprintf[ 	]*([ 	]*)/d
/scanf[ 	]*([ 	]*)/d
/fscanf[ 	]*([ 	]*)/d
/sscanf[ 	]*([ 	]*)/d
/fread[ 	]*([ 	]*)/d
/frwrite[ 	]*([ 	]*)/d
/fgetc[ 	]*([ 	]*)/d
/fputc[ 	]*([ 	]*)/d
/fgets[ 	]*([ 	]*)/d
/fputs[ 	]*([ 	]*)/d
/gets[ 	]*([ 	]*)/d
/puts[ 	]*([ 	]*)/d
./pdksh/std/stdc/stdlib.h   644    653   1762        2110  5243743550  12563 0ustar  hlu/* ANSI utility functions */

/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#if ! _STDLIB_H
#define	_STDLIB_H 1

#include <stddef.h>

double	atof ARGS((const char *s));
int	atoi ARGS((const char *s));
long	atol ARGS((const char *s));
double	strtod ARGS((const char *s, char **));
long	strtol ARGS((const char *s, char **, int base));
unsigned long	strtoul ARGS((const char *s, char **, int base));
int	rand ARGS((void));
void	srand ARGS((unsigned int seed));
void   *malloc ARGS((size_t size));
void   *realloc ARGS((void *ptr, size_t size));
void   *calloc ARGS((size_t n, size_t size));
void	free ARGS((void *ptr));
void	abort ARGS((void));
int	atexit ARGS((void (*func)(void)));
void	exit ARGS((int status));
char   *getenv ARGS((const char *name));
int	system ARGS((const char *cmd));
void   *bsearch ARGS ((const void *key, const void *base, size_t n, size_t size,
		       int (*compar)(const void *, const void *)));
void   *qsort ARGS ((const void *base, size_t n, size_t size,
		     int (*compar)(const void *, const void *)));
#define	abs(a)	((a) < 0 : -(a) : (a))

#endif

./pdksh/std/stdc/strchr.c   644    653   1762         737  5243743551  12600 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strchr - find first occurrence of a character in a string
 */

char *				/* found char, or NULL if none */
strchr(s, charwanted)
const char *s;
register char charwanted;
{
	register const char *scan;

	/*
	 * The odd placement of the two tests is so NUL is findable.
	 */
	for (scan = s; *scan != charwanted;)	/* ++ moved down for opt. */
		if (*scan++ == '\0')
			return(NULL);
	return(scan);
}
./pdksh/std/stdc/strcmp.c   644    653   1762        1456  5243743552  12623 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/* Modified by Eric Gisin */

/*
 * strcmp - compare string s1 to s2
 */

int				/* <0 for <, 0 for ==, >0 for > */
strcmp(s1, s2)
const char *s1;
const char *s2;
{
	register const char *scan1;
	register const char *scan2;
#if 0				/* some machines prefer int to char */
	register int c1, c2;
#else
	register char c1, c2;
#endif

	scan1 = s1;
	scan2 = s2;
	while ((c1 = *scan1++) == (c2 = *scan2++) && c1 != 0)
		;

	/*
	 * The following case analysis is necessary so that characters
	 * which look negative collate low against normal characters but
	 * high against the end-of-string NUL.
	 */
	if (c1 == '\0' && c2 == '\0')
		return(0);
	else if (c1 == '\0')
		return(-1);
	else if (c2 == '\0')
		return(1);
	else
		return(c1 - c2);
}
./pdksh/std/stdc/strcspn.c   644    653   1762        1014  5243743554  12777 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strcspn - find length of initial segment of s consisting entirely
 * of characters not from reject
 */

size_t
strcspn(s, reject)
const char *s;
const char *reject;
{
	register const char *scan;
	register const char *rscan;
	register size_t count;

	count = 0;
	for (scan = s; *scan != '\0'; scan++) {
		for (rscan = reject; *rscan != '\0';)	/* ++ moved down. */
			if (*scan == *rscan++)
				return(count);
		count++;
	}
	return(count);
}
./pdksh/std/stdc/string.h   644    653   1762        2401  5243743555  12620 0ustar  hlu/* ANSI string handling (missing wide char stuff) */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#if ! _STRING_H
#define _STRING_H 1

#include <stddef.h>		/* define NULL and size_t */

#ifndef __GNUC__
void   *memcpy ARGS((void *s1, const void *s2, size_t));
int	memcmp ARGS((const void *s1, const void *s2, size_t));
size_t	strlen ARGS((const char *s));
#endif
void   *memmove ARGS((void *s1, const void *s2, size_t));
void   *memchr ARGS((const void *s, int c, size_t));
void   *memset ARGS((void *s, int c, size_t));
char   *strcpy ARGS((char *s1, const char *s2));
char   *strncpy ARGS((char *s1, const char *s2, size_t));
char   *strcat ARGS((char *s1, const char *s2));
char   *strncat ARGS((char *s1, const char *s2, size_t));
int	strcmp ARGS((const char *s1, const char *s2));
int	strncmp ARGS((const char *s1, const char *s2, size_t));
char   *strchr ARGS((const char *s1, int c));
char   *strrchr ARGS((const char *s1, int c));
size_t	strspn ARGS((const char *s1, const char *s2));
size_t	strcspn ARGS((const char *s1, const char *s2));
char   *strpbrk ARGS((const char *s1, const char *s2));
char   *strstr ARGS((const char *s1, const char *s2));
char   *strtok ARGS((char *s1, const char *s2));
char   *strerror ARGS((int errno));

#endif /* _STRING_H */

./pdksh/std/stdc/strncat.c   644    653   1762         744  5243743556  12754 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strncat - append at most n characters of string src to dst
 */
char *				/* dst */
strncat(dst, src, n)
char *dst;
const char *src;
size_t n;
{
	register char *dscan;
	register const char *sscan;
	register size_t count;

	for (dscan = dst; *dscan != '\0'; dscan++)
		continue;
	sscan = src;
	count = n;
	while (*sscan != '\0' && --count >= 0)
		*dscan++ = *sscan++;
	*dscan++ = '\0';
	return(dst);
}
./pdksh/std/stdc/strncmp.c   644    653   1762        1503  5243743556  12776 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strncmp - compare at most n characters of string s1 to s2
 */

int				/* <0 for <, 0 for ==, >0 for > */
strncmp(s1, s2, n)
const char *s1;
const char *s2;
size_t n;
{
	register const char *scan1;
	register const char *scan2;
	register size_t count;

	scan1 = s1;
	scan2 = s2;
	count = n;
	while (--count >= 0 && *scan1 != '\0' && *scan1 == *scan2) {
		scan1++;
		scan2++;
	}
	if (count < 0)
		return(0);

	/*
	 * The following case analysis is necessary so that characters
	 * which look negative collate low against normal characters but
	 * high against the end-of-string NUL.
	 */
	if (*scan1 == '\0' && *scan2 == '\0')
		return(0);
	else if (*scan1 == '\0')
		return(-1);
	else if (*scan2 == '\0')
		return(1);
	else
		return(*scan1 - *scan2);
}
./pdksh/std/stdc/strncpy.c   644    653   1762         723  5243743557  12776 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strncpy - copy at most n characters of string src to dst
 */
char *				/* dst */
strncpy(dst, src, n)
char *dst;
const char *src;
size_t n;
{
	register char *dscan;
	register const char *sscan;
	register size_t count;

	dscan = dst;
	sscan = src;
	count = n;
	while (--count >= 0 && (*dscan++ = *sscan++) != '\0')
		continue;
	while (--count >= 0)
		*dscan++ = '\0';
	return(dst);
}
./pdksh/std/stdc/strpbrk.c   644    653   1762         744  5243743560  12760 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strpbrk - find first occurrence of any char from breakat in s
 */

char *				/* found char, or NULL if none */
strpbrk(s, breakat)
const char *s;
const char *breakat;
{
	register const char *sscan;
	register const char *bscan;

	for (sscan = s; *sscan != '\0'; sscan++) {
		for (bscan = breakat; *bscan != '\0';)	/* ++ moved down. */
			if (*sscan == *bscan++)
				return(sscan);
	}
	return(NULL);
}
./pdksh/std/stdc/strrchr.c   644    653   1762         730  5243743560  12753 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strrchr - find last occurrence of a character in a string
 */

char *				/* found char, or NULL if none */
strrchr(s, charwanted)
const char *s;
register char charwanted;
{
	register const char *scan;
	register const char *place;

	place = NULL;
	for (scan = s; *scan != '\0'; scan++)
		if (*scan == charwanted)
			place = scan;
	if (charwanted == '\0')
		return(scan);
	return(place);
}
./pdksh/std/stdc/time.h   644    653   1762        2020  5243743562  12243 0ustar  hlu/* time, time/date conversion */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#if ! _TIME_H
#define	_TIME_H 1

#include <stddef.h>		/* need size_t */

#ifndef HAVE_SYS_STDTYPES
#ifndef _TIME_T
typedef long time_t;
#endif
typedef long clock_t;		/* seconds/CLK_TCK */
#endif

#if _V7 || _SYSV
#define	CLK_TCK	60		/* todo: get from <sys/param.h> */
#endif

#if _BSD
#define	CLK_TCK	100
#endif

#if _ST
#define	CLK_TCK	200		/* ST system clock */
#endif

struct tm {
	int	tm_sec, tm_min, tm_hour;
	int	tm_mday, tm_mon, tm_year, tm_wday, tm_yday;
	int	tm_isdst;
	long	tm_gmtoff;	/* BSD */
	char   *tm_zone;	/* BSD */
};

clock_t	clock ARGS((void));
time_t	time ARGS((time_t *tp));
#define	difftime(t1, t2)	(double)((t2)-(t1))
time_t	mktime ARGS((struct tm *tmp));
char   *asctime ARGS((const struct tm *tmp));
char   *ctime ARGS((const time_t *tp));
struct tm *gmtime ARGS((const time_t *tp));
struct tm *localtime ARGS((const time_t *tp));
size_t	strftime ARGS((char *buf, size_t len, const char *fmt, const struct tm *tmp));

#endif

./pdksh/std/stdc/strspn.c   644    653   1762        1033  5243743560  12632 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strspn - find length of initial segment of s consisting entirely
 * of characters from accept
 */

size_t
strspn(s, accept)
const char *s;
const char *accept;
{
	register const char *sscan;
	register const char *ascan;
	register size_t count;

	count = 0;
	for (sscan = s; *sscan != '\0'; sscan++) {
		for (ascan = accept; *ascan != '\0'; ascan++)
			if (*sscan == *ascan)
				break;
		if (*ascan == '\0')
			return(count);
		count++;
	}
	return(count);
}
./pdksh/std/stdc/strstr.c   644    653   1762        1260  5243743561  12645 0ustar  hlu#ifndef lint
static char *RCSid = "$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $";
#endif

#include "stdh.h"

/*
 * strstr - find first occurrence of wanted in s
 */

char *				/* found string, or NULL if none */
strstr(s, wanted)
const char *s;
const char *wanted;
{
	register const char *scan;
	register size_t len;
	register char firstc;

	/*
	 * The odd placement of the two tests is so "" is findable.
	 * Also, we inline the first char for speed.
	 * The ++ on scan has been moved down for optimization.
	 */
	firstc = *wanted;
	len = strlen(wanted);
	for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
		if (*scan++ == '\0')
			return(NULL);
	return(scan);
}
./pdksh/std/stdc/strtok.c   644    653   1762        2214  5243743561  12632 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * Get next token from string s (NULL on 2nd, 3rd, etc. calls),
 * where tokens are nonempty strings separated by runs of
 * chars from delim.  Writes NULs into s to end tokens.  delim need not
 * remain constant from call to call.
 */

static char *scanpoint = NULL;

char *				/* NULL if no token left */
strtok(s, delim)
char *s;
register const char *delim;
{
	register char *scan;
	char *tok;
	register const char *dscan;

	if (s == NULL && scanpoint == NULL)
		return(NULL);
	if (s != NULL)
		scan = s;
	else
		scan = scanpoint;

	/*
	 * Scan leading delimiters.
	 */
	for (; *scan != '\0'; scan++) {
		for (dscan = delim; *dscan != '\0'; dscan++)
			if (*scan == *dscan)
				break;
		if (*dscan == '\0')
			break;
	}
	if (*scan == '\0') {
		scanpoint = NULL;
		return(NULL);
	}

	tok = scan;

	/*
	 * Scan token.
	 */
	for (; *scan != '\0'; scan++) {
		for (dscan = delim; *dscan != '\0';)	/* ++ moved down. */
			if (*scan == *dscan++) {
				scanpoint = scan+1;
				*scan = '\0';
				return(tok);
			}
	}

	/*
	 * Reached end of string.
	 */
	scanpoint = NULL;
	return(tok);
}
./pdksh/std/stdc/types.h   644    653   1762         652  5243743562  12442 0ustar  hlu/* work around multiple typedefs in stddef.h and sys/types.h */
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <stddef.h>		/* defines size_t and ptrdiff_t */
#include <time.h>		/* defines time_t and clock_t */

/* "inhibit" the typedefs in sys/types.h */
#define size_t _size_t
#define	time_t _time_t
#define	clock_t _clock_t
#include "/./usr/include/sys/types.h"
#undef	size_t
#undef	time_t
#undef	clock_t

./pdksh/std/stdc/memchr.c   644    653   1762         412  5243743544  12536 0ustar  hlu/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <string.h>

void *
memchr(ap, c, n)
	const void *ap;
	register int c;
	register size_t n;
{
	register char *p = ap;

	if (n++ > 0)
		while (--n > 0)
			if (*p++ == c)
				return --p;
	return NULL;
}

./pdksh/std/stdc/memcpy.c   644    653   1762         415  5243743545  12561 0ustar  hlu/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <string.h>

void *
memcpy(dap, sap, n)
	void *dap;
	const void *sap;
	register size_t n;
{
	register char *dp = dap, *sp = (void*) sap;

	if (n++ > 0)
		while (--n > 0)
			*dp++ = *sp++;
	return dap;
}

./pdksh/std/stdc/memset.c   644    653   1762         355  5243743545  12564 0ustar  hlu/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

#include <string.h>

void *
memset(ap, c, n)
	void *ap;
	register int c;
	register size_t n;
{
	register char *p = ap;

	if (n++ > 0)
		while (--n > 0)
			*p++ = c;
	return ap;
}

./pdksh/std/stdc/strcat.c   644    653   1762         572  5243743551  12570 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strcat - append string src to dst
 */
char *				/* dst */
strcat(dst, src)
char *dst;
const char *src;
{
	register char *dscan;
	register const char *sscan;

	for (dscan = dst; *dscan != '\0'; dscan++)
		continue;
	sscan = src;
	while ((*dscan++ = *sscan++) != '\0')
		continue;
	return(dst);
}
./pdksh/std/stdc/strcpy.c   644    653   1762         516  5243743553  12614 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strcpy - copy string src to dst
 */
char *				/* dst */
strcpy(dst, src)
char *dst;
const char *src;
{
	register char *dscan;
	register const char *sscan;

	dscan = dst;
	sscan = src;
	while ((*dscan++ = *sscan++) != '\0')
		continue;
	return(dst);
}
./pdksh/std/stdc/strerror.c   644    653   1762         600  5243743554  13145 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strerror - map error number to descriptive string
 *
 * This version is obviously somewhat Unix-specific.
 */
char *
strerror(errno)
int errno;
{
	extern int sys_nerr;
	extern char *sys_errlist[];

	if (errno > 0 && errno < sys_nerr)
		return(sys_errlist[errno]);
	else
		return("unknown error");
}
./pdksh/std/stdc/strlen.c   644    653   1762         451  5243743555  12577 0ustar  hlu#include <string.h>
/* $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ */

/*
 * strlen - length of string (not including NUL)
 */
size_t
strlen(s)
const char *s;
{
	register const char *scan;
	register size_t count;

	count = 0;
	scan = s;
	while (*scan++ != '\0')
		count++;
	return(count);
}
./pdksh/std/stdc/ChangeLog   644    653   1762         644  5243743637  12703 0ustar  hluThu May  7 20:36:40 1992  Simon J. Gerraty  (sjg@zen)

	* fprintf.c: avoid use of #if __STDC__ some compilers don't handle it.

	* vprintf.c: avoid side effects from putc() macro!

Sat Apr 25 14:52:01 1992  Simon J. Gerraty  (sjg@zen)

	* Added RCS keys to sources.

Mon Nov 25 13:19:01 1991  Simon J. Gerraty  (sjg at zen)

	* Added all source modules to Makefile, but most remain commented
	out as they are untested.

./pdksh/std/Makefile   644    653   1762        1563  5243743530  11645 0ustar  hlu#
# Makefile for the compatibility libraries
#
# $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
#

SHELL = /bin/sh
MAKE  = make

#CONFIG = -D_SYSV
CONFIG = -D_BSD

LN = ln

libs:	h libstdc.a libposix.a

h:
	mkdir h
	( cd stdc ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' 'LN=$(LN)' clobber link )
	( cd posix  ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' 'LN=$(LN)' clobber link )
	( cd ../sh ;  $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' 'LN=$(LN)' link )

libstdc.a: FORCED
	( cd stdc ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' all )

libposix.a: FORCED
	( cd posix ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' all )

clean:
	-rm -f *.out
	( cd stdc ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' $@ )
	( cd posix  ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' $@ )

clobber:
	-rm -rf h *.a
	( cd stdc ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' $@ )
	( cd posix  ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' $@ )

FORCED:
./pdksh/std/mklinks   644    653   1762         231  5243743473  11555 0ustar  hlu:
# Make links 
# we do it this way so that we can support symlinks
# easily.

src=`pwd`
cd $1
shift
LN="${LN:-ln}"

for f in $*
do
  $LN $src/$f .
done
./pdksh/PATCHDATES   644    653   1762         167  5243743672  10744 0ustar  hlu# PD ksh Version 4
09-Nov-91
10-Nov-91
25-Nov-91
25-Apr-92
26-Apr-92
27-Apr-92
12-May-92
02-Aug-92
12-Aug-92
25-Apr-92
./pdksh/ksh.1   644    653   1762      101151  5243743650  10317 0ustar  hlu.\" $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $
.nr OJ 1 \" Job Control
.nr OE 1 \" Command Editing
.nr OB 1 \" BSD enhanced ulimit options
.ds OK [\|
.ds CK \|]
.TH KSH 1 "July 1992"
.SH NAME
ksh \- Bourne / Korn Shell (Public Domain)
.SH SYNOPSIS
\fBksh\fP
[\fB\-st\fP] [\fB\-c\fP \fIcommand\fP]
[\fIfile\fP [\fIargument ...\fP]]
.SH INTRODUCTION
This document only summarizes the System V, release 2 shell features.
All of the System V features except for ``restricted mode''
are implemented.
See also the BUGS section.
.LP
Features of the Korn shell are described in more detail.
Only a subset of the Korn shell features are currently implemented.
.SH DESCRIPTION
.SS Command syntax
The ``#'' character begins a one-line comment,
unless the ``#'' occurs inside a word.
The tokens ``;'', ``|'', ``&'', ``;;'', ``||'', ``&&'', ``('', and ``)''
stand by themselves.
A \fIword\fP is a sequence of any other non-whitespace characters,
which may also contain quoted strings
(quote character are ``\''', ``"'', ``\`'',
or a matching ``${ }'' or ``$( )'' pair).
A \fIname\fP is an unquoted word made up of letters, digits, or ``_''.
Any number of whitespace characters (space and tab) may separate words and tokens.
.LP
In the following syntax, { ... }? indicates an optional thing,
{ ... }* indicates zero or more repetitions, { ... | ... } indicates alternatives.
.de S
.br
\\$1
.br
..
.IP statement:
.S "\fB(\fP list \fB)\fP"
.S "\fB{\fP list \fB;\fP \fB}\fP"
.S "\fBfor\fP name { \fBin\fP { word }* }? \fBdo\fP list \fB;\fP \fBdone\fP"
.S "\fBselect\fP name { \fBin\fP { word }* }? \fBdo\fP list \fB;\fP \fBdone\fP"
.S "{ \fBwhile\fP | \fBuntil\fP } list \fB;\fP \fBdo\fP list \fB;\fP \fBdone\fP"
.S "\fBif\fP list \fB;\fP \fBthen\fP list \fB;\fP { \fBelif\fP list \fB;\fP \fBthen\fP list \fB;\fP }* { \fBelse\fP list \fB;\fP }?\fBfi\fP"
.S "\fBcase\fP name \fBin\fP { \fB(\fP word { \fB|\fP word } \fB)\fP list \fB;;\fP }* \fBesac\fP"
.S "\fBfunction\fP name \fB{\fP list \fB;\fP \fB}\fP"
.S "name \fB() {\fP list \fB;\fP \fB}\fP"
.S "\fBtime\fP pipe"
The opening parenthesis of the pattern is optional. 
Redirection may occur at the beginning or end of a statement.
.IP command:
.S "{ name=word }* { word }*"
Redirection may occur anywhere in a command.
.IP list:
.S "cond"
.S "cond \fB;\fP list"
.S "cond \fB&\fP list"
.IP cond:
.S "pipe"
.S "pipe \fB&&\fP cond"
.S "pipe \fB||\fP cond"
.IP pipe:
.S "statement { \fB|\fP statement }*"
.SS The select statement
The \fBselect\fP statement provides an automatic method of presenting the
user with a menu selection from several options.
The \fIwords\fP given in the list are printed on standard error, each
preceded by a number.
Typing the number on standard input sets the variable \fIname\fP to the
word that was selected.
The data that was typed is preserved in a variable called REPLY.
The contents of the loop are then executed using the selected value.
A new prompt PS3 is used to indicate that a number should be typed in
to choose a value from the menu.
.LP
Menus will continue to be presented until an interrupt is received or
end-of-file is typed on input.
.SS Alias expansion
Alias expansion occurs when the first word of a
statement is a defined alias,
except when that alias is already being expanded.
It also occurs after the expansion of an alias whose
definition ends with a space.
.SS Alternation
Csh provides a filename expansion method known as alternation.
This has been added into this version of ksh.
When performing filename subsitution, you can get the shell to create
a set of strings for you. For example, `exampl{a,b,c,d,e}' will expand
to ``exampla examplb examplc exampld example''.
A comma separated set of strings in curly braces 
will be expanded into a set of strings that are passed into the command.
The strings are not sorted.
.SS Shell variables
The following standard special variables exist:
\fB!\fP, \fB#\fP, \fB$\fP, \fB\-\fP, \fB?\fP.
.IP "_"
In interactive use this parameter is set to the last word of
the previous command.  When a command is executed this parameter
is set to the full path of the command and placed in the environment
for the command.  See also \fBMAILPATH\fP.
.IP CDPATH
The search path for the \fIcd\fP command.
.IP ENV
If this variable is set at start-up
(after any profile files are executed),
the expanded value is used as shell start-up file.
It typically contains function and alias definitions.
.IP FCEDIT
The editor used by the \fIfc\fP command.
During startup the shell checks the value of \fBFCEDIT\fP, 
\fBEDITOR\fP and finally \fBVISUAL\fP to try and determin what
command line edit mode to use.  Note that this is not strictly
ksh compatible behaviour.
.IP COLUMNS
The width to use for the commandline editing (emacs mode only).
.IP HISTFILE
The name of the file used to store history.
If defined, history will be loaded from this file on startup.
Also, several invocations of the shell running on the same machine
will share history if their HISTFILE variables all point at the same file.
.IP HISTSIZE
The number of commands normally stored for history, default 128.
.IP HOME
The default directory for the \fIcd\fP command.
.IP IFS
\fIInternal field separator\fP,
used during substitution and the \fIread\fP command.
.IP MAIL
If set, the user will be informed of the arrival of mail
in the named file.  This variable is ignored if
the \fBMAILPATH\fP variable is set.
.IP MAILCHECK
How often, in seconds, the shell will check for mail in the
file(s) specified by \fBMAIL\fP or \fBMAILPATH\fP.  If 0,
the shell checks before each prompt.  The default is 600
seconds.
.IP MAILPATH
A list of files to be checked for mail.  The list is colon
separated, and each file may be followed by a \fB?\fP and
a message to be printed if new mail has arrived.  Command
and parameter substitution is performed on the message, and
the parameter \fB$_\fP is set to the name of the file.
The default message is ``you have mail in $_''.
.IP PATH
The search path for executable commands and \fB.\fP'd files.
.IP PPID
The process number of the parent of the shell.
.IP "PS1 PS2"
\fBPS1\fP is the primary prompt for interactive shells.
Dollar substitution is performed, and \fB!\fP is replaced
with the command number (see \fIfc\fP).
.IP "PWD OLDPWD"
The current and previous working directories.
.IP RANDOM
A random integer.  The random number generator may be seeded
by assigning an integer value to this variable.
.IP SECONDS
The number of seconds since the shell timer was started or
reset.  Assigning an integer value to this variable resets
the timer.
.SS Substitution
In addition to the System Vr2 substitutions,
the following are available.
.IP "$(command)"
Like `command`, but no escapes are recognized.
.IP "$(<file)"
Equivalent to $(cat file), but without forking.
.IP "${#var}"
The length of the string value of \fIvar\fP,
or the number of arguments if \fIvar\fP is \fB*\fP or \fB@\fP.
.IP "${var#pattern} ${var##pattern}"
If \fIpattern\fP matches the beginning of the value of \fIvar\fP,
the matched text is deleted from the result of substitution.
A single \fB#\fP results in the shortest match,
two \fB#\fP's results in the longest match.
.IP "${var%pattern} ${var%%pattern}"
Like \fB#\fP substition, but deleting from the end of the value.
.SS Expressions
Expressions can be used with the \fBlet\fP command,
as numeric arguments to the \fBtest\fP command,
and as the value of an assignment to an integer variable.
.LP
Expression may contain alpha-numeric variable identifiers and integer constants
and may be combined with the following operators:
.IP "== != <= < > >= + - * / % ! ( )"
.SS Command execution
After evaluation of keyword assignments and arguments,
the type of command is determined.
A command may execute a shell function, a shell built-in,
or an executable file.
.LP
Any keyword assignments are then performed according to
the type of command.
In function calls assignments are local to the function.
Assignments in built-in commands marked with a \(dg persist,
otherwise they are temporary.
Assignments in executable commands are exported to the sub-process
executing the command.
.LP
Even on systems where the exec() family does not support #!
notation for scripts, ksh can be configured to fake it.
.LP
There are several built-in commands.
.IP ":"
Only expansion and assignment are performed.
This is the default if a command has no arguments.
.IP ". \fIfile\fP"
Execute the commands in \fIfile\fP without forking.
The file is searched in the directories of $PATH.
Passing arguments is not implemented.
.IP "alias [\fIname\fB=\fIvalue\fI ...]\fR"
Without arguments, \fBalias\fP lists all aliases and their values.
For any name without a value, its value is listed.
Any name with a value defines an alias, see "Alias Expansion" above.
Korn's tracked aliases are not implemented,
but System V command hashing is (see "hash").
.IP "alias -d [\fIname\fB=\fIvalue\fI ...]\fR"
Directory aliases for tilde expansion, eg.
.br
alias -d fac=/usr/local/usr/facilities
.br
cd ~fac/bin
.IP "break [\fIlevels\fP]"
.IP "builtin \fIcommand arg ...\fP"
\fICommand\fP is executed as a built-in command.
.IP "cd [\fIpath\fP]"
Set the working directory to \fIpath\fP.  If the parameter
CDPATH is set, it lists the search path for the directory
containing \fIpath\fP.  A null path means the current directory.
If \fIpath\fP is missing, the home directory ($HOME) is used.
If \fIpath\fP is \fB\-\fP, the previous working directory is used.
If \fIpath\fP is \fB..\fP, the shell changes directory to the
parent directory, as determined from the value of PWD.
The PWD and OLDPWD variables are reset.
.IP "cd \fIold new\fP"
The string \fInew\fP is substituted for \fIold\fP in the current
directory, and the shell attempts to change to the new directory.
.IP "continue [\fIlevels\fP]"
.IP "echo ..."
\fIEcho\fP is replaced with the alias echo='print' in the Korn shell.
.IP "eval \fIcommand ...\fP"
.IP "exec \fIcommand arg ...\fP"
The executable command is executed without forking.
If no arguments are given, any IO redirection is permanent.
.IP "exit [\fIstatus\fP]"
.IP "fc [\fB\-e\fP \fIeditor\fP] [\fB\-lnr\fP] [\fIfirst\fP [\fIlast\fP]]"
\fIFirst\fP and \fIlast\fP select commands.
Commands can be selected by history number,
or a string specifing the most recent command starting with that string.
The \fB\-l\fP option lists the command on stdout,
and \fB\-n\fP inhibits the default command numbers.
The \fB\-r\fP option reverses the order of the list.
Without \fB\-l\fP, the selected commands can be edited by
the editor specified with the \fB\-e\fP option, or if no \fB\-e\fP
is specified,
the \fB$FCEDIT\fP editor, then executed by the shell.
.IP "fc \fB\-e \-\fP [\fB\-g\fP] [\fIold\fB=\fInew\fR] [\fIcommand\fP]"
Re-execute the selected command (the previous command by default)
after performing the optional substitution of \fIold\fP with \fInew\fP.
If \fB\-g\fP is specified, all occurrences of \fIold\fP are
replaced with \fInew\fP.
This command is usually accessed with the predefined alias
r=``fc \-e \-''.
.IP "getopts"
See the attached manual page.
.IP "hash [\fB\-r\fP] [\fIname ...\fP]"
Without arguments, any hashed executable command pathnames are listed.
The \fB\-r\fP flag causes all hashed commands to be removed.
Each \fIname\fP is searched as if it were a command name
and added to the hash table if it is an executable command.
.IP "kill [\fB\-\fIsignal\fR] \fIprocess\fP ..."
Send a signal (TERM by default) to the named process.
The signal may be specified as a number or a mnemonic from <signal.h>
with the SIG prefix removed.
.IP "let [\fIexpression ...\fP]"
Each expression is evaluated, see "Expressions" above.
A zero status is returned if the last expression evaluates
to a non-zero value, otherwise a non-zero status is returned.
Since may expressions need to be quoted, \fI(( expr ))\fP is
syntactic sugar for \fIlet "expr"\fP.
.IP "print [\fB\-nreu\fIn\fR] [\fIargument ...\fP]"
\fBPrint\fP prints its arguments on the standard output,
separated by spaces, and terminated with a newline.
The \fB\-n\fP option eliminates the newline.
.IP
By default, certain C escapes are translated.
These include \eb, \ef, \en, \er, \et, \ev, and \e### (# is an octal digit).
\ec is equivalent to the \fB\-n\fP option.
This expansion may be inhibitted with the \fB\-r\fP option,
and may be re-enabled with the addition of the \fB\-e\fP option.
.IP "read [\fB\-ru\fIn\fR] \fIname ...\fP"
The first variable name may be of the form \fIname\fB?\fIprompt\fR.
.IP "readonly [\fIname ...\fP]"
.IP "return [\fIstatus\fP]"
.ta 5n 10n 30n
.de O
.br
\t\\$1\t\\$2\t\\$3
..
.IP "set [\fB\(+-\fP\fI[a-z]\fP] [\fB\(+-o\fP \fIkeyword\fP] ..."
Set (\fB\-\fP) or clear (\fB+\fP) a shell option:
.O \-a allexport "all new variable are created with export attribute"
.O \-e errexit "exit on non-zero status [incorrect]"
.O "" bgnice "background jobs are run with lower priority"
.if \n(OE \{
.O "" emacs "BRL emacs-like line editing"\}
.O "" ignoreeof "shell will not exit of EOF, must use \fIexit\fP"
.O \-k keyword "variable assignments are recognized anywhere in command"
.O "" markdirs "[not implemented]"
.O \-m monitor "job control enabled (default for interactive shell)"
.O \-n noexec "compile input but do not execute (ignored if interactive)"
.O \-f noglob "don't expand filenames"
.O \-u nounset "dollar expansion of unset variables is an error"
.O \-v verbose "echo shell commands on stdout when compiling"
.O \-h trackall "add command pathnames to hash table"
.O "" vi "VI-like line editing"
.O \-x xtrace "echo simple commands while executing"
.IP "set [\fB\-\-\fP] \fIarg ...\fP"
Set shell arguments.
.IP "shift [\fInumber\fP]"
.IP "test"
See the attached manual page.
.IP "times"
.IP "trap [\fIhandler\fP] [\fIsignal ...\fP]"
.IP "typeset [\fB\(+-irtx\fP] [\fIname\fP[\fB=\fIvalue\fR] ...]"
If no arguments are given, lists all variables and their attributes.
.PP
If options but no names are given, lists variables with specified
attributes, and their values if unless ``+'' is used.
.PP
If names are given, set the attributes of the named variables.
Variables may also be assigned a value.
If used inside a function, the created variable are local to the function.
.PP
The attributes are as follows.
.ta 5n 10n
\t\-i\tThe variable's value is stored as an integer.
.br
\t\-x\tThe variable is exported to the enviroment.
.br
\t\-r\tThe variable is read-only cannot be reassigned a value.
.br
\t\-t\tTrace (not implemented).
.br
\t\-f\tList functions instead of variable.
.\".IP "ulimit [\fB\-f\fP] [\fIvalue\fP]"
.ds OZ <OZ>
.IP "\fBulimit\fP \*(OK \fB\-\*(OZ\fP \*(CK \*(OK \fIn\fP \*(CK"
.RS
.TP "\w'\fB\-\-\ \ \ 'u"
.if \n(OB \{.B \-c
Impose a size limit of
.I n\^
blocks on the size of core dumps.
.TP
.B \-d
Impose a size limit of
.I n\^
blocks on the size of the data area.\}
.TP
.B \-f
Impose a size limit of
.I n
blocks on files written by the shell
and its child processes (files of any size may be read).
.if \n(OB \{.TP
.B \-m
Impose a soft limit of
.I n\^
blocks on the size of physical memory.
.TP
.B \-t
Impose a time limit of
.I n\^
seconds to be used by each process.\}
.PP
If no option is given,
.B \-f
is assumed.
If
.I n
is omitted, the current limit is printed.
As far as
.B ulimit
is concerned, a ``block'' is 512 bytes.
.PP
You may lower your own resource limit,
but only a super-user (see
.IR su (1M))
can raise a limit.
.RE
.IP "umask [\fIvalue\fP]"
.IP "unalias \fIname ...\fP"
The aliases for the given names are removed.
.IP "unset [\fB\-f\fP] \fIname ...\fP"
.IP "wait [\fIprocess-id\fP]"
.IP "whence [\fB\-v\fP] name ..."
For each name, the type of command is listed.
The \fB\-v\fP flag causes function and alias values to be listed.
.SS Job Control
Job control features are enabled by the
\fB\-m\fP or \fB\-o monitor\fP flags.
When job control is enabled, and the system supports job control,
background commands and foreground commands that have been stopped
(usually by a
.SM SIGTSTP
signal generated by typing
.IR ^Z\^ )
are placed into separate individual
.IR "process groups" .
The following commands are used to manipulate these process groups:
.PP
.PD 0
.TP "\w'\fBkill\fP \*(OK \fIjob\fP \*(CK\ \ \ 'u"
\fBjobs\fP
Display information about the controlled jobs.
The job number is given preceeded by a percent sign,
followed by a plus sign if it is the ``current job'',
or by a minus sign if it is the ``previous job'',
then the process group number for the job,
then the command.
.TP
\fBkill\fP [\fB\-\fIsignal\fR] \fIjob\fP ...
Send a signal (TERM by default) to the named job process group.
.TP
\fBfg\fP \*(OK \fIjob\fP \*(CK
Resume the stopped foreground job in the foreground.
If the process group
.I n
is not specified then the ``current job'' is resumed.
.TP
\fBbg\fP \*(OK \fIjob\fP \*(CK
Resume the stopped foreground job in the background.
If the process group
.I n
is not specified then the ``current job'' is resumed.
.PD
.PP
The \fBfg\fP, \fBbg\fP, \fBkill\fP, and \fBwait\fP commands
may refer to jobs with the following ``percent'' sequences.
The percent sign is optional with the fg and bg commands.
.PP
.PD 0
.TP "\w'\fBbg\fP \*(OK \fIn\fP \*(CK\ \ \ 'u"
.BR %+ ( %\- )
If there is a ``current job'' (``previous job''),
then that job is selected.
.TP
.BI % n
If the specified job number is one of the known jobs,
then that job is selected.
.TP
.BI % string
If the string matches the initial part of a job's command,
then that job is selected.
.TP
.BI %? string
As above, but the string may match any portion of the command.
.sp
.PP
If the system does not support job control, monitor mode enables
job reporting.  The jobs and kill commands
functions as above, and you will
be informed when background jobs complete.  Fg and bg are not 
availiable.
.PD
.br
.SS "Interactive Input Line Editing"
When the
.B emacs
option is set,
interactive input line editing is enabled.
This mode is slightly different from the emacs mode in AT&T's KornShell.
In this mode various
.I "editing commands"
(typically bound to one or more control characters)
cause immediate actions without waiting for a new-line.
Several
.I "editing commands"
are bound to particular control characters
when the shell is invoked;
these bindings can be changed using the following commands:
.br
.PP
.PD 0
.TP 2i
\fBbind\fP
The current bindings are listed.
.TP
\fBbind\fP \*(OK \fIstring\fP \*(CK = \*(OK \fIediting-command\fP \*(CK
The specified
.I "editing command\^"
is bound to the given
.IR string ,
which should consist of a control character
(which may be written using ``caret notation'' \fB^\fP\fIx\fP\|),
optionally preceded by one of the two prefix characters.
Future input of the
.I string
will cause the
.I "editing command\^"
to be immediately invoked.
.br
Note that although only two prefix characters (normal ESC and ^X)
are supported, some multi-character sequences can be supported:
.br
bind '^[['=prefix-2
.br
bind '^XA'=up-history
.br
bind '^XB'=down-history
.br
bind '^XC'=forward-char
.br
bind '^XD'=backward-char
.br
will bind the arrow keys on an ANSI terminal, or xterm.  Of course some escape
sequences won't work out quite that nicely.
.TP
\fBbind -m\fP \*(OK \fIstring\fP \*(CK = \*(OK \fIsubstitute\fP \*(CK
The specified input
.I string
will afterwards be immediately replaced by the given
.I substitute
string,
which may contain
.IR "editing commands" .
.PD
.PP
The following
.I "editing commands"
are available;
first the command name is given
followed by its default binding (if any)
using caret notation
(note that the ASCII
.SM ESC
character is written as \s-1^[\s0\|),
then the editing function performed is decribed.
Note that
.I "editing command"
names are used only with the
.B bind
command.
Furthermore,
many
.I "editing commands"
are useful only on terminals with a visible cursor.
The default bindings were chosen to resemble corresponding EMACS key bindings.
The users tty characters (eg. erase) are bound to reasonable
substitutes.
.br
.PP
.PD 0
.TP "\w'\fBdelete-word-backward\ \ ^[\|ERASE\fP\ \ \ 'u"
\fBabort\ \ ^G\fP
Useful as a response to a request for a
.B search-history
pattern in order to abort the search.
.br
.TP
\fBauto-insert\fP
Simply causes the character to appear as literal input.
(Most ordinary characters are bound to this.)
.br
.TP
\fBbackward-char\ \ ^B\fP
Moves the cursor backward one character.
.br
.TP
\fBbackward-word\ \ ^[\|b\fP
Moves the cursor backward to the beginning of a word.
.br
.TP
\fBbeginning-of-line\ \ ^A\fP
Moves the cursor to the beginning of the input line
(after the prompt string).
.br
.TP
\fBcomplete\ \ ^[\|^[\fP
Automatically completes as much as is unique of the hashed command name
or the file name containing the cursor.
If the entire remaining command or file name is unique
a space is printed after its completion,
unless it is a directory name in which case
.B /
is postpended.
If there is no hashed command or file name with the current partial word
as its prefix,
a bell character is output (usually causing a ``beep'').
.br
.TP
\fBcomplete-command\ \ ^X^[\fP
Automatically completes as much as is unique of the hashed command name
having the partial word up to the cursor as its prefix,
as in the
.B complete
command described above.
Only command and function names seen since the last
.B "hash \-r"
command are available for completion;
the
.B "hash"
command may be used to register additional names.
.br
.TP
\fBcomplete-file\ \ ^[\|^X\fP
Automatically completes as much as is unique of the file name
having the partial word up to the cursor as its prefix,
as in the
.B complete
command described above.
.br
.TP
\fBcopy-last-arg\ \ ^[\|_\fP
The last word of the previous command is inserted at the
cursor.  Note I/O redirections do not count as words of
the command.
.br
.TP
\fBdelete-char-backward\ \ ERASE\fP
Deletes the character before the cursor.
.br
.TP
\fBdelete-char-forward\fP
Deletes the character after the cursor.
.br
.TP
\fBdelete-word-backward\ \ ^[\|ERASE\fP
Deletes characters before the cursor back to the beginning of a word.
.br
.TP
\fBdelete-word-forward\ \ ^[\|d\fP
Deletes characters after the cursor up to the end of a word.
.br
.TP
\fBdown-history\ \ ^N\fP
Scrolls the history buffer forward one line (later).
Each input line originally starts just after
the last entry in the history buffer,
so
.B down-history
is not useful until either
.B search-history
or
.B up-history
has been performed.
.br
.TP
\fBend-of-line\ \ ^E\fP
Moves the cursor to the end of the input line.
.br
.TP
\fBeot\ \ ^_\fP
Acts as an end-of-file;
this is useful because edit-mode input
disables normal terminal input canonicalization.
.br
.TP
\fBeot-or-delete\ \ ^D\fP
Acts as eot if alone on a line;
otherwise acts as delete-char-forward.
.br
.TP
\fBexchange-point-and-mark\ \ ^X\|^X\fP
Places the cursor where the mark is, and sets the
mark to where the cursor was.
.br
.TP
\fBforward-char\ \ ^F\fP
Moves the cursor forward one position.
.br
.TP
\fBforward-word\ \ ^[\|f\fP
Moves the cursor forward to the end of a word.
.br
.TP
\fBkill-line\ \ KILL\fP
Deletes the entire input line.
.br
.TP
\fBkill-to-eol\ \ ^K\fP
Deletes the input from the cursor to the end of the line.
.br
.TP
\fBkill-region\ \ ^W\fP
Deletes the input between the cursor and the mark.
.br
.TP
\fBlist\ \ ^[\|?\fP
Prints a sorted, columnated list of hashed command names or file names
(if any) that can complete the partial word containing the cursor.
Directory names have
.B /
postpended to them,
and executable file names are followed by
.BR \(** .
.br
.TP
\fBlist-command\ \ ^X\|?\fP
Prints a sorted, columnated list of hashed command names
(if any) that can complete the partial word containing the cursor.
.br
.TP
\fBlist-file\fP
Prints a sorted, columnated list of file names
(if any) that can complete the partial word containing the cursor.
File type indicators are postpended as described under
.B list
above.
.br
.TP
\fBnewline\ \ ^J\ \fP\fIand\^\fP\fB\ ^M\fP
Causes the current input line to be processed by the shell.
(The current cursor position may be anywhere on the line.)
.br
.TP
\fBnewline-and-next\ \ ^O\fP
Causes the current input line to be processed by the shell, and
the next line from history becomes the current line.  This is
only useful after an up-history or search-history.
.br
.TP
\fBno-op\ \ QUIT\fP
Does nothing.
.br
.TP
\fBprefix-1\ \ ^[\fP
Introduces a 2-character command sequence.
.br
.TP
\fBprefix-2\ \ ^X\fP
Introduces a 2-character command sequence.
.br
.TP
\fBquote\ \ ^^\fP
The following character is taken literally
rather than as an
.IR "editing command" .
.br
.TP
\fBredraw\ \ ^L\fP
Reprints the prompt string and the current input line.
.br
.TP
\fBsearch-character\ \ ^]\fP
Search forward in the current line for the next keyboard character.
.br
.TP
\fBsearch-history\ \ ^R\fP
Enter incremental search mode.
The internal history list is searched backwards for commands matching the input.
An initial ``^'' in the search string anchors the search.
The escape key will leave search mode.
Other commands will be executed after leaving search mode (unless
of course they are prefixed by escape, in which case they will
almost certainly do the wrong thing).
Successive
.B search-history
commands continue searching backward
to the next previous occurrence of the pattern.
The history buffer retains only a finite number of lines;
the oldest are discarded as necessary.
.br
.TP
\fBset-mark-command\ \ ^]\|<space>\fP
Search forward in the current line for the next keyboard character.
.br
.ie \n(OX \{.TP
\fBstuff\ \ ^T\fP\}
.el \{.TP
\fBstuff\fP\}
On systems supporting it,
pushes the bound character back onto the terminal input
where it may receive special processing by the terminal handler.
.if \n(OX \{This is useful for the BRL
.B ^T
``mini-systat'' feature,
for example.\}
.br
.TP
\fBstuff-reset\fP
Acts like
.BR stuff\^ ,
then aborts input the same as an interrupt.
.br
.ie \n(OX \{.TP
\fBtranspose-chars\fP\}
.el \{.TP
\fBtranspose-chars\ \ ^T\fP\}
Exchanges the two characters on either side of the cursor, or
the two previous characters if the cursor is at end of line.
.br
.TP
\fBup-history\ \ ^P\fP
Scrolls the history buffer backward one line (earlier).
.br
.TP
\fByank\ \ ^Y\fP
Inserts the most recently killed text string at the current cursor position.
.br
.TP
\fByank-pop\ \ ^[\|y\fP
Immediately after a
.BR yank ,
replaces the inserted text string with the
next previous killed text string.
.PD
.br
.SH FILES
~/.profile
.br
/etc/profile
.SH SEE ALSO
Sh(1) on System V or Sun OS.
.LP
.I "UNIX Shell Programming,"
Stephan G. Kochan,
Patrick H. Wood,
Hayden.
.LP
.I "KornShell: Command and Programming Language (not yet published),"
Morris Bolsky and David Korn.
.SH AUTHORS
Based on the public domain 7th edition Bourne shell.
.LP
System V and Korn modifications by Eric Gisin,
with contributions by
Ron Natalie, Arnold Robbins, Doug Gwyn, Erik Baalbergen, AT&T (getopt(3)),
John McMillan, Simon Gerraty and Peter Collinson.
.SH DIFFERENCES FROM AT&T VERSION
Csh-style alternations are implemented.
Variable arrays are not implemented.
Variable attributes other than integer are not implemented.
The \fBERR\fP and \fBEXIT\fP traps are not implemented for functions.
Alias expansion is inhibited at the beginning of an alias definition
in the AT&T version.
Korn evaluates expressions differently [elaborate].
.SH BUGS
Interactive shells may occasionally hang while waiting for a job
in the BSD version.
.LP
The 8th bit is stripped in emacs mode.
.LP
Quoting double-quote (") characters inside back-quote (`) inside
double-quotes does not behave properly.  Why are you doing this?
.LP
The emacs mode can ``lose'' stty command done by the user.
.LP
Unsetting special variables
may cause unexpected results.
.LP
Functions declared as having local scope really have global scope.
.LP
Here documents inside functions do not work correctly.
.LP
Exit on error (\fBset \-e\fP or \fBset -o errexit\fP) does not work
correctly.
.TH TEST 1 "January 1988" "Korn shell"
.ta 30n
.de X
.br
\\$1\t\\$2
..
.SH NAME
test \- test condition (Korn and 8th edition)
.SH SYNOPSIS
\fBtest\fP \fIexpression\fP
.br
\fB[\fP \fIexpression\fP \fB]\fP
.SH DESCRIPTION
\fBTest\f evalutates the \fIexpression\fP and returns zero status if true,
and non-zero status otherwise.
It is normally used as the controlling command of the \fBif\fP and \fBwhile\fP statements.
.LP
The following basic expressions are available.
.IP
.X "-r file" "file exists and is readable"
.X "-w file" "file exists and is writable"
.X "-x file" "file exists and is executable"
.X "-f file" "file is a regular file"
.X "-d file" "file is a directory"
.X "-c file" "file is a character special device"
.X "-b file" "file is a block special device"
.X "-p file" "file is a named pipe"
.X "-u file" "file mode has setuid bit"
.X "-g file" "file mode has setgid bit"
.X "-k file" "file mode has sticky bit"
.X "-s file" "file is not empty"
.X "-L file" "file is a symbolic link"
.X "-S file" "file is a socket"
.X "file -nt file" "first file is newer than second file"
.X "file -ot file" "first file is older than second file"
.X "file -ef file" "first file is the same file as second file"
.X "-t filedes" "file descriptor is a tty device"
.IP
.X "string" "string is not null"
.X "-z string" "string is null"
.X "-n string" "string is not null"
.X "string = string" "strings are equal"
.X "string != string" "strings are not equal"
.IP
.X "number -eq number" "numbers compare equal"
.X "number -ne number" "numbers compare not equal"
.X "number -ge number" "numbers compare greater than or equal"
.X "number -gt number" "numbers compare greater than"
.X "number -le number" "numbers compare less than or equal"
.X "number -lt number" "numbers compare less than"
.LP
The above basic expressions may be combined with the following operators.
.IP
.X "expr -o expr" "logical or"
.X "expr -a expr" "logical and"
.X "! expr" "logical not"
.X "( expr )" "grouping"
.SH AUTHOR
Erik Baalbergen. Modified by Arnold Robbins.
.rn LP P
.TH GETOPTS 1 "January 1988" "Korn shell"
.SH NAME
getopts \- parse command options
.SH SYNOPSIS
.B getopts
optstring name [arg ...]
.SH DESCRIPTION
.I getopts
is used by shell procedures
to parse positional parameters and to check for legal options.
It supports all applicable rules of the command syntax standard
(see Rules 3-10,
.IR intro (1)).
It should be used in place of the
.IR getopt (1)
command.
(See the
.BR \s-1WARNING\s0 ,
below.)
.PP
.I optstring
must contain the option letters the command using
.I getopts
will recognize;
if a letter is followed by a colon,
the option is expected to have an argument
which should be separated from it by white space.
.PP
Each time it is invoked,
.I getopts
will place the next option in the shell variable
.I name
and the index of the next argument to be processed in the shell variable
.BR \s-1OPTIND\s0 .
Whenever the shell or a shell procedure is invoked,
.B \s-1OPTIND\s0
is initialized to
.BR 1 .
.PP
When an option requires an option-argument,
.I getopts
places it in the shell variable
.BR \s-1OPTARG\s0 .
.P
If an illegal option is encountered,
.B ?\&
will be placed in
.IR name .
.P
When the end of the options is encountered,
.I getopts
exits with a non-zero exit status.
The special option
.RB `` \-\- ''
may be used to delimit the end of the options.
.P
By default,
.I getopts
parses the positional parameters.
If extra arguments
.RI ( arg
\&...) are given on the
.I getopts
command line,
.I getopts
will parse them instead.
.PP
So all new commands will adhere to the command syntax standard described in
.IR intro (1),
they should use
.IR getopts (1)
or
.IR getopt (3C)
to parse positional parameters
and check for options that are legal for that command
(see
.BR \s-1WARNINGS\s0 ,
below).
.SH EXAMPLE
The following fragment of a shell program
shows how one might process the arguments
for a command that can take the options
.B a
or
.BR b ,
as well as the option
.BR o ,
which requires an option-argument:
.PP
.RS
.nf
.ss 18
.ta +.5i +1i
\fBwhile getopts abo: c
do
	case $c in
	a\(bvb)	FLAGS=$FLAGS$c;;
	o)	OARG=$OPTARG;;
	\e?)	echo $USAGE 1>&2
		exit 2;;
	esac
done
shift OPTIND\-1\fP
.fi
.ta
.ss 12
.RE
.PP
This code will accept any of the following as equivalent:
.PP
.RS
.nf
.ss 18
\fBcmd \-a \-b \-o "xxx z yy" file
cmd \-a \-b \-o "xxx z yy" \-\- file
cmd \-ab \-o "xxx z yy" file
cmd \-ab \-o "xxx z yy" \-\- file\fP
.fi
.ss 12
.RE
.SH SEE ALSO
intro(1),
sh(1).
.br
getopt(3C)
in the
.IR "Programmer's Reference Manual" .
.br
.IR "UNIX System V Release 3.0 Release Notes" .
.SH WARNING
Although the following command syntax rule (see
.IR intro (1))
relaxations are permitted under the current implementation,
they should not be used because they may not be supported
in future releases of the system.
As in the
.B \s-1EXAMPLE\s0
section above,
.B a
and
.B b
are options,
and the option
.B o
requires an option-argument:
.PP
.RS
.nf
.ta +1i +1.5i
\fBcmd \-aboxxx file\fP	(Rule 5 violation: options with
	option-arguments must not be grouped with other options)
\fBcmd \-ab \-oxxx file\fP	(Rule 6 violation: there must be
	white space after an option that takes an option-argument)
.fi
.ta
.RE
.PP
Changing the value of the shell variable
.B \s-1OPTIND\s0
or parsing different sets of arguments
may lead to unexpected results.
.SH DIAGNOSTICS
.I getopts
prints an error message on the standard error output
when it encounters an option letter not included in
.IR optstring .
./pdksh/INSTALL   644    653   1762       11466  5243743523  10471 0ustar  hluBUILDING THE PD KSH
===================

The PD KSH can be built in two ways.  The default method uses
the POSIX/ANSI compatability libraries in ./std.  The
alternative method is to build the ksh in ./sh without the ./std
tree.  The second method should be used only if a) you have a
real POSIX environemnt or b) you have major difficulties with
building the ./std tree.

I have modified the source slightly to make standalone building
simpler.  Using -DNOSTDHDRS avoids attempts to include ANSI
headers that may be lacking.  I have built the shell this way on
all Sun platforms and on a Bull DPX/2 (which has good POSIX
support).  The config file defines USE_SIGACT so that the shell
will use the XPG3 signalaction() and friends.  You should leave
USE_SIGACT defined, sh/sigact.c contains an implementation for
systems that lack this facility. 

It is recommended that you try using the ./std tree first.  This
avoids problems like BSD times() calls that do not return an
indication of elapsed time and so on.

Using ./std:
------------

If you are on a Sun building it quite simple:

	make CONFIG=-D_BSD

will do it.  If you have a sun386 or sun3 and have gcc, it is
worth using, just add CC="gcc -pipe" to the above command line.
If you have SunOS 4.1 or later you probably need to add
-DHAVE_SYS_STDTYPES

Building on other systems may well be more difficult.
Apparently the creating of the ./std/h tree causes problems on
some systems.  


Notes on ./std:
---------------

I have updated the Makefiles in ./std/stdc and ./tsd/posix to
maintain the objects within the libraries.  Ie.
libstdc.a(strstr.o) If your make(1) doesn't know how to do this
then you will need to modify the makefiles accordingly.

In ReadMe.jrm, John MacMillan recommends being cautious of
std/libstdc.a and using only those routines which your system
lacks.  Please note that I have tested virtually none of
./std/stdc.  The Makefile contains target lines for most modules
but most are commented out.  I suggest you uncomment _only_
those that you need.

On the other hand std/libposix.a seems quite safe, and
indeed provides a better times() call for BSD systems.

Read ReadMe.jrm for more...


Building without ./std:
-----------------------

On some systems it might be worth forgetting about ./std/lib*
either because they proved too difficult to build or they seem
unnecessary.  As previously indicated I have done this on Sun's
and on a Bull system.  On Sun's it is perhaps not a great idea
as you then get the system's times() call which does not behave
the way the shell wants.

In anycase to build without ./std, you simply cd to ./sh and
either edit the Makefile accordingly, or use an appropriate
command line.  For instance:

Sun with SunOS 4.0:

	cd ./sh
	ln -s ../std/stdc/strstr.c .
	ln -s ../std/stdc/memmove.c .
	make CFLAGS="-D_BSD -DNOSTDHDRS" \
		XOBJS="strstr.o memmove.o" LDLIBS="" LDFLAGS=""

Note that we still need a couple of functions from ./std/stdc

On the Bull system which is a POSIX compliant System V machine:

	cd ./sh
	make CFLAGS="-D_SYSV" LDLIBS="-lc_s" LDFLAGS=""
	make CC=gcc CFLAGS="-D_POSIX_SOURCE" LDLIBS="-lc_s" LDFLAGS=""

INSTALLING:
===========

This is quite simple.  

	# cp ./ksh /bin
	# chmod 555 /bin/ksh

The above assumes of course that you don't already have a
/bin/ksh :-)
The manual page ksh.1 should be copied to an appropriate
location.
BSD:
	# cp ksh.1 /usr/man/man1
SYSV:
	# nroff -man ksh.1 > /usr/catman/u_man/man1/ksh.1
	# pack /usr/catman/u_man/man1/ksh.1

Or something similar.  For systems such as Sun's that really
only ship with a C-shell environment, the ./etc directory
contains a useful /etc/profile and /etc/ksh.kshrc file to
provide a suitable environemnt for /bin/sh and /bin/ksh users,
they should work, they are straight of my system and I use them
on Sun,Bull and even an SCO system.


PROBLEMS:
=========

Clearly building will not be so simple on all systems.
Apparently some of the enum manipulations border on ilegal and
cause some compilers problems.  Curiously both gcc -ansi and the
GreenHills compiler on the Bull system are quite picky and did
not complain.  Note if you want to use gcc -ansi you may well
need to add some definitions, for instance the following all
work on the sun386:

	CC=cc
	CC=gcc
	CC=gcc -ansi -Dsun -Di386 -Dsun386

The last three items on the last line are normally all defined
automatically, but this is disabled when -ansi is used.  The
system headers do not work unless they know what architecture is
in use.  

On the Bull DPX/2 I used gcc-2.1, my gcc port will be available
as of release 2.2.  To save effort I found it necessary to copy
stdio.h and stdlib.h to gcc's private include directory and edit
them to remove unnecessary #ifdef's and unwanted #include's.

If you find and fix a problem please fill in a copy of
./bug-report and e-mail it to [email protected]

Enjoy!

Simon J. Gerraty <[email protected]>

./pdksh/Changes.mlj   644    653   1762        3361  5243742730  11466 0ustar  hluI got the pd-ksh from John MacMillan after he indicated that he
had a version of it that had vi editing (I'd seen various versions
with emacs-editing, but none with vi).

It had a few bugs and areas which were not quite complete.  I fixed
(or at least tried) to fix several; there are still some things
which I plan on doing (or at least looking into).

Bugs fixed (or at least abated):

    vi-mode changes:
    - Changed memcpy() to memmove(), which fixed the trashing of
      the end of the edit buffer while inserting in the middle
      of a line or with use of '#'
    - using 'r' replacing the current character with ^@
    - typing ctrl-c resulting in next command being garbled
    - lack of support for '-' and '+' (pretty trivial)
    - finish adding support for '*' (not entirely sure I'm freeing
      malloc'ed memory correctly here, but I haven't had any problems)
    - treats '_' as end of a word

    general changes:
    - reporting "not found" when a file actually doesn't have
      the appropriate execute bit set (now says "cannot execute"
      or "not found", as appropriate)


Still to do:

    vi changes:
    - fix ctrl-r (I've come up with a hack, but it involves
      redrawing the screen a lot when it isn't necessary; I
      really wouldn't consider this a fix)
    - add support for 'v'

    general changes:
    - seems to be a memory leak when executing shells in the
      current shell; repeatedly executing ". /etc/profile"
      increased the size of the program as reported in the
      "SZ" field of "ps -l"
    - don't give a file its complete pathname in argv[0]; only
      its filename (religious issue?)
    - history recall should start at the previous command, not
      the current one (typing "r r" causes an infinite loop)
./pdksh/ChangeLog   644    653   1762        2332  5243743644  11166 0ustar  hluSat Aug  1 17:11:24 1992  Simon J. Gerraty  (sjg@zen)

	* Incorporated massive contribution from Peter Collinson
	Refer to Changes.pc

	* Incorporated Emacs-style completion provided by
	[email protected] this a bit nicer than the standard ksh
	file completion.

Sun May  3 17:50:03 1992  Simon J. Gerraty  (sjg@zen)

	* Updated MACHINES.
	* Placed source under CVS.  This should help with processing fixes
	from the field.

Sat Apr 25 10:53:20 1992  Simon J. Gerraty  (sjg@zen)

	* Getting ready for 4.3 release.  

Fri Nov 22 22:24:29 1991  Simon J. Gerraty  (sjg at zen)

	* Cleaned up the build process slightly.  Makefiles in ./std tree
	now maintain objects within the libraries rather than simply
	building the .o's and archiving them.  Of course the make(1) used
	must know how to maintain libraries :-)

	* Added bug.report as a template for bug reporting.

	* Source in ./sh can be built independently of ./std tree if
	desired.  See comments in ./sh/Makefile.

	* As originally distributed some of libstdc.a was not used and
	libposix.a was not used at all.  On Sun's this highlighted a bug
	(incompatibility) in the times() call.  Now the ./std/libs are
	used fully, and the supplied times() call functions as expected.

./pdksh/MACHINES   644    653   1762        3150  5243743645  10526 0ustar  hluThis file documents some the machines that pdksh has been build
on and notes that apply.

Notes:
(1)	Built and tested by me (sjg), seems ok :-)
(2)	Reported ok (may mean earlier version)
(3)	Reported no good
(4)	Built with ./std/lib*
(5)	Built without ./std/lib*
(6)	No job control

If you succesfully build this shell on another system please let
me know. 

System, OS			Notes	Compiler/Flags
--------------------------	-----	--------------
sun386, SunOS 4.0.2		1,4	{cc,gcc} -D_BSD
sun4c,	SunOS 4.1.1		1,4	{cc,gcc-2.1} -ansi -D_BSD -DHAVE_SYS_STDTYPES
sun3,	SunOS 4.0.3		1,4	{cc,gcc} -D_BSD
sun3,	SunOS 4.1.1		1,4	{cc,gcc} -ansi -D_BSD -DHAVE_SYS_STDTYPES
Bull DPX/2, B.O.S. 2.00.45	1,5	{cc,gcc-2.1} -ansi -D_POSIX_SOURCE
Bull XPS-100			1,6	cc -D_SYSV -DUSE_SIGNAL
i386,	BSDI BSD/386		2

NOTES:
The table above sumarizes the config used.  {cc,gcc} indicates
either compiler can be used.  If gcc-2.1 rather than gcc is
indicated then gcc < 2 may not work.  This is at least true of
sun4c (sparc) systems.

Bull DPX/2:

pdksh is not needed on this system.  It is simply used as a
System V / POSIX test bed.  Build without ./std tree.  I only
tried with gcc-2.1. -D_SYSV must be left out of CFLAGS for POSIX
functions such as sigaction() to be used.

Bull XPS-100:	

Be sure to rm std/h/dirent.h std/h/sys/types.h and undef JOBS as
the kernel does not support it.  This machine has a sigaction()
implementation that appears to be faulty.  A SIGINT terminates
the shell, when using the system's sigaction().  Undefining
USE_SIGACT does the trick.  sigact.c can now be forced to build
by defining USE_SIGNAL, but this is not tested on the XPS.

./pdksh/ReadMe.jrm   644    653   1762       11527  5243742743  11310 0ustar  hluBUILDING THE PD KSH
===================

As usual, there are differences between BSD and System V
versions.  Ideally, all you have to do is edit the Makefile in
this directory to set the CONFIG macro to the appropriate value.
(Actually, you may wish to change the CONFIG macro in all
Makefiles; if you always invoke make(1) from here, CONFIG will
be passed down, but if you invoke make(1) from a subdirectory
you'll want the appropriate definition in that Makefile.)

Of course it's not quite that simple.  You may, however, take
solace in the knowledge that it used to be worse.

The Compatibility Libraries
---------------------------

Eric Gisin wrote this shell using ANSI C and POSIX as
portability guidlines.  Realizing that nobody had a POSIX
system and almost no one had an ANSI C environment, he provided
minimal compatibility libraries.

There are two libraries, one for POSIX (libposix.a) and one for
ANSI C (libstdc.a).

Libposix.a is pretty simple.  Nothing in it has ever broken on
me, so I'd just leave it.  It provides a version of dup2() for
System V systems.

Libstdc.a is a bit hairy.  I recommend looking at the routines
provided and, and editing the std/stdc Makefile and only
including objects that have routines your system libc.a is
lacking.  Various of the provided routines are just plain
flaky, but only when they're not really needed.  The other
hairy thing he does is craft an ANSI stdio.h from the system
supplied one and one of his own.  Again, it's better than it
used to be, but it's still a hack, and you may have to modify
it by hand.

You will also need a POSIX compatible set of directory reading
routines.  System V.3 systems have this in libc.a.  The
std/posix directory provides a something for BSD systems.  I
use a slightly modified version of Doug Gwyn's PD version.

(The ``slightly modified'' is to work around a bug in Gwyn's version.
The POSIX routines are documented as returning failure if the file for
opendir(3) is not a directory.  Gwyn attempts to open(2) the file, and
then stats it to see if the file is a directory.  However, if the file
is a special file, and the open(2) doesn't return, you're screwed.  My
change was to open the file with the O_NDELAY flag, but Gwyn didn't
feel this was portable (true, but I only do it where it works) and
that stat-ing before the open would be too slow (true).  The upshot is
if you use his routines unmodified, don't ever do an "ls -l /dev/*/*".)

The Shell Source
----------------

The source for the shell itself is in the sh directory.  There you
will want to edit config.h to determine the configuration options.  Vi
mode is in kind of rough shape, but does work.  DIRSTACK routines
aren't implemented yet, so again, why bother.  SWTCH is a bit arcane,
but it you use shl(1) and you define EMACS or VI you want to define
this.  JOBS is really only useful on BSD systems.  It might work on
systems that have POSIX job control, but I wouldn't bet on it.
SHARPBANG is only useful on systems where the exec() family don't
honour the #!/prog/path convention.

This is where the shell gets built so you may wish to change
the OTHERLIBS macro in the Makefile to point to your POSIX
directory routines, or to use -lc_s, or whatever.

Miscellaneous
-------------

The Makefiles that actually compile things use the macro
CCOPTS, so you can change it in individual Makefiles or specify
it on the command line, eg. "make CCOPTS=-O OTHERLIBS=-lc_s".
LDOPTS is used in the Makefile where the ksh is actually built.

The very first time on a new system, do a "make clobber"

Good luck.

Documentation
-------------

The ksh.1 is a man page for the PD ksh, although it lags
somewhat behind the code.  You get what you pay for.

The ksh88.1 is a man page for AT&T's ksh88 (the latest version)
provided for comparison.

History
-------

Much of the shell was written by Eric Gisin at the University
of Waterloo, using some pieces of other stuff, notably Charles
Forsythe's V7 shell, and some enhancements from the BRL shell.
He placed it (in a alpha test state) into the public domain
while I was at UW.  I snarfed a copy, and got it running on my
UNIXpc, and later some machines at work.  I sent Gisin some bug
reports, but he seems to have lost interest in the project.
This may be because he now does some work for MKS, who produce a
commercial version of the ksh for MS-DOS machines, so there may
be a conflict of interest.

So I gave up on getting future versions, and adopted it.  I've
made some enhancements, and quite a few bug fixes, and various
people at work have contributed as well.  It remains in the
public domain, although I imagine the people involved would
appreciate leaving their names attached (I'm exempt; I haven't
actually included my name anywhere but here).

The README in the sh directory is Gisin's, and tells a bit of
the story from his point of view.  Note that his compilation
instructions don't really apply anymore.

John R. MacMillan
./pdksh/MANIFEST   644    653   1762       10307  5243743645  10567 0ustar  hlu   File Name		Archive #	Description
-----------------------------------------------------------
 ChangeLog                 1	Current change history
 Changes.jrm               1	
 Changes.pc                1	
 Changes.mlj               1	
 INSTALL                   1	Installation notes
 MACHINES                  1	Systems the shell has been built on
 MANIFEST                  1	This shipping list
 Makefile                  1	
 PATCHDATES                1	C-News style patch tracking
 README                    1	Please read
 ReadMe.jrm                1	General info and Install instructions
 ReadMe.sjg                1	
 ReadMe.vimode             1	
 bug-report                1	Bug report template
 etc                       1	
 etc/ksh.kshrc             1	global .kshrc
 etc/profile               1	
 etc/sys_config.sh         1	
 ksh.1                     2	Manual page
 sh                        1	ksh source
 sh/ChangeLog              2	Current change list
 sh/Changes                1	
 sh/Makefile               2	
 sh/ReadMe                 1	Original ReadMe (out of date)
 sh/alloc.c                2	
 sh/alloc.h                1	
 sh/c_ksh.c                3	
 sh/c_sh.c                 3	
 sh/c_test.c               3	
 sh/config.h               1	
 sh/edit.c                 3	
 sh/edit.h                 3	
 sh/emacs.c                4	
 sh/eval.c                 4	
 sh/exec.c                 5	
 sh/expand.h               3	
 sh/expr.c                 3	
 sh/getopts.c              5	
 sh/history.c              5	
 sh/io.c                   5	
 sh/jobs.c                 6	
 sh/lex.c                  5	
 sh/lex.h                  5	
 sh/mail.c                 6	
 sh/main.c                 6	
 sh/misc.c                 6	
 sh/patchlevel.h	   6	version/patch level.
 sh/proto.h		   1	Prototypes for ANSI compilers.
 sh/sh.h                   6	
 sh/sigact.h		   6	Header for sigaction() implementation.
 sh/sigact.c		   6	sigaction() implementation.
 sh/stdh.h                 6	Centralise std header inclusion.
 sh/syn.c                  7	
 sh/table.c                7	
 sh/table.h                7	
 sh/trace.c                7	Simple trace facilty
 sh/trace.h                7	
 sh/trap.c                 7	
 sh/tree.c                 7	
 sh/tree.h                 7	
 sh/tty.h                  1	
 sh/do_ulimit.c            7	
 sh/var.c                  8	
 sh/version.c              3	
 sh/vi.c                   8	
 std                       1	libraries
 std/Makefile              3	
 std/mklinks               1	make symlinks
 std/posix                 2	
 std/posix                 4	posix lib source
 std/posix/ChangeLog       4	change history
 std/posix/Makefile        5	
 std/posix/dirent.C        7	
 std/posix/dirent.H        7	
 std/posix/dirent.h        7	
 std/posix/dup2.c          7	
 std/posix/fcntl.c         7	
 std/posix/fcntl.h         7	
 std/posix/fixincludes     8	
 std/posix/io.h            8	
 std/posix/time.h          8	
 std/posix/times.c         8	
 std/posix/times.h         8	
 std/posix/unistd.c        9	
 std/posix/unistd.h        9	
 std/posix/wait.h          9	
 std/stdc                  5	stdc lib source
 std/stdc/ChangeLog        7	change history
 std/stdc/Makefile         9	
 std/stdc/clock.c          9	
 std/stdc/fprintf.c        9	
 std/stdc/limits.h         9	
 std/stdc/memchr.c         8	
 std/stdc/memcmp.c         9	
 std/stdc/memcpy.c         9	
 std/stdc/memmove.c        9	
 std/stdc/memset.c         9	
 std/stdc/setvbuf.c        9	
 std/stdc/sprintf.c        9	
 std/stdc/stdarg.h         9	
 std/stdc/stddef.h         9	
 std/stdc/stdio.c          9	
 std/stdc/stdio.h_std      9	
 std/stdc/stdio.sed        9	
 std/stdc/stdlib.h         9	
 std/stdc/strcat.c         9	
 std/stdc/strchr.c         9	
 std/stdc/strcmp.c         9	
 std/stdc/strcpy.c         9	
 std/stdc/strcspn.c        9	
 std/stdc/strerror.c       9	
 std/stdc/string.h         9	
 std/stdc/strlen.c         9	
 std/stdc/strncat.c        9	
 std/stdc/strncmp.c        9	
 std/stdc/strncpy.c        9	
 std/stdc/strpbrk.c        9	
 std/stdc/strrchr.c        9	
 std/stdc/strspn.c         9	
 std/stdc/strstr.c         9	
 std/stdc/strtok.c         9	
 std/stdc/time.h           9	
 std/stdc/types.h          9	
 std/stdc/vprintf.c        9	
./pdksh/Changes.jrm   644    653   1762        4477  5243742753  11512 0ustar  hluChanges to the PD ksh since last time:

- clean up the option configuration stuff.  Options in config.h should
  now just be #define'd or not, not #define'd to 1 if you want them
  and 0 if you don't

- ksh now uses the shell specified by the variable EXECSHELL to run
  shell scripts.  If EXECSHELL is unset or null it defaults to
  /bin/sh.  It does a path lookup on the value, so if you set it to
  ``ksh'' the ksh will run all scripts that don't start with #!.  It
  seems to run most sh scripts fine (now).  I'd be very interested to
  hear your experiences if you try this out, as for my next trick I'd
  like to make ksh just fork itself to run scripts, which would speed
  things up, and allow exportable functions and aliases (like he real
  ksh).  Just to assure you that it can do some hairy sh scripts, both
  CC and coco work with ksh.

  EXECSHELL won't work if the system's exec(2) call runs scripts...

- the ``let'' builtin now evaluates null or unset vars to 0, as per
  The Book

- Various memory allocation/use problems were cleaned up.  Hopefully
  you'll never see the ``freeing free object'' error again (if you've
  ever seen it).

- the ``test'' builtin is now much more tolerant in parsing its
  arguments.  This was to make it like the /bin/sh test.

- Temp files (for here documents or ``fc'') are now mode 0600

- Some format strings in the tree printing routines got ``expanded''
  into SCCS keywords, so the results of``type <function>'' were
  gave you interesting things like the time I last checked in the
  file.  This has been fixed.

- ``unset -f'' now really does unset functions.

- the ``trailing blank or tab in alias definition'' feature now works.

- A bug in command completion was fixed.  Note command completion only
  works on commands that have been hashed, so you want to ``set -h''
  in your .kshrc, and you may wish to force hashing of some common
  commands with the ``hash'' builtin.

- ``echo $$ | cat'' now works as in /bin/sh

Not new features, but newly discovered bugs:

- Local functions don't work correctly.  This shouldn't be much
  problem, since sh doesn't have them.

- Here documents in functions don't work.  This is a problem with the
  temp file allocation that requires more work to fix than I've gotten
  around to doing.  So avoid things like:

foo() {
	cat <<- HereDoc
This is a test
HereDoc
}
./pdksh/ReadMe.sjg   644    653   1762        5273  5243742753  11265 0ustar  hluHORIZONTAL SCROLLING
====================

I have migrated my 3.2 ksh edit.c mods into the 3.3 ksh
This file describes the mods in general and really only applies
(at this stage) to emacs-mode.  I have not touched vi-mode apart
from making it use pprompt() so that '!' is correctly expanded
as in emacs-mode.

I would prefer to see both vi.c and emacs.c use a common set of
primatives in edit.c - but that looks like a lot of work.

Basically my mods affect the functions that move the cursor
about and redraw the edit line.  

The input buffer "buf" is pointed to by "xbuf" and its end is
pointed to by "xend".  The current position in "xbuf" and end of
the edit line are pointed to by "xcp" and "xep" respectively.
I have added "xbp" which points to the start of a display window
within "xbuf".

[A] starting position

buf
|<-------- $COLUMNS --------->|
|    |<---- x_displen ------->|
| PS1|
     +==========+==============--------+.......+
     |\          \                      \       \
  xbuf xbp        xcp                    xep     xend

[B] scrolled

buf
|           |<----- COLUMNS -------->|
|           |<----- x_displen ------>|
|      
+-----------+==========+==============--------+.......+
 \           \          \                      \       \
  xbuf        xbp        xcp                    xep     xend

In the above -------- represents the current edit line while
===== represents that portion which is visible on the screen.
Note that initially xbp == xbuf and PS1 is displayed.
PS1 uses some of the screen width and thus "x_displen" is less
than $COLUMNS.

Any time that "xcp" moves outside the region bounded by "xbp"
and "xbp" + "x_displen", the function x_adjust() is called to
relocate "xbp" appropriately and redraw the line.

Excessive I/O is avoided where possible.  x_goto() for instance
calculates whether the destination is outside the visible
region, and if so simply adjusts "xcp" and calls x_adjust()
directly.  Normally though x_adjust() is called from x_putc().

The above mechanism has be updated to use a function x_lastcp()
that returns a pointer that accurately  reflects the last
visible char in the edit buffer.  That is a more accurate
version of xbp + x_displen which does not account for TABS.

Other changes
=============

I have also added some emacs mode functions.
M-[0-9]
	Set a numeric arg (positive only).
	Used by all word related commands.
M-_
M-.
	Retrieve word from previous command (default is last
	word).  Use M-[1-9] to select word.
M-u
M-l
M-c
	UPPER,lower,Capitalize word.


Commands like delete-word now push the deleted text so that it
may be yanked back into place.

BUGS?
=====

There are bound to be some.  Please report same to me:

Simon J. Gerraty	<[email protected]>

./pdksh/Makefile   644    653   1762        1420  5243743646  11053 0ustar  hlu# PD Bourne/Korn Shell
# $Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $

SHELL = /bin/sh
MAKE  = make
CC=gcc -pipe -g -O
LN=ln -s
#LN=ln
#CONFIG= -D_SYSV
CONFIG= -D_BSD 
#CONFIG= -D_BSD -DHAVE_SYS_STDTYPES
#CONFIG= -D_V7
#CONFIG= -D_ST				# Atari ST
#CONFIG= -D_BSDI -D_POSIX_TERM		# BSD/386
MANPAGES = ksh.1
#MANDIR=/usr/catman/u_man/man1
#MANDIR=/usr/man/man1

#INSTALL=bsdinstall
INSTALL=install

all:	ksh

ksh:	libs
	( cd sh ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' $@ )

libs:
	( cd std ; $(MAKE) 'CC=$(CC)' 'CONFIG=$(CONFIG)' 'LN=$(LN)' libs )

install: sh/ksh
	( cd sh ; $(INSTALL) -s ksh $(DESTDIR)/bin )

sh/ksh:	ksh

inst-man: $(MANPAGES)
	$(INSTALL) -c -m 444 $(MANPAGES) $(MANDESTDIR)/man1

clean clobber:
	( cd std ; $(MAKE) $@ )
	( cd sh ; $(MAKE) $@ )
	-rm -f *.out

./pdksh/ReadMe.vimode   644    653   1762        2445  5243742767  11770 0ustar  hlu
The changes I have made are all relevant to the VI edit mode. The vi-edit
source seems mostly complete, so these changes are minimal. What is available
now is pretty useful. I will make further fixes as I notice the bugs (or
anyone else does).

A summary of changes follows:

1) two changes to turn on the vi-editing feature.
2) motion edit fix: back space and space bar now do something: have
the same behaviour as the 'h' and 'l' keys.
3) input edit fix: backspace key now works.

Known bugs (not fixed yet):

a) proviso on 1) and 2) above: the backspace key was hardwired to the
<delete> key. I have temporarily extended it to include the '^H' or
<backspace> key. I will generalize this to use whatever key is defined
as the erase character by stty.

b) the interrupt key does not clear the edit buffer. This means the next
edit command after an interrupt will be garbage.

c) Same sort of thing as b) occurs for the <EOF> key.

d) insertions near the beginning of an edit buffer seem to screw up the rest
of the buffer.

Known missing features:

a) search edit commands: [count]-, [count]+
b) text modification edit commands: P, p, *
c) r (replace) doesn't seem to work too well.
d) tilde does not do anything (should reverse upper to lower and vice versa)

e) ! in prompt doesn't get expanded to history number
./pdksh/bug-report   644    653   1762        2037  5243743673  11431 0ustar  hluTo: [email protected]
Subject: [area]: [synopsis]   [replace with actual area and short description]

VERSION:
    PD KSH: 4.7 12-Aug-92
    [Official patches will edit this line to indicate the patch level]

MACHINE and OPERATING SYSTEM:
    [e.g. Sparc/SunOS 4.1.1, DECstation 3100/Ultrix 4.2, ...]

COMPILER:
    [e.g. native cc, native ANSI cc, gcc 1.40, ...]

AREA:
    [Area of the source tree affected,
     e.g., std/posix, std/stdc, sh]

SYNOPSIS:
    [Brief description of the problem and where it is located]

DESCRIPTION:
    [Detailed description of problem.  Please provide as much detail
     as you can manage.  The more information we have the more likely 
     a fix]

SAMPLE FIX:
    [Preferred, but not necessary.  Please send context diffs (diff -c)
     name old file first.  eg. diff -c file.c.old file.c]

[PLEASE make your Subject: line as descriptive as possible.
 Subjects like "pdksh bug" or "bug report" are not helpful!]
[Remove all the explanatory text in brackets before mailing.]
[Send to [email protected]]
./pdksh/Changes.pc   644    653   1762        2110  5243743644  11302 0ustar  hluChanges by Peter Collinson - Hillside Systems/BSDI - July 1992


a)	Add select command - this cannot be ksh without that.
	(It NEEDS typedefs too)
b)	Remove all the bcopys from vi.c
	add 
	#define memmove in sh.h for BSD systems
c)	Add <Esc>* command to vi mode - expands to a list of files
	using the menu printing routine
d)	Add my version of history, that works much like the `proper' ksh
	storing data in a file that is shared between different invocations
	of the shell.
e)	Add the ability to redirect to am expansion... ie

		ls > o*
	if o* is unique then it puts it into the file that matches
	otherwise it puts it to a file called o*... this is current
	behaviour.
f)	Add alternations, from Csh.d) This is not part of ksh but is something
	that csh users really miss from the Bourne shell derivatives. The idea
	is that lists inside curly braces expand to arguments. ie.
		exampl{a,b,c,d,e}
	will expand to 5 arguments
		exampla examplb examplc exampld example
	Recursive lists are permitted.
g)	Add suspend as a built-in alias.
h)	Port to BSD/386 - add _POSIX_TERM and _BSDI as defines.
./pdksh/ksh   755    653   1762      262000  5302770105  10153 0ustar  hluPX��C�-�̀�\	`�-:�D$�4	`�:P�`[�̀��r$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $${SHELL:=/bin/sh} ${PATH:=/bin:/usr/bin:.} ${HOME:=/} ${PS1:=$ } ${PS2:=> } ${PS3:=#? } ${MAILCHECK:=600}cd.typeset-xSHELLPATHHOME-rPWDOLDPWD-iSECONDS=0OPTIND=1aliasinteger=typeset -ipwd=print -r "$PWD"history=fc -lr=fc -e -nohup=nohup login=exec loginnewgrp=exec newgrptype=whence -vfunctions=typeset -fecho=printtrue=:false=let[=\[suspend=kill -STOP $$PPIDRANDOM# PS1r%s: cannot open
/etc/profile.profileENV��UWVS�\$,�D@�D$�D$�<_��^��^�(_�@_��^��^�,_��^�|^�$_��h�b�����^h�^�����^ d��^��^�	j�!��j�!��j�!����
h�bh_���h�bhb���h�bh�^���h�bh�`����	��t�;t���3������;u��m`�t^jjh0P����jjhP�����i!1��=��t!�������t��3�������F�;u�1��=��t!�������t��3�ͦ����F�;u�jh��}"����`Pjjh#�^��P����jhh#�A��j��
`��Pjjh(�%��P����8P�=8Pt6�����;t�h�^�3��������;u�V�����s�{u�h�^����{`f��uh/h2�	��P�
��j�/���Ë=`b�{1�L$(�9�|$��|$$��A�8-uq�xtk�QB��:t]���L$����<ct<qt&�0�9t$$~6�C�L$�9�;�D$F����D$�����<w	����cB�:u��{��9t$$~}�=dut�L$(�<��|$�{Fh6�t$�c��_���C��u�t$h8�����D$�s� ��_��P���P�s��`��hjj�s�`���{u]�s����_����u�dj�A`����t j�3`����t��u�|$u�	d�=	dt�=dt�C�{u%j
jj���_���tQjjP���_���:R荮�|$u
j�'����L$(���(d�|$$)��=$d�(d�L$�����|$�?-u!�	dhI���hV���j h_�z��P�e
��P�`���€:t	R����=	dt$jh$_j�v`��j�����T5�	���d�{u�
d�g��=	dt	S�x��S�����D$$�t$$���1�[^_]���-UWVS�l$������tMh6U�B��_����u	1�[^_]�S���_��P���PS��`��hjjS�`����`bj�G,���X�hP�L��9`bt	S�K��_���[^_]�S�\$j�,���P���[�
Use `exit'
��VS�t$�D$
�D$j�8����^�ah�^���_����t8�$b��t
h��	���D$��t�~u	�~t�N��R��$b��t���=	dtjh$_j�`���~u
�d�V�g��~��%��D$��u�~u+jh2�%��P���P����_�4�D$V������D$�f���tB�;u=�D$��te�=dt\�D$H�D$�D$��~Kh��
���F������j�Q���=dt�~ujS��������������a[^��Ã=�^u�=�^t�Qh�R�۽���=	dt�����t$���_����=du	�=	du
j����������^��t��t�.����t�%�j�u�����jh�^�n��_��jh�^�`��_�[빐WVSh�^j4�����É߾�^��
�h�^�?���L$�
�^��^��^��^[^_�UWVS�-�^��u�5a�/��_����M9
�^t���=�^t1ې��^�XPS���C��	~��"��^����
�h�^U�4��[^_]�S��^��t��s��`�����u���^h�^�w��[�alloc internal error: %s
�t$h6����$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $S�T$�\$��}�a�b�� @9�~��
a����aB�:u�[�0123456789 	
|&;<>()*@#!$-?=-+?#%�ea�~a���@9�~��Ea�^a���@9�~��
cajh��e�����jh��V�����jh��G�����j@h��8������0123456789ABCDEFS�D$�\$��V��V���I1���`
���u��[���W�L$��u1�_��ÐQ�t$0҉ψ���������щL$�t$�:���D$�t$�6`���D$�D$_���allexportbgniceemacserrexithashallignoreeofinteractivekeywordmarkdirsmonitornoexecnoglobnounsetprivilegedstdintrackallverbosevixtraceVS�t$��P�=�Pt V�3�`��_����u	�C[^Ð�����;u�1�[^�����a�����ct�ЈAB��z~��h�^�D$P���������%s 
S��P�=�Pt$��C��dt�3h	������;u�h
����[�%s: bad number
VS�t$��>-u�N1������\B�A���a$u�9tVhR�|���؀>-u��[^�VS�t$�\$��t>��u~�8�F���uo�C<?t$<*t*�T<[uP��tRS�q���Å�uL�����uD1�[^Ð��N����;tSV��������t	�[^Ð�F��u��ϐ���C�9�t��9�u��C���x����>��%�[^�WVS�T$�|$1�1ۀ:�u
B�:!���؅�tB��:�uB�:t=�
�z-u�z]t
�BB������9�t	9��B�:]u�9�t�B[^_Ð�1�[^_Ð�1�[^_��T$�t$�L$���PR����UWVS�D$+D$����������"�L$�<����t$�l$�����9�s,�3�6�L$$�у���u��������ސ���}���Ӑ��9�vd�u�7�L$$�у���u����M��E�ې����~49�u����M���M�����븋�M��E������s���������뛐��9�uT��+T$���D$)���9�|�t$�t$�GP�	������\$������t$S�t$����������|$������������E��M��������������[^_]��t$�t$����_���/UWVS�|$�\$�Q1��ڀ?/t&�L$����AB��u��C9�r�z�/uJ����B�/���9ti���AB</uC�C9�v<�z�/uJ�3���z�.u+�z�/u���� ����z�.u�B��z�/u�9�vH�8/u��P�9u���u��y�/t����땐���z�/u	�B�9�v���[^_]�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $��V�,b��Vj�G����V��uj� ����V1�Ð�g��Vjj
����=,b��%��WVS1��t$����Dž�����=�Vt��V��V���j������V��|uHj�Q���Å�u����ujSWj�$���lj�룐��jS�vj����F��뉐��V��[^_�WVSj�R������Dž�����=�Vt��V�5�V��j�!����V�Ɓ�t��u;j�������Å�u�.jSW���u�P�j����닐����V��[^_�VS1��W����ƅ�����=�Vt��V��V���j�����V��;t%��&t%�=L_u��`�zt�zu|��
uw��&u+��tjj�sj�����C�jjVj������������u��[^Ð��ujPVj����Ɖ��Q����jP�sj����C���6�������V��[^�too many <<'s
S�=�Vt
��V������V�t$�����V=t1�[���V�P_jh�P���P_�S�C����u4�=�bt�K�=\b\br
h��
���\b��\b��[��=�Vt��V��V����t$������V9D$t��WVS�|$�\$�L_������jS�������
L_jjVW�8
��[^_�too many redirectionsunexpected EOFletinvalid function name
��UWVS�|$01�h�^j,�	���D$h�^j@�	���D$$�D$ ��@�D$(h�^j@�n	���D$�D$��@�D$�=L_t����t$���W�&�������t��	~
h�~�����E����ԃ=�Vt��V��V��W�����V�Á���J��{����t��(�z�����|�����l��	��^��������
F����td���f�(���$���h1���1�[^_]����V��u
1�[^_]���j������~�����Vj����ǁ�����V�T$(9T$ r9�\$ +\$$��h�^��P�t$,�
	���D$$����‰T$ Ӊ\$(�D$ �@�D$ jh�������T$(9T$ r9�\$ +\$$��h�^��P�t$,����D$$����‰T$ Ӊ\$(�D$ �P_��D$ �T$�4��=�Vt��V���Vj�����V=t =t;�U��=��C��	~
h���j���������E���V�D$ +D$$��t	�=dtlj=h�b�x��_����tY�T$9T$r9�\$+\$��h�^��P�t$ ����D$����‰T$Ӊ\$�D$�P_��D$�����T$(9T$ r9�\$ +\$$��h�^��P�t$,�Q���D$$����‰T$ Ӊ\$(�D$ �P_��D$ ���������V�D$ +D$$����t�
�=�bu
hD����j�
����h�^h�b�������Gj	j{�������j}j�)������G��[^_]��Ðj)j���j}j�������������u�P�	����jh������h�^h�b�������G�L_��Gj�����G�
L_�8��L_���u�P�:	���������Gj����G�
L_���j	�
	����jh��������P_�W�L_j	h���������Gjh
�+���L_j
������	����G��Gjh�������
L_�n���j��������jjWj������L�j�e����jh�T�����h�^h�b�B������Gj	j{�3�����j}j�c������G�T$�4���j�i�������t��	~
h�������E�֐���uh�^�t$�b���G�-���T$��h�^��P�t$�s���T$�W�?���T$(9T$ r9�\$ +\$$��h�^��P�t$,�5���D$$����‰T$ Ӊ\$(�D$ ��D$ h�^�D$$+D$($�P�t$,�����G�T$9T$r9�\$+\$��h�^��P�t$ �����D$����‰T$Ӊ\$�D$��D$h�^�D$+D$$�P�t$ ����G�"h�^�t$(�.��h�^�t$�����[^_]���S�=�Vt��V��V��j	�y����V=u�|$t1�[Ð��=t�������jh�)�������[�S�=�Vt��V��V��j�����V=t��V1�[�j�������'����C��u��
�C��[�S�=�Vt��V��V��j�����V=t
=t�5��������u%����j
�]���������C�+����C��[���V1�[�VS1�1����=�Vt��V���Vj	�����V=
t �#��u�É��F뺐��C��뱐��[^���VSh�^j@�3���D$�D$��@�D$j����ƻ	�=�Vt��V��V���j	�����V��(t��V�1ې�Sh�U������T$9T$r9�\$+\$��h�^��P�t$�����D$����‰T$Ӊ\$�D$�P_��D$1ۃ=�Vt��V��V���j������V��|�h�����V�T$9T$r9�\$+\$��h�^��P�t$�[���D$����‰T$Ӊ\$�D$��D$h�^�D$+D$$�P�t$����Fjj)�D����������F�=�Vt��V����Vj	�+����V=
tj	h���������[^�����Sh�^j@�P����D$�D$��@�D$�=�Vt��V��V�j	������V=t��V1�[��Ð�=�Vt��V��V���j�}����V=uZ�T$9T$r9�\$+\$��h�^��P�t$������D$����‰T$Ӊ\$�D$�P_��D$�u������
t
��;t�A�D$+D$����uh�^�t$�\���1�[��Ð��T$9T$r4h�^��P�t$�p����D$����T$�T$ЉD$�D$��D$h�^�D$+D$$�P�t$�*���[���WVS�\$�t$�|$�t$�@���X�p�x[^_�forselectcaseesacwhiledodoneifinthenelseelifuntilfifunctiontime{}t$x$$	�$
�$�$�$�$�$�$�$�$�$
�$�$�$�${�$}S��$�=�$t3��3����P�3h�^�5�����@�S�P���;u�[�S�\$h�^j�_�����@�@�@�@�@�@[�syntax errorh�%�n���S�\$�,b�L_�\b4b��`������t�����CH��v�{u�TV��V[�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $no closing quoteexcessive recusrsive aliasing��dUWVS�l$4�=PWtC�PW��Q�
�Q��~ �����Q��W� �����
�Q�����Q�D$0@h�^jH������D$$��L$0�L$ �ƊD$x$t
�D$�s�D$x$t�D$�a���D$��`��8t�8���
�ǃ� t���	tۃ�#u&����`��8t�8���_
�Dž�t��
uܡ�`��=TWt�TW�L$x�L$�L$�L$�M����`��8t�8���
�Dž����|$u����%���a$�e9t$ w:�\$$�L$0L$0h�^�D$4��PS�"����D$$��L$0�L$ ��)؉�t$$�9D$�p����L$�$��(��(l,x,�,�,�,)P-��'tK	��"tT�j����\uh��`��8t
�8��
����7�ǃ�
t��`9t$$�%���������E�D$�E��E�D$�E�F���������\t#��\��$�����`������`��8t�8����ǃ�$�t�����
�u�����"�`��������\�S�����`�J���9t$ w:�\$$�L$0L$0h�^�D$4��PS�����D$$��L$0�L$ ��)؉�t$$�F�\F��b����`��8t�8����ǃ�(uE�D$�E�O����{�'E�D$�E�F��`��8t	�8��
���
�ǐ9t$ w:�\$$�L$0L$0h�^�D$4��PS������D$$��L$0�L$ ��)؉�t$$���ȈF��`��8t�8����[
�lj�����a$u��F��}�{��#t��%u5��`��8t�����
9�u�π�A��`��5��:u+��F��`��8t����
�����	���������F�������L$�ъ�a$���F�9t$ w:�\$$�L$0L$0h�^�D$4��PS������D$$��L$0�L$ ��)؉�t$$���ȈF��`��8t�8����G	�lj���%���a$u��F��h���a
tW9t$ w:�\$$�L$0L$0h�^�D$4��PS�^����D$$��L$0�L$ ��)؉�t$$�F�L$�F�F�����F�$F��`�����E�D$�E�F�z�������'t�b�������"�����M�M�L$�F�Q������(uE�L$�M����)u	M�M�L$�|$���F��������}�����M�M�L$�F�������`u�FM�M�L$��������\u@��`��8t
�8��
������ǃ�\t��
�������$t
�����`t�\F���ȈF���������)�������`��8t
���������)t��`�������1�9t$ w:�\$$�L$0L$0h�^�D$4��PS�����D$$��L$0�L$ ��)؉�t$$�L$9L$t
h�&�����<t��>u8�T$$9�v!�:u�B��a$t���F���������>��%��D$9t$$�'�|$�h�^V�������;t=��(��%��
���&t"���>tk	��<td�����|t��[^_]��d��`��8t����g9�����;t��|t�,��&u��
������먐��h�^j�0����ËL$���`��8t��D$��
����D$�|$>t�|$<uM9|$u��>u
�C���C�
����C��`��8t��D$��$���D$����>u�C�	���C�{u�|$-u4�C$�2����|$&u	�C��|$!u�{u�CB�	����`��P_�[^_]��d��'�D$x$�����
[^_]��d���`��8t��D$��	���D$�|$)u��K������|$(u
��8��������`��)����Fh�^��+D$(P�t$,������P_�D$�����w�[^_]��d���`��P_��b����
@B���bs�8@��t������B���bv��t��b�=�b��D$x�
h�b�����Ph�bh�^�8��������$���{u'�D$x$th�^�5P_������C[^_]��d�{���D$x$��f�f% ���=�Quh�&��������Q��W��Q� ��`�xu�9X������@�xt�h�^�5P_�Z���j�����K��X�
�`�H��`�������[^_]��d�S�4b9\bv���3�Y����9\bw��\b4b[�wCannot create temporary file
here document `%s' unclosed
��UWVSj��$ �r������h�^�r����
�^���^�H��$�Jh=2�p���_���Dž�u
h?2�9���hjjW���_���t$��`�T$��8t�������
t$��uUh]2�������$9�s�؈F븡�`���t$��$�A$ t�|$	u�F��t�>	t�VU���_�����������&���W9Wr��%�PW����_���	��G��G�F��uԋ5�`��8t����3�Ã�
t<��uUh]2�1����O9Or��%�PW���_��볐���G��G릐��W9Wr��%�PW�b��_����������G��G�������W���_��[^_]���%s[%d]: %s
�,b��@��`��`�xt���`�xt�p�ph\4������`�}Q�t$he4�^����S�\$h�^j�?����X�}Q�@�@�@�@[�PS2
 VS�5�`������9F���F�$�85��\5h5<78�7�7�7�6�7�}Q1�[^Ð�=�b}�F�}Q���F��b��b�w�5_���j�����j������=dthh�b�5tQ�3�6��=dthh�b�5tQ��hh�b�5tQ����_���Å�}�4_��u�1�ƃ�bh�4����P�����_��u��N����1ۀ=�bt1��b��a}��bBC�:t���a|퀻�bu���b��N�\���b�P�.����F���=�bu�F�}Q�S��F��b��b�xQ����6he4�;����6h�b���_��jh�b����_����
�����b������F�vhh�b����_��������
`b9N���v�s��_�������F���F�F�p�F�8u�5�F�Y��5�F�I��F�@���8t#jP�5��_���X��� t��	u
�TW�v�5�`�PW�+��>u�F�G�������~t�5hb�6�m��_��������������[^�%dS�\$�;tr�;!t)�hb�J9Jr�PCR� ��_�L���B���)���C�;!u&�hb�J9Jrj!CR����_���B�!C�B롡�`�phB8�~���느�5hb�Q��_��[�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $sttyVS�t$�\$�=�Q*td��Q*��b��c��^�����b�����H_�����b������`������^��^�=�bt��=�QtSV�5tQ�1��_��[^Ð��j����=dt	SV��	��=dtSV�U�����������j�x����~h9V���_����t
��b��}�=<	`u
j�ȍ����[^Ã�j�D$P�5tQ���_����u�D$����á4_��uҸ��������5db���_�����^��^���^����c)‰У�c9(bv�(b��c��Q�5�Q���������S�\$��
t��
u
��c�
�Q9
�c}S�db�J9Jr��%�PR�y��_����B��B��t	��t�����
t��
u
��
�c���c�=�^t�=�c|��Q���9�c|����[�VS�\$�5�^�;t����PC�>������;t95�^t�[^���WVS��bh|W�5tQ�D��_����W$u
��Q�XW�|W��	��kW��^�
lW�L$�
b�iW�b�jW��`�%XW�����%dW��nW�oWPR�5H_�t$S���[^_���S�D$9�Qt.��Q��Q��thXW��h|Wj�5tQ���_����[�WVS�L$1ۀ9t4�5�`�A<!tC����9!uAC�����F�C�
������9u҉�[^_�FCEDITEDITORVISUALVS1��=�QtC��Q���3����P������t�8u	��F�;uۃ<��Qt
��t	P���1�[^�emacsviS�\$j/S���_����t�Xh]=S���_����t�d�d[��hc=S����_����t�d�d[�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $auto-inserterrormacro-stringdelete-char-backwardeot-or-deletedelete-word-backwardbackward-wordkill-lineabortno-opforward-worddelete-char-forwarddelete-word-forwardbackward-charforward-charsearch-characternewlineeotup-historydown-historysearch-historybeginning-of-historyend-of-historyend-of-linebeginning-of-lineredrawprefix-1prefix-2kill-to-eolyankyank-popquotestuff-resetstufftranspose-charscompletecomplete-listlistcomplete-filecomplete-commandlist-filelist-commandnewline-and-nextset-mark-commandkill-regionexchange-point-and-markprev-hist-wordupcase-worddowncase-wordcapitalize-wordTE�=�U>�E>�F>�M->�H;>�HP>b�O^>\Uh>$[n>�Ht>fG�>�H�>d�K�>�K�>L�>|L�>
|L�>
�L�>\Uh>�L�>�L�>�M�>�L?<�L?>lP,?�P8?�PJ?8SQ?HSZ?XSc?To?�Tt?y(S}?�U�?�U�?8R�?�^�?_�?�^�??�^�?�^�?�^�?�^�??�M�?dZ@ tZ@�Z%@Le=@.Le=@_eL@0eL@1eL@2eL@3eL@4eL@5eL@6eL@7eL@8eL@9TfM@UTfY@LTfg@CTfM@uTfY@lTfg@cWVS�D$�T$�(b��c‰ b��c��c��c���Q��W�X�XTV�=xQ���=�W�=�Wt�5�W������W�5_�z�������c��^��c���=�Q)lj=�^��^�����X�8u��������}"��[^_Ê�X�X�8u
�XTV�=X�u�TE��ȃ��X��	�Q�����u��U���X����	��XV�Ӄ��Ƹ9��c����$�EE`D$E@E`D��W�=�����5�c+5(b��W��[^_��<	`�����[^_����D$��t%�D$f�T$f�T$�D$P�X��1���Ð��j�I�����1���ËT$�X�8u��������	�Q���X1�Ðj�
�����1��WVS�\$�5�^0������������Ѝx����c9 bwj�������[^_Ð���c9�ct&��+�c@P�5�c���cP���_��������c�WS�5�c���_����c=�c=�c��Q�&!��c9�c���ƒ���^S���95�^u$��c9�cs�K�P����9�cr���^[^_��(b9�ct��cHP�"��j�D��1�Ð�j�������1����c9�ctj���1�Ðj������1��UWVS�l$���5�=�Wt3���c9�Ws��c��W����c9�Wv)-�W��~	U����)-�c�5�c1��]����t�PF�:���K���u��c+�c@P���cP�5�c����_����^�5�c�����c����Q)Å�~79�~�ߍ_����t�j ������K���u��_����tj������K���u���^��Q�;��95�cs�N�P�&��95�cr�[^_]��CP������1���/1�����cP�[��1���P�u�����1��S1ۋ�c9(buj�������1�[Ð�=�Wet
��c�
�c�=�c�tP�
	`����JC9(bt,�B��Au�z�$u���B��Au�z�$u
JC9(bu��
�c�=�c�u�R�����[�S1ɋ�c9�cuj�@�����1�[Ð�=�Wet
��c�
�c�=�c�tR�	`�9�ct4��Cu�:$uBA9�cu����BA9�ct��Cu�:$u��
�c�=�c�u���[�S�\$9�cw��c�^9�r��c�=���[��9�cv(vQ���
�c��c�P�@��9�cw�[��9�cs#s!����c�P��c����9�cr�[�S�t$�J�����
���j������K���u�[�VS�\$1��;t����PC���ƀ;u��[^��D$��	u�Ð��~��u�ø�VS�\$�5�^�s���PC�"���;t9�cv95�^t�[^�    S�\$��	uhYK������[Ð����~��u&j^�G������?��t��@P�0�����[Ð��S���(b9�ct��cHP�N�����1��j�������1����c9�ct��c@P������1��j�������1��S��c������Å�|9��c9�ctS��c@P����_���1���u"S�5(b���_����uj�p�����1�[ÐP������1�[�j
�Q������������c�
��c����hT_�B��1���5xQ�1��1����W���P���1�á�W��P���1��WS�|$��T_r9=xQsj�������[_Ð�=�W�5(b���������7�5(b����_���(b��c0��?����������H(b��c��c��Q�*9�cv�5�c������[_ÐS�
��[_ËD$��W����WP���������D$�(b9�ct
P�@������P�������
I-search: ��WVS������t$�D$�������}h�M�Z�����W��������=������������}1�[^_��Ð��ȃ���Q�����t=�MtT=�Ft�=TEuZ�ȈF���|:W�5(b�
���Å�|%��(b��)�Ѐ|$^uHP�i������Y����SW�9�����G�������
�W�X�W��}
j����1�[^_���UWVS�t$�l$�=�W�\V�7�����|K��}
j
������W���������(b0������������ЍD��>^uHP��������[^_]Ð������T_s�j�Z������xQ��W�����[^_]�WS�\$�D$�8^u1�P0�������������HPRS衾�_������%���[_Ð��PS赾�_����t)�[_Ð�����[_�VS��c���c+(b�5(b�������Ƌ(b��cS�l���(b��c��c��c��Q��c���WV�C��1�[^��5�c������1���5(b������1��j��	��1��VS�\$��^���uj
����j
�
����������(b9�cu!�5_�`������5_��������c��c����Q)‰�^��Q��5�c��������(b9�cu��c9�cv��Q������c9�cv1�������c+�c��)�1���j �I�����C9�}��Q���9�c|� ��c9�cv�>�(b9�cv�*��(b9�cv�<V����������t���j�������K���u���c9�cs��K�P������9�cr���^[^��
(b9
�cuj������1��
�c9
�cun��c+(b��tԡ�c�@�P�#�������c�@�P��������c�@�P��������c�@�P��������c�P��H��H��P��X�����c�@�P���������c�P�p�������c�@�P�^�������c�P���H����c�P������1���X����1���X���X��S��c+�c��c��c��QS���S������1�[�VS�\$h�W�CP�l�����S�5�cV�&��_���3�X�<��Wth�W�4��W�K����X�4��W�X@�����X[^�
nothing to yank�=Xu�X�����X�X�
X�X�<��Wt��c��W�4��W�g�����1�ÐhT�������j�� �����1��
yank something first��WS�=�WTt+�=�W�Tth�T������j��������1�[_���0ҡX�<��W������������K��c)�P������S�5��������=Xu�X�	����
X�X�<��Wt��4��W������1�[_����(b��c��c��c��c��Q���j�E�����1���t$�������(b��c��c��c��c��Q�j��������1��1��VS�T$�Ѐ:t6����8^u#@�8>~��B��8?t��������^BH����B@�8u��[^��D$��~��u"��W^��W�?��t�€�@��W�
����W��W���W�%s%s = %s
'%s'
VS�\$�t$��u�5�Q������PhlV������u�5�Q�m�����PhlV�s���V�V�����PhoV�\���������	���Q��8�Et�phuV�-���[^�����Q�4hyV��cannot bind, not a tty
%s: no such function
��UWVS�\$�l$ �D$�=�Qu
h*W������uG1��1�������	�Q����t�;TEt�;�Ut
VW�������F��~�G��~�[^_]���S������1���Q����3����	Ћ��88Su��
�8HSu�C�ԅ�uVW�e�����[^_]��Ð��}u
�x@��|$$ua�x@�=x@t'���U�s践�_����t���;u�;t�C
$tUhBW�����;8Su�5�Q�;HSu(�5�Q� ��@U�1�����h�WU�������D$������	���Q��@
$t���Q�<th�W�4�3���������	��
�Q�L$��Q�L$�[^_]���Sh�W�e���h�Wh�������Q����x@���Jy����Q������ڸ����@���y��A��~�x@�=x@t%��Qf�yt�A�Q	��	؉����9u�h�Wh�6�����Q����������y�A��~�[�WVS�|$�T$�L$�\$�t$ ��Q���@���@���@���@���@DŽ��@[^_���c��W1��VS�=�Wuj�N�����1�[^Ð���c9�Wv��W+�c�5�c�����c+�W�5�WV�L�����S������S�f������5�W1�[^Ã=�Wt��W��c��WP������1�Ð�j������1����./��HUWVS�D$0ҋ|$`����������щ�M�|$\��h�^�|$`��������щL$�D$�D�D$�t$�����Ët$\�*[����u��=���t$\�,[����uf�,[f��h,[�t$`S�E��_��P���_���t$`S���_���D$PS�ٱ�_����u<f�T$ f���f��@u
�D$/�(���f���ujS�5��_����u�D$*�|$tEh�^S�����9- X}�- Xh�^�]S�����t$`h�^S������V菱�_���|$\t�|$t
�D$�D.��D5�,X9$XrN�$X+(X��h�^���D$�t$�5(X�����(X����(X�$XÉ,X�$X�0�$X[^_]��HÃ� UWVS�$X+(X���T$(�(X�D$,�Yh@�t$,�t$4�}������
 X��}������ʃ�� X�t$(N�
�Q�ș�= X�É�����A�L$ �D$9L$�����1��D$$j
�������D$�D$(9D$���l$���|$t,9t$$~&���j	����������}�N���4�9t$$݋T$,���3�W�������\$0ɋ|$����������щL$�t�� XT$$h�^�t$�����l$ �D$ D$9l$(�k����D$�T$ 9T$�)���h�^�t$0����j�������[^_]�� �j���1��j���1��j�I��1��j�9��1��j�}��1��j�m��1��j�	��1��S�\$��c�H9(bt�8 t�8	u�9(buj/P轮�_����uS�l��[Ð��S�
��[� ��\UWVS�D$�����D$��$h��c9(btK�; t�;	u�C���a$t
�{<t�{>uC�;<t��;>t���$pt)���P��c�u�������c�8t
�8 t�8	uڃ�$pt6� Xh�^j@������(X�$X��@�,X�	�����CF�;t
�; t�;	u��j ��$lS�u�����VS豭�_��h�^V����j/S���_���Ņ�t�E�,[9�t�؉D$ �
���D$ *[�t$ ����_���D$�|$uj������[^_]��\Å�u��$h����E0�������������H�D$�\$d���t$�ϩ�_�������p
�x
.u�xt݀x.u�xt��t$VU���_����u���$ptD�|$�u"VS迬�_��0�������������H�D$���D$VS�e���D$�Dd��$p�c���V�t$$�������Q�����t$藠�_����$p���|$�����u��$p������T$�tdV��������|$����$h9�uƄ$h�0����$i9�uƄ$iƄ$h/����h,[Q赫�_���D$dP��$lS蠫�_���D$$PS�j��_����uf�D$,f%�f=@uh,[��hk_�:�������$pt��$pu�|$t�g���[^_]��\Á�UWVS��$ �=�c9=(btO�? t�?	u�G��$(t)���P��c�U�������c�8t
�8 t�8	uڃ�$(t6� Xh�^j@�ҽ���(X�$X��@�,X�	�����GC�?t
�? t�?	u��0���$ ����������H�D$������D$h_������T$�T$����ƅ����$t�^0������������Ѝx�9|$��t$S��$(P�m��_����u���$(t4���uS�t$�
��_��������D$S�t$�������D,��$(�j����FPj��������W��������$(tx��|u ��$(tj�W�����[^_]��Ð�T$�\S�6������|$uhk_�"���������$(u�]�����$(t��$(u�|$t�=���[^_]���S�\$�L$�؊A8u��t��@�A8u��u�)�[ËD$����У�cx	�=�c	~��cj������1��WVS��W���=T_r9xQsj�g�����[^_Ë�=�WetV0������������Ѝt�9�v%���> t�>	uN9�w�����N9�v
�> t�>	u�> t�>	uFV�������x����ր>t9��> t�>	u.F�>u��&��F�>t�> t�>	u��
���> t�>	uF�>u��c�
�c��͉��F�>t
�> t�>	u���R�������1�[^_�VS�t$��c9�cuj�e�����1�[^��_�=�We����c����9�c����	`��C9�c����Bu�;$u�9�c����Lu ��	`�P$������9�ul�n����	`�P$th����9�uP�	`�R���	`�Pu�;$uM��Uu �P$t8��%�9�u�	`�� ����P$t����9�t���	�	`��C9�cu��
�c�=�c��	���S������1�[^�VS�=�Qu21���c�����P�3������C9�cv95�^��c��Q��c[^�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $VS�t$�\$��[j��͢��@��[��[��[��[��Z��[a��[��[SV���[^�/?VS�\$�=�[	t-��
t��
u#j
������j
�����������[^��
9�[�G��[�$��h��� i�j�j$k�k,m,m,m4j�k�k�=�[t_��u��[�^S������tj�����"���=�[u�|Y�H�&���=�[��%�P�����\X�`X�Cσ�w��Љ`X��[�p�0X�\XS������[�=�[	�E�T�|Y�@�@��/u$jjh�h�^�����w�����[^Ð��jjh�h�ڐ���Q$ t"�|Y�B@P�r���j�y�������|Y�H�P�
�@j�d ����[����	`�X$t�`X���DCУ`X�~���\X��0X�\X�����dX�Cσ�w��ЉdX��[1�[^Ð��\X��0X�\X�0X9������Q$uw���	`�X$t�dX���DCУdX�����=`Xu�5dX�����5`X�5dX�5`X�\X��0X�\X�0X9�tR���Q$tS�	����[���[�u���u��[�`�\X��0X�\X��[�@��
t#
��
t�����������t&����Zƀ4Xh4Xh�[���_��멃=�Zu�2��[�F���
�Z��Z��4X~	��4Xu�|Y�H�|Y�H�p�pj�R��1�[^Ð�j�A������Z�|Y�@�@����=�Z'uj����봐���Z��4X��Z��~��u�|Y�H�P�
^�@�H�P��@��|Y�H�P�
�@�|Y�R������[��t"���G�V�������F����[h0X�5`X�����t����������t7����=�[t
��Z�=�[��%�P������j�
����������[�=`Xt�5`X�5�[h�[�5�[�!������%���t �n������uyj������j��c���=�[t;�=�[st�=�[ct	�=�[Cuj��5�[������t
j�[�����j�Y������[j�;�����1�[^��T$��ru�
Ð���Q$t�À��Q}�	Ð���Q$t�Ã�.u�Ð���Qu�Ð��VS�\$����������t^�u���t�����_�����t;�R���=�[st�=�[ct	�=�[Cu
j����[^á�[HP�쐐��|Y�z���=�Z~�
�Z�J�=�[�k�B+BP�B@BP�BBP���_���|Y�H�@���|Y�z�.��Z�B+BP�BBP�r�И�_���|Y�p)p�@�����|Y�x��j�j���á|Y�P+PR�PPR��p��P�y��_���|Y�P)�)P�@)�9�Z}��Z�)�Z�|Y�X�~�|Y�BH9Bu	�����[^Ð��Z���Y��Z�=�[u&�B+BP�BBP�B@BP���_���|Y�@�
|Y�Q�A��A�=�[u�q9q~�A1�[^� #��UWVS�\$,1��u!�t$0�>Gu
��[C���|$0�?_t��D$0����Q$t5j�t$4S�����…����|Y9Pu��tJ�|Y�P�����Q$uZ��Y�5|Y�t$�>�:�v�D$ �p�r���_����Y�5|Y�~�z�F�B��[j�t$4h�[�ߖ�_���t$0���Ѓ�l�(�$� r��s@}@}@}@}@}@}@}@}@}@}@}@}@}@}@}@}�z@}@}@}@}@}@}{hv@}�v@}6x@}@}@}@}@}@}@}@}@}@}@}@}@}{@},x@}�s@}�u�u@}@}v@}Lv@}@}@}@}Rx@}�u@}w@}@}@}@}@}�w@}@}@}@}@}@}�x@}�s@}0t0t@}@}@}@}<vhv�v@}@}Rx@}$u@}�v w@}x@}@}`w0t@}@}@}@}Dz���b	����[�|Y�zt(�B�#���[jj�E���=|Y�G�G��[�	����t$0�8Fu1ۡ|Y�P����D$0�x���Q$�j�D$4@PS�����…����t$0�>cu7�~wt�~Wu+�|Y�X�@��
	`�A$u��J��A$u�B�
|Y9Q}�Y�����ӋQ�|$0�?ct9�tRS�T$��
���T$�D$0�8ytRS�P���|Y�X�t$0�>c�$������[�|Y�zt�B���j�5�[h�Z�����uK���|Y�zt�J���������[^_]�����[��j�5�[h�Z������u�K������[�|Y�p�p����|Y�p�p�����|Y�p�p�e���|Y�z�>�J�6��KS�5�[�'�����Q�����[��[������[��������[�|Y�@��������[P�5�[�������������[�[���[)�P�5�[������������[)�[�q��
|Y�y�������[�Q�I�L$�t$0�F��=���[��[�#����|Y�z�E�����[��B9B}�Z+Z��BP�r��
�������|Y�z������[��B9B}�Z+Z��BP�r����|Y��BP�r�
�����|Y�z�������[9Z}�Z�r�B)�P��
���|Y�p�@)�P�V
���|Y)X�2���=|Y��Y�|Y�=�Y����[�������Z�t$0�>�=\R�=\R �����=\R?���؋t$0�>Nu��4��h�[S�5�[�5�[�Q���…�}���������
j�,��������[��[�s���j��5�����������:������
	`��A$u�:
uB�:u�:�_���KtP�
	`����B�:�G�����A$u�:
u�:�/�������A$u�:
uB�:u�:����Ku��:�������B����1ɀ}t4�=	`�|$��Ƌ|$�w$u�:
u����t1ɉ�B�:u։���[�
|Y�yt�A�:t$��
	`�
���CB�:t��A$u�:
u�jjh#q�h
����ujSU�X
����t�������������|Y�z�9����J�1����|Y�z�!����ZZ��	`�J$t��[�����9�u.�	`�#��J$t!��[�����9�u	�	`���|Y�BH9B�}�B�u��|Y�@jjh%q�	����������[^_]��Ð��D$$��Y�h�|Y�B�J��	`�C$�D����L$�|$�~!�щ��L$�|$�~�A�|$�4�r$t��D$�|Y�r�t$9r~4�z�>�D$�
	`�t$����D$�|$9z~�B�4�q$t�\$+\$S�|$�5|Y~�|$ �t$ U���_���|�*t�+*�D��+U����É\$ U�3���_����u�{u�D$$�����|Y�p�pU迌�_���|$$}
�D$$[^_]���D$0�8=u_�5hbj
�B��_��j�t$$�7���5hb趇�_���|Y�zt�B���[��[1�[^_]��Ð�t$�t$����t$�=|Y�w���j��D$ �T$ ��0�����������JR�t$$����D$��u���;tjjh#q�h����t��D$$������[��[j�
���|$$������=�[u�|Y�zt�B9B|�J1�[^_]�����UWVS�t$�l$$�D$1ۋ|$ ���иo9��e�$��}������������������������������������������������������������������������������������ �������H����d�������������������������u�|Y�x��V�/�����u�|Y�x�kV�������u�|Y�B@9B�GV�{�����x���u�|Y�B@9B�V�������P��L$ �9�=XR�y�=�[�=XR ���D$�=XRft	�=XRFu�D$�=XRa���ЋL$ �9,u��4���t$RV�5�[�T$$�(���ËT$�����������������u�|Y�x�[�|Y�X)���1������u�|Y�B@9B�+�|Y�x�b��X9X�T�XK�K�����u�|Y�B@9B��V������u�|Y�B@9B��V��������1ۋ-|Y�uN9����E��	`�B$���C9����E��B$u���|Y�x�����X���|Y�X9X~)����@�P����D$�|$uC�|Y9Xڡ|Y9Xt�����|$~C�|Y9X�����[^_]��ÐKx�|Y�@�P�����9T$uF���D$��9�uN��u���tC��[^_]���S�\$�1��=�[��%�P�5�Zh�Y������t	�����[Ð���K��ɡ|Y�x~�H��[1�[��T$�D$)У�[tP�|YP��Ph�Z�	��_����D$��[t/
��(t ��)t3�I���{t#	��]t,�:����}t+�1��Ð��Ð��Ð������Ð������Ð������Ð�1���|Y�p�ph�\苅�_���|Y�@��]��]ƀ�\��|Y�@��]�P�5�]h�\�p�D��_��ËD$�T$�|YhY�lY�pY��YDR�LR�PR�tY�TR�xY�DR�hY�5_蔸������[��[��Q+�[�����[j
虶�����)����5_���������\��\ ��\�VS�\$��u1�[^Ð�|$t)�|Y��J�BH9�|
�����[^�9J}A�J�<���
|Y��Q�AH9�}׋A+AP�AAP��AAP���_���|YXS�t$�|Y�pp��P�ރ�_���|YX1�[^�S1ҋ
|Y9Q~"�A��	`�
B9Q~�A��C$u�Rj���[�VS�t$�\$�|Y9Zt�B)�P��BP��BP�`��_���|Y��)�)B[^�WVS�|$�L$�t$�|Y�xt�PI���t-�����tB9Su
�����[^_ÐJx�C�9�u�I���u؃|$u
��tJ���B��[^_�UWVS�|$�|Y�H9H��O������Ëk�5	`���)�Fu�<)_u ��S�����Fu�:_u2BA9K��)��F$u!��S��Fu�:_t�F$uBA9K�S���F$tA9K�9K~O���u���[^_]�UWVS�|$�|Y�H��~tO���tn�ŋ5	`��I��~_�]��V$u��Vu�<_uIx7������Fu�:_u#JIy��Ix�E��Vu
�<_t�V$t�A��~O���u���[^_]���UWVS�l$�|Y�P9P��M������Ƌ^K�\$�=	`��B9T$~n�^�\$��O$u�FH9�}T�Ou�<_u'B9V~A��L$�����Gu�9_u*AB9V��!�B9V~�F��Ou
�<_t�O$t�J9V~M���u���[^_]���UWVS�t$�|Y�P9P~CN���t=���i�=	`���*�G$uB9Q�Y��G$tB9Q�9Q~N���uЉ�[^_]�VS�L$�|Y�P��~>I���t8�Ƌ	`Jx"�F��C$u�Jx�F��C$t�B��~I���uЉ�[^�WVS�\$�|Y�P�pN9�}LK���tF�����5	`�B9�}6�A��F$u�AH9�} �B9Q~�A��F$t�J9�}K���uʼn�[^_�grabhist: bad history array
��WS�T$��|89�[|0u
����1�[_���R袁��芁���uh!�躚�������[_��Ã|$t�����|Y�D$0҉߈�����������J�D$�PRS�D$�p��_���|Y�@1�[_���UWVS�|$�t$�l$ ��u��t��[H9�|��u
�����[^_]Ð��UVW�0����Å�u'��tޅ�t�Uh�\�ԃ�_����|��,���1�[^_]Ð���t��|$t������|Y0�������������H�BPS�r�[~�_���|Y�@�k�[^_]�j
�-�����j
�#�����賯���5_脭������[��[��\ �S�\$��}��\�	�����\�Y��t�S��\����)Ѝ���[P�+�\����)Ѝ���[P�U���+
�\�
�\[�S�|Y�9H}�[�1ҋ9X~&���R�|Y�@�PC�����¡|Y9X�9�[|1�[Ð�[���UWVS1��D$1�1��D$1��|Y9h~m�����+T$��[���[��9�~�l$�|$�\$�t$V�|Y�@�PC�V���ơ|Y9X���W�|Y�@�DPE�/���lj�)���[���[��9�Ρ|Y�([^_]����T$�D$��~��u��	u@Ð���@���UWVS�|$$�D$1ۡ|Y��D$�t$�L$9
�[��9P�����9Pu��t��
�[�L$�|Y�@�<~�<u;�<	u�� FC9�[~.��$u��&����^FC9�[~�|Y�@�4@���FC�|Y9Pu��u��
�[�L$�L$B9�[~�|Y9P�`����|Y9Pu��
�[�L$9�[~~� FC9�[����D$� ��[�t$�l$ �=�[�4����8Mt'9�[t
�t$S����P��������[FECO���uɡ|Y�8~�|$t�+��8~�<����� �|$t�>8�\t-�t$��Q���P�?����P臬������[��\�L$9
�[t�t$�t$���[^_]���VS�t$�\$95�[���V��[)�9�}Xj
�)�����蹫���5_芩�����
�[�
�[��[��[9�}x�PC��������[��[9�|��Z����[�
�[9�~I�j���������[�
�[9���-���[+�[����PC蒫������[��[9�|�5�[[^�S�\$�D$=v�PS�����������S���tP��������u
�␐������[Ð�|Y9Xt�p�pS�"y�_���|Y�@�
�|Y�@�@[���j�D$P�5tQ��z�_����u�D$$<t<����������hj�|Y�p��x�_���|Y��@�@�@hj��Y�p�x�_����Y��@�@�@j�߫����j�]7���D$��������T$�$�D$j&�D$P�n������$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $%S (%T)%T| %T%;||&&%s %Tfor %s in do %T%;done case %S in%;(%S%c %T;;%;esac if %Tthen %Telse %Tfi whileuntil%;do %T{%;%T%;} %T&function %s %Ttime %T<botch>UWVS�|$�l$���o�J�9��0�$���0�������ؒؒ��|����������Ԕ����|��_�;t�3��h��U�����;u�_�;���3��h��U����;u�������@����wh��o����wh�U�~�����������wh
�U�b��h
�U�T����������wh
�U�:���w���?u��Ph������wh�U�
���t?h$�U�����_�;t����3��h��U�����;u�h
�U�����wh(�U���h.������wh6�U����w��tghC�U����^�;t9���3hE�U�g���)�{t�|PhH�U�H�����;u��vhK�U�/���v��u�hS������whY�U�
��h
�U������t�wh_�U����h
�U�����t�whg�U���h
�U���ho�����w�y��?u�s�Ph�U����wh�U�q��h.��X����wh��U�V��h���=�wh���"���w�wh��U�/���$���wh��U�����h��U�	���_��t�;t���3��U�5���;u�[^_]�< <<- << '>> >! > <&>&%s %s' WVS�\$�|$�w�?~���0PhH�S��������P��9����$����ĕ�2�̕���h@��^���$ t
hC�����hH�S�9����$uBhL��2�hN��*���$@t
hR�����hV����?uhY��h\�S����������u(��$t�wh_�S����[^_Ð�whc��萐�wh����S�\$�T$��t'�J9Jr��%�PR��i�_���!�B��B����
�]x
��]���]��[�VS�\$�t$��`u-V�^��}�$P������V�؃�@P�{�����[^Ð�؃���uV�^��}�$P�U�����Vj?�͐VS��WVS�\$�t$1�����C�9�r��$�L��×l���������ؗ��uSVj\��������F����Vj"����1�Vj"�w�Vj$�������Vj{�VR��������C��u�;�u���V�PC��������b�����Vj}�1���Vj$������Vj(�}�������V�PC�������;u�Vj)�]����������[^_ÍD$P�t$�t$�F��1��S�D$�L$�T$�\$��]��]RQj���jj������1�[�; 
UWVS�l$�|$������%���U�Z�E�:9����$������P�����������������������������������������������ܙ<������������������������������������������������������������������t$���w�������_��;����t$�PC�������;u������t$�w��=�������G�1���du����j
��t��P�ds������tK�-�;tk���t$�PC�>������;u��Q�t$���w��m����=����s��|$u�p��;t'���t$�PC��������;u��
�t$R��������UE�������[^_]�UWVS�|$��u1�[^_]Ð�t$j�U����ŋ�U�t�t$�w����1��E�u	�E�Q�_������u��t$��+G$�P�����E�Ƌ_�;t���t$�3���������;u���u	�E�Q�_������u��t$��+G$�P袅���E�Ƌ_�;t���t$�3���Z������;u���t�t$�w�����1��E�t$�w��������E�t$�w��������E��[^_]�WVS�t$�|$jV�%����)�WS������SVW�l�_����[^_�VS�T$�t$1��
B�9�r��$�D���t�t���0�0�d�x�C����B��u��:t�B빐��u��u��[^Ð�K륐�B��u�뛐����UWVS�\$�ݐ���E����u��t$ ��)�$�P�R������D$�;tY�߉l$���7�t$ j�+����ËT$����V�S�V�S�~t�t$ �v��������C���D$�D$�?u��T$�D���[^_]���WVS�t$�|$�����~tW�v�ƅ���~t(�^�;t�W�3謅�����;u�W�v蘅���~t*�^�;t���W�3�|������;u�W�v�h����~tW�v�*��W�v�b�����W�v�V�����WV�4���[^_�WVS�|$�t$�����{tW�s�
���WS���������u�[^_�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $%s: %s
��UWVS�|$ �D$��u
1�[^_]��Ð���D$$$ t$�D$$$u�?t�t$$W����[^_]��Ð�j�el�����$b��t�p)�u�?uOh�^j�!�����^1Ґ����^f�PB��	~�D$$$t
��^f����D$$$t��^f�@���t�_�;t�3�������;u�J�9��
�$�p���������4�\�\���s���D�ܢܢD�s���H���(�8���^�t$$j&�w�X���Pj �w�J���PW����D$�w�D$$ P�w�i��������D$$ �D$$�D$$$��D$$j轄����^f�j誄����^f�B�D$$�D$$j��^�P��b�_���?uV�\$���S�2���j�t$�b�_���t$$�w���j�t$�b�_��S�:����D$$�D$$��?t��D$$$��D$$j��^�@P�Vb�_���t$$W����j��^�P�6b�_���D$$$�b��D$�a�Oj�w�F�������?t�jW�3��������D$$"P�w������j�w�������D$����D$�����Ѓ?��%�9���j�w������y�����^�tj&�w�n�����������^�X���h�^��^�_���…�t
����␐�;�r����3���w��l��P�p��j�w�M������D$�;u��;��^�tj&�w�ބ����������^�X���h�^�N^�_���…�t
�����␐h��j��j�_��1퐐�US�%���Ń���U�w�&l��P��o��j�w�������D$�Ð����^��h�^��]�_���…�t
���o�␐j�w�b����������Ѓ?��%�9��Cj@�w�:������D$�Ő��%j�w��������u
j�G�p����j�G�p��������j�w�"����ŋ�����?����_�;t(j�3������ƅ�tVU��k������u ���;u؋�����?t�����j�w�~����&j�w�r�����w�w�A�
����t$$W�/���D$�L��G�0�s��S�w�w�_�_���=<	`u
SW����5<	`��i�_��PVhl�����g���=�^t�5db�_�_���5hb�_�_���D$$$t�t$�"_�_���D$[^_]���_:%s: not builtin
%s: undefined function
%s: not found
%s: cannot execute
��UWVS�t$ �|$$�D$�=dt
WV�������t0�?t+������8u��p�jhh���pp��P�Sm��h�^j8�{���D$�
�^�H4��^�h���u����dPS����ŋE����
��tJ�S���_�E�������t5S�w��PShb�Nx���Ņ�uSh���~���} �t}�u%���?u��^�����L$(�P�����f�Ef%t
�T$�J4�
�^f�Ef%��%��؉Á��>t��jS�6���Go���>u�W�E�Ѓ��x��E$uShѤ�j}���T$�z1��C�����u�K�L$�Y�1U�>tjh�6����n���>u���^h�^�Y�_����t�a�T$���j�u�J�������E$u5jS�)Z�_����}
Sh����Sh����|���D$���ujhh���Pn��P�3k���>t���jh�6���+n���>u�D$($t8��
�=
du�D$($u"jh�^j�?e�_��jh�^j�.e�_���L$�
xR�m�-�R�=lR�t$(hhR����D$�|$t�=dt�t$�Lb�����T$�a�D$[^_]���EXECSHELL/bin/shNo shell
��WVS��$hM��Zf��P�Ei���ƅ�t�>tj�5�bV�e���ƅ�u�W��G�O��G��D$j�w��`�_���Å�|%h��D$PS��a�_����~�DS�QY�_���|$#���|$
!���T$�|$����: t�:	uB�:u��:���:
t~�G�����B�:tg�:
t
�: t�:	u�:tS�:
tN�B�:tE�: t�:	uB�:u��:t0�:
t+�G��G�H��G�P���B�:t�:
t
�: t�:	u������G�0��$�w�G�0��Y�_��h_��2z��[^_���%s: shcomexec botch
VS�t$�6��r��P�6hb�t���Å�u�6h����y��V�C�Ѓ�[^�UWVS�l$�5�^��t[���5bU�r��PU�~W��s���Å�t�$u0�~4u#U�_r��PUW�t������C�v4��u��$t�5b�s�s������#��|$t"�5b�t$�������C�1�[^_]Ð��S�t��1�[^_]�VS�\$��;=uC�S��q��PShb�s��	0�@�T$�P[^�UWVS�|$W�q����1�j/W�b�_����t ��]��]��]�����^��t#��UW�CP�r���ƅ�t�$u�[4��u߅���UWh_�kr���ƅ�t9j�v�|U�_����t$�$t�5_�v�%w���F���u3UWhb�r���ƅ�uUWh_�r�����F��~u_�$uY�|$u��]��]��]j�5�bW����Dž�t"��b���]u��^PW��`�����F���[^_]�VS�t$h_��r�����r�Å�t1�$t��u�C�8/t�$t�5_�s�+v�����[^���@WVS�t$P�|$Xj/V��`�_����tWV�4T�_������%���!�[^_��@Ë\$T������b�;t����C<:twB�;u���bt�/B�������1�AB��u�Wh�b��S�_������u=��u%�D$Ph�b�`�_����u"f�D$f%�f=�u��b[^_��@Ð��K댐�C���]���1�1�[^_��@�%s: illegal >& argument
createopen%s: cannot %s
WVS�|$������w�?v�?u
��^�7�v�����^f�J�G����t
j$V�z���ƋG���P��9����$�����������Ȯ�jV��Z�_�K��jV��Z�_���Å�|jjS�Y�_���jh�V�}S�_����jV�Z�_����G��PV������:�>-u�S�+S�_���(�����a$t��X�����Vh����t����}$�G������u��RVh#��t��9t�7S�S�_���t	S�R�_���7�t��[^_�rexec:herein error
w+��VS�D$�D$h��P�T�_���D$�D$��u
�����[^��Ð�hjj�t$��\�_���|$�j�[����h�^�P�_����t%�D$��t�t$�S�_���<[�������[^��Ðj�e������T$�P��`j�Cv����=t
h���s��j�5P_�x����h�^�pu����^���^��u�Z��h���s�S�_���D$�D$��u��Y��hjj�t$�\�_���t$V�S�_���t$�hZ�_���pZ���t$�7S�_��P�R�_�����t$�R�_����[^���+ %s
VS�\$�t$hC���r���;t.�3��hE���r���;u������6��hE��r���>u�hI��r��[^�PS3%sRead error
REPLYUWVS�l$�=�Ruh�bj@�/o����R��]@�|$ujU�r����]h����\��P�_��Ph���
r���5hb��Q�_����]1�1�����Ã�������uh�������]@9�]&��]��@��]h�bP�5�R��o����R��|(�CЃ�	w ��R��]���]���tC�냐����
u3�=�]ujU���� ����������~/95�]|'�|���!��������R��]���]�*�������uhI��q�����R��]�Ph���[��P�[_����[^_]�%*d) %-*.*s ��UWVS�l$�|$���]��]��}t7���:0���������щ�K��9
�]~�
�]�
�]��]���:uˋ�]��]��	~����]�ؾ
����Ã�	�=�]��]��]��]�c���5�]5�]���t$��Q�Й�����
�]��]�Й���É�]��t��]�5�]95�]~�
�]��]1�9�]~g�1�9=�]~F������]�9�]~'�t��5�]�5�]�BP�5�]hk��\o��G9=�]�hI��Fo��C9�]���][^_]�����Sj�D$Pj�U�_����t	���t�����u�\$�
��������������[���$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $�P�_��]�4_� _�_�VS1���R��t3��f�Cf��u!Fj�C��P�PR�_��j�C��P�@R�_�����uυ�t
j�W�_����
�=
dt�
d�[^�job control requires tty
�=
d���=tQ}�
dh���m��Ð�8_Լ�<_�@_jh8_j�V�_���@_��Th�]h|^j�`V�_����Th�]h|^j�BV�_���Uh�]h|^j�$V�_��� Ujh _j�iV�_���5�]�5tQ�
X�_��Ðjh�^j��U�_��jh�]j��U�_����Tjh�]j�U�_���Ujh�]j�U�_��� U�%Tcannot fork - try again
/dev/null��UWVS�D$�l$��߉�$tU�t$������[^_]��Ð���5�R��t��f�Ff��t+�6��u�h�bjX�i���Ƌ�R�f�F�5�R��$t��]�V�
����F�F�Ff�n��$t
��R�V�
���+�F�t$h��j0�F(P�������FWf�F��������	��W��k��G��	~�1�jh_j�T�_�����K�_�Dž�}@�=<	`u ����tS�T�_����֐���͐��}f�Fh���k����t�~��M�_�F�=
dtG��$uA��$u�V�V������]�@�F��$u�v�5tQ��U�_���v�v�S�_���5�]������^�=	dt����$tp�=
dugjh�^j�eS�_��jh�^j�TS�_���=	dtjh�^j�:S�_����$u%jh���O�_����jW�8I�_��W�GH�_���5�R��t��f�F�6��u��tQ����jh _j�<S�_���	d�
d�b��P�t$��������$t0�V�0b��R��R�V��R�=	dt	V�F��jh _j��R�_����$u����ujV�)���D$�D$[^_]���j�5�]����UWVS�l$�1��=
dtjh_j�jR�_��������O����=
dt�4_��uh _�TR�_�	��j����4_��t���R��t�|$�f�Cf��t�f�Cf��u�C$u�{f�C
�a�f�Cf��u>�S��u�C������C����t	��
u
��tf�C
�C�������w�f�Cf��u�C��u��[���m������t����K 
�c�K$
x^�[��u�f�Ef��u�
�R�
�R�m�-�R�B��1���R��R��t*��f�Cf��t
f�Cf��u9S~	�S��R���u؀=
dt%jh _j��P�_���5�]�5tQ�R�_����t�5hbj
��G�_���1��[^_]��4_@�4_�(S�D$Pjj�P�_���D$P�R�_���=
dtj�D$Pj��S�_������D$P�~S�_����}�=<	`
u�4_[��(����D$P�"R�_����R��t�f�Bf��t9Zt���u�=
du�[��(�f�B
�L$�J�D$��u	f�B�(��|$u	f�B���D$H%��=�wf�B�L$+L$$�J �L$+L$(�J$�L$�L$�L$�L$ �L$�L$$�L$�L$(jh_j�]O�_���4_H�4_�4_��}
�4_j�D$Pj�.O�_���=
d�����[��(��4_��t�r���1��no current job
no such job: %d
VS�t$��u�=�Ru
hq��ke������u��RP�����uVh���Ce���=	dt	S�����=�^t�5db�E�_���5hb�E�_��jS�������[^�cannot find job
kill: %s
killpg: %s
VS�t$�t$�����u
h!��d���{u1V�s�H�_����}j�5<	`�N�_��Ph2��d��[^���t��uj�C��P�mH�_��V�C��P�^H�_����}�5<	`�\N�_��Ph<��2d��[^�job not job-controlled
cannot continue job %%%d
WVS�t$�|$����u��RP�����uVh!���c���{u
h��c��f�CS�f��j�d����u�s�5tQ�N�_��j�C��P�G�_����}Vh��ec����t1�[^_�jS������[^_�S��R��t�f�Cf��t	S�������u�[�S�4_��t�������R��t]���f�Cf��u�=	duf�C
f�Cf��tf�C
f��t	S���f�Cf��t
f�Cf��uf�Cf�C
���u�[�RunningStopped Done (%d)%sSignal %d - core dumpedHideous job state|%%%-2d%c %5d %-20s %s%s
��@WVS�|$P�t$f�Gf����f��t �����f����f��t������t�������
|��L$�
���L$�
���L$j(�W��)��4��R�K�_���ƅ�t
VS�K�_���������_Sh��V�K�_����ufj(V�eK�_����V��W����)Ћ��R��t
Ph�����Rh��V��J�_���}h���D$P�K�_���������f�G�G$�����t���R�G(PV�w�O9
�Rt� 9
�Ru�-����+P�wh����`��[^_��@�%s: no such job
UWVS�t$1�>%uF�<9<0}6<+t��t�v��<-t�n��<?t0�f���-�R���-�R��j
jV��J�_����������R��tr�~���f�Cf��tW�C(P�J�_����t�k���u��G���0������������Ѝx���R��t'���f�Cf��tW�C(PV�J�_����u�k���u܅�uVha��_����[^_]���R��t��f�Bf��u�Ë��u�1��1���R��R��t��f�Bf��t�zt9J~�J���u�9
�R~A�
�R��R��L$��R��t ��f�Bf��t9Ju
�B$u��Ë��u�1��$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $EXITSignal 0HUPHangupINTInterruptQUITQuitILLIllegal instructionTRAPTrace trapABRTAbortUNUSEDUnused signalFPEFloating exceptionKILLKilledUSR1User defined signal 1SEGVMemory faultUSR2User defined signal 2PIPEBroken pipeALRMAlarm clockTERMTerminatedSTKFLTStack faultCHLDChild exitedCONTContinueSTOPStop (signal)TSTPStopTTINStop (tty input)TTOUStop (tty output)IOPossible I/OXCPUCPU time limit exceededXFSZFile size limit exceededVTALRMVirtual time alarmPROFProfile signalWINCHWindow size changedWVS�|$���a$t@W��G�����ƃ�w W��G������)Ѝ��R[^_Ð1�[^_Ð���[^_Ð���R����{tW�s�5F�_����tփ�Ny�1�[^_��T$��)���ǀ�R�$b��u�=�^t	�=�^u
jh�^�Q8�_�jh$_R��D�_���VS��R��C��t	S�����Ny��$b[^�VS�\$�C�s��u
�;u�NB���;u�CV�@����[^�VS��R�=�Rth�b�5�R�XZ����R����C�{t.h8_h|^�3�D�_���=8_tjh�^�3��C�_����Ny�[^�S�\$h8_h|^S��C�_���<_�@_�=8_t��)����R[�VS��R��{t�Cjh�^�3�yC�_����Ny�[^�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $1��nothing to shift
S�D$��^�xt�p�3������9S|�C�����C)S1�[Ðh����Y���[�%#3.3o
S�D$�P��u(j�E�_����S�}E�_��ShL��?�_�����1����\��B��<v�S�NE�_��1�[�%s: not found
VS�D$�X��u1�[^Ð�j�5�bS�6������ƅ�uSh���.Y��V�=������u
�����[^��a[^�%�D$�����u��P�H�����P�_������bad -u argument
missing name
%s ��UWVS1ҋ5`b��|$�\���C<rt<et�F�<ut�?����6�1��1���a$t��4��aC��uh9��T$�VX���T$�;u������t�C<-t�?uhJ��T$�'X���T$j?�7�T$��A�_���ËT$�����=	d��CPhX��T$�X���5hb��7�_��������b���c����
���N9NrV�l4�_�����t�F��F����������u�[^_]����t<��\u7�N9NrV�)4�_�����t
�F��F����������
u%1��t��������
t#�t��%���a|
�ЈC�L�������h�b�7�T$�A��P�E�����T$�?����1�[^_]���S�\$j�lg�������XP�q;����[�%s: %s
trap: bad signal %s
UWVS�t$���>u4��R����{t�s�shl��~V����Oy�1�[^_]��6��������u
�.������1�����}-���}��1������6���R������Å�u�v�ht���U���{th�b�s��T���C��t00�������������Hth�bU�2?�����Ch����j�����1҃�w
�=	d����RS����>�`���1�[^_]�S�\$�;tYh8_h|^�3�E>�_���=8_u�{t6�C�T$�8_jh8_�3�>�_���<_�@_[��D$���8t�0�1@�����a��G<����^�����v�=�^u
jh�^�%1�_��5a�;�����cannot %s
VS�t$�~t�v��?�������5���-��=�^u#K�����8bu�Rh�^�0�_���;����^�����v��6hs��.T��[^�There are stopped jobs
S�\$�$V�=$Vu(�=
dt�B�����th����S���[���^�C��tP�?�����a�5a�:����[�set-w�{�%s: unknown option
%c: bad flag
��UWVS�-�^�

d�L$�|$���7��u'h������[^_]��Ð��>��1�[^_]��Ð�>-t	�>+���F<-���Ѓ��>u�����d�d���>-���>�����>oug�?t��7���T$�0=�����ËT$��u����7h���T$�R���T$��d��u��t
�d�B���u<��t8�d�/����<w����c���Ph���T$�>R���T$F�>�]����=	dt�d�7��������
d9D$t�����?tW������E��U�7�p;��������?u��)���H�EU����P�N���E�ǐ����������u��)1�[^_]���VS1��\$�	��@�8fuF�����t.�8-t��'���uP�.<��P��D���jP�����������u�1�[^��D$�p�p�q%���Shell: %8s user %8s system
Kids:  ����P�]<�_��h����6�_���4$�U��Ph���6�_���t$�;��Ph��6�_��h
��6�_���t$���Ph���v6�_���t$����Ph��\6�_��1����%8s real %8s system 
�� WVS�t$0�\$4�x^��c�D$P�;�_����S�v�r������ÍD$P�o;�_��)�P�t��Ph���P���D$+D$�cP�O��Ph����O���D$+D$ x^P�*��Ph����O��h���O����[^_�� ���UWVS�|$�^��)P�������ؾ<����������<����Ǎ�Ǎ���I�I�s�������uI�.I���
����׉ŀ�0���C��~݅�ى�[^_]���1��1��=:=.[=builtin=exec=shift=waitread=eval=trap=break=continue=exit=return=setunsetumasktest=timesulimit#���&���)��+� �4��:���A��G�\�L�L�R���X���_���i��o� �w���|�����T�����������$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $%s
-rWVS�\$���;u9h_�gI������$t�rhu��Q3�_�������u�1�[^_���3�y�����uj���������j�3���d������;u�1�[^_�HOMEno home directoryPWDsubstitution too long
substitution failed
OLDPWD%s: bad directory
CDPATH��(UWVS��$<�D$,1��D$$�k��u)h���D7��P�/:����u
h��dL��h��7���D$(�t$(��9���D$0�|$0TVu2h��$<P�p-�_��P�t$,�:���t$(��9���D$0�{���[�\$4�|$4���\$0��0���������щL$�����������щL$�T$)ʉT$�\$4����������щL$�D
�=�v
h��K��U�t$4��5�_���D$�|$u
h0��hK���\$+\$0S�t$4��$@V�5�_���t$4�S�@5�_�����0���������щL$�T$�D
�PV��4�_��h�^V�4�����,����}-u*�}u$hE��5���D$$�t$$�8���ž�}/t�}.uT�}/t�}.uH�}/uB�\$8SU�t$8��8����S�(�_����}ShL��J�#������S���h_��*5��P�8���Ã|$,��������$8�|$ �T$8�T$����$8�D$������D$�C�D$�;t
�;:u�;u1��C�|$ 9|$�����t!�D$�/�D$U�t$��3�_���|$�����l$�t$�t$�t$8��7�����t$�'�_����u�D$,�|$,u	���]�����|$,u��u�UhL��vI����t�D$8Phu��I��j��������\$0�|$8�|$0�|$$uhE���3���D$$��t�;tS�t$(�7�������t$$�o<���T$0�:t�t$0�t$,�7���
��t$(�G<��1�[^_]��(�bad -u argument
��UWVS�D$�D$�5db�l$���]C�;������C<nt<et�Z�<rt <ut(�O���D$�C���D$�7���D$�+�����a$t��4��aC��u
hI��&H���;u����}�`�E�8-�i����E�}��|$����\����S�G�F9����$�T������������������������������������������������������������������������������������������������������p�|��������������������������������������������D$������j��
�b��
�Z��	�R���J���Њ�<w>��\��G��<w.��\��G�$����N9Nrj\V�"�_�������F�\�F�N9Ns���N9Nr��%�PV�r"�_���	��F��F�G����������}t*�N9Nrj V�?"�_������F� �F�}������|$t'�N9Nrj
V�"�_�������Ԑ���F�
�F1�[^_]���%s is unknown
%s is a shell builtin
%s is a function
function %s %T
unknown%s is %s
%s is the alias '%s'
%s is a shell keyword
%s is *GOK*

builtin %s
*GOK*
��UWVS�D$1�|$���~vu�D$���7�����>-t������V�b=��PVh�^�>����u
jV�������Ã|$��1҅�t�S�9����$������$���P�t���Vh����)�_����5Vh����Vh����)�_���sVh���5db�ڷ���������$�����t�SRVh���)�_����sVh���~)�_������Vh���Vh*���1҅�t�S�9����$����������0�@���(�0�h7��)�_����YVh9��:�$�E���t�SRhu���(�_���$u-��&��s����Vhu���(�_���
hF��(�_���7�����6�����[^_]���unknown flag -%c
typeset -i -x -r -t function %s
%s=%s
%s: not identifier
��UWVS�|$$1��D$�D$�D$�D$��<rt#	<et� <tt ������
��������D$������>-t	�>+��1���L$����и9����$�d�������������������������������������������D$�4������,������$����������������Phd��.A��F�>�M�����t�|$-u	����	\$�D$���7�������?�R�=�^���7�|$u�G��GP�<�������$���|$u{�|$ut��uphv��~&�_���$t
h��k&�_��f�f%t
h���U&�_��f�f%t
h���?&�_��f�f%t
h���)&�_���CPhu��N����|$+t�|$t�D$#9D$u�CPhu��&����|$-t��t@��#9�u8f��t�CPh����%�_������S�-��P�CPh���%�_�������������4�������1�[^_]�����|$t.���&��t$U�7�41����u�7h���m?�����?u�1�[^_]���-d%s='%s'
cannot alias keyword
��UWVS�D$�^�D$�l$���}t%�u�������u�D$�`���}uG�t$��:�����#����{u�$t�s�CPh���$�_�������u׃}����]j=S�(�_���ƅ�uLS�f7��PS�t$�8���Å�t#�{u�$t�s�CPh���:$�_���q��D$�f���FS�7��PS�t$��8���Ã{u
h���>���$th�b�s�=���#��Ch�bV�q'�����C����}�/����D$[^_]�����UWVS��^�T$���:ts����������uY��`�O�2�T$�a6��P�T$�2U�7���ËT$��t'�{u!�$th�b�s�T$�[<���T$�#����:u�1�[^_]���S��\$��3�������%����;u�[�����1��bgJob control not enabled
%UWVS�l$�u�$��������؀=
du
h'��<��S�E��u�@�P�������P������1�[^_]�Usage: kill [-l] [-signal] {pid|job} ...
-l%2d %8s %s
%s: %s
bad signal %s
invalid argument
��UWVS��D$�D$�T$ ���T$�:u
h����;���T$�2��������J��R1퐃;t�s�s�3h���!�_��E����~�1�[^_]��Ð���;-uw�|$up�T$�ztf�C��a$t(j
j�CP��%�_�������D$��U�g��sV��������uVh���#;���+�D$���D$���a$u�;-uN�C��a$t@Uj
jS�i%�_��P���_����}N�5<	`��$�_��PSh����:���D$�+���;%uUS�������P���������h���:���D$�T$���������D$[^_]���VS1��\$�
���xmu������t�8-t�;ujjj�gm�����;t+���j=�3�$�_����t�@VP�3�?m�������;u�1�[^�cdprintgetopts=typeset=export=readonlywhence=aliasunaliashashletfcjobskillfgbind)�h�,�\�2�@�:���C���K���U�P�\���c�X�k�|�p���t��w��|����D�$�D�����$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $-r-w-x-f-d-c-b-p-u-g-k-s-t-z-n-U-G-L-S=!=-eq-ne-ge-gt-le-lt-nt-ot-ef!-a-o()N�Q�T�W�Z�]�`�c�f�i�l�o�r�u�x�{�#~�$����"��	��
������
���������� ��!����������[][: missing ]
unknown operandWVS�\$�ڃ���c�3�������u8�;t
�����;u�����3�������t
h����6���1ۡ�c�8t�0�	��P�����u���c�8t ��c��c�8th���0�$����[^_�test: %s: %s
test: %s
�D$�T$��t�8tRPh���/6��Ð��Rh���6���VS�t$�a���ƃ�c��c�0�M����u51ۃ�c��c�0�0��P��������u��t���[^Ð���c���[^�VS�t$�a���ƃ�c��c�0������u51ۃ�c��c�0����P��������t�����؉�[^Ð����c���[^ËD$��tP�]��Ð��c��c�0�q��P�����������%��argument expectedclosing paren expected0��WVS�\$��uh�j�n�������uV��c��c�0����P�~������Ã�c��c�0������th,�j��������[^_��Ð��=_���_f�z����c��c�8u��th��2���������t<�������tW��%����c�0�b������d[^_��Ð0ҡ�c�8����������щ�H��%��D$�D$[^_��Ð0ҡ�c�8����������щ�H���ΐ����c����a$ujhC����[^_��Ð�S��c�0�吐��c���c��c�0����=_��5_f�~�	��c��c�8��uh��6������f�Ff����и9����$�H���������4�\�������������������������WS�]�_������%�[^_��ÐWS�A�_������%�[^_��ÐS�����W���9���%�[^_��Ð��S�����W���9���%�[^_��Ð��S�n����W�c��9���%�[^_��Ð��S�F����W�;��9���%�[^_��Ð��S�����W���9���%�[^_��Ð��S��
����W��
��9���%�[^_����WS���[^_����WS�A��[^_����WS���[^_������c�0�������������H��%�[^_�����@S�L$H�T$LJ�#9���$�\��������@�p���h�h�h�h�h�h�h�h�h�h�h�h�h�h�h�h��h��������D��h�h�h�8�����jQ�t
�_������%�[��@Ð�j��j��1ۍD$PQ��_����uf�D$f%�f=����؉�[��@Ð�1ۍD$PQ��_����u�f�D$f%�f=@���ΐ�1ۍD$PQ�c�_����u�f�D$f%�f= ��릐�1ۍD$PQ�;�_����u�f�D$f%�f=`���{������1ۍD$PQ��_�����c���f�D$f%�f=���K������1ۍD$PQ���_�����3���f�D$f%���������1ۍD$PQ��_��������f�D$f%����������1ۍD$PQ��_���������f�D$f%����������1ۍD$PQ�[�_����������|$���������Q������P�!�_��[��@Ð1ۍD$PQ��_�����o�����_f9D$���Z�����1ۍD$PQ���_�����C�����_f9D$���.�����1ۍD$PQ�{�_��������f�D$f%�f=�����������1ۍD$PQ��_���������f�D$f%�f=������������[��@�VS�t$�����u!�_1�[^Ð��_�C[^Ð���=��t����3V�X�_����tՃ��;u��_�[^���S1ۍD$DP��$����_����u&�D$P��$����_����u�T$,9T$l���؉�[�Ā���S1ۍD$DP��$���_����u&�D$P��$��v�_����u�T$,9T$l���؉�[�Ā���S1ۍD$DP��$��:�_����u2�D$P��$��"�_����uf�T$f9T$Du�T$9T$H���؉�[�Ā�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ulimitUsage: %s [-cdmstf] [limit]
unlimited
%ld
bad ulimit
��UWVS�\$$�D$�D$������;-���S�B���w�D$�� ��9����$������4�,�4�4�4�4�4�4��4�4�4�4�4�� ���?���7���/���'��D$1�����h�h ���*���\$(��t31�������tBЅ����C��/~��9~���������l$UW���_����uy��t)���D$�D$�|$u�D$UW��_����uQ�D����|$t	�t$�����t$�����uh=��V*�������|$PhH��>*��1�[^_]��ÐhM��*��[^_]���$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $--illegal option -- %s%c
option requires an argument -- UWVS�l$�\$�=^u?9-^},�^���8-u�xt�ƿW�����u�^�����[^_]Ð�^���^�4��:tV�t$ ��_����uQVhZ�hm��)���^�^���^�<u�^�^�^�?[^_]Ð@�8:uf�^�^��xt�^@��/����^9-^|Vhs�hm��(��떐�^���^�^�^�4��^�^���^�<u�^�^�^��[^_]��^�^�missing arguments
OPTINDOPTARG��WVS�\$���3��t	���;��u
h��'����{t
�C���B�8u���~VSR�(���^�Z��8u�B4�P�@���R��VP�BP��������Ã=^t�5^h0��
��P������u
�[^_���=^t�5^h7�����P����\$f�L$f�L$�D$PW���P���1�[^_���$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $%s: %s
�t$�5 ^hx��&���bad expressionS�D$�$^� ^��7P�����Ã=(^t
h���������C[�bad assignmentWVS�h�Éރ=(^=uU�=b�$f�f%t
h���U����������P����É=b�sV����$t�~u�S�V��[^_�VS�]���E��(^�V�7�����=P�'���@9F��%��F��u
4�ƒ��V�(^�����v���[^�VS����k��5(^�YS�������P������u�@9C���.��<u�@9C�����u�@9C�����>u�@9C���ƒ��S�=(^t��=(^<t��=(^>�w����=(^�j�����[^�VS�i���@��5(^�S�+�����IP�����+u�@C������-u�@)C�=(^+t��=(^-t���[^�zero divisorWVS����k�=(^�AV������P����Ã�*u
�N�K�N�4��{u
h���H�������/u�F��{�F���%u
�F��{�V�=(^*t��=(^/t��=(^%�v�����[^_�missing )VS�=(^!t	�=(^-u@�5(^������P����Ã�!u�{���ƒ��S�d�����-u\�[�W���=(^(u'�N�����Ã=(^)t#h��x����������(^H��w
�,^��
h���N�������[^�VS�5$^�F��t
�� t��	t��I�
$^���Њ�a$tJ��a����F��%���a$u�N���5$^�A
���,^��(^����a$t^��a����F��%���a$u��#t�N����,^�5$^P����,^���(^�\��F��=u��=u
��@�����!u��=u
��,�����<u��=u
�������>u��=u
�����N�(^�5$^[^�h�^j����b�^��@�@�bad numberVS�t$�������C
VS�����u7�$t �~t�F�8th�������������C
�C��[^�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $ $_argument expected
cannot find history
can't find history
wcannot create temp file %s%3d: %s
_${FCEDIT:-/bin/ed} $_rcannot open temp file %s
��$UWVS�D$,�D$(�D$$�D$ �D$�D$1�t$8���>���/�G<-�$��������G�
9����$�d�@�@@@@�@�@@@��D$(�����D$$�����D$�����D$�~����t_���tY�;-u�{u�D$ �Uh�^0������������Ѓ�P����D$,S�t$0�
	�_��hO�t$0���_������hS�����f����E�?t����������>��t�G<-u��t߃|$ ���D$�D$�-xQ����0�j=W�t�_���Å�t�|$�\$��D$�
��W����ŋ>����uȅ�t��T_s
hg�B���|$u�uh�b�/�_������t$�t$�t$�u�����th�b�����
�b��b1�[^_]��$Ã>t7�6������ǃ>t�6�x�����E����|$(t;�5xQ�3����|$(t�=xQ����5xQ��=xQ�������T_s�T_��t��u
h|�f���|$(t�db�b�D$$h�^�B���D$0��^���^h��L$4�q�u��_���Å�u�T$0�rh����hjjS���_�����|$t���W�9�wV�|$$u$��`�xQ)����@)�Ph�S�$��_���uh�S���_���|$t�������|$t�9�s��|$(t1�[^_]��$ÐS�>��_���L$0�qh��v	��P��
���|$,t�t$,������h�^�t$0�A���
h������h��T$4�r�b��_����u�L$0�qh�����hjjS���_�����Shh�b���_����th�b����
�b����bS�o��_��1�[^_]��$��=xQT_v;��`�P9DVt+�Hh�b�xQ�0�t���xQ���`�@�DV�WVS�t$�>-u
V������!�����a$tV�e������`+B����xQ�t�>?u/�xQ�����T_r^F�V�3�X�_����uM�����T_s��@�xQ��T_r2����0���������щ�HPV�3���_���D$��t�����T_sиT_9�w9xQr��[^_��Ð�1�[^_���substitution too long
substitution failed
��UWVS�l$ �D$0ۋ|$$����������щ�H�D$������������ҋ|$$��������щL$)ʋ|$(��������щL$�T
��T$���v
h�	������b��b��t$$U��_���ƅ�tE��)�SUW���_���t$(�S��_���D$�,0�t$jW�X�_���ǃ|$,u��f멐�|$t�D$D$PW�F�_����h�	�2����b[^_]����_���`��T$�xQ-T_����|9�|�
xQ�
_��`��T_�_��`���UWVS�l$�t$��tF��NV�����������������t$S��_����uE��tF���NV�q������Y������t
�;t9�t����t$�M�������~1�[^_]����[^_]�����[^_]�S�xQ�����`r2h�b�5T_�&���T_���`s���S������`r�h�b�t$�n�����j
P���_����t��xQ[�VS�t$�HV�=HVuOh��1���Å�t<Shh�b����_����th�b�C������F�א����bS�/��_��[^��HISTSIZEWVS�LV�=LV��j
jh�����P����P��_���ƃ�d���d�xQ-T_��9�|���xQ)����T_h��a���Dž�t1��~$�;t�4��3h�W���_����9�}�;u�W�j��_��[^_�HISTFILE.pdksh_histHOME%s/%s��Sh�
�'��P�����t�8u0h�
h�
���P����Ph�
�\$S���_������$�P�e��_��[��$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $S��^S�G���C�CXV�C,�C0S�CP���S��S���[�WVS�=�^�w�O4�
�^�_�&�������t�$t�BP���P����Ky�W����[^_�UWVS�|$�5�^W�������L$�\$��a$tz�X^�b�^�X^�\^�
d^1����a$t"������LB�G���a$t���~�9N|�F�4�S�?����[^_]��Ð���a$�6�X^�b�^�X^�\^�T$�d^�t�X^[^_]��Ð��X^��߸9����$�������|����������������������������t^�S��������0b�S��������a�S��������v�s�������#������C�����#������5�^��t-��UW�FP�]
���É5b��������~4t�v4��u�UW�FP�
���ÀW�����t���[^_]���WVS�t$�=�^V��������a$u'�b�^�X^�\^�X^[^_�RV�GP�1
���É=b�V�-����t���[^_�0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZVS�t$�$t	V�Z	���$u	�TV[^Ð�$u
�NN�A���F��}�؋^��u�
�W^�W^���I1��󊒯���u�~}I�-��[^�%s: bad number
S�\$�$t	S�����$t�C[�X^�\^ShX^������u�shL�m���`^[�VS�\$�t$�$uP�$t�5b�s�L���#��Cf�f%tVS�������5bV�������C��;��X^�\^�5`^hX^S�+����uVhL������$t	S�/��[^�WVS�L$�T$�ZZ1��	�$t
��u�$u�!�1�[^_�$t�R�Q��[^_��A�
�x����-uG�n��#u�A�A���A�X����%���a$tM�BЃ�	w�������B���w�©�����B���w��Ʌ��o���9��g������AЉA�C��u���t�Y�A�����"v�A��[^_�S�\$�T$�$u5�X^�\^�`^hX^�A�����PS����������S��$t	S����[�VS�t$j=V�>��_���Å�u1�[^��V�S��������=C�
�r)�Z�$t	R����[^���UWVS�\$�l$�$1���t�s�5b0ҍ{����������щL$������������T$R�������K�C��S
��t��A��B��u��=A��+C�C���BA��u���t�5bV�
��[^_]���cannot set readonly %s
UWVS�l$�|$�����a$u1�[^_]��>=t���a$t�F�>u�>=u����1���f%t
U�������U�������Á�������t�=F�$u�D$��#	����$uv��$tp�X^�\^�KK�
`^�$t�5b�s����#���C��uVhX^S��������uD�#��5`^hL�G
�,��D$$t&�$t S��������`^�#��5`^S�������D$��#	����t4f�f%tUh������$t
U�o��������VS�u������%=u �{u�$�TV��t�SRS��������[^_]�S�\$�$t�5b�s����#[��T$���a$u1�À:t����a$t�B�:=u����UWVSh�^h�&	���D$$�D$ �D$(��^�T$����L$�Q�T$�i����L$�9�D$�����%=���wV����D$�T$�b�Z4��t$���t$V�CP������t� �����[4��uފ$tW�6������'�PW�������L$(9L$ r9�\$ +\$$��h�^��P�t$,�	���D$$����‰T$ Ӊ\$(�D$ ��8�D$ M�"����L$�I4�L$��������T$(9T$ r9�\$ +\$$��h�^��P�t$,�(	���D$$������L$ ˉ\$(�D$ ��D$ h�^�D$$+D$($�P�t$,����[^_]���PATHIFSSECONDSOPTINDMAILMAILPATHRANDOMFCEDITCOLUMNSWV�D$��8u���ǹ���u	�^_Ð��8u���ǹ���u�^_Ð����8u���ǹ���u�^_Ð����8u���ǹ���u�^_Ð����8u���ǹ���u�^_Ð����8u���ǹ	���u�^_Ð����8u���ǹ���u�^_Ð����8u���ǹ���u�
^_Ð����8u���ǹ���u�^_Ð��1�^_�S�\$�CP�~�������t
��t)[���#�j���_��+h^PS��������[��#��$��_%���S�\$�CP�*������P��
9���$��� 4L`t����S���������bj运����[Ð�h�S�������P�|�����[Ð��j�Q��_���h^[Ð��S�"�������u~�����[Ð��S������P�#��[�S�n�����P�}#��[Ã#�S�������P�Z��_���[Ð�S�>�����P�� ����[�S��������Q��
��QP[�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $�T$1ɀ:t
���HB�:u����	���)ȍ�����D$�T$��@�@�@Ã�UWVS�|$ �\$$�w�t$�O�L$�7��P�����1�9�}�ꐐ����@9�|�_���
����G�o�|$���|$~u�L$�L$�t$���tM�$t<�CP�������WJ!ЍT��:t�9�u�O��ƒ���:u��O���7S����D$�t$�L$��9D$|��7�t$����[^_]���UWVS�|$�l$�u1�[^_]Ð����[^_]Ð�GH#D$����w�5���S8UuU�CP���_����u�$u�9wu�W��ƃ�����u�1�[^_]�UWVS�l$�t$�}ujU�n������EH#D$����}�-��S8uV�CP���_����t09}u�U��ǃ�����u΃}�U�UP럐����[^_]Ð���8t�@�8u��u)���
P�������C�C�>t
����F@�>u���M���[^_]��D$���D$�P�l^�@�p^�����p^��p^��t
�$t���
l^y�1���D$��P�D$��P���_���WVS�|$h�^�G@��P�����ƋO��1�9_~��������t	�$t��C9_��)�����h�SV����������[^_�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $�D$�dV�VS�t$���t=dVt��P����_����9u��dV[^�allocate bad sizecannot allocateallocated object too small��UWVS�D$��uh� �t$$������1�[^_]��Ð�H���P�t$ ��,�������D$�C9Ct9P����D$�9Cu�L$ �193un�����u�P�T$����_���ËT$�����L$ �9dVu���t$ �����߉{�C�C�у�c�K�s�s�D$������]�����L$ ��ŋ}�)�yh� �t$$�T$�/������T$O���E����U��D��x��u�0�|$u�C��h� ��������L$���[^_]���UWVS�t$�T$�|$���uh� W�������1�[^_]Ð�B���@��t9F�s0��WR�c������Ɖ��t�C��
�����
����H���u�WU��V�)�J��~�F��\��S�WS�9����[^_]�freeing with invalid areafreeing free object��UWVS�l$�\$�u�
�U9���6�F9�w�9^v�1��N9�s
���ϋ9�r�9�uh#U�������[^_]��Ð��S���؍Q�9�u�C�@A��C��	���u�^[^_]��ËW�����S�9�u�G�@C��G���[^_]��Ð��h�"느$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $�D$P�t$�5hb�(��_��������D$P�t$�5hb���_��1��r+S�\$�<�`bu+hV$S���_����`b��thjjP�u��_��[�S�\$�<�`bt"jj�4�`b�	��_���4�`b�Z��_��[�too many files open in shell
VS�t$��	UV������j
jV����_����}�=<	`	u�����[^�h�$�������jjS���_��V���_���������[^�VS�\$�t$��t+S�0�����S����_����|SjV�o��_��V����_��[^�can't create pipe - try again
S�\$S�5��_����}
h�%�P������3��������s�	������C[�S�\$�3�X��_���s�M��_��[�/tmp/sh%05u%02u��WVS��$�5xV�xV����_Ph&�t$V�g��_��h�V���_��P����_��Wj���������WV�'������C��[^_���$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $eval:substitute error
VS�\$�5�`j��
�������`j������=t
h�&�������5�`�t$�5P_���[^���WVS�t$�|$ �>u	��[^_���h�^h��������‰T$�T$�с���L$9L$r6�\$+\$��h�^��PR��������D$������L$ˉ\$�D$��D$�L$9L$r9�\$+\$��h�^��P�t$�������D$������L$ˉ\$�D$��D$�>t�\$��WS�6�������>u�L$9L$r9�\$+\$��h�^��P�t$�������D$������L$ˉ\$�D$��D$h�^�D$+D$$�P�t$���������[^_�����VS�t$�\$h�^j�O������D$�D$���D$S�D$PV����D$+D$��t	�D$�0����(h�^�t$��������[^�����VS�\$�t$h�^j��������D$�D$���D$V�D$PS����D$+D$��t	��t�����(���D$����$�PS�%�������h�^�t$��������[^���eval:expand(NULL)
%s: unset variable
ridiculous ${} nesting
missing value for %s
%s
���UWVS�D$,��$��T$(��$��L$�D$��$�u
h�)��������=dt��$��f��$�f%uY��$�$tNj{��$����_���ƅ�t7�~�u1�~u�~}t%��$���$���$��������i��$�����DŽ$��h�^h��0�������$����$���$����D$0��$��D$$��$���L$ �d$ �t$ ��9�$�wR��$���$��$�h�^��$���PS��������$����$���$���)؉��$��9D$0�Z�T$0�$��+����+�.�.�.@/�}E�9��&�$��+����+,,8,,(,x,�-1��)��L$,�}E����D$,�D$ ��������D$,��������U��$�P����D$0jU���_���h��+�$��L$�D$���������$�j��$��{��_���h�xt�x�h���1�������#t��%uc�=dt3��$�������P������=TVu��$�h�)�.������D$�D$0�D$(��L$,�T$(�
�D$,���W��$���$�P����D$0�|$0uA�D$49D$u
h�)��������D$��T$f�:��f+�$�f�J��$��J�����jU�n���������������$�$t��$���T$f�f��f��%t%f��#t��f��=tzf��?���������L$�A���$��T$(�
�L$,�D$(�T$�PV�L$ �q�������P������P������$��D$0�L$���������T$�B�$�P�L$�q������P�S����0��T$�B�$�9�u��$�h�)�	���Ph�)�������D$�D$0������$��8��$����/�ؐ�D$0�D$,��$��8��$������$����$���$���t��|$,tf��$�t�D$0�D$,�=�V����|$u]���$��H9HrP���_�����t��$��P�:�@���������
u�D$���|$t���t��$�W�g��_���
�L$���uB�T$�$���$��D$��$����_��f��$����������������t0�|$,�	��$�$�J����%���a�4�|$ ��Fh�^��+�$�P��$���������$��D$$$ t��$�������$��D$$$t��$���$��	���e����$��J9
r@�+Z��h�^��P��$��r��������$��A����Q��Y��$����$����D$ �D$$���DŽ$��h�^h����������$����$���$��ƅ�����������|$,����?t$��!tA��*t������[t��~tJ����$�u�|$tp��$���	D$$�S�����$�u�|$tL�~�[uF�~��u@�1���$�$ t	9�$�t��$�$u�~�=t�~�:u�L$$ ��F����d$,��D$ ���ЈF�������[^_]������WVS�\$�t$�>#���V��ty��*t��@u��^�P�;�F�t$�t$�j������D$�t$�N������D$0ҋ|$����������щ�Jh�^j
R�������P���������[^_�������*t��@u7�=�^�tC����|$�{���C��@��f��f�C��$�V�������P���������u�TV��T$����%t6��#t1�|$}	��8u��;TVu��=t��-t��?t
�
�����+u1���t$�=dt�;TVu��+tVh�)��������[^_���funny $() command
rcannot open $() input
��UWVS�l$�\$ j�������P�������ƅ�t~�>uy�F�8uq�F�8ui�~tc�F��C����t
h�3�������h�3j �s�g�����P�"��_���Dž�tW����_��P������PW���_��f�E�l��D$P�*�����h�3�t$�i��_����j�I�������j�t$���_���t$���_��j8V�i����jS�c��_��S�r��_��f�E��u
h�3�'�����hjjW���_���}�[^_]�����UWVS�|$�l$�\$ jW����_������%��
��#t�=�tE=��������9�������T$�UW�(�������ue�T$�C9�v�����9�������T$�UW���������u1�T$�K9�s�����9�r}��US���������uK9�s��f����T$���[^_]��Ê�T$�h�bW�������T$�[^_]��Ð����T$�h�^�։�9�w��US�e�������u�C9�v��[^_]���Missing }.
Missing comma.
��UWVS�|$(�|$ h�^W�����V�o������É\$jj{�D$$P�l$,U������u0�D$0%P�t$0W�$�����h�^S�B�����[^_]��Ð��h�^V�������D$�|$�D$ jj}�D$ PU�j����u)h�^S�������h�^W�������ha6��������D$��D$�D$�,�D$�D$��l$ ���|$ �?���t$��T$�T$j�j,V�D$,P������u)h�^S�{�����h�^W�m�����hm6�P������D$ �l$jjV�D$P����t$0�t$0S�������D$ �8u�h�^S������h�^W�����VS�T$1��:tW����ȸ9�r��$�D8`8`8l8h8h8l8h8������FB뼉�jS���_���P��)���F��[^���UWVS�L$$�L$�D$(1�1�1��t	E�������L$��L$ ��:��������D$�9D$w�L$�$��89`9�9t9|9�9��u�z]uU1��Q���uL�z[u
��?�����t�z{uG�z}uO�L$8Ju!��u��L$ ��L$��[^_]���
�BC�
�BC�M���������1����BC��u��/������L$��L$ �1�[^_]�����WVS��$��$�+C����jSW�D$PP����+C��9�uQ�K9r.h�^��P�s�e������C����K�ȉCW������[^_��Ð�h@)�P��CP������[^_���.��UWVS�t$ �����|$(tj�t$����_�������|$$�O9r:�+_��h�^��P�|$,�w�������L$$�A����y�9�Yh�^�t$�������L$$���[^_]��Ð���|$9|$v�L$�/�
���|$�F�D$�>/t�j/V����_����t�EE�L$�j�V���_����u.�T$���CB��u�J�t$(�t$(UR�t$(�����������a:�|$�?t�D$P���_���D$�|$t~���t$�/��_����t`�X
�x
.u�xt�x.u�xtՀ>.u�VS���������t‹T$����CB��u�J����%�P�t$(UR�t$(�S�����뒐��t$�7��_����t�E�/[^_]���S�D$�‰��8t���:�t��AB�:u��[�HOMEPWDOLDPWD��UWVS��$0��t$(��C��� ���u�;~t�F��1Ҁ{t�{/t�{:u hY<�"�����P�
�������C����{+u�{/t�{:t�{uh^<���{-u2�{/t�{:t�{u hb<�������P�������ƒ��d����C��a$tS�ߍT$C���a$t'�L$$�L$9�s����
CB���a$t9T$w���D$P�^���…�u
����������:��������
�BF�:u�������h�^U�n�����h�^�D$,P�������[^_]���S�\$S�
�����PSh�`�J������…�t
�$t�B[Ð�S�b��_����t�@[Ð�1�[�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $MAILCHECKMAILPATHMAIL��PShX>�b������Š$��R�D$HP������������=�Vuj����_����Vj���_����+�V9D$L����Vhb>��������…�t�$t
��V�o��hk>���������1ۅ�tX�$tR��V�K���D$P�s���_����u,f�D$f%�f=�u�L$9Ks	S�&���L$�K�	���C���u�[��P���@S�\$H�=�Vth�b�5�V��������V��V�D$PS�!��_����uf�D$f%�f=�u�T$��V[��@���V[��@�VS�\$�5�V�k����Vh�bS�������Å�tG����j:V����_���Å�t�Cj?V����_����t�@PV�S����V���V��u�[^�VS�\$��t,���ދ��uh�b�v������h�bV��������u�[^���@WVS�\$P�t$Th�bj�V���������_�w�D$P�w����_����uf�D$f%�f=�u
�T$ �W���G��[^_��@�%s
S�D��3hA�������5hb����_��h�b�3��������S��Vh�bS���������V��u�[�_you have mail in $_WVS�t$h�bj���������vjhhcA�(�������W�	������~th�bj�v�h�bjheA�������P��������W��������V�S��V[^_�$Id: ksh4.7.tar,v 1.1.1.1 2019/05/29 04:56:40 root Exp $U��VS��^���u1҃<��^t��^�����B�8u��Ӆ�t�4��^����Ѓ��Ku��e�[^��U��S��^�=�^t������Ѓ;u�h8B���_�]���U��=�Vu��V�������V�V�VS��\$�L$�T$̀��}�أ�V�����[�VS�t$�\$�T$��t'���Ѐ:t�@�8u�)�PRV���������S���u�[^�'
	: can't load library 'Incompatible version.
Too many libraries.
No such library.
Permission denied.
Exec format error.
Unspecified error.
)
 (	��UWVS�l$ �|$����V�=�V���P�>�V�̀����}
�ى
�V�����������5�VjhHC�0hLC�uj�������9����$�tD���DE�DEEEEEEEEEE�DEEEEEEEE�DjhcC�:���jhzC�.���jh�C�"���jh�C����jh�C�
���jh�Cj����������̀�򐐋��T$�H��t
9L$�����6��D$�T$�����%�9�u�T$��9�}�D$�T$��t;�jhHC�0hLC�uj�m�����jhcCj�\������̀�򐐃��>�D���[^_]��þ�V�=�Vt.��jh�C��ph�C�0h�Cj�	��������>u֐��1�̀���[^_]��üV�V�V/lib/libc.so.4Jump table 4.2�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V�V@KSH_VERSION=@(#)PD KSH v4.7 92/08/12tIFS= 	
$).15<?IRXk���������
d�
!+	7?H
PW^fqw���X&����P_�8P�<�<�<�=�g @@@@@@@��



hX  ̐<�T��D�I�R�V�]�a�k�p�u�y�����������������	����
�������
��
(�-�9�>�J�O�Z�a�m�r�����������������������������	�"�)�<�A�P�V���D����$�H�����G�h dVpVpV�#�& (>B�V0F?F`�O�V

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.