pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (12/15/90)
---cut here---cut here---cut here--- -bash(1), -ksh(1), -cat(1), -cd(1), -chmod(1), -cut(1), -echo(1), -emacs(1), -env(1), -gmacs(1), -newgrp(1), -stty(1), -test(1), -umask(1), -vi(1), -dup(2), -exec(2), -fork(2), -ioctl(2), -lseek(2), -paste(1), -pipe(2), -signal(2), -umask(2), -ulimit(2), -wait(2), -rand(3), -a.out(5), -profile(5), -environ(7), -xtetris(6). -.SH AUTHOR -Paul Falstad <pfalstad@phoenix.princeton.edu> -.PP -The command line editor is a hacked-up version -of the GNU readline library, -written by Brian Fox (<bfox@ai.MIT.Edu>) of the Free -Software Foundation. This shell is therefore -under the GNU public license. I eventually plan -to write my own command line editor to make everything -my own code, but \fBzsh\fP will probably still be under -the GPL, or perhaps something less restrictive. -.SH CAVEATS -.PP -Using -.B fc -built-in command within a compound command will cause the whole -command to disappear from the history file. -.PP -Shell functions are put in the function table when their declarations -are parsed, not when they are executed. Thus function declarations -inside \fBif\fP clauses, for example, will not work as expected. -(This is a bug, not a caveat.) -.PP -The command line editor gets confused if you have termcap sequences -(like %S) in your prompt. -.PP -The main shell does not get along with the command line editor. -One of them will have to go. -.PP -Use of this shell is reserved for faculty, staff, -graduate students, -and special guests -of the Princeton University -Computer Science department. End of zsh.1 echo COPYING 1>&2 sed 's/^-//' >COPYING <<'End of COPYING' - - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 - - Copyright (C) 1989 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of a such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. - - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. - - 7. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of the license which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -the license, you may choose any version ever published by the Free Software -Foundation. - - 8. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. - - To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) 19yy <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19xx name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -That's all there is to it! End of COPYING echo README 1>&2 sed 's/^-//' >README <<'End of README' -Read "INSTALL" for information on getting this shell running. - -zsh is free software. See the file COPYING for copying permission. - - This shell was "developed" by me, Paul Falstad, a sophomore at Princeton -University. I borrowed _heavily_ from ksh, bash, tcsh, sh, and csh, as -well as adding a few (IMHO) useful features. zsh was at first intended -to be a subset of csh for the Commodore Amiga, but the project sort of -ballooned; now I want it to be a cross between ksh and tcsh. It should -be a powerful "command and programming language" that is well-designed -and logical (like ksh), but it should also be built for humans (like -tcsh), with all the neat features like spell checking, login/logout -watching and termcap support that are probably too weird to make it into -an AT&T product. This version of the shell has fallen far short of that -goal; I just wanted to release _something_, because this is obviously -going to be an extremely long project. - - This is version v1.0 of zsh. I incorporated the GNU "readline" -editor, written by Brian Fox, into the shell, just to make my life -temporarily easier. I made lots of changes to it, so if there are any -bugs in the editor, they're probably my fault. readline will not be a -part of the next version of zsh. - - If anyone has any questions, suggestions, comments, bugs, flames, or -any other mail of any kind, send it to pfalstad@phoenix.princeton.edu. -Thanks to Kartik Subbarao, Daniel Bernstein ("Yay. So sell it."), -Kennedy Lemke, Chet Ramey (for the bash man page, and for putting features -in the man page that weren't in our version of bash), Brian Fox (for -helping me put off a lot of work, and for writing bash), Richard M. Stallman -(for gdb and gcc; not for emacs though ;-) ) and many others. - End of README echo INSTALL 1>&2 sed 's/^-//' >INSTALL <<'End of INSTALL' -I was not able to port zsh to many platforms because I don't have -accounts on many platforms. It shouldn't be too much trouble if you -manage to decipher my code. I have tested zsh on SunOS 4.1, SunOS 4.0.3, -4.3BSD UNIX. - -You need to edit the files config.h, config.local.h, makefile, and -readline/Makefile. The comments should make clear what you have to do. -Note that the files in the readline directory have been greatly -modified, so you can't just copy over your changes from bash if you -have it installed. - -Once you have done that, you might be able to do a make without any -problem. If you have trouble, and can't get zsh to work, send me mail, -and I'll try to help. If anyone manages to get zsh ported to some other -platform, please mail me so I can tell other people about your changes -and incorporate them into the next version. - End of INSTALL echo makefile 1>&2 sed 's/^-//' >makefile <<'End of makefile' -#! /bin/make -f -# -# makefile for zsh -# -# This file is part of zsh, the Z shell. -# -# zsh is free software; no one can prevent you from reading the source -# code, or giving it to someone else. -# This file is copyrighted under the GNU General Public License, which -# can be found in the file called COPYING. -# -# Copyright (C) 1990 Paul Falstad -# -# zsh is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY. No author or distributor accepts -# responsibility to anyone for the consequences of using it or for -# whether it serves any particular purpose or works at all, unless he -# says so in writing. Refer to the GNU General Public License -# for full details. -# -# Everyone is granted permission to copy, modify and redistribute -# zsh, but only under the conditions described in the GNU General Public -# License. A copy of this license is supposed to have been given to you -# along with zsh so you can know your rights and responsibilities. -# It should be in a file named COPYING. -# -# Among other things, the copyright notice and this notice must be -# preserved on all copies. -# -OBJS=hist.o glob.o table.o subst.o builtin.o loop.o vars.o\ -parse.o lex.o init.o jobs.o exec.o zhistory.o utils.o math.o test.o -READLINE=readline/funmap.o readline/keymaps.o readline/readline.o -BINDIR=/usr/local/bin -MANDIR=/usr/local/man/man1 -CFLAGS=-O -fstrength-reduce -fomit-frame-pointer -finline-functions \ - -fsigned-char -fdelayed-branch -CC=gcc -ZSHPATH=zsh -THINGS_TO_TAR=zsh.1 COPYING README INSTALL makefile sample.zshrc \ -sample.zlogin sample.zshrc.mine sample.zlogin.mine \ -alias.pro builtin.c builtin.pro config.h config.local.h \ -exec.c exec.pro funcs.h glob.c glob.pro hist.c hist.pro init.c \ -init.pro jobs.c jobs.pro lex.c lex.pro loop.c loop.pro math.c \ -math.pro parse.c parse.pro subst.c subst.pro table.c \ -table.pro test.c test.pro utils.c utils.pro vars.c vars.pro zhistory.c \ -readline/chardefs.h readline/emacs_keymap.c \ -readline/funmap.c readline/history.h readline/keymaps.c \ -readline/keymaps.h readline/readline.c readline/readline.h \ -readline/vi_keymap.c readline/vi_mode.c readline/Makefile \ -zsh.h proto - -.c.o: - $(CC) $(CFLAGS) -c -o $*.o $< - -$(ZSHPATH): $(OBJS) $(READLINE) - $(CC) -o $(ZSHPATH) $(OBJS) $(READLINE) -s -ltermcap - -$(OBJS): config.h - -zhistory.o: readline/history.h - -$(READLINE): - cd readline;make - -clean: - rm -f *.o zsh core readline/*.o - -install: zsh - install -s -m 755 zsh $(BINDIR) - install -m 444 zsh.1 $(MANDIR) - -tar: zsh.tar.Z - -zsh.tar: $(THINGS_TO_TAR) - tar -cf zsh.tar $(THINGS_TO_TAR) - -zsh.tar.Z: zsh.tar - compress -f zsh.tar - -shar: $(THINGS_TO_TAR) - bundle $(THINGS_TO_TAR) > zsh.shar - End of makefile echo sample.zshrc 1>&2 sed 's/^-//' >sample.zshrc <<'End of sample.zshrc' -setenv() { export $1=$2 } - -umask 022 - -PATH=$HOME/scr:$HOME/bin/$HOSTTYPE:/usr/local/bin:/usr/ucb:\ -/usr/bin:/bin:/usr/local/bin/X11:/usr/etc:/etc -CDPATH=$HOME:/usr:/ -export MANPATH=/usr/man:/usr/local/man - -HISTSIZE=50 -setopt ignoreeof - -PROMPT='%n@%m [%h] %# ' - -alias a alias - -a vi. 'vi ~/.cshrc' -a s. '. ~/.cshrc' -a more. 'more ~/.cshrc' - -chpwd() { pwd; ls -F } -lsl() { ls -algF $* | more } - -a back cd - -a h history -a cls /usr/ucb/clear -a type cat -a copy cp -a move mv -a del rm -a lo exit -a lsa 'ls -aF' -a dir 'ls -l' -a ll 'ls -F' - End of sample.zshrc echo sample.zlogin 1>&2 sed 's/^-//' >sample.zlogin <<'End of sample.zlogin' -eval $(tset -Q -s '?xterm') -stty dec crt kill ^U dsusp ^X -msgs -q -date -biff y - -WATCH=$(echo $(<~/.friends) | tr ' ' :) -MAIL=/usr/spool/mail/$USERNAME -export DISPLAY=$(hostname):0.0 - -limit coredumpsize 0 -/usr/games/fortune -uptime End of sample.zlogin echo sample.zshrc.mine 1>&2 sed 's/^-//' >sample.zshrc.mine <<'End of sample.zshrc.mine' -# -# my rc file for zsh -# -PATH=~/scr:~/bin/$HOSTTYPE:/usr/princeton/bin:/usr/ucb:/usr/bin:/bin:\ -/u/maruchck/scr:/u/cs320/bin:/u/maruchck/bin:\ -/usr/princeton/bin/X11:/usr/etc:/etc -CDPATH=~:~/src/cs320:~/src -umask 022 -alias a alias -a pd pushd -a pop popd -limit core 0 -a c cp -a grep egrep -a ps sps -a j jobs -a hide 'ARGV0=$(randline ~/pub/strings) ' -a rn hide /usr/princeton/bin/rn.4.1 -a v mv -a t cat -a where hostname'; echo >/dev/null' -a l ls -AF -a m make -a mm hide less -a talk hide talk -a h history -a a.out ./a.out -a more less -a strings strings - -a lock lock -p -a nw 'l -ltr | tail' -a -a 'M' \| less -a -a 'GF' \| fgrep -f ~/.friends -a -a 'sub' subbarao -a -a 'mjm' maruchck -a -a 'paswd' '<(ypcat passwd)' -a -a 'cex' '/u/pup/centrex' -a rable ls -AFltrd '*(R)' -a nrable ls -AFltrd '*(^R)' -a ';' vi -a 0 vi -a '<<' more -mostglob egrep sed -noglob find -PROMPT='Z %h %M:%~ ' -FCEDIT=vi -LESSTERM=$(echo $TERMCAP | sed s/:ti=[^:]*:te=[^:]*:/:ti=:te=:/) -a less TERMCAP='"$LESSTERM"' /usr/princeton/bin/less -zsh=~/src/zsh -a k9 kill -9 -cx() { chmod +x $* } -acx() { chmod 755 $* } -mere() { nroff -man -Tman $1 | less -s } - -[ `tty` = /dev/console ] || { - PERIOD=40 - periodic() { - echo checking news... # check news every 40 minutes - rn -c - } -} - -randline() { - integer z; - z=$(wc -l <$1) - sed -n $[RANDOM%z+1]p $1 - unset z -} - -eval "proto () { $(grep -v '^#' ~/scr/proto) }" - -snoop() { - (( $# )) || set `users` - fgrep -i -f </u/pup/st{udents,aff} <( - for i - do - ypmatch $i passwd - done | cut -d: -f5 | cut -d, -f1 | - awk '{ printf "%s,%s\n",$NF,substr($1,1,1) }') -} - -MAIL=/usr/spool/mail/pfalstad -MAILCHECK=30 -HISTSIZE=600 -setopt notify globdots autolist correct dextract pushdtohome cdablevars -unsetopt bgnice -WATCH=$(echo $(<~/.friends) | tr ' ' :) -WATCHFMT='%n %a %l from %m at %t.' -LOGCHECK=0 - -[ -t ] && { - (cd ; hostname >! .where) -} - -export MANPATH=/usr/man:/usr/princeton/man:/u/cad/man - -setenv() { export $1=$2 } - End of sample.zshrc.mine echo sample.zlogin.mine 1>&2 sed 's/^-//' >sample.zlogin.mine <<'End of sample.zlogin.mine' -# -# my login file for zsh -# -cd -ls -l /etc/motd -stty dec new cr0 -eval $(tset -s -Q '?xterm') -stty -tabs -umask 022 -export MAIL=/usr/spool/mail/$USER -MAILCHECK=60 -# biff y -msgs -fp -uptime -/usr/games/fortune -log -echo Thought for the day: $(randline ~/pub/commands) -from 2>/dev/null -cat .todo -cat '. ' -echo last login $(date) on $(hostname) >! .' ' End of sample.zlogin.mine echo alias.pro 1>&2 sed 's/^-//' >alias.pro <<'End of alias.pro' -char *dynread(char stop); -int filesub(void **namptr); -char *gethome(char *user,int len); -char *completehome(char *user,int len); -char *getsparmval(char *s,int len); -void setparml(char *s,int len,char *v); -void parmsub(table list); -void parminsall(table l,Node *nn,char **aptr,char **bptr); -void comminsall(table l,Node *nn,char **aptr,char **bptr); -void parmsuber(void **aptr,char **bptr); -void modify(void **str,char **ptr); -void tabmodify(table tab,char **ptr); -int napply(int (*func)(void **),table list); -int napplysplit(int (*func)(void **),table list); -void split(Node node,table list); -char *dstackent(int val); -void doshfuncs(comm comm); -void execshfunc(comm comm); -struct anode *mkanode(char *txt,int cmflag); -char *docompsubs(char *str,int *i); -void docmdsubs(char **str); -void dovarsubs(char **str); End of alias.pro echo builtin.c 1>&2 sed 's/^-//' >builtin.c <<'End of builtin.c' -/* - - builtin.c - handles builtin commands - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include <sys/signal.h> -#include <sys/fcntl.h> -#include <sys/errno.h> -#include <utmp.h> -#define MAXPATHLEN 1024 - -int echo(comm comm) -{ -table list; -char *str; -int nline = 1; - - list = comm->args; - if (full(list)) - if (!strcmp("--",list->first->dat)) - free(getnode(list)); - else if (!strcmp("-n",list->first->dat)) - { - free(getnode(list)); - nline = 0; - } - if (str = getnode(list)) - { - printf("%s",str); - free(str); - while (str = getnode(list)) - { - printf(" %s",str); - free(str); - } - } - if (nline) - printf("\n"); - return 0; -} - -/* print the directory stack */ - -void pdstack(void) -{ -Node node; - - printdir(cwd); - for (node = dirstack->first; node; node = node->next) - { - putchar(' '); - printdir(node->dat); - } - putchar('\n'); -} - -/* exit */ - -int zexit(comm comm) -{ - if (interact) - if (!stopmsg) - { - checkjobs(); - if (stopmsg) - { - stopmsg = 2; - return 1; - } - } - else - killrunjobs(); - if (islogin && unset(NORCS)) - sourcehome(".zlogout"); - if (comm && full(comm->args)) - lastval = atoi(getnode(comm->args)); - if (sigtrapped[SIGEXIT]) - dotrap(SIGEXIT); - exit(lastval); return 0; -} - -/* return */ - -int zreturn(comm comm) -{ - if (full(comm->args)) - lastval = atoi(getnode(comm->args)); - retflag = 1; - return lastval; -} - -int logout(comm comm) -{ - if (!islogin) - { - zerrnam("logout","not login shell"); - return 1; - } - return zexit(comm); -} - -int Unset(comm comm) -{ -table list = comm->args; -char *s; - - while (full(list)) - { - s = getnode(list); - unsetparm(s); - free(s); - } - return 0; -} - -int set(comm comm) -{ -char *s,*t; - - if (!full(comm->args)) - { - char **p = environ; - - while (*p) - puts(*p++); - listhtable(parmhtab,(void (*)(char *,char *)) pparm); - return 0; - } - s = getnode(comm->args); - t = getnode(pparms); - freetable(pparms,freestr); - pparms = newtable(); - addnode(pparms,t); - while (s) - { - addnode(pparms,s); - s = getnode(comm->args); - } - return 0; -} - -struct option { - char *name; - char id; - }; - -static struct option optns[] = { - "clobber",'1', - "nobadpattern",'2', - "nonomatch",'3', - "globdots",'4', - "notify",'5', - "allexport",'a', - "errexit",'e', - "bgnice",'6', - "ignoreeof",'7', - "keyword",'k', - "markdirs",'8', - "monitor",'m', - "noexec",'n', - "noglob",'F', - "norcs",'f', - "shinstdin",'s', - "nounset",'u', - "verbose",'v', - "xtrace",'x', - "interactive",'i', - "autolist",'9', - "correct",'0', - "dextract",'A', - "nobeep",'B', - "printexitvalue",'C', - "pushdtohome",'D', - "pushdsilent",'E', - "nullglob",'G', - "rmstarsilent",'H', - "ignorebraces",'I', - "cdablevars",'J', - "nobanghist",'K', - NULL,0 -}; - -int setopt(comm comm) -{ - return csetopt(comm,0); -} - -int unsetopt(comm comm) -{ - return csetopt(comm,1); -} - -/* common code for setopt and unsetopt */ - -int csetopt(comm comm,int isun) -{ -char *s,*os,*cmd; -int flag; -struct option *opp; - - cmd = (isun) ? "unsetopt" : "setopt"; - if (!full(comm->args)) - { - if (isun) - return 0; - for (opp = optns; opp->name; opp++) - if (opts[opp->id] == OPT_SET) - puts(opp->name); - return 0; - } - while ((os = s = getnode(comm->args)) && ((flag = *s == '-') || *s == '+')) - { - while (*++s) - if (*s == INTERACTIVE || *s == MONITOR) - zerrnam(cmd,"can't change that option"); - else if (opts[*s & 0x7f] != OPT_INVALID) - opts[*s & 0x7f] = (flag^isun) ? OPT_SET : OPT_UNSET; - else - zerrnam(cmd,"illegal option: %c",*s); - free(os); - } - if (!s) - return 0; - while (s) - { - for (opp = optns; opp->name; opp++) - if (!strcmp(opp->name,s)) - break; - if (opp->name) - { - if (opp->id == INTERACTIVE || opp->id == MONITOR) - zerrnam(cmd,"can't change that option"); - else - opts[opp->id] = (isun) ? OPT_UNSET : OPT_SET; - } - else - { - zerrnam(cmd,"no such option: %s",s); - free(s); - return 1; - } - free(s); - s = getnode(comm->args); - } - return 0; -} - -/* print a positional parameter */ - -void pparm(char *s,struct pmnode *t) -{ - if (s && t) - if (t->isint) - printf("%s=%ld\n",s,t->u.val); - else - { - printf("%s=",s); - niceprint(t->u.str); - putchar('\n'); - } -} - -int dirs(comm comm) -{ - if (comm->args->first) - { - if (dirstack) - freetable(dirstack,freestr); - dirstack = comm->args; - comm->args = NULL; - } - else - pdstack(); - return 0; -} - -/* call func once for each entry in a hash table */ - -void listhtable(htable ht,void (*func)(char *,char *)) -{ -int t0; -struct hnode *hn; - - for (t0 = ht->hsize-1; t0 >= 0; t0--) - for (hn = ht->nodes[t0]; hn; hn = hn->hchain) - func(hn->nam,hn->dat); -} - -/* print an alias (used with listhtable) */ - -void palias(char *s,struct anode *t) -{ - if (t && t->cmd >= 0) - { - printf((t->cmd) ? "alias %-13s " : "alias -a %-10s ",s); - niceprint(t->text); - putchar('\n'); - } -} - -/* print a shell function (used with listhtable) */ - -void pshfunc(char *s,list l) -{ -char *t; - - t = getltext(l); - untokenize(t); - printf("%s() {\n%s\n}\n",s,t); - free(t); -} - -void niceprint(char *s) -{ - niceprintf(s,stdout); -} - -void niceprintf(char *s,FILE *f) -{ - for (; *s; s++) - { - if (*s >= 32 && *s <= 126) - fputc(*s,f); - else if (*s == '\n') - { - putc('\\',f); - putc('n',f); - } - else - { - putc('^',f); - fputc(*s | 0x40,f); - } - } -} - -/* build a command line from a linked list */ - -char *buildline(table t) -{ -char *str = strdup(""),*s,*os; - - while (s = getnode(t)) - { - os = str; - str = (*os) ? tricat(os," ",s) : strdup(s); - free(s); - free(os); - } - return str; -} - -int Alias(comm comm) -{ -char *s1,*s2; -int anyflag = 0; - - if (!(s1 = getnode(comm->args))) - { - listhtable(alhtab,(void (*)(char *,char *)) palias); - return 0; - } - if (!strcmp(s1,"-a")) - { - anyflag = 1; - free(s1); - if (!(s1 = getnode(comm->args))) - { - zerrnam("alias","alias -a requires 2 arguments"); - return 1; - } - } - if (!comm->args->first) - { - palias(s1,gethnode(s1,alhtab)); - free(s1); - return 0; - } - s2 = buildline(comm->args); - addhnode(s1,mkanode(s2,!anyflag),alhtab,freeanode); - return 0; -} - -int cd(comm comm) -{ - if (!full(comm->args)) - return chcd("cd",strdup(getparm("HOME"))); - if (comm->args->first->next) - { - char *s,*t,*u,*v; - int sl,tl; - - if (comm->args->first->next->next) - { - zerrnam("cd","too many arguments"); - return 1; - } - s = getnode(comm->args); - t = getnode(comm->args); - if (!(u = (char *) strstr(cwd,s))) - { - zerrnam("cd","string not in pwd: %s",s); - return 1; - } - sl = strlen(s); - tl = strlen(t); - v = zalloc((u-cwd)+tl+strlen(u+sl)+1); - strncpy(v,cwd,u-cwd); - strcpy(v+(u-cwd),t); - strcat(v,u+sl); - free(s); - free(t); - return chcd("cd",v); - } - return chcd("cd",getnode(comm->args)); -} - -int dot(comm comm) -{ -char *s; - - if (!full(comm->args)) - return 1; - s = getnode(comm->args); - if (source(s)) - { - zerrnam(".","%e: %s",errno,s); - free(s); - return 1; - } - free(s); - return 0; -} - -int Umask(comm comm) -{ -char *s,*t; -int t0; - - if (!full(comm->args)) - { - t0 = umask(0); - umask(t0); - printf("%03o\n",t0); - return 0; - } - s = getnode(comm->args); - t0 = strtol(s,&t,8); - if (*t) - { - zerrnam("umask","bad umask"); - free(s); - return 1; - } - umask(t0); - free(s); - return 0; -} - -int which(comm comm) -{ -struct chnode *chn; -struct anode *a; -char *str = getnode(comm->args),*cnam; - - if (!str) - { - zerrnam("which","argument required"); - return 1; - } - if ((a = gethnode(str,alhtab)) && a->cmd) - { - if (a->cmd < 0) - printf("%s: shell reserved word\n",str); - else - printf("%s: aliased to %s\n",str,a->text); - free(str); - return 0; - } - if (gethnode(str,shfunchtab)) - printf("%s: shell function\n",str); - else if (chn = gethnode(str,chtab)) - { - if (chn->type != BUILTIN) - puts(chn->u.nam); - else - printf("%s: shell built-in command\n",str); - } - else if (!(cnam = findcmd(str))) - { - zerr("command not found: %s",str); - free(str); - return 1; - } - else - puts(cnam); - free(str); - return 0; -} - -int popd(comm comm) -{ -int val = 0; -char *s; -Node node; - - if (comm->args->first && *(s = comm->args->first->dat) == '+') - val = atoi(s+1); - if (val--) - { - if (val < 0) - node = dirstack->last; - else - for (node = dirstack->first; val && node; node = node->next, - val--); - free(remnode(dirstack,node)); - if (unset(PUSHDSILENT)) - pdstack(); - return 0; - } - else - { - if (!full(dirstack)) - { - zerrnam("popd","dir stack empty"); - return 1; - } - val = chcd("popd",getnode(dirstack)); - if (unset(PUSHDSILENT)) - pdstack(); - return val; - } -} - -int pushd(comm comm) -{ -char *s; -int num; - - if (comm->args->first) - { - s = getnode(comm->args); - - if (*s == '+') - { - if (!(num = atoi(s+1))) - { - free(s); - return 0; - } - free(s); - if (isset(DEXTRACT)) - { - Node n = dirstack->first; - - insnode(dirstack,(Node) dirstack,strdup(cwd)); - while (--num && n) - n = n->next; - if (!n) - { - zerrnam("pushd","not that many dir stack entries"); - return 1; - } - insnode(dirstack,(Node) dirstack,remnode(dirstack,n)); - } - else - { - addnode(dirstack,strdup(cwd)); - while(--num) - addnode(dirstack,getnode(dirstack)); - } - num = chcd("pushd",getnode(dirstack)); - if (unset(PUSHDSILENT)) - pdstack(); - return num; - } - pushnode(dirstack,strdup(cwd)); - num = chcd("pushd",s); - if (num) - free(getnode(dirstack)); - else if (unset(PUSHDSILENT)) - pdstack(); - return num; - } - else - { - char *s; - - if (isset(PUSHDTOHOME)) - s = strdup(getparm("HOME")); - else - s = getnode(dirstack); - if (!s) - { - zerrnam("pushd","dir stack empty"); - return 1; - } - pushnode(dirstack,strdup(cwd)); - num = chcd("pushd",s); - if (num) - free(getnode(dirstack)); - else if (unset(PUSHDSILENT)) - pdstack(); - return num; - } -} - -/* common code for pushd, popd, cd */ - -int chcd(char *cnam,char *cd) -{ -char *s,*t; -char buf[MAXPATHLEN],*new = cd; -int t0,val,esav,pnew = 0; - - if (cd[0] == '-' && !cd[1]) - { - free(cd); - cd = getparm("OLDPWD"); - cd = strdup((cd) ? cd : "."); - } - if (*cd == '/') - { - val = chdir(new = cd); - esav = errno; - } - else - for (t0 = 0; t0 != cdpathct; t0++) - { - sprintf(buf,"%s/%s",cdpath[t0],cd); - if ((val = chdir(new = buf)) != -1) - { - if (t0) - pnew = 1; - break; - } - if (t0 && errno != ENOENT && errno != ENOTDIR) - zerrnam(cnam,"warning: %e: %s",errno,buf); - if (!t0) - esav = errno; - } - if (val == -1 && errno == ENOENT) - { - t = strdup(cd); - if (isset(CDABLEVARS) && (s = getparm(t)) && *s == '/') - if (chdir(new = s) != -1) - { - val = 0; - pnew = 1; - goto goneto; - } - free(t); - zerrnam(cnam,"%e: %s",esav,cd); - free(cd); - return 1; - } -goneto: - if (val == -1) - { - zerrnam(cnam,"%e: %s",esav,cd); - free(cd); - return 1; - } - else - { - list l; - - if (cwd) - setparm(strdup("OLDPWD"),cwd,0,0); - cwd = findcwd(new); - setparm(strdup("PWD"),strdup(cwd),0,0); - if (pnew) - { - printdir(cwd); - putchar('\n'); - } - if (l = gethnode("chpwd",shfunchtab)) - newrunlist(l); - } - return 0; -} - -int shift(comm comm) -{ -char *s; -int sh = 1; - - if (comm->args->first && (s = comm->args->first->dat)) - sh = atoi(s); - while (sh-- && pparms->first->next) - remnode(pparms,pparms->first->next); - return 0; -} - -int unhash(comm comm) -{ -char *s; - - if (!(s = getnode(comm->args))) - { - zerrnam("unhash","argument required"); - return 1; - } - while (s) - { - if (!gethnode(s,chtab)) - { - zerrnam("unhash","not in command table: %s",s); - return 1; - } - free(remhnode(s,chtab)); - free(s); - s = getnode(comm->args); - } - return 0; -} - -int rehash(comm comm) -{ - parsepath(); - return 0; -} - -int hash(comm comm) -{ -char *s,*t; -struct chnode *chn; - - if (!(s = getnode(comm->args)) || !(t = getnode(comm->args))) - { - zerrnam("hash","not enough arguments"); - if (s) - free(s); - return 1; - } - chn = alloc(sizeof(struct chnode)); - chn->type = EXCMD_PREDOT; - chn->globstat = GLOB; - chn->u.nam = t; - addhnode(s,chn,chtab,freechnode); - return 0; -} - -int Break(comm comm) -{ -char *s; - - if (!loops) - { - zerrnam("break","not in loop"); - return 1; - } - if (!(s = getnode(comm->args))) - breaks = 1; - else if (atoi(s)) - { - breaks = atoi(s); - free(s); - } - else - { - zerrnam("break","numeric argument required"); - free(s); - return 1; - } - return 0; -} - -int colon(comm comm) -{ - return 0; -} - -int Glob(comm comm) -{ -struct chnode *chn; -char *s; - - while (s = getnode(comm->args)) - { - chn = gethnode(s,chtab); - free(s); - if (chn) - chn->globstat = GLOB; - } - return 0; -} - -int noglob(comm comm) -{ -struct chnode *chn; -char *s; - - while (s = getnode(comm->args)) - { - chn = gethnode(s,chtab); - free(s); - if (chn) - chn->globstat = NOGLOB; - } - return 0; -} - -int mostglob(comm comm) -{ -struct chnode *chn; -char *s; - - while (s = getnode(comm->args)) - { - chn = gethnode(s,chtab); - free(s); - if (chn) - chn->globstat = MOSTGLOB; - } - return 0; -} - -int unfunction(comm comm) -{ -char *s1; -list l; - - while (s1 = getnode(comm->args)) - { - unsettrap(s1); - if (l = remhnode(s1,shfunchtab)) - freelist(l); - free(s1); - } - return 0; -} - -int unalias(comm comm) -{ -char *s1; -struct anode *an; - - while (s1 = getnode(comm->args)) - { - if (an = remhnode(s1,alhtab)) - freeanode(an); - free(s1); - } - return 0; -} - -/* != 0 if s is a prefix of t */ - -int prefix(char *s,char *t) -{ - while (*s && *t && *s == *t) s++,t++; - return (!*s); -} - -/* convert %%, %1, %foo, %?bar? to a job number */ - -int getjob(char *s,char *prog) -{ -int t0,retval; -char *os = s; - - if (*s++ != '%') - { - zerrnam(prog,"bad job specifier"); - retval = -1; goto done; - } - if (*s == '%' || *s == '+' || !*s) - { - if (topjob == -1) - { - zerrnam(prog,"no current job"); - retval = -1; goto done; - } - retval = topjob; goto done; - } - if (*s == '-') - { - if (prevjob == -1) - { - zerrnam(prog,"no previous job"); - retval = -1; goto done; - } - retval = prevjob; goto done; - } - if (isdigit(*s)) - { - t0 = atoi(s); - if (t0 && t0 < MAXJOB && jobtab[t0].stat && t0 != curjob) - { retval = t0; goto done; } - zerrnam(prog,"no such job"); - retval = -1; goto done; - } - if (*s == '?') - { - struct procnode *pn; - - for (t0 = 0; t0 != MAXJOB; t0++) - if (jobtab[t0].stat && t0 != curjob) - for (pn = jobtab[t0].procs; pn; pn = pn->next) - if (strstr(pn->text,s+1)) - { retval = t0; goto done; } - zerrnam(prog,"job not found: %s",s); - retval = -1; goto done; - } - for (t0 = 0; t0 != MAXJOB; t0++) - if (jobtab[t0].stat && jobtab[t0].procs && t0 != curjob && - prefix(s,jobtab[t0].procs->text)) - { retval = t0; goto done; } - zerrnam(prog,"job not found: %s",s); - retval = -1; -done: - free(os); - return retval; -} - -int fg(comm comm) -{ -char *s1; -int ocj = curjob,job; - - scanjobs(); - if (!jobbing) - { - zerr("no job control in this shell."); - return 1; - } - if (s1 = getnode(comm->args)) - job = getjob(s1,"fg"); - else - { - if (topjob == -1 || topjob == curjob) - { - zerrnam("fg","no current job"); - return 1; - } - job = topjob; - } - if (job == -1) - return 1; - makerunning(jobtab+job); - if (topjob == job) - { - topjob = prevjob; - prevjob = job; - } - if (prevjob == job) - setprevjob(); - printjob(jobtab+job,-1); - curjob = job; - if (strcmp(jobtab[job].cwd,cwd)) - { - printf("(pwd: "); - printdir(jobtab[job].cwd); - printf(")\n"); - } - settyinfo(&jobtab[job].ttyinfo); - attachtty(jobtab[job].gleader); - killpg(jobtab[job].gleader,SIGCONT); - waitjobs(); - curjob = ocj; - return 0; -} - -int bg(comm comm) -{ -char *s1; -int job,stopped; - - scanjobs(); - if (!jobbing) - { - zerr("no job control in this shell."); - return 1; - } - if (s1 = getnode(comm->args)) - job = getjob(s1,"bg"); - else - { - if (topjob == -1 || topjob == curjob) - { - zerrnam("bg","no current job"); - return 1; - } - job = topjob; - } - if (job == -1) - return 1; - if (!(jobtab[job].stat & STAT_STOPPED)) - { - zerrnam("bg","job already in background"); - return 1; - } - stopped = jobtab[job].stat & STAT_STOPPED; - if (stopped) - makerunning(jobtab+job); - if (topjob == job) - { - topjob = prevjob; - prevjob = -1; - } - if (prevjob == job) - prevjob = -1; - if (prevjob == -1) - setprevjob(); - if (topjob == -1) - { - topjob = prevjob; - setprevjob(); - } - printjob(jobtab+job,(stopped) ? -1 : 0); - if (stopped) - killpg(jobtab[job].gleader,SIGCONT); - return 0; -} - -int jobs(comm comm) -{ -int job,lng = 0; - - if (full(comm->args)) - { - if (comm->args->first->next || (strcmp(comm->args->first->dat,"-l") - && strcmp(comm->args->first->dat,"-p"))) - { - zerrnam("jobs","usage: jobs [ -lp ]"); - return 1; - } - lng = (strcmp(comm->args->first->dat,"-l")) ? 2 : 1; - } - for (job = 0; job != MAXJOB; job++) - if (job != curjob && jobtab[job].stat) - printjob(job+jobtab,lng); - stopmsg = 2; - return 0; -} - -int Kill(comm comm) -{ -int sig = SIGTERM; -char *s; - - s = getnode(comm->args); - if (s && *s == '-') - { - if (isdigit(s[1])) - sig = atoi(s+1); - else - { - if (s[1] == 'l' && s[2] == '\0') - { - printf("%s",sigs[0]); - for (sig = 1; sig != SIGCOUNT; sig++) - printf(" %s",sigs[sig]); - putchar('\n'); - return 0; - } - for (sig = 0; sig != SIGCOUNT; sig++) - if (!strcmp(sigs[sig],s+1)) - break; - if (sig == SIGCOUNT) - { - zerrnam("kill","unknown signal: SIG%s",s+1); - zerrnam("kill","type kill -l for a list of signals"); - return 1; - } - } - s = getnode(comm->args); - } - while (s) - { - if (*s == '%') - { - int job = getjob(s,"kill"); - - if (killjb(jobtab+job,sig) == -1) - { - zerrnam("kill","kill failed: %e",errno); - return 1; - } - if (jobtab[job].stat & STAT_STOPPED && sig == SIGCONT) - jobtab[job].stat &= ~STAT_STOPPED; - if (sig != SIGKILL) - killpg(jobtab[job].gleader,SIGCONT); - } - else - if (kill(atoi(s),sig) == -1) - { - zerrnam("kill","kill failed: %e"); - return 1; - } - s = getnode(comm->args); - } - return 0; -} - -int export(comm comm) -{ -char *s,*t; -struct pmnode *pm; - - while (s = getnode(comm->args)) - { - if (t = strchr(s,'=')) - { - *t = '\0'; - if (pm = gethnode(s,parmhtab)) - freepm(remhnode(s,parmhtab)); - *t = '='; - putenv(s); - } - else - { - if (!(pm = gethnode(s,parmhtab))) - { - if (!getenv(s)) - { - zerrnam("export","parameter not set: %s",s); - free(s); - return 1; - } - } - else if (pm->isint) - { - zerrnam("export","can't export integer parameters"); - free(s); - return 1; - } - else - { - t = tricat(s,"=",pm->u.str); - putenv(t); - free(remhnode(s,parmhtab)); - } - } - } - return 0; -} - -int integer(comm comm) -{ -char *s,*t; -struct pmnode *uu; - - while (s = getnode(comm->args)) - { - if (t = strchr(s,'=')) - { - *t = '\0'; - setparm(s,t+1,0,1); - *t = '='; - } - else - { - uu = gethnode(s,parmhtab); - if (uu) - { - if (!uu->isint) - { - uu->isint = 1; - uu->u.val = matheval(uu->u.str); - } - } - else - setiparm(s,0,1); - } - } - return 0; -} - -static char *recs[] = { - "cputime","filesize","datasize","stacksize","coredumpsize", - "resident","descriptors" - }; - -int limit(comm comm) -{ -char *s; -int hard = 0,t0,lim; -long val; - - if (!(s = getnode(comm->args))) - { - showlimits(0,-1); - return 0; - } - if (!strcmp(s,"-s")) - { - if (full(comm->args)) - zerr("limit","arguments after -s ignored"); - for (t0 = 0; t0 != RLIM_NLIMITS; t0++) - if (setrlimit(t0,limits+t0) < 0) - zerr("limit","setrlimit failed: %e",errno); - return 0; - } - if (!strcmp(s,"-h")) - { - hard = 1; - free(s); - if (!(s = getnode(comm->args))) - { - showlimits(1,-1); - return 0; - } - } - while (s) - { - for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++) - if (!strncmp(recs[t0],s,strlen(s))) - { - if (lim != -1) - lim = -2; - else - lim = t0; - } - if (lim < 0) - { - zerrnam("limit", - (lim == -2) ? "ambiguous resource specification: %s" - : "no such resource: %s",s); - free(s); - return 1; - } - free(s); - if (!(s = getnode(comm->args))) - { - showlimits(hard,lim); - return 0; - } - if (!lim) - { - char *ss = s; - - val = strtol(s,&s,10); - if (*s) - if ((*s == 'h' || *s == 'H') && !s[1]) - val *= 3600L; - else if ((*s == 'm' || *s == 'M') && !s[1]) - val *= 60L; - else if (*s == ':') - val = val*60+strtol(s+1,&s,10); - else - { - zerrnam("limit","unknown scaling factor: %s",s); - free(ss); - return 1; - } - } -#ifdef RLIMIT_NOFILE - else if (lim == RLIMIT_NOFILE) - val = strtol(s,&s,10); -#endif - else - { - char *ss = s; - - val = strtol(s,&s,10); - if (!*s || ((*s == 'k' || *s == 'K') && !s[1])) - val *= 1024L; - else if ((*s == 'M' || *s == 'm') && !s[1]) - val *= 1024L*1024; - else - { - zerrnam("limit","unknown scaling factor: %s",s); - free(ss); - return 1; - } - free(ss); - } - if (hard) - if (val > limits[lim].rlim_max && geteuid()) - { - zerrnam("limit","can't raise hard limits"); - return 1; - } - else - { - limits[lim].rlim_max = val; - if (limits[lim].rlim_max < limits[lim].rlim_cur) - limits[lim].rlim_cur = limits[lim].rlim_max; - } - else - if (val > limits[lim].rlim_max) - { - zerrnam("limit","limit exceeds hard limit"); - return 1; - } - else - limits[lim].rlim_cur = val; - s = getnode(comm->args); - } - return 0; -} - -int unlimit(comm comm) -{ -char *s = getnode(comm->args); -int hard = 0,t0,lim; - - if (s && !strcmp(s,"-h")) - { - hard = 1; - if (geteuid()) - { - zerrnam("unlimit","can't remove hard limits"); - return 1; - } - free(s); - s = getnode(comm->args); - } - if (!s) - { - for (t0 = 0; t0 != RLIM_NLIMITS; t0++) - { - if (hard) - limits[t0].rlim_max = RLIM_INFINITY; - else - limits[t0].rlim_cur = limits[t0].rlim_max; - } - return 0; - } - while (s) - { - for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++) - if (!strncmp(recs[t0],s,strlen(s))) - { - if (lim != -1) - lim = -2; - else - lim = t0; - } - if (lim < 0) - { - zerrnam("unlimit", - (lim == -2) ? "ambiguous resource specification: %s" - : "no such resource: %s",s); - free(s); - return 1; - } - free(s); - if (hard) - limits[lim].rlim_max = RLIM_INFINITY; - else - limits[lim].rlim_cur = limits[lim].rlim_max; - s = getnode(comm->args); - } - return 0; -} - -void showlimits(int hard,int lim) -{ -int t0; -long val; - - for (t0 = 0; t0 != RLIM_NLIMITS; t0++) - if (t0 == lim || lim == -1) - { - printf("%-16s",recs[t0]); - val = (hard) ? limits[t0].rlim_max : limits[t0].rlim_cur; - if (val == RLIM_INFINITY) - printf("unlimited\n"); - else if (!t0) - printf("%d:%02d:%02d\n",(int) (val/3600), - (int) (val/60) % 60,(int) (val % 60)); -#ifdef RLIMIT_NOFILE - else if (t0 == RLIMIT_NOFILE) - printf("%d\n",(int) val); -#endif - else if (val >= 1024L*1024L) - printf("%ldMb\n",val/(1024L*1024L)); - else - printf("%ldKb\n",val/1024L); - } -} - -int sched(comm comm) -{ -char *s = getnode(comm->args); -time_t t; -long h,m; -struct tm *tm; -struct schnode *sch,*sch2,*schl; -int t0; - - if (s && *s == '-') - { - t0 = atoi(s+1); - - if (!t0) - { - zerrnam("sched","usage for delete: sched -<item#>."); - return 1; - } - for (schl = (struct schnode *) &scheds, sch = scheds, t0--; - sch && t0; sch = (schl = sch)->next, t0--); - if (!sch) - { - zerrnam("sched","not that many entries"); - return 1; - } - schl->next = sch->next; - free(sch->cmd); - free(sch); - return 0; - } - if (s && !full(comm->args)) - { - zerrnam("sched","not enough arguments"); - return 1; - } - if (!s) - { - char tbuf[40]; - - for (t0 = 1, sch = scheds; sch; sch = sch->next,t0++) - { - t = sch->time; - tm = localtime(&t); - strftime(tbuf,20,"%a %b %e %k:%M:%S",tm); - printf("%3d %s %s\n",t0,tbuf,sch->cmd); - } - return 0; - } - if (*s == '+') - { - h = strtol(s+1,&s,10); - if (*s != ':') - { - zerrnam("sched","bad time specifier"); - return 1; - } - m = strtol(s+1,&s,10); - if (*s) - { - zerrnam("sched","bad time specifier"); - return 1; - } - t = time(NULL)+h*3600+m*60; - } - else - { - h = strtol(s,&s,10); - if (*s != ':') - { - zerrnam("sched","bad time specifier"); - return 1; - } - m = strtol(s+1,&s,10); - if (*s && *s != 'a' && *s != 'p') - { - zerrnam("sched","bad time specifier"); - return 1; - } - t = time(NULL); - tm = localtime(&t); - t -= tm->tm_sec+tm->tm_min*60+tm->tm_hour*3600; - if (*s == 'p') - h += 12; - t += h*3600+m*60; - if (t < time(NULL)) - t += 3600*24; - } - sch = alloc(sizeof(struct schnode)); - sch->time = t; - sch->cmd = buildline(comm->args); - sch->next = NULL; - for (sch2 = (struct schnode *) &scheds; sch2->next; sch2 = sch2->next); - sch2->next = sch; - return 0; -} - -int eval(comm comm) -{ -char *s = buildline(comm->args); -list list; - - hungets(s); - strinbeg(); - if (!(list = parlist(1))) - { - hflush(); - strinend(); - return 1; - } - strinend(); - runlist(list); - return lastval; -} - -int Brk(comm comm) -{ - printf("%lx\n",(long) sbrk(0)); - return 0; -} - -static struct utmp *wtab; -static int wtabsz; - -int log(comm comm) -{ - if (!getparm("WATCH")) - return 1; - if (wtab) - free(wtab); - wtab = (struct utmp *) zalloc(1); - wtabsz = 0; - watch(); - return 0; -} - -int let(comm comm) -{ -char *str; -long val; - - while (str = getnode(comm->args)) - val = matheval(str); - return !val; -} - -int Read(comm comm) -{ -char *str,*pmpt; -int r = 0,bsiz,c,gotnl = 0; -char *buf,*bptr; -char cc; - - str = getnode(comm->args); - if (str && !strcmp(str,"-r")) - { - r = 1; - str = getnode(comm->args); - } - if (!str) - str = strdup("REPLY"); - if (interact) - { - for (pmpt = str; *pmpt && *pmpt != '?'; pmpt++); - if (*pmpt++) - { - write(2,pmpt,strlen(pmpt)); - *pmpt = '\0'; - } - } - while (full(comm->args)) - { - buf = bptr = zalloc(bsiz = 64); - FOREVER - { - if (gotnl) - break; - if (read(0,&cc,1) == 1) - c = cc; - else - c = EOF; - if (c == EOF || znspace(c)) - break; - *bptr++ = c; - if (bptr == buf+bsiz) - { - buf = realloc(buf,bsiz *= 2); - bptr = buf+(bsiz/2); - } - } - if (c == EOF) - return 1; - if (c == '\n') - gotnl = 1; - *bptr = '\0'; - setparm(str,buf,0,0); - str = getnode(comm->args); - } - buf = bptr = zalloc(bsiz = 64); - if (!gotnl) - FOREVER - { - if (read(0,&cc,1) == 1) - c = cc; - else - c = EOF; - if (c == EOF || c == '\n') - break; - *bptr++ = c; - if (bptr == buf+bsiz) - { - buf = realloc(buf,bsiz *= 2); - bptr = buf+(bsiz/2); - } - *bptr = '\0'; - } - if (c == EOF) - return 1; - setparm(str,buf,0,0); - return 0; -} - -int fc(comm comm) -{ -char *ename = getparm("FCEDIT"),*str,*s; -int n = 0,l = 0,r = 0,first = -1,last = -1,retval; -table subs = NULL; - - if (!interact) - { - zerrnam("fc","not interactive shell"); - return 1; - } - remhist(); - if (!ename) - ename = DEFFCEDIT; - str = getnode(comm->args); - for (; str && *str == '-' && str[1] && !isdigit(str[1]); - str = getnode(comm->args)) - while (str[1]) - switch(*++str) - { - case 'e': - if (str[1]) - { - zerrnam("fc","editor name expected after -e"); - return 1; - } - ename = getnode(comm->args); - if (!ename) - { - zerrnam("fc","editor name expected after -e"); - return 1; - } - break; - case 'n': - n = 1; - break; - case 'l': - l = 1; - break; - case 'r': - r = 1; - break; - default: - zerrnam("fc","bad option: %c",*str); - return 1; - } - subs = newtable(); - while (str) - { - for (s = str; *s && *s != '='; s++); - if (!*s) - break; - *s++ = '\0'; - addnode(subs,str); - addnode(subs,s); - str = getnode(comm->args); - } - if (str) - { - first = fcgetcomm(str); - if (first == -1) - { - freetable(subs,freestr); - return 1; - } - str = getnode(comm->args); - } - if (str) - { - last = fcgetcomm(str); - if (last == -1) - { - freetable(subs,freestr); - return 1; - } - if (full(comm->args)) - { - zerrnam("fc","too many arguments"); - freetable(subs,freestr); - return 1; - } - } - if (first == -1) - { - first = (l) ? cev-16 : cev; - if (last == -1) - last = cev; - } - if (first < tfev) - first = tfev; - if (last == -1) - last = first; - if (l) - retval = fclist(stdout,!n,r,first,last,subs); - else - { - FILE *out; - char *fn = gettemp(); - - out = fopen(fn,"w"); - if (!out) - zerrnam("fc","can't open temp file: %e",errno); - else - { - retval = 1; - if (!fclist(out,0,r,first,last,subs)) - if (fcedit(ename,fn)) - if (stuff(fn)) - zerrnam("fc","%e: %s",errno,s); - else - retval = 0; - } - unlink(fn); - free(fn); - } - freetable(subs,freestr); - return retval; -} - -/* get the history event associated with s */ - -int fcgetcomm(char *s) -{ -int cmd; - - if (cmd = atoi(s)) - { - if (cmd < 0) - cmd = cev+cmd+1; - return cmd; - } - cmd = hcomsearch(s); - if (cmd == -1) - zerrnam("fc","event not found: %s",s); - return cmd; -} - -/* list a series of history events to a file */ - -int fclist(FILE *f,int n,int r,int first,int last,table subs) -{ -int done = 0,ct; -Node node; -char *s; - - if (!subs->first) - done = 1; - last -= first; - first -= tfev; - if (r) - first += last; - for (node = histlist->first,ct = first; ct && node; - node = node->next, ct--); - first += tfev; - while (last-- >= 0) - { - if (!node) - { - zerrnam("fc","no such event: %d",first); - return 1; - } - s = makehlist(node->dat,0); - done |= fcsubs(&s,subs); - if (n) - fprintf(f,"%5d ",first); - if (f == stdout) - { - niceprintf(s,f); - putc('\n',f); - } - else - fprintf(f,"%s\n",s); - node = (r) ? node->last : node->next; - (r) ? first-- : first++; - } - if (f != stdout) - fclose(f); - if (!done) - { - zerrnam("fc","no substitutions performed"); - return 1; - } - return 0; -} - -/* perform old=new substituion */ - -int fcsubs(char **sp,table tab) -{ -Node n; -char *s1,*s2,*s3,*s4,*s = *sp,*s5; -int subbed = 0; - - for (n = tab->first; n; ) - { - s1 = n->dat; - n = n->next; - s2 = n->dat; - n = n->next; - s5 = s; - while (s3 = (char *) strstr(s5,s1)) - { - s4 = zalloc(1+(s3-s)+strlen(s2)+strlen(s3+strlen(s1))); - strncpy(s4,s,s3-s); - s4[s3-s] = '\0'; - strcat(s4,s2); - s5 = s4+strlen(s4); - strcat(s4,s3+strlen(s1)); - free(s); - s = s4; - subbed = 1; - } - } - *sp = s; - return subbed; -} - -int fcedit(char *ename,char *fn) -{ - if (!strcmp(ename,"-")) - return 1; - return !zyztem(ename,fn); -} - -int disown(comm comm) -{ -char *str; -int t0; -static struct jobnode zero; - - while (str = getnode(comm->args)) - { - t0 = getjob(str,"disown"); - if (t0 == -1) - return 1; - jobtab[t0] = zero; - } - return 0; -} - -int function(comm comm) -{ - if (full(comm->args)) - { - zerrnam("function","too many arguments"); - return 1; - } - listhtable(shfunchtab,(void (*)(char *,char *)) pshfunc); - return 0; -} - -int (*funcs[])(comm) = { - echo,zexit,logout,Unset,dirs, - Alias,cd,which,popd, - dot,pushd,shift,unhash,Break, - colon,Glob,noglob,mostglob,unalias, - fg,bg,jobs,Kill,export, - Umask,cd,limit,unlimit,eval, - unfunction,set,Brk,log,builtin, - sched,let,fc, - rehash,hash,disown,test,Read, - integer,setopt,unsetopt,zreturn,function, - test, - NULL - }; -char *funcnams[] = { - "echo","exit","logout","unset","dirs", - "alias","cd","which","popd", - ".","pushd","shift","unhash","break", - ":","glob","noglob","mostglob","unalias", - "fg","bg","jobs","kill","export", - "umask","chdir","limit","unlimit","eval", - "unfunction","set","brk","log","builtin", - "sched","let","fc", - "rehash","hash","disown","test","read", - "integer","setopt","unsetopt","return","function", - "[" - }; - -int builtin(comm comm) -{ -char *s; -int t0; - - s = getnode(comm->args); - if (!s) - { - zerrnam("builtin","not enough arguments"); - return 1; - } - for (t0 = 0; funcs[t0]; t0++) - if (!strcmp(funcnams[t0],s)) - break; - if (!funcs[t0]) - { - zerrnam("builtin","no such builtin: %s",s); - return 1; - } - return (funcs[t0])(comm); -} - -/* add builtins to the command hash table */ - -void addintern(htable ht) -{ -int (**ptr)(comm); -struct chnode *ch; -char **nam; - - for (ptr = funcs, nam = funcnams; *ptr; ptr++,nam++) - { - ch = alloc(sizeof(struct chnode)); - ch->type = BUILTIN; - ch->u.func = *ptr; - addhnode(strdup(*nam),ch,ht,freechnode); - } -} - -/* get the time of login/logout for WATCH */ - -static time_t getlogtime(struct utmp *u,int inout) -{ -FILE *in; -struct utmp uu; -int first = 1; - - if (inout) - return u->ut_time; - if (!(in = fopen(WTMP_FILE,"r"))) - return time(NULL); - fseek(in,0,2); - do - { - if (fseek(in,((first) ? -1 : -2)*sizeof(struct utmp),1)) - { - fclose(in); - return time(NULL); - } - first = 0; - if (!fread(&uu,sizeof(struct utmp),1,in)) - { - fclose(in); - return time(NULL); - } - } - while (memcmp(&uu,u,sizeof(struct utmp))); - do - if (!fread(&uu,sizeof(struct utmp),1,in)) - { - fclose(in); - return time(NULL); - } - while (strncmp(uu.ut_line,u->ut_line,8)); - fclose(in); - return uu.ut_time; -} - -/* print a login/logout event */ - -static void watchlog2(int inout,struct utmp *u,char *fmt) -{ -char *p,buf[40],*bf; -int i; -time_t timet; -struct tm *tm = NULL; - - while (*fmt) - if (*fmt != '%') - putchar(*fmt++); - else - { - fmt++; - switch(*fmt++) - { - case 'n': - printf("%.*s",8,u->ut_name); - break; - case 'a': - printf("%s",(!inout) ? "logged off" : "logged on"); - break; - case 'l': - printf("%.*s",5,u->ut_line+3); - break; - case 'm': - for (p = u->ut_host,i = 16; i && *p;i--,p++) - { - if (*p == '.' && !isdigit(p[1])) - break; - putchar(*p); - } - break; - case 'M': - printf("%.*s",16,u->ut_host); - break; - case 't': - case '@': - timet = getlogtime(u,inout); - tm = localtime(&timet); - strftime(buf,40,"%l:%M%p",tm); - printf("%s",(*buf == ' ') ? buf+1 : buf); - break; - case 'T': - timet = getlogtime(u,inout); - tm = localtime(&timet); - strftime(buf,40,"%k:%M",tm); - printf("%s",buf); - break; - case 'w': - timet = getlogtime(u,inout); - tm = localtime(&timet); - strftime(buf,40,"%a %e",tm); - printf("%s",buf); - break; - case 'W': - timet = getlogtime(u,inout); - tm = localtime(&timet); - strftime(buf,40,"%m/%d/%y",tm); - printf("%s",buf); - break; - case 'D': - timet = getlogtime(u,inout); - tm = localtime(&timet); - strftime(buf,40,"%y-%m-%d",tm); - printf("%s",buf); - break; - case '%': - putchar('%'); - break; - case 'S': - bf = buf; - if (tgetstr("so",&bf)) - fputs(buf,stdout); - break; - case 's': - bf = buf; - if (tgetstr("se",&bf)) - fputs(buf,stdout); - break; - case 'B': - bf = buf; - if (tgetstr("md",&bf)) - fputs(buf,stdout); - break; - case 'b': - bf = buf; - if (tgetstr("me",&bf)) - fputs(buf,stdout); - break; - case 'U': - bf = buf; - if (tgetstr("us",&bf)) - fputs(buf,stdout); - break; - case 'u': - bf = buf; - if (tgetstr("ue",&bf)) - fputs(buf,stdout); - break; - default: - putchar('%'); - putchar(fmt[-1]); - break; - } - } - putchar('\n'); -} - -/* check the list for login/logouts */ - -static void watchlog(int inout,struct utmp *u,char *w,char *fmt) -{ -char *v; - - if (!strcmp(w,"all")) - { - watchlog2(inout,u,fmt); - return; - } - for(;;) - if (v = strchr(w,':')) - { - if (!strncmp(u->ut_name,w,v-w)) - watchlog2(inout,u,fmt); - w = v+1; - } - else - { - if (!strncmp(u->ut_name,w,8)) - watchlog2(inout,u,fmt); - break; - } -} - -/* compare 2 utmp entries */ - -static int ucmp(struct utmp *u,struct utmp *v) -{ - if (u->ut_time == v->ut_time) - return strncmp(u->ut_line,v->ut_line,8); - return u->ut_time - v->ut_time; -} - -/* initialize the user list */ - -void readwtab(void) -{ -struct utmp *uptr; -int wtabmax = 32; -FILE *in; - - wtabsz = 0; - uptr = wtab = (struct utmp *) zalloc(wtabmax*sizeof(struct utmp)); - in = fopen(UTMP_FILE,"r"); - while (fread(uptr,sizeof(struct utmp),1,in)) - if (uptr->ut_host[0]) - { - uptr++; - if (++wtabsz == wtabmax) - uptr = (wtab = (struct utmp *) realloc(wtab,(wtabmax*=2)* - sizeof(struct utmp)))+wtabsz; - } - fclose(in); - if (wtabsz) - qsort(wtab,wtabsz,sizeof(struct utmp),ucmp); -} - -/* check for login/logout events; executed before each prompt - if WATCH is set */ - -void watch(void) -{ -char *s = getparm("WATCH"); -char *fmt = getparm("WATCHFMT"); -FILE *in; -int utabsz = 0,utabmax = wtabsz+4,uct,wct; -struct utmp *utab,*uptr,*wptr; - - holdintr(); - if (!fmt) - fmt = "%n has %a %l from %m."; - if (!wtab) - { - readwtab(); - noholdintr(); - return; - } - uptr = utab = (struct utmp *) zalloc(utabmax*sizeof(struct utmp)); - in = fopen(UTMP_FILE,"r"); - while (fread(uptr,sizeof *uptr,1,in)) - if (uptr->ut_host[0]) - { - uptr++; - if (++utabsz == utabmax) - uptr = (utab = (struct utmp *) realloc(utab,(utabmax*=2)* - sizeof(struct utmp)))+utabsz; - } - fclose(in); - noholdintr(); - if (errflag) - { - free(utab); - return; - } - if (utabsz) - qsort(utab,utabsz,sizeof(struct utmp),ucmp); - - wct = wtabsz; uct = utabsz; - uptr = utab; wptr = wtab; - if (errflag) - { - free(utab); - return; - } - while ((uct || wct) && !errflag) - if (!uct || (wct && ucmp(uptr,wptr) > 0)) - wct--,watchlog(0,wptr++,s,fmt); - else if (!wct || (uct && ucmp(uptr,wptr) < 0)) - uct--,watchlog(1,uptr++,s,fmt); - else - uptr++,wptr++,wct--,uct--; - free(wtab); - wtab = utab; - wtabsz = utabsz; - fflush(stdout); -} - End of builtin.c echo builtin.pro 1>&2 sed 's/^-//' >builtin.pro <<'End of builtin.pro' -int echo(comm comm); -void pdstack(void); -int zexit(comm comm); -int zreturn(comm comm); -int logout(comm comm); -int Unset(comm comm); -int set(comm comm); -int setopt(comm comm); -int unsetopt(comm comm); -int csetopt(comm comm,int isun); -void pparm(char *s,struct pmnode *t); -int dirs(comm comm); -void listhtable(htable ht,void (*func)(char *,char *)); -void palias(char *s,struct anode *t); -void pshfunc(char *s,list l); -void niceprint(char *s); -void niceprintf(char *s,FILE *f); -char *buildline(table t); -int Alias(comm comm); -int cd(comm comm); -int dot(comm comm); -int Umask(comm comm); -int which(comm comm); -int popd(comm comm); -int pushd(comm comm); -int chcd(char *cnam,char *cd); -int shift(comm comm); -int unhash(comm comm); -int rehash(comm comm); -int hash(comm comm); -int Break(comm comm); -int colon(comm comm); -int Glob(comm comm); -int noglob(comm comm); -int mostglob(comm comm); -int unfunction(comm comm); -int unalias(comm comm); -int prefix(char *s,char *t); -int getjob(char *s,char *prog); -int fg(comm comm); -int bg(comm comm); -int jobs(comm comm); -int Kill(comm comm); -int export(comm comm); -int integer(comm comm); -int limit(comm comm); -int unlimit(comm comm); -void showlimits(int hard,int lim); -int sched(comm comm); -int eval(comm comm); -int Brk(comm comm); -int log(comm comm); -int let(comm comm); -int Read(comm comm); -int fc(comm comm); -int fcgetcomm(char *s); -int fclist(FILE *f,int n,int r,int first,int last,table subs); -int fcsubs(char **sp,table tab); -int fcedit(char *ename,char *fn); -int disown(comm comm); -int function(comm comm); -int builtin(comm comm); -void addintern(htable ht); -void readwtab(void); -void watch(void); End of builtin.pro echo config.h 1>&2 sed 's/^-//' >config.h <<'End of config.h' -/* - - config.h - configuration file - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -/* define this if you have WAITPID */ - -#define WAITPID - -/* define if the return type of signal handlers is int */ - -/* #define INTHANDTYPE */ - -/* the return type of handlers */ - -#define HANDTYPE void - -/* define this if you have putenv */ - -#define PUTENV - -/* define this if you have strstr */ - -#define STRSTR - -/* define this if you have strftime */ - -/* #define STRFTIME */ - -/* define if you have struct termios, else struct sgttyb */ - -#define TERMIOS - -#include "config.local.h" - End of config.h echo config.local.h 1>&2 sed 's/^-//' >config.local.h <<'End of config.local.h' -/* - - config.local.h - local machine configuration file - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -/* a string corresponding to the host type */ - -#define HOSTTYP "sun4" - -/* define if you prefer "suspended" to "stopped" */ - -#define USE_SUSPENDED - -/* the path of zsh in the file system */ - -#define MYSELF "/usr/princeton/bin/zsh" - -/* the default editor for the fc builtin */ - -#define DEFFCEDIT "/usr/ucb/vi" - -/* the file to source whenever zsh is run; if undefined, don't source - anything */ - -#define GLOBALZSHRC "/etc/zshrc" - -/* the file to source whenever zsh is run as a login shell; if - undefined, don't source anything */ - -#define GLOBALZLOGIN "/etc/zlogin" - -/* the default HISTSIZE */ - -#define DEFAULT_HISTSIZE 128 - -/* the path of utmp */ - -#define UTMP_FILE "/etc/utmp" - -/* the path of wtmp */ - -#define WTMP_FILE "/var/adm/wtmp" - -/* define if you have problems with job control or tty modes. - gcc-cpp does not seem to handle ioctls correctly. */ - -/*#define BUGGY_GCC*/ - -/* define if you like interactive comments */ - -/*#define INTERACTIVE_COMMENTS*/ - -/* define if you want warnings about nonexistent path components */ - -#define PATH_WARNINGS - End of config.local.h echo exec.c 1>&2 sed 's/^-//' >exec.c <<'End of exec.c' -/* - - exec.c - command execution - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include <sys/errno.h> -#include <sys/dir.h> - -#define execerr() { if (forked) exit(1); freecmd(comm); \ - closemnodes(mfds); errflag = 1; return; } -#define magicerr() { if (magic) putc('\n',stderr); errflag = 1; } - -/* execute a string */ - -void execstring(char *s) -{ -list l; - - hungets(strdup("\n")); - hungets(s); - strinbeg(); - if (!(l = parlist(1))) - { - strinend(); - hflush(); - return; - } - if (peek != EOF && peek != EMPTY) - { - strinend(); - hflush(); - return; - } - strinend(); - execlist(l); -} - -/* duplicate a list and run it */ - -void newrunlist(list l) -{ -list a = duplist(l); runlist(a); -} - -/* fork and set limits */ - -int phork(void) -{ -int pid = fork(),t0; - - if (pid == -1) - { - zerr("fork failed: %e",errno); - return -1; - } - if (!pid) - for (t0 = 0; t0 != RLIM_NLIMITS; t0++) - setrlimit(t0,limits+t0); - return pid; -} - -/* execute a current shell command */ - -void execcursh(comm comm) -{ - runlist(comm->left); - comm->left = NULL; -} - -/* execve an external command */ - -void execute(char *arg0,table args) -{ -char **argv; -char *z,*s,buf[MAXPATHLEN],buf2[MAXPATHLEN]; -struct chnode *cn; -int t0,tl,ee = 0; - -#define zexecve(X,Y,Z) {execve(z=(X),Y,Z);\ - if(errno!=ENOENT){ee = errno;strcpy(buf2,buf);}} - - cn = gethnode(arg0,chtab); - if (s = getenv("STTY")) - zyztem("stty",s); - if (z = getenv("ARGV0")) - z = strdup(z); - else - z = arg0; - argv = makecline(z,args); - fixsigs(); - if (cn) - { - if (cn->type == EXCMD_POSTDOT) - {zexecve(arg0,argv,environ);} - {zexecve(cn->u.nam,argv,environ);} - } - for (s = arg0; *s; s++) - if (*s == '/') - { - execve(arg0,argv,environ); - zerr("%e: %s",errno,arg0); - _exit(1); - } - for (t0 = pathct; t0; t0--,path++) - if (**path == '.') - {zexecve(arg0,argv,environ);} - else - { - tl = strlen(*path); - strcpy(buf,*path); - buf[tl] = '/'; - if (strlen(arg0)+strlen(buf)+1 >= MAXPATHLEN) - { - zerr("command too long: %s",arg0); - _exit(1); - } - strcpy(buf+tl+1,arg0); - {zexecve(buf,argv,environ);} - } - if (ee) - { - z = buf2; - errno = ee; - goto errs; - } - zerr("command not found: %s",arg0); - _exit(1); -errs: - zerr("%e: %s",errno,z); - _exit(1); -} - -#define try(X) { if (!access(X,X_OK)) return strdup(X); } - -/* get the pathname of a command */ - -char *findcmd(char *arg0) -{ -char *s,buf[MAXPATHLEN]; -int t0,tl; -struct chnode *cn = gethnode(arg0,chtab); -char **pp = path; - - if (cn) - { - if (cn->type == EXCMD_POSTDOT) - { - strcpy(buf,"./"); - strcat(buf,arg0); - try(buf); - } - try(cn->u.nam); - } - for (s = arg0; *s; s++) - if (*s == '/') - { - try(arg0); - goto failed; - } - for (t0 = pathct; t0; t0--,pp++) - if (**pp == '.') - { - strcpy(buf,"./"); - strcat(buf,arg0); - try(buf); - } - else - { - tl = strlen(*pp); - strcpy(buf,*pp); - buf[tl] = '/'; - strcpy(buf+tl+1,arg0); - try(buf); - } -failed: - return NULL; -} - -void execlist(list list) -{ - execlist1(list); - freelist(list); -} - -void execlist1(list list) -{ - if (breaks) - return; - switch(list->type) - { - case SYNC: - case ASYNC: - execlist2(list->left,list->type,!list->right); - if (sigtrapped[SIGDEBUG]) - dotrap(SIGDEBUG); - if (sigtrapped[SIGERR] && lastval) - dotrap(SIGERR); - if (list->right && !retflag) - execlist1(list->right); - break; - } -} - -void execlist2(list2 list,int type,int last1) -{ - switch(list->type) - { - case END: - execpline(list,type,last1); - break; - case ORNEXT: - if (!execpline(list,SYNC,0)) - execlist2(list->right,type,last1); - break; - case ANDNEXT: - if (execpline(list,SYNC,0)) - execlist2(list->right,type,last1); - break; - } -} - -int execpline(list2 l,int how,int last1) -{ -int ipipe[2] = {0,0},opipe[2] = {0,0}; - - sigblock(sigmask(SIGCHLD)); - curjob = getfreejob(); - initjob(l->flags); - if (l->flags & PFLAG_COPROC) - { - how = ASYNC; - mpipe(ipipe); - mpipe(opipe); - if (spin) - { - close(spin); - close(spout); - } - spin = ipipe[0]; - spout = opipe[1]; - } - execpline2(l->left,how,opipe[0],ipipe[1],last1); - if (how == ASYNC) - { - spawnjob(); - sigsetmask(0); - return 1; - } - else - { - waitjobs(); - sigsetmask(0); - if (l->flags & PFLAG_NOT) - lastval = !lastval; - return !lastval; - } -} - -void execpline2(pline pline,int how,int input,int output,int last1) -{ -int pid; -int pipes[2]; - - if (breaks) - return; - if (!pline) - return; - if (pline->type == END) - { - execcomm(pline->left,input,output,how==ASYNC,last1); - pline->left = NULL; - } - else - { - mpipe(pipes); - - /* if we are doing "foo | bar" where foo is a current - shell command, do foo in the current shell and do - the rest of the pipeline in a subshell. */ - - if (pline->left->type >= CURSH && how == SYNC) - { - if (!(pid = fork())) - { ---cut here---cut here---cut here---
pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (12/15/90)
---cut here---cut here---cut here--- - case 'M': - stradd(&bp,hostM); - break; - case 'm': - stradd(&bp,hostm); - break; - case 'S': - if (tgetstr("so",&bp)) - bp--; - break; - case 's': - if (tgetstr("se",&bp)) - bp--; - break; - case 'B': - if (tgetstr("md",&bp)) - bp--; - break; - case 'b': - if (tgetstr("me",&bp)) - bp--; - break; - case 'U': - if (tgetstr("us",&bp)) - bp--; - break; - case 'u': - if (tgetstr("ue",&bp)) - bp--; - break; - case 't': - case '@': - timet = time(NULL); - tm = localtime(&timet); - strftime(bp,16,"%l:%M%p",tm); - if (*bp == ' ') - chuck(bp); - bp += strlen(bp); - break; - case 'T': - timet = time(NULL); - tm = localtime(&timet); - strftime(bp,16,"%k:%M",tm); - bp += strlen(bp); - break; - case '*': - timet = time(NULL); - tm = localtime(&timet); - strftime(bp,16,"%k:%M:%S",tm); - bp += strlen(bp); - break; - case 'n': - stradd(&bp,username); - break; - case 'w': - timet = time(NULL); - tm = localtime(&timet); - strftime(bp,16,"%a %e",tm); - bp += strlen(bp); - break; - case 'W': - timet = time(NULL); - tm = localtime(&timet); - strftime(bp,16,"%m/%d/%y",tm); - bp += strlen(bp); - break; - case 'D': - timet = time(NULL); - tm = localtime(&timet); - strftime(bp,16,"%y-%m-%d",tm); - bp += strlen(bp); - break; - case 'l': - if (ss = ttyname(SHTTY)) - stradd(&bp,ss+8); - else - stradd(&bp,"(none)"); - break; - case '%': - *bp++ = '%'; - break; - case '#': - *bp++ = (geteuid()) ? '%' : '#'; - break; - default: - *bp++ = '%'; - *bp++ = *fm; - break; - } - else - *bp++ = *fm; - } - *bp = '\0'; - return buf; -} - -void herrflush(void) -{ - if (strin) - hflush(); - else while (lastc != '\n' && lastc != HERR) - hgetch(); - if (magic) - putc('\n',stderr); -} - -/* read an arbitrary amount of data into a buffer until stop is found */ - -char *hdynread(char stop) -{ -int bsiz = 256,ct = 0,c; -char *buf = zalloc(bsiz),*ptr; - - ptr = buf; - while ((c = hgetch()) != stop && c != '\n') - { - if (c == '\\') - c = hgetch(); - *ptr++ = c; - if (++ct == bsiz) - { - buf = realloc(buf,bsiz *= 2); - ptr = buf+ct; - } - } - *ptr = 0; - if (c == '\n') - { - hungetch('\n'); - zerr("delimiter expected"); - errflag = 1; - free(buf); - return NULL; - } - return buf; -} - -char *hdynread2(char stop) -{ -int bsiz = 256,ct = 0,c; -char *buf = zalloc(bsiz),*ptr; - - ptr = buf; - while ((c = hgetch()) != stop && c != '\n') - { - if (c == '\n') - { - hungetch(c); - break; - } - if (c == '\\') - if ((c = hgetch()) == '&') - c = '&'; - *ptr++ = c; - if (++ct == bsiz) - { - buf = realloc(buf,bsiz *= 2); - ptr = buf+ct; - } - } - *ptr = 0; - if (c == '\n') - hungetch('\n'); - return buf; -} - -/* set cbreak mode, or the equivalent */ - -void setcbreak(void) -{ -struct ttyinfo ti; - - ti = shttyinfo; -#ifdef TERMIOS - ti.termios.c_lflag &= ~ICANON; - ti.termios.c_cc[VMIN] = 1; - ti.termios.c_cc[VTIME] = 0; -#else - ti.sgttyb.sg_flags |= CBREAK; -#endif - settyinfo(&ti); -} - -int getlineleng(void) -{ -int z; - - z = shttyinfo.winsize.ws_col; - return (z) ? z : 80; -} - -void unsetcbreak(void) -{ - settyinfo(&shttyinfo); -} - -/* give the tty to some process */ - -void attachtty(long pgrp) -{ -static int ep = 0; - - if (jobbing) -#ifdef BUGGY_GCC - if (SHTTY != -1 && ioctl(SHTTY,(0x80000000|((sizeof(int)&0xff)<<16)| - ('t'<<8)|118),&pgrp) == -1 && !ep) -#else - if (SHTTY != -1 && ioctl(SHTTY,TIOCSPGRP,&pgrp) == -1 && !ep) -#endif - { - zerr("can't set tty pgrp: %e",errno); - opts[MONITOR] = OPT_UNSET; - ep =1; - } -} - End of hist.c echo hist.pro 1>&2 sed 's/^-//' >hist.pro <<'End of hist.pro' -void hwaddc(int c); -int hgetc(void); -void strinbeg(void); -void strinend(void); -int stuff(char *fn); -int hgetch(void); -void hungetch(int c); -void hungetc(int c); -void hflush(void); -void hungets(char *str); -void hbegin(void); -void inittty(void); -int hend(void); -void remhist(void); -void hwbegin(void); -char *hwadd(void); -int getargspec(int argc,int marg); -int hconsearch(char *str,int *marg); -int hcomsearch(char *str); -int apply1(int gflag,int (*func)(void **),table list); -int remtpath(void **junkptr); -int remtext(void **junkptr); -int rembutext(void **junkptr); -int remlpaths(void **junkptr); -int subst(int gbal,table slist,char *ptr1,char *ptr2); -int subststr(void **strptr,char *in,char *out,int gbal); -char *convamps(char *out,char *in); -char *makehlist(table tab,int freeit); -table quietgetevent(int ev); -table getevent(int ev); -int getargc(table tab); -table getargs(table elist,int arg1,int arg2); -int quote(void **tr); -int quotebreak(void **tr); -void stradd(char **p,char *d); -char *putprompt(char *fm); -void herrflush(void); -char *hdynread(char stop); -char *hdynread2(char stop); -void setcbreak(void); -int getlineleng(void); -void unsetcbreak(void); -void attachtty(long pgrp); End of hist.pro echo init.c 1>&2 sed 's/^-//' >init.c <<'End of init.c' -/* - - init.c - initialization, main loop - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include <pwd.h> - -void main(int argc, char **argv) -{ -int notect = 0; - - setflags(); - parseargs(argv); - setmoreflags(); - setupvals(); - initialize(); - runscripts(); - FOREVER - { - do - loop(); - while (peek != EOF); - if (!(isset(IGNOREEOF) && interact)) - { - if (interact) - fputs(islogin ? "logout\n" : "exit\n",stderr); - zexit(NULL); - continue; - } - zerrnam("\nzsh",(!islogin) ? "use 'exit' to exit." - : "use 'logout' to logout."); - notect++; - if (notect == 10) - zexit(NULL); - } -} - -/* keep executing lists until EOF found */ - -void loop(void) -{ -list list; - - FOREVER - { - peek = EMPTY; - if (interact) - preprompt(); - hbegin(); /* init history mech */ - intr(); /* interrupts on */ - ainit(); /* init alias mech */ - if (!(list = parlist1(0))) - { /* if we couldn't parse a list */ - hend(); - if (!errflag) - if (peek == OUTPAR) - { - errflag = 1; - zerr("mismatched parenthesis"); - } - else if (peek == OUTBRACE) - { - errflag = 1; - zerr("mismatched brace"); - } - else if (peek != EOF && peek != EMPTY && peek != NEWLIN) - { - errflag = 1; - zerr("semicolon or newline expected"); - } - if (peek == EOF && !errflag) - return; - continue; - } - if (peek != EMPTY && peek != EOF) - { - if (peek == OUTPAR) - zerr("mismatched parenthesis"); - else if (peek == OUTBRACE) - zerr("mismatched brace"); - else - zerr("semicolon or newline expected"); - hend(); - errflag = 1; - } - else if (hend()) - { - if (stopmsg) /* unset 'you have stopped jobs' flag */ - stopmsg--; - execlist(list); - } - if (ferror(stderr)) - { - zerr("write error"); - clearerr(stderr); - } - if (subsh) /* how'd we get this far in a subshell? */ - exit(lastval); - if ((!interact && errflag) || retflag) - return; - if ((opts['t'] == OPT_SET) || (lastval && opts[ERREXIT] == OPT_SET)) - { - if (sigtrapped[SIGEXIT]) - dotrap(SIGEXIT); - exit(lastval); - } - } -} - -void setflags(void) -{ -int c; - - for (c = 0; c != 128; c++) - opts[c] = OPT_INVALID; - opts['a'] = opts['e'] = opts['f'] = opts['h'] = opts['k'] = opts['n'] = - opts['s'] = opts['t'] = opts['u'] = opts['v'] = opts['x'] = - opts['c'] = OPT_UNSET; - opts['i'] = (isatty(0)) ? OPT_SET : OPT_UNSET; - for (c = '0'; c <= '9'; c++) - opts[c] = OPT_UNSET; - for (c = 'A'; c <= 'K'; c++) - opts[c] = OPT_UNSET; - opts[BGNICE] = opts[NOTIFY] = OPT_SET; -} - -static char *cmd; - -void parseargs(char **argv) -{ -char *argv0 = *argv; -int bk = 0; - - islogin = **(argv++) == '-'; - SHIN = 0; - while (!bk && *argv && **argv == '-') - { - while (*++*argv) - { - if (opts[**argv] == OPT_INVALID) - { - zerr("bad option: -%c",**argv); - exit(1); - } - opts[**argv] = OPT_SET; - if (bk = **argv == 'b') - break; - if (**argv == 'c') /* -c command */ - { - argv++; - if (!*argv) - { - zerr("string expected after -c"); - exit(1); - } - cmd = strdup(*argv); - opts[INTERACTIVE] = OPT_UNSET; - break; - } - } - argv++; - } - pparms = newtable(); - if (*argv) - { - if (opts[SHINSTDIN] == OPT_UNSET) - { - SHIN = movefd(open(argv0 = *argv,O_RDONLY)); - if (SHIN == -1) - { - zerr("can't open input file: %s",*argv); - exit(1); - } - opts[INTERACTIVE] = OPT_UNSET; - argv++; - } - addnode(pparms,argv0); /* assign positional parameters */ - while (*argv) - addnode(pparms,strdup(*argv++)); - } - else - { - addnode(pparms,strdup(argv0)); - opts[SHINSTDIN] = OPT_SET; - } -} - -void setmoreflags(void) -{ - setlinebuf(stderr); - setlinebuf(stdout); - subsh = 0; - opts[MONITOR] = (interact) ? OPT_SET : OPT_UNSET; - if (jobbing) - { - SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty",O_RDWR)); - if (SHTTY == -1) - opts[MONITOR] = OPT_UNSET; - else - gettyinfo(&shttyinfo); /* get tty state */ - if ((shpgrp = getpgrp(0)) <= 0) - opts[MONITOR] = OPT_UNSET; - } - else - SHTTY = -1; -} - -void setupvals(void) -{ -struct passwd *pwd; -char *ptr; - - shtimer = time(NULL); /* init $SECONDS */ - /* build various hash tables; argument to newhtable is table size */ - alhtab = newhtable(37); - parmhtab = newhtable(17); - shfunchtab = newhtable(17); - if (interact) - { - if (!getparm("PROMPT")) - setparm(strdup("PROMPT"),strdup("%M%# "),0,0); - if (!getparm("PROMPT2")) - setparm(strdup("PROMPT2"),strdup("> "),0,0); - if (!getparm("PROMPT3")) - setparm(strdup("PROMPT3"),strdup("?# "),0,0); - } - if (!getparm("PATH")) - setparm(strdup("PATH"),strdup("/bin:/usr/bin:/usr/ucb"),1,0); - setparm(strdup("VERSION"),strdup(VERSIONSTR),1,0); - home = xsymlink(getparm("HOME")); - setparm(strdup("HOME"),strdup(home),0,0); - setiparm(strdup("UID"),getuid(),1); - setiparm(strdup("EUID"),geteuid(),1); - setiparm(strdup("PPID"),getppid(),1); - lineno = 0; - pwd = getpwuid(getuid()); - setparm(strdup("USERNAME"),strdup(pwd->pw_name),0,0); - username = strdup(pwd->pw_name); - setparm(strdup("HOSTTYPE"),strdup(HOSTTYP),0,0); - cwd = zgetwd(); - setparm(strdup("PWD"),strdup(cwd),0,0); - if (!getparm("IFS")) - { - ifs = strdup(" \t\n"); - setparm(strdup("IFS"),strdup(ifs),0,0); - } - hostM = alloc(512); /* get hostname, with and without .podunk.edu */ - hostm = hostM+256; - gethostname(hostm,256); - gethostname(hostM,256); - procnum = getpid(); - for (ptr = hostM; *ptr && *ptr != '.'; ptr++); - *ptr = '\0'; -} - -void initialize(void) -{ -int t0; - - breaks = loops = incmd = 0; - lastmailcheck = 0; - lastmailval = -1; - tfev = 1; - tevs = DEFAULT_HISTSIZE; - histlist = newtable(); - dirstack = newtable(); - ungots = ungotptr = NULL; - signal(SIGQUIT,SIG_IGN); - for (t0 = 0; t0 != RLIM_NLIMITS; t0++) - getrlimit(t0,limits+t0); - last = rast = NULL; - proclast = 0; - if (!interact || SHTTY == -1) - bshin = fdopen(SHIN,"r"); - signal(SIGCHLD,handler); - addreswords(); - addhnode(strdup("false"),mkanode(strdup("let 0"),1),alhtab,NULL); - addhnode(strdup("history"),mkanode(strdup("fc -l"),1),alhtab,NULL); - addhnode(strdup("nohup"),mkanode(strdup("nohup "),1),alhtab,NULL); - addhnode(strdup("r"),mkanode(strdup("fc -e -"),1),alhtab,NULL); - addhnode(strdup("true"),mkanode(strdup(":"),1),alhtab,NULL); - addhnode(strdup("pwd"),mkanode(strdup("echo $PWD"),1),alhtab,NULL); - parsepath(); - parsecdpath(); - if (jobbing) - { - signal(SIGTTOU,SIG_IGN); - signal(SIGTSTP,SIG_IGN); - signal(SIGTTIN,SIG_IGN); - signal(SIGPIPE,SIG_IGN); - attachtty(shpgrp); - } - if (interact) - { - signal(SIGTERM,SIG_IGN); - intr(); - } -} - -void addreswords(void) -{ -char *reswds[] = { - "do", "done", "esac", "then", "elif", "else", "fi", "for", "case", - "if", "while", "function", "repeat", "time", "until", "exec", "command", - "select", "coproc", NULL - }; -int t0; - - for (t0 = 0; reswds[t0]; t0++) - addhnode(strdup(reswds[t0]),mkanode(NULL,-1-t0),alhtab,NULL); -} - -void runscripts(void) -{ - if (interact) - checkfirstmail(); - if (opts[NORCS] == OPT_UNSET) - { -#ifdef GLOBALZSHRC - source(GLOBALZSHRC); -#endif - sourcehome(".zshrc"); - if (islogin) - { -#ifdef GLOBALZLOGIN - source(GLOBALZLOGIN); -#endif - sourcehome(".zlogin"); - } - } - if (opts['c'] == OPT_SET) - { - close(SHIN); - SHIN = movefd(open("/dev/null",O_RDONLY)); - hungets(cmd); - strinbeg(); - } -} - -void ainit(void) -{ - alix = 0; /* reset alias stack */ - alstat = 0; - firstln = 1; -} End of init.c echo init.pro 1>&2 sed 's/^-//' >init.pro <<'End of init.pro' -void main(int argc, char **argv); -void loop(void); -void setflags(void); -void parseargs(char **argv); -void setmoreflags(void); -void setupvals(void); -void initialize(void); -void addreswords(void); -void runscripts(void); -void ainit(void); End of init.pro echo jobs.c 1>&2 sed 's/^-//' >jobs.c <<'End of jobs.c' -/* - - jobs.c - job control - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include <sys/errno.h> - -#define WCOREDUMPED(x) ((x)&0x80) - -/* != 0 means the handler is active */ - -static int handling = 0; - -/* != 0 means the shell is waiting for a job to complete */ - -static int waiting = 0; - -/* != 0 means readline is active */ - -extern int rl_active; - -/* != 0 means readline is waiting for a keypress */ - -extern int rl_waiting; - -#ifdef INTHANDTYPE -#define RETURN return 0 -#else -#define RETURN return -#endif - -/* the signal handler */ - -HANDTYPE handler(int sig,int code) -{ -long pid; -int statusp; -struct jobnode *jn; -struct procnode *pn; -struct rusage ru; - - if (sig == SIGINT) - { - if (sigtrapped[SIGINT]) - dotrap(SIGINT); - else - errflag = 1; - RETURN; - } - if (sig != SIGCHLD) - { - dotrap(sig); - RETURN; - } - for (;;) - { - pid = wait3(&statusp,WNOHANG|WUNTRACED,&ru); - if (pid == -1) - { - if (errno != ECHILD) - zerr("%e",errno); - RETURN; - } - if (!pid) - RETURN; - findproc(pid,&jn,&pn); /* find the procnode of this pid */ - if (jn) - { - pn->statusp = statusp; - handling = 1; - pn->ru_utime = ru.ru_utime; - pn->ru_stime = ru.ru_stime; - pn->endtime = time(NULL); - updatestatus(jn); - handling = 0; - } - else if (WIFSTOPPED(SP(statusp))) - kill(pid,SIGKILL); /* kill stopped untraced children */ - } - if (rl_active) - rl_prep_terminal(); - RETURN; -} - -/* change job table entry from stopped to running */ - -void makerunning(struct jobnode *jn) -{ -struct procnode *pn; - - jn->stat &= ~STAT_STOPPED; - for (pn = jn->procs; pn; pn = pn->next) - if (WIFSTOPPED(SP(pn->statusp))) - pn->statusp = SP_RUNNING; -} - -/* update status of job, possibly printing it */ - -void updatestatus(struct jobnode *jn) -{ -struct procnode *pn; -int notrunning = 1,alldone = 1,val,job = jn-jobtab,somestopped = 0; - - for (pn = jn->procs; pn; pn = pn->next) - { - if (pn->statusp == SP_RUNNING) - notrunning = 0; - if (pn->statusp == SP_RUNNING || WIFSTOPPED(SP(pn->statusp))) - alldone = 0; - if (WIFSTOPPED(SP(pn->statusp))) - somestopped = 1; - if (!pn->next && jn) - val = (WIFSIGNALED(SP(pn->statusp))) ? - 0200 | WTERMSIG(SP(pn->statusp)) : WEXITSTATUS(SP(pn->statusp)); - } - if (!notrunning) - return; - if (somestopped && (jn->stat & STAT_STOPPED)) - return; - jn->stat |= (alldone) ? STAT_CHANGED|STAT_DONE : - STAT_CHANGED|STAT_STOPPED; - if (!alldone) - gettyinfo(&jn->ttyinfo); - if (job == curjob) - { - if (!val) - gettyinfo(&shttyinfo); - else - settyinfo(&shttyinfo); - lastval = val; - } - if (jn->stat & STAT_STOPPED) - { - prevjob = topjob; - topjob = job; - } - if ((isset(NOTIFY) || job == curjob) && jn->stat & STAT_LOCKED) - printjob(jn,0); - if (sigtrapped[SIGCHLD] && job != curjob) - dotrap(SIGCHLD); -} - -/* find procnode and jobnode associated with pid */ - -void findproc(int pid,struct jobnode **jptr,struct procnode **pptr) -{ -struct procnode *pn; -int jn; - - for (jn = 1; jn != MAXJOB; jn++) - for (pn = jobtab[jn].procs; pn; pn = pn->next) - if (pn->pid == pid) - { - *pptr = pn; - *jptr = jobtab+jn; - return; - } - *pptr = NULL; - *jptr = NULL; -} - -static char *sigmsg[32] = { - "done","hangup","interrupt","quit", - "illegal instruction","trace trap","IOT instruction","EMT instruction", - "floating exception","killed","bus error","segmentation fault", - "bad system call","broken pipe","SIGALRM","terminated", -#ifdef USE_SUSPENDED - "SIGURG","suspended (signal)","suspended","continued", - "SIGCHLD","suspended (tty input)","suspended (tty output)","SIGIO", -#else - "SIGURG","stopped (signal)","stopped","continued", - "SIGCHLD","stopped (tty input)","stopped (tty output)","SIGIO", -#endif - "CPU time limit exceeded","file size limit exceeded","SIGVTALRM","SIGPROF", - "window changed","resource lost","SIGUSR1","SIGUSR2" - }; - -/* lng = 0 means jobs - lng = 1 means jobs -l - lng = 2 means jobs -p -*/ - -void printjob(struct jobnode *jn,int lng) -{ -int job = jn-jobtab,len = 9,sig = -1,sflag = 0,llen,printed = 0; -int conted = 0,lineleng = getlineleng(),doputnl = 0; -struct procnode *pn; -extern void rl_on_new_line(void); - - if (lng < 0) - { - conted = 1; - lng = 0; - } - - /* find length of longest signame, check to see if we - really need to print this job */ - - for (pn = jn->procs; pn; pn = pn->next) - { - if (pn->statusp != SP_RUNNING) - if (WIFSIGNALED(SP(pn->statusp))) - { - sig = WTERMSIG(SP(pn->statusp)); - llen = strlen(sigmsg[sig]); - if (WCOREDUMPED(pn->statusp)) - llen += 14; - if (llen > len) - len = llen; - if (sig != SIGINT && sig != SIGPIPE) - sflag = 1; - if (sig == SIGINT && job == curjob && interact) - doputnl = 1; - } - else if (WIFSTOPPED(SP(pn->statusp))) - { - sig = WSTOPSIG(SP(pn->statusp)); - if (strlen(sigmsg[sig]) > len) - len = strlen(sigmsg[sig]); - } - else if (isset(PRINTEXITVALUE) && WEXITSTATUS(SP(pn->statusp))) - sflag = 1; - } - if (doputnl) - putc('\n',stderr); - - /* print if necessary */ - - if (interact && jobbing && ((jn->stat & STAT_STOPPED) || sflag || - job != curjob)) - { - int len2,fline = 1; - struct procnode *qn; - - if (handling && (!waiting || jn->stat & STAT_STOPPED)) - putc('\n',stderr); - for (pn = jn->procs; pn;) - { - len2 = ((job == curjob) ? 5 : 10)+len; /* 2 spaces */ - if (lng) - qn = pn->next; - else for (qn = pn->next; qn; qn = qn->next) - { - if (qn->statusp != pn->statusp) - break; - if (strlen(qn->text)+len2+((qn->next) ? 3 : 0) > lineleng) - break; - len2 += strlen(qn->text)+2; - } - if (job != curjob) - if (fline) - fprintf(stderr,"[%d] %c ",jn-jobtab,(job == topjob) ? '+' : - (job == prevjob) ? '-' : ' '); - else - fprintf(stderr,(job > 9) ? " " : " "); - else - fprintf(stderr,"zsh: "); - if (lng) - if (lng == 1) - fprintf(stderr,"%d ",pn->pid); - else - { - fprintf(stderr,"%d ",jn->gleader); - lng = 0; - } - if (pn->statusp == SP_RUNNING) - if (!conted) - fprintf(stderr,"running%*s",len-7+2,""); - else - fprintf(stderr,"continued%*s",len-9+2,""); - else if (WIFEXITED(SP(pn->statusp))) - if (WEXITSTATUS(SP(pn->statusp))) - fprintf(stderr,"exit %-4d%*s",WEXITSTATUS(SP(pn->statusp)), - len-9+2,""); - else - fprintf(stderr,"done%*s",len-4+2,""); - else if (WIFSTOPPED(SP(pn->statusp))) - fprintf(stderr,"%-*s",len+2,sigmsg[WSTOPSIG(SP(pn->statusp))]); - else if (WCOREDUMPED(pn->statusp)) - fprintf(stderr,"%s (core dumped)%*s", - sigmsg[WTERMSIG(SP(pn->statusp))], - len-14+2-strlen(sigmsg[WTERMSIG(SP(pn->statusp))]),""); - else - fprintf(stderr,"%-*s",len+2,sigmsg[WTERMSIG(SP(pn->statusp))]); - for (; pn != qn; pn = pn->next) - fprintf(stderr,(pn->next) ? "%s | " : "%s",pn->text); - putc('\n',stderr); - fline = 0; - } - printed = 1; - } - - /* print "(pwd now: foo)" messages */ - - if (interact && job==curjob && strcmp(jn->cwd,cwd)) - { - printf("(pwd now: "); - printdir(cwd); - printf(")\n"); - fflush(stdout); - } - - /* delete job if done */ - - if (jn->stat & STAT_DONE) - { - static struct jobnode zero; - struct procnode *nx; - char *s; - - if (jn->stat & STAT_TIMED) - { - dumptime(jn); - printed = 1; - } - for (pn = jn->procs; pn; pn = nx) - { - nx = pn->next; - if (pn->text) - free(pn->text); - free(pn); - } - free(jn->cwd); - if (jn->filelist) - { - while (s = getnode(jn->filelist)) - { - unlink(s); - free(s); - } - free(jn->filelist); - } - *jn = zero; - if (job == topjob) - { - topjob = prevjob; - prevjob = job; - } - if (job == prevjob) - setprevjob(); - } - else - jn->stat &= ~STAT_CHANGED; - if (printed && rl_active) - { - rl_on_new_line(); - if (rl_waiting) - rl_redisplay(); - } -} - -/* set the previous job to something reasonable */ - -void setprevjob(void) -{ -int t0; - - for (t0 = MAXJOB-1; t0; t0--) - if (jobtab[t0].stat && jobtab[t0].stat & STAT_STOPPED && - t0 != topjob && t0 != curjob) - break; - if (!t0) - for (t0 = MAXJOB-1; t0; t0--) - if (jobtab[t0].stat && t0 != topjob && t0 != curjob) - break; - prevjob = (t0) ? t0 : -1; -} - -/* initialize a job table entry */ - -void initjob(int flags) -{ - jobtab[curjob].cwd = strdup(cwd); - jobtab[curjob].stat = (flags & PFLAG_TIMED) | STAT_INUSE; - jobtab[curjob].ttyinfo = shttyinfo; - jobtab[curjob].gleader = 0; -} - -/* add a process to the current job */ - -struct procnode *addproc(long pid,char *text) -{ -struct procnode *procnode; - - if (!jobtab[curjob].gleader) - jobtab[curjob].gleader = proclast = pid; - proclast = pid; - procnode = alloc(sizeof(struct procnode)); - procnode->pid = pid; - procnode->text = text; - procnode->next = NULL; - procnode->statusp = SP_RUNNING; - procnode->bgtime = time(NULL); - if (jobtab[curjob].procs) - { - struct procnode *n; - - for (n = jobtab[curjob].procs; n->next && !n->next->lastfg; n = n->next); - procnode->next = n->next; - n->next = procnode; - } - else - jobtab[curjob].procs = procnode; - return procnode; -} - -/* determine if it's all right to exec a command without - forking in last component of subshells; it's not ok if we have files - to delete */ - -int execok(void) -{ -struct jobnode *jn; - - if (!exiting) - return 0; - for (jn = jobtab+1; jn != jobtab+MAXJOB; jn++) - if (jn->stat && jn->filelist) - return 0; - return 1; -} - -/* wait for a SIGCHLD, wait for the handler to execute, and return */ - -void chldsuspend(void) -{ -struct sigvec vec = { handler,sigmask(SIGCHLD),SV_INTERRUPT }; - - sigvec(SIGCHLD,&vec,NULL); - sigpause(0); - signal(SIGCHLD,handler); -} - -/* wait for the current job to finish */ - -void waitjobs(void) -{ -static struct jobnode zero; -struct jobnode *jn; - - if (jobtab[curjob].procs) /* if any forks were done */ - { - jobtab[curjob].stat |= STAT_LOCKED; - waiting = 1; - if (jobtab[curjob].stat & STAT_CHANGED) - printjob(jobtab+curjob,0); - while (jobtab[curjob].stat && - !(jobtab[curjob].stat & (STAT_DONE|STAT_STOPPED))) - chldsuspend(); - waiting = 0; - } - else /* else do what printjob() usually does */ - { - char *s; - - jn = jobtab+curjob; - free(jn->cwd); - if (jn->filelist) - { - while (s = getnode(jn->filelist)) - { - unlink(s); - free(s); - } - free(jn->filelist); - } - *jn = zero; - } - curjob = -1; -} - -/* clear jobtab when entering subshells */ - -void clearjobtab(void) -{ -static struct jobnode zero; -int t0; - - for (t0 = 1; t0 != MAXJOB; t0++) - jobtab[curjob] = zero; -} - -/* get a free entry in the job table to use */ - -int getfreejob(void) -{ -int mask,t0; - - FOREVER - { - mask = sigblock(sigmask(SIGCHLD)); - for (t0 = 1; t0 != MAXJOB; t0++) - if (!jobtab[t0].stat) - { - sigsetmask(mask); - jobtab[t0].stat |= STAT_INUSE; - return t0; - } - sigsetmask(mask); - sleep(1); - } -} - -/* print pids for & */ - -void spawnjob(void) -{ -struct procnode *pn; - - if (!subsh) - { - if (topjob == -1 || !(jobtab[topjob].stat & STAT_STOPPED)) - { - topjob = curjob; - setprevjob(); - } - else if (prevjob == -1 || !(jobtab[prevjob].stat & STAT_STOPPED)) - prevjob = curjob; - if (interact && jobbing) - { - fprintf(stderr,"[%d]",curjob); - for (pn = jobtab[curjob].procs; pn; pn = pn->next) - fprintf(stderr," %d",pn->pid); - fprintf(stderr,"\n"); - } - } - jobtab[curjob].stat |= STAT_LOCKED; - curjob = -1; -} - -void fixsigs(void) -{ - sigsetmask(0); -} - -/* timing */ - -static void addtimeval(struct timeval *s,struct timeval *t) -{ - s->tv_sec += t->tv_sec+(s->tv_usec+t->tv_usec)/1000000; - s->tv_usec = (s->tv_usec+t->tv_usec)%1000000; -} - -static void printtime(time_t real,struct timeval *u,struct timeval *s,char *desc) -{ - if (!desc) - desc = ""; - fprintf(stderr,"real: %lds user: %ld.%03lds sys: %ld.%03lds\n", - real,u->tv_sec,u->tv_usec/1000,s->tv_sec,s->tv_usec/1000); -} - -static void printheader(void) -{ - fprintf(stderr," real user system\n"); -} - -static void printtimes(time_t real,struct timeval *u,struct timeval *s,char *desc) -{ - if (!desc) - desc = ""; - fprintf(stderr,"% 8lds % 4d.%03lds % 4d.%03lds %s\n", - real,u->tv_sec,u->tv_usec/1000,s->tv_sec,s->tv_usec/1000,desc); -} - -void dumptime(struct jobnode *jn) -{ -struct procnode *pn = jn->procs; -struct timeval utot = { 0,0 },stot = { 0,0 }; -time_t maxend,minbeg; - - if (!jn->procs) - return; - if (!jn->procs->next) - printtime(pn->endtime-pn->bgtime,&pn->ru_utime,&pn->ru_stime,pn->text); - else - { - maxend = jn->procs->endtime; - minbeg = jn->procs->bgtime; - printheader(); - for (pn = jn->procs; pn; pn = pn->next) - { - printtimes(pn->endtime-pn->bgtime,&pn->ru_utime,&pn->ru_stime,pn->text); - addtimeval(&utot,&pn->ru_utime); - addtimeval(&stot,&pn->ru_stime); - if (pn->endtime > maxend) - maxend = pn->endtime; - if (pn->bgtime < minbeg) - minbeg = pn->bgtime; - } - printtimes(maxend-minbeg,&utot,&stot,"total"); - } -} - -/* SIGHUP any jobs left running */ - -void killrunjobs(void) -{ -int t0,killed = 0; - - for (t0 = 1; t0 != MAXJOB; t0++) - if (t0 != curjob && jobtab[t0].stat && - !(jobtab[t0].stat & STAT_STOPPED)) - { - killpg(jobtab[t0].gleader,SIGHUP); - killed++; - } - if (killed) - zerr("warning: %d jobs SIGHUPed",killed); -} - -/* check to see if user has jobs running/stopped */ - -void checkjobs(void) -{ -int t0; - - for (t0 = 1; t0 != MAXJOB; t0++) - if (t0 != curjob && jobtab[t0].stat) - break; - if (t0 != MAXJOB) - { - if (jobtab[t0].stat & STAT_STOPPED) - { -#ifdef USE_SUSPENDED - zerr("you have suspended jobs."); -#else - zerr("you have stopped jobs."); -#endif - } - else - zerr("you have running jobs."); - stopmsg = 1; - } -} - -/* send a signal to a job (simply involves killpg if monitoring is on) */ - -int killjb(struct jobnode *jn,int sig) -{ -struct procnode *pn; -int err; - - if (jobbing) - return(killpg(jn->gleader,sig)); - for (pn = jn->procs; pn; pn = pn->next) - if ((err = kill(pn->pid,sig)) == -1 && errno != ESRCH) - return -1; - return err; -} - End of jobs.c echo jobs.pro 1>&2 sed 's/^-//' >jobs.pro <<'End of jobs.pro' -HANDTYPE handler(int sig,int code); -void makerunning(struct jobnode *jn); -void updatestatus(struct jobnode *jn); -void findproc(int pid,struct jobnode **jptr,struct procnode **pptr); -void printjob(struct jobnode *jn,int lng); -void setprevjob(void); -void initjob(int flags); -struct procnode *addproc(long pid,char *text); -int execok(void); -void chldsuspend(void); -void waitjobs(void); -void clearjobtab(void); -int getfreejob(void); -void spawnjob(void); -void fixsigs(void); -void dumptime(struct jobnode *jn); -void killrunjobs(void); -void checkjobs(void); -int killjb(struct jobnode *jn,int sig); End of jobs.pro echo lex.c 1>&2 sed 's/^-//' >lex.c <<'End of lex.c' -/* - - lex.c - lexical analysis - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" - -/* match the current token and get another - (actually just get another) */ - -void matchit(void) -{ - do - gettok(); - while (exalias()); -} - -int len = 0,bsiz = 256; -char *bptr; - -/* add a char to the string buffer */ - -void add(int c) -{ - *bptr++ = c; - if (bsiz == ++len) - bptr = len+(tstr = realloc(tstr,bsiz *= 2)); -} - -/* get a token */ - -void gettok(void) -{ -int bct = 0,pct = 0; -int c,d,intpos = 1; -static int dbparens = 0; - -beginning: - hlastw = NULL; - tstr = NULL; - while (zspace(c = hgetc()) || c == '\t' || c == ' '); - firstln = 0; - hwbegin(); - hwaddc(c); - if (dbparens) /* handle ((...)) */ - { - int pct = 2; - - peek = STRING; - len = dbparens = 0; - bptr = tstr = zalloc(bsiz = 256); - for (;;) - { - if (c == '(') - pct++; - else if (c == ')') - pct--; - else if (c == '\n') - { - zerr("parse error: )) expected"); - peek = HERR; - free(tstr); - return; - } - else if (c == '$') - c = Qstring; - if (pct >= 2) - add(c); - if (pct) - c = hgetc(); - else - break; - } - *bptr = '\0'; - return; - } - peekfd = -1; - if (isdigit(c)) /* handle 1< foo */ - { - d = hgetc(); - hungetc(d); - if (d == '>' || d == '<') - { - peekfd = c-'0'; - c = hgetc(); - } - } - - /* chars in initial position in word */ - - switch (c) - { - case '\\': - d = hgetc(); - if (d == '\n') - goto beginning; - hungetc(d); - break; - case EOF: - peek = EOF; - return; - case HERR: - peek = HERR; - return; - case '\n': - peek = NEWLIN; - return; - case ';': - d = hgetc(); - if (d != ';') - { - hungetc(d); - peek = SEMI; - } - else - peek = DSEMI; - return; - case '!': - if (!incmd) - { - peek = BANG; - return; - } - break; - case '&': - d = hgetc(); - if (d != '&') - { - hungetc(d); - peek = AMPER; - } - else - peek = DAMPER; - return; - case '|': - d = hgetc(); - if (d == '|') - peek = DBAR; - else if (d == '&') - peek = BARAMP; - else - { - hungetc(d); - peek = BAR; - } - return; - case '(': - if (incmd) - break; - d = hgetc(); - if (d == '(') - { - peek = STRING; - tstr = strdup("let"); - dbparens = 1; - return; - } - hungetc(d); - peek = INPAR; - return; - case ')': - peek = OUTPAR; - return; - case '{': - if (incmd) - break; - peek = INBRACE; - return; - case '}': - peek = OUTBRACE; - return; - case '<': - d = hgetc(); - if (incmd && d == '(') - { - hungetc(d); - break; - } - else if (d == '<') - { - int e = hgetc(); - - hungetc(e); - if (e == '(') - { - hungetc(d); - peek = INANG; - } - else - peek = DINANG; - } - else if (d == '&') - peek = INANGAMP; - else - { - peek = INANG; - hungetc(d); - } - return; - case '>': - d = hgetc(); - if (d == '(') - { - hungetc(d); - break; - } - else if (d == '&') - { - d = hgetc(); - if (d == '!') - peek = OUTANGAMPBANG; - else - { - hungetc(d); - peek = OUTANGAMP; - } - } - else if (d == '!') - peek = OUTANGBANG; - else if (d == '>') - { - d = hgetc(); - if (d == '&') - { - d = hgetc(); - if (d == '!') - peek = DOUTANGAMPBANG; - else - { - hungetc(d); - peek = DOUTANGAMP; - } - } - else if (d == '!') - peek = DOUTANGBANG; - else if (d == '(') - { - hungetc(d); - hungetc('>'); - peek = OUTANG; - } - else - { - hungetc(d); - peek = DOUTANG; - } - } - else - { - hungetc(d); - peek = OUTANG; - } - return; - case '#': -#ifndef INTERACTIVE_COMMENTS - if (interact) - break; -#endif - while ((c = hgetch()) != '\n' && !istok(c) && c != EOF); - if (c == '\n') - peek = NEWLIN; - else - errflag = 1; - return; - } - - /* we've started a string, now get the rest of it, performing - tokenization */ - - peek = STRING; - len = 0; - bptr = tstr = zalloc(bsiz = 256); - for(;;) - { - if (c == ';' || c == '&' || c == EOF || - c == HERR || c == '\03' || c == '\n' || - c == ' ' || c == '\t' || znspace(c)) - break; - if (c == '#') - c = Pound; - else if (c == ')') - { - if (!pct) - break; - pct--; - c = Outpar; - } - else if (c == ',') - c = Comma; - else if (c == '|') - { - if (!pct) - break; - c = Bar; - } - else if (c == '$') - { - d = hgetc(); - - c = String; - if (d == '[') - { - add(String); - add(Inbrack); - while ((c = hgetc()) != ']' && !istok(c) && c != EOF) - add(c); - c = Outbrack; - } - else if (d == '(') - { - add(String); - skipcomm(); - c = Outpar; - } - else - hungetc(d); - } - else if (c == '^') - c = Hat; - else if (c == '[') - c = Inbrack; - else if (c == ']') - c = Outbrack; - else if (c == '*') - c = Star; - else if (intpos && c == '~') - c = Tilde; - else if (c == '?') - c = Quest; - else if (c == '(') - { - int d = hgetc(); - - hungetc(d); - if (!incmd) - break; -#if 0 - if (d != ')' && intpos) - { - add(Inang); - skipcomm(); - c = Outpar; - } - else -#endif - { - pct++; - c = Inpar; - } - } - else if (c == '{') - { - c = Inbrace; - bct++; - } - else if (c == '}') - { - if (!bct) - break; - c = Outbrace; - bct--; - } - else if (c == '>') - { - d = hgetc(); - if (d != '(') - { - hungetc(d); - break; - } - add(Outang); - skipcomm(); - c = Outpar; - } - else if (c == '<') - { - d = hgetc(); - if (!(isdigit(d) || d == '-' || d == '>' || d == '(' || d == ')')) - { - hungetc(d); - break; - } - c = Inang; - if (d == '(') - { - add(c); - skipcomm(); - c = Outpar; - } - else if (d == ')') - hungetc(d); - else - { - add(c); - c = d; - while (c != '>' && !istok(c) && c != EOF) - add(c),c = hgetc(); - if (c == EOF) - { - errflag = 1; - peek = EOF; - return; - } - c = Outang; - } - } - else if (c == '=') - { - if (intpos) - { - d = hgetc(); - if (d != '(') - { - hungetc(d); - c = Equals; - } - else - { - add(Equals); - skipcomm(); - c = Outpar; - } - } - else if (peek != ENVSTRING) - { - peek = ENVSTRING; - intpos = 2; - } - } - else if (c == '\\') - { - c = hgetc(); - - if (c == '\n') - { - c = hgetc(); - continue; - } - add(c); - c = hgetc(); - continue; - } - else if (c == '\'') - { - add(Nularg); - - /* we add the Nularg to prevent this: - - echo $PA'TH' - - from printing the path. */ - - while ((c = hgetc()) != '\'' && !istok(c) && c != EOF) - add(c); - if (c == EOF) - { - errflag = 1; - peek = EOF; - return; - } - c = Nularg; - } - else if (c == HQUOT) - { - add(Nularg); - while ((c = hgetc()) != HQUOT && !istok(c) && c != EOF) - add(c); - if (c == EOF) - { - errflag = 1; - peek = EOF; - return; - } - c = Nularg; - } - else if (c == '\"') - { - add(Nularg); - while ((c = hgetc()) != '\"' && !istok(c) && c != EOF) - if (c == '\\') - { - c = hgetc(); - if (c != '\n') - { - if (c != '$' && c != '\\' && c != '\"' && c != '`') - add('\\'); - add(c); - } - } - else - { - if (c == '$') - { - int d = hgetc(); - - if (d == '(') - { - add(Qstring); - skipcomm(); - c = Outpar; - } - else if (d == '[') - { - add(String); - add(Inbrack); - while ((c = hgetc()) != ']' && c != EOF) - add(c); - c = Outbrack; - } - else - { - c = Qstring; - hungetc(d); - } - } - else if (c == '`') - c = Qtick; - add(c); - } - if (c == EOF) - { - errflag = 1; - peek = EOF; - return; - } - c = Nularg; - } - else if (c == '`') - { - add(Tick); - while ((c = hgetc()) != '`' && !istok(c) && c != EOF) - if (c == '\\') - { - c = hgetc(); - if (c != '\n') - { - if (c != '`' && c != '\\' && c != '$') - add('\\'); - add(c); - } - } - else - { - if (c == '$') - c = String; - add(c); - } - if (c == EOF) - { - errflag = 1; - peek = EOF; - return; - } - c = Tick; - } - add(c); - c = hgetc(); - if (intpos) - intpos--; - } - if (c == HERR) - { - free(tstr); - peek = HERR; - return; - } - hungetc(c); - *bptr = '\0'; -} - -/* expand aliases, perhaps */ - -int exalias(void) -{ -struct anode *an; -char *s; - - s = hwadd(); - if (alix != MAXAL && (an = gethnode(s,alhtab)) && !an->inuse && - !(an->cmd && incmd && alstat != ALSTAT_MORE)) - { - if (an->cmd < 0) - { - peek = DO-an->cmd-1; - return 0; - } - an->inuse = 1; - hungets(strdup(ALPOPS)); - hungets(strdup((alstack[alix++] = an)->text)); - alstat = 0; - if (tstr) - free(tstr); - return 1; - } - return 0; -} - -/* != 0 if c is not a newline, but in IFS */ - -int zspace(int c) -{ - if (c == '\n') - return 0; - return znspace(c); -} - -/* != 0 if c is in IFS */ - -int znspace(int c) -{ -char *ptr = ifs; - - while (*ptr) - if (*ptr++ == c) - return 1; - return 0; -} - -/* skip (...) */ - -void skipcomm(void) -{ -int pct = 1,c; - - c = Inpar; - do - { - add(c); -reget: - c = hgetc(); - if (istok(c) || c == EOF) - break; - else if (c == '(') pct++; - else if (c == ')') pct--; - else if (c == '\\') - { - add(c); - c = hgetc(); - } - else if (c == '\'') - { - add(c); - while ((c = hgetc()) != '\'' && !istok(c) && c != EOF) - add(c); - } - else if (c == HQUOT) - { - while ((c = hgetc()) != HQUOT && !istok(c) && c != EOF) - add(c); - goto reget; - } - else if (c == '\"') - { - add(c); - while ((c = hgetc()) != '\"' && !istok(c) && c != EOF) - if (c == '\\') - { - add(c); - add(hgetc()); - } - else add(c); - } - else if (c == '`') - { - add(c); - while ((c = hgetc()) != '`' && c != HERR && c != EOF) - if (c == '\\') add(c), add(hgetc()); - else add(c); - } - } - while(pct); -} - End of lex.c echo lex.pro 1>&2 sed 's/^-//' >lex.pro <<'End of lex.pro' -void matchit(void); -void add(int c); -void gettok(void); -int exalias(void); -int zspace(int c); -int znspace(int c); -void skipcomm(void); End of lex.pro echo loop.c 1>&2 sed 's/^-//' >loop.c <<'End of loop.c' -/* - - loop.c - parsing and executing loop constructs - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" - -/* parse a for/select loop */ - -int parfor(comm comm,int isfor) -{ -struct fornode *node = alloc(sizeof(struct fornode)); -char *comnam = (isfor) ? "for" : "select"; - - comm->type = (isfor) ? CFOR : CSELECT; - comm->info = node; - if (peek != STRING) - { - zerr("parse error in %s: identifier expected",comnam); - errflag = 1; - return 0; - } - node->name = tstr; - matchit(); - node->list = NULL; - node->inflag = 0; - if (peek == STRING && !strcmp("in",tstr)) - { - node->inflag = 1; - free(tstr); - matchit(); - while (peek == STRING) - { - addnode(comm->args,tstr); - matchit(); - } - } - if (peek != NEWLIN && peek != SEMI) - { - zerr("parse error: bad token in '%s' list",comnam); - freecmd(comm); - return 1; - } - incmd = 0; - matchit(); - while (peek == NEWLIN) - matchit(); - if (peek != DO) - { - zerr("parse error: 'do' expected"); - freecmd(comm); - return 1; - } - matchit(); - if (!(node->list = parlist(1))) - { - freecmd(comm); - return 1; - } - if (peek != DONE) - { - zerr("parse error: 'done' expected"); - freecmd(comm); - return 1; - } - matchit(); - return 0; -} - -int parcase(comm comm) -{ -struct casenode *node = alloc(sizeof(struct casenode)),*last = NULL; -char *tok; /* add FREES to this function */ - - comm->type = CCASE; - comm->info = node; - if (peek != STRING) - { - zerr("parse error in case: identifier expected"); - errflag = 1; - return 0; - } - addnode(comm->args,tstr); - matchit(); - if (peek != STRING || strcmp(tstr,"in")) - { - zerr("parse error in case: `in' expected"); - errflag = 1; - return 0; - } - while (tok = getcasepat()) - { - node = alloc(sizeof(struct casenode)); - node->pat = tok; - if (last) - last->next = node; - else - comm->info = node; - (last = node)->list = parlist(1); - if (peek != DSEMI) - { - zerr("parse error: ;; expected"); - return 1; - } - } - if (!last) - { - zerr("null case construct"); - return 1; - } - return 0; -} - -/* get a case pattern: foo) */ - -char *getcasepat(void) -{ -int c,bsiz = 256,ct = 0,pct = 0,qt = 0; -char *buf = zalloc(bsiz),*ptr,*s; - - peek = EMPTY; - while (znspace(c = hgetc())) - { - if (c == '\n') - { - hwbegin(); - hwaddc('\n'); - hwadd(); - } - } - ptr = buf; - hwbegin(); - hwaddc(c); - while (c != ')' || pct) - { - for (s = tokens; *s; s++) - if (*s == c) - { - c = (s-tokens)+Pound; - break; - } - if (qt) - { - if (c == '\'') - { - qt = 0; - c = hgetc(); - continue; - } - if (c == EOF) - { - qt = 0; - continue; - } - } - else - { - if (c == '\\') - c = hgetc(); - if (c == '\'') - { - qt = 1; - c = hgetc(); - continue; - } - if (c == Inpar) - pct++; - if (c == Outpar) - pct--; - if (ct == 4 && (znspace(c)||c ==';'||c=='&') && !strncmp(buf,"esac",4)) - { - hungetc(c); - hwadd(); - free(buf); - matchit(); - return NULL; - } - if (c == '\n' || c == EOF) - { - free(buf); - zerr("parse error: 'esac' expected"); - return NULL; - } - } - if (c == HERR) - { - free(buf); - return NULL; - } - *ptr++ = c; - if (++ct == bsiz) - { - ptr = zalloc(bsiz *= 2); - memcpy(ptr,buf,ct); - free(buf); - buf = ptr; - ptr = buf+ct; - } - c = hgetc(); - } - *ptr = 0; - hwadd(); - return buf; -} - -int parif(comm comm) -{ -struct ifnode *node = alloc(sizeof(struct ifnode)); - - comm->type = CIF; - comm->info = node; -do_then: - node->next = NULL; - if (!(node->ifl = parlist(1))) - { - freecmd(comm); - return 1; - } - if (peek != THEN) - { - zerr("parse error: 'then' expected"); - freecmd(comm); - return 1; - } - matchit(); - if (!(node->thenl = parlist(1))) - { - freecmd(comm); - return 1; - } - if (peek == ELIF) - { - matchit(); - node = node->next = alloc(sizeof(struct ifnode)); - goto do_then; - } - else if (peek == ELSE) - { - matchit(); - node = node->next = alloc(sizeof(struct ifnode)); - node->next = NULL; - node->ifl = NULL; - if (!(node->thenl = parlist(1))) - { - freecmd(comm); - return 1; - } - } - if (peek != FI) - { - zerr("parse error: 'fi' expected"); - freecmd(comm); - return 1; - } - matchit(); - return 0; -} - -/* parse while or until */ - -int parwhile(comm comm,int cond) -{ -struct whilenode *node = alloc(sizeof (struct whilenode)); - - comm->type = CWHILE; - comm->info = node; - node->cond = cond; - node->loop = node->cont = NULL; - if (!(node->cont = parlist(1))) - { - freecmd(comm); - return NULL; - } - if (peek != DO) - { - zerr("parse error: 'do' expected"); - freecmd(comm); - return 1; - } - matchit(); - node->loop = parlist(1); - if (peek != DONE) - { - zerr("parse error: 'done' expected"); - freecmd(comm); - return 1; - } - matchit(); - return 0; -} - -int parrepeat(comm comm) -{ -struct repeatnode *node = alloc(sizeof (struct repeatnode)); - - comm->type = CREPEAT; - comm->info = node; - node->list = NULL; - if (peek != STRING || !isdigit(*tstr)) - { - zerr("parse error: number expected"); - freecmd(comm); - return 1; - } - node->count = atoi(tstr); - free(tstr); - incmd = 0; - do - matchit(); - while (peek == NEWLIN); - if (peek != DO) - { - zerr("parse error: 'do' expected"); - freecmd(comm); - return 1; - } - matchit(); - node->list = parlist(1); - if (peek != DONE) - { - zerr("parse error: 'done' expected"); - freecmd(comm); - return 1; - } - matchit(); - return 0; -} - -void execfor(comm comm) -{ -list list; -struct fornode *node; -char *str; -table args; -int cj = curjob; - - loops++; - exiting = 0; - node = comm->info; - args = comm->args; - if (!node->inflag) - { - args = duptable(pparms,dupstr); - freestr(getnode(args)); - } - while (str = getnode(args)) - { - setparm(strdup(node->name),str,0,0); - list = duplist(node->list); - execlist(list); - if (breaks) - { - breaks--; - if (breaks || !contflag) - break; - contflag = 0; - } - } - curjob = cj; -} - -void execselect(comm comm) -{ -list list; -struct fornode *node; -char *str,*s; -table args; -Node n; -int cj = curjob,t0; - - loops++; - node = comm->info; - args = comm->args; - exiting = 0; - for (;;) - { - do - { - for (t0 = 1,n = args->first; n; n=n->next,t0++) - fprintf(stderr,"%d %s\n",t0,n->dat); - if (interact && SHTTY != -1) - { - inittty(); - str = readline(putprompt("PROMPT3")); - } - else - str = fgets(zalloc(256),256,bshin); - if (!str || errflag) - { - fprintf(stderr,"\n"); - goto done; - } - if (s = strchr(str,'\n')) - *s = '\0'; - } - while (!*str); - setparm(strdup("REPLY"),str,0,0); - t0 = atoi(str); - if (!t0) - str = ""; - else - { - for (t0--,n = args->first; n && t0; n=n->next,t0--); - if (n) - str = n->dat; - else - str = ""; - } - setparm(strdup(node->name),strdup(str),0,0); - list = duplist(node->list); - execlist(list); - if (breaks) - { - breaks--; - if (breaks || !contflag) - break; - contflag = 0; - } - if (errflag) - break; - } -done: - curjob = cj; -} - -void execwhile(comm comm) -{ -list list; -struct whilenode *node; -int cj = curjob; - - loops++; - node = comm->info; - exiting = 0; - FOREVER - { - list = duplist(node->cont); - execlist(list); - if (!((lastval == 0) ^ node->cond)) - break; - if (breaks) - { - breaks--; - if (breaks || !contflag) - break; - contflag = 0; - } - list = duplist(node->loop); - execlist(list); - } - curjob = cj; -} - -void execrepeat(comm comm) -{ -list list; -struct repeatnode *node; -int cj = curjob; - - loops++; - node = comm->info; - exiting = 0; - while (node->count--) - { - list = duplist(node->list); - execlist(list); - if (breaks) - { - breaks--; - if (breaks || !contflag) - break; - contflag = 0; - } - if (lastval) - break; - } - curjob = cj; -} - -void execif(comm comm) -{ -list list; -struct ifnode *node; -int cj = curjob; - - node = comm->info; - exiting = 0; - while (node) - { - if (node->ifl) - { - list = duplist(node->ifl); - execlist(list); - if (lastval) - { - node = node->next; - continue; - } - } - list = duplist(node->thenl); - execlist(list); - break; - } - curjob = cj; -} - -void execcase(comm comm) -{ -list list; -struct casenode *node; -char *word; -table args; -int cj = curjob; - - node = comm->info; - args = comm->args; - exiting = 0; - if (!args->first || args->first->next) - { - zerr("bad case statement"); - errflag = 1; - return; - } - word = args->first->dat; - while (node) - if (matchpat(word,node->pat)) - break; - else - node = node->next; - if (node) - { - list = duplist(node->list); - execlist(list); - } - curjob = cj; -} - -list duplist(list xlist) -{ -list nlist; - - if (!xlist) - return NULL; - nlist = alloc(sizeof(struct lnode)); - nlist->left = duplist2(xlist->left); - nlist->right = duplist(xlist->right); - nlist->type = xlist->type; - return nlist; -} - -void freelist(list xlist) -{ - if (xlist) - { - freelist2(xlist->left); - freelist(xlist->right); - free(xlist); - } -} - -list2 duplist2(list2 x) -{ -list2 y; - - if (!x) - return NULL; - y = alloc(sizeof(struct l2node)); - *y = *x; - y->left = duppline(x->left); - y->right = duplist2(x->right); - return y; -} - -void freelist2(list2 x) -{ - if (x) - { - freepline(x->left); - freelist2(x->right); - free(x); - } -} - -pline duppline(pline xpline) -{ -pline npline; - - if (!xpline) - return NULL; - npline = alloc(sizeof(struct pnode)); - npline->left = dupcomm(xpline->left); - npline->right = duppline(xpline->right); - npline->type = xpline->type; - return npline; -} - -void freepline(pline x) -{ - if (x) - { - freecmd(x->left); - freepline(x->right); - free(x); - } -} - -comm dupcomm(comm xcomm) -{ -comm ncomm; -void *(*duprs[])(void *) = {dupfor,dupwhile,duprepeat,dupif,dupcase}; -int type; - - if (!xcomm) - return NULL; - ncomm = alloc(sizeof(struct cnode)); - ncomm->left = duplist(xcomm->left); - ncomm->cmd = dupstr(xcomm->cmd); - ncomm->args = duptable(xcomm->args,dupstr); - ncomm->redir = duptable(xcomm->redir,dupfnode); - ncomm->vars = (xcomm->vars) ? duptable(xcomm->vars,dupstr) : NULL; - ncomm->type = type = xcomm->type; - if (type >= CFOR && type <= CCASE) - ncomm->info = (duprs[type-CFOR])(xcomm->info); - return ncomm; -} - -void freecmd(comm x) -{ - if (x) - { - freelist(x->left); - if (x->cmd) - free(x->cmd); - if (x->args) - freetable(x->args,freestr); - if (x->redir) - freetable(x->redir,freeredir); - if (x->vars) - freetable(x->vars,freestr); -/* if (x->info) - freeinfo(x->info);*/ - free(x); - } -} - -void *dupstr(void *str) -{ - if (!str) - return NULL; - return strdup(str); -} - -void *dupfnode(void *i) -{ -struct fnode *fn = i,*nfn = alloc(sizeof(struct fnode)); - - if (!i) - return NULL; - *nfn = *fn; - if (nfn->type < HEREDOC) - nfn->u.name = strdup(fn->u.name); - return nfn; -} - -void *dupfor(void *i) -{ -struct fornode *nnode,*node = i; - - nnode = alloc(sizeof(struct fornode)); - *nnode = *(struct fornode *) i; - nnode->name = strdup(node->name); - nnode->list = duplist(node->list); - return nnode; -} - -void *dupcase(void *i) -{ -struct casenode *nnode,*node = i; - - if (!i) - return NULL; - nnode = alloc(sizeof(struct casenode)); - nnode->next = dupcase(node->next); - nnode->list = duplist(node->list); - nnode->pat = strdup(node->pat); - return nnode; -} - -void *dupif(void *i) -{ -struct ifnode *nnode,*node = i; - - if (!i) - return NULL; - nnode = alloc(sizeof(struct ifnode)); - nnode->next = dupif(node->next); - nnode->ifl = duplist(node->ifl); - nnode->thenl = duplist(node->thenl); - return nnode; -} - -void *dupwhile(void *i) -{ -struct whilenode *nnode,*node = i; - - if (!i) - return NULL; - nnode = alloc(sizeof(struct whilenode)); - nnode->cond = node->cond; - nnode->cont = duplist(node->cont); - nnode->loop = duplist(node->loop); - return nnode; -} - -void *duprepeat(void *i) -{ -struct repeatnode *nnode,*node = i; - - if (!i) - return NULL; - nnode = alloc(sizeof(struct repeatnode)); - nnode->count = node->count; - nnode->list = duplist(node->list); - return nnode; -} - -table duptable(table tab,void *(*func)(void *)) -{ -table ret; -Node node; - - ret = newtable(); - for (node = tab->first; node; node = node->next) - addnode(ret,func(node->dat)); - return ret; -} End of loop.c echo loop.pro 1>&2 sed 's/^-//' >loop.pro <<'End of loop.pro' -int parfor(comm comm,int isfor); -int parcase(comm comm); -char *getcasepat(void); -int parif(comm comm); -int parwhile(comm comm,int cond); -int parrepeat(comm comm); -void execfor(comm comm); -void execselect(comm comm); -void execwhile(comm comm); -void execrepeat(comm comm); -void execif(comm comm); -void execcase(comm comm); -list duplist(list xlist); -void freelist(list xlist); -list2 duplist2(list2 x); -void freelist2(list2 x); -pline duppline(pline xpline); -void freepline(pline x); -comm dupcomm(comm xcomm); -void freecmd(comm x); -void *dupstr(void *str); -void *dupfnode(void *i); -void *dupfor(void *i); -void *dupcase(void *i); -void *dupif(void *i); -void *dupwhile(void *i); -void *duprepeat(void *i); -table duptable(table tab,void *(*func)(void *)); End of loop.pro echo math.c 1>&2 sed 's/^-//' >math.c <<'End of math.c' -/* - - math.c - evaluating arithmetic expressions - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <math.h> -#include <assert.h> - -extern int errflag; -extern char *setiparm(char *,long,int); -extern long getiparm(char *); -extern void zerr(char *,...); -extern char *strdup(char *); - -char *ptr; - -typedef int LV; - -long yyval; -LV yylval; - -/* nonzero means we are not evaluating, just parsing */ - -int noeval = 0; - -/* != 0 means recognize unary plus, minus, etc. - The parser was originally written in lex, hence the name. */ - -int initial = 1; - -void mathparse(int); - -/* LR = left-to-right associativity - RL = right-to-left associativity - BOO = short-circuiting boolean */ - -enum xtyp { LR,RL,BOO }; - -enum xtok { -INPAR, OUTPAR, NOT, COMP, POSTPLUS, -POSTMINUS, UPLUS, UMINUS, AND, XOR, -OR, MUL, DIV, MOD, PLUS, -MINUS, SHLEFT, SHRIGHT, LES, LEQ, -GRE, GEQ, DEQ, NEQ, DAND, -DOR, DXOR, QUEST, COLON, EQ, -PLUSEQ, MINUSEQ, MULEQ, DIVEQ, MODEQ, -ANDEQ, XOREQ, OREQ, SHLEFTEQ, SHRIGHTEQ, -DANDEQ, DOREQ, DXOREQ, COMMA, EOI, -PREPLUS, PREMINUS, NUM, ID, TOKCOUNT -}; - -/* precedences */ - -int prec[TOKCOUNT] = { -1,200,2,2,2, -2,2,2,3,4, -5,6,6,6,7, -7,8,8,9,9, -9,9,10,10,11, -12,12,13,13,14, -14,14,14,14,14, -14,14,14,14,14, -14,14,14,15,200, -2,2,0,0, -}; - -#define TOPPREC 15 - -int type[TOKCOUNT] = { -LR,LR,RL,RL,RL, -RL,RL,RL,LR,LR, -LR,LR,LR,LR,LR, -LR,LR,LR,LR,LR, -LR,LR,LR,LR,BOO, -BOO,LR,RL,RL,RL, -RL,RL,RL,RL,RL, -RL,RL,RL,RL,RL, -BOO,BOO,RL,RL,RL, -RL,RL,LR,LR, -}; - -#define LVCOUNT 32 - -/* table of lvalues (variables) */ - -int lvc; -char *lvals[LVCOUNT]; - -int yylex(void) -{ - for(;;) - switch (*ptr++) - { - case '+': - if (*ptr == '+' && (initial || !isalnum(*ptr))) - { - ptr++; - return (initial) ? PREPLUS : POSTPLUS; - } - if (*ptr == '=') { initial = 1; ptr++; return PLUSEQ; } - return (initial) ? UPLUS : PLUS; - case '-': - if (*ptr == '-' && (initial || !isalnum(*ptr))) - { - ptr++; - return (initial) ? PREMINUS : POSTMINUS; - } - if (*ptr == '=') { initial = 1; ptr++; return MINUSEQ; } - return (initial) ? UMINUS : MINUS; - case '(': initial = 1; return INPAR; - case ')': return OUTPAR; - case '!': if (*ptr == '=') - { initial = 1; ptr++; return NEQ; } - return NOT; - case '~': return COMP; - case '&': initial = 1; - if (*ptr == '&') { if (*++ptr == '=') - { ptr++; return DANDEQ; } return DAND; } - else if (*ptr == '=') { ptr++; return ANDEQ; } return AND; - case '|': initial = 1; - if (*ptr == '|') { if (*++ptr == '=') - { ptr++; return DOREQ; } return DOR; } - else if (*ptr == '=') { ptr++; return OREQ; } return OR; - case '^': initial = 1; - if (*ptr == '^') { if (*++ptr == '=') - { ptr++; return DXOREQ; } return DXOR; } - else if (*ptr == '=') { ptr++; return XOREQ; } return XOR; - case '*': initial = 1; - if (*ptr == '=') { ptr++; return MULEQ; } return MUL; - case '/': initial = 1; - if (*ptr == '=') { ptr++; return DIVEQ; } return DIV; - case '%': initial = 1; - if (*ptr == '=') { ptr++; return MODEQ; } return MOD; - case '<': initial = 1; if (*ptr == '<') - { if (*++ptr == '=') { ptr++; return SHLEFTEQ; } return SHLEFT; } - else if (*ptr == '=') { ptr++; return LEQ; } return LES; - case '>': initial = 1; if (*ptr == '>') - { if (*++ptr == '=') { ptr++; return SHRIGHTEQ; } return SHRIGHT; } - else if (*ptr == '=') { ptr++; return GEQ; } return GRE; - case '=': initial = 1; if (*ptr == '=') { ptr++; return DEQ; } - return EQ; - case '?': initial = 1; return QUEST; - case ':': initial = 1; return COLON; - case ',': initial = 1; return COMMA; - case '\0': initial = 1; ptr--; return EOI; - case '[': initial = 0; - { int base = strtol(ptr,&ptr,10); - yyval = strtol(ptr+1,&ptr,base); return NUM; } - case ' ': case '\t': - break; - default: - if (isdigit(*--ptr)) - { initial = 0; yyval = strtol(ptr,&ptr,10); return NUM; } - if (isalpha(*ptr) || *ptr == '$') - { - char *p,q; - - if (*ptr == '$') - ptr++; - p = ptr; - if (lvc == LVCOUNT) - { - zerr("too many identifiers in expression"); - errflag = 1; - return EOI; - } - initial = 0; - while(isalpha(*++ptr)); - q = *ptr; - *ptr = '\0'; - lvals[yylval = lvc++] = strdup(p); - *ptr = q; - return ID; - } - zerr("illegal character: %c",*ptr); - errflag = 1; - return EOI; - } -} - -/* the value stack */ - -#define STACKSZ 1000 -int tok; /* last token */ -int sp = -1; /* stack pointer */ -struct value { - LV lval; - long val; - } stack[STACKSZ]; - -void push(long val,LV lval) -{ - sp++; - stack[sp].val = val; - stack[sp].lval = lval; -} - -long getvar(LV s) -{ -long t; - - if (!(t = getiparm(lvals[s]))) - return 0; - return t; -} - -long setvar(LV s,long v) -{ - if (s == -1) - { - zerr("lvalue required"); - errflag = 1; - return 0; - } - if (noeval) - return v; - setiparm(strdup(lvals[s]),v,0); - return v; -} - -int notzero(int a) -{ - if (a == 0) - { - errflag = 1; - zerr("division by zero"); - return 0; - } - return 1; -} - -#define pop2() { b = stack[sp--].val; a = stack[sp--].val; } -#define pop3() {c=stack[sp--].val;b=stack[sp--].val;a=stack[sp--].val;} -#define nolval() {stack[sp].lval=-1;} -#define pushv(X) { push(X,-1); } -#define pop2lv() { pop2() lv = stack[sp+1].lval; } -#define set(X) { push(setvar(lv,X),lv); } - -void op(int what) -{ -long a,b,c; -LV lv; - - switch(what) { - case NOT: stack[sp].val = !stack[sp].val; nolval(); break; - case COMP: stack[sp].val = ~stack[sp].val; nolval(); break; - case POSTPLUS: (void) setvar(stack[sp].lval,stack[sp].val+1); break; - case POSTMINUS: (void) setvar(stack[sp].lval,stack[sp].val-1); break; - case UPLUS: nolval(); break; - case UMINUS: stack[sp].val = -stack[sp].val; nolval(); break; - case AND: pop2(); pushv(a&b); break; - case XOR: pop2(); pushv(a^b); break; - case OR: pop2(); pushv(a|b); break; - case MUL: pop2(); pushv(a*b); break; - case DIV: pop2(); if (notzero(b)) pushv(a/b); break; - case MOD: pop2(); if (notzero(b)) pushv(a%b); break; - case PLUS: pop2(); pushv(a+b); break; - case MINUS: pop2(); pushv(a-b); break; - case SHLEFT: pop2(); pushv(a<<b); break; - case SHRIGHT: pop2(); pushv(a>>b); break; - case LES: pop2(); pushv(a<b); break; - case LEQ: pop2(); pushv(a<=b); break; - case GRE: pop2(); pushv(a>b); break; - case GEQ: pop2(); pushv(a>=b); break; - case DEQ: pop2(); pushv(a==b); break; - case NEQ: pop2(); pushv(a!=b); break; - case DAND: pop2(); pushv(a&&b); break; - case DOR: pop2(); pushv(a||b); break; - case DXOR: pop2(); pushv(a&&!b||!a&&b); break; - case QUEST: pop3(); pushv((a)?b:c); break; - case COLON: break; - case EQ: pop2lv(); set(b); break; - case PLUSEQ: pop2lv(); set(a+b); break; - case MINUSEQ: pop2lv(); set(a-b); break; - case MULEQ: pop2lv(); set(a*b); break; - case DIVEQ: pop2lv(); if (notzero(b)) set(a/b); break; - case MODEQ: pop2lv(); if (notzero(b)) set(a%b); break; - case ANDEQ: pop2lv(); set(a&b); break; - case XOREQ: pop2lv(); set(a^b); break; - case OREQ: pop2lv(); set(a|b); break; - case SHLEFTEQ: pop2lv(); set(a<<b); break; - case SHRIGHTEQ: pop2lv(); set(a>>b); break; - case DANDEQ: pop2lv(); set(a&&b); break; - case DOREQ: pop2lv(); set(a||b); break; - case DXOREQ: pop2lv(); set(a&&!b||!a&&b); break; - case COMMA: pop2(); pushv(b); break; - case PREPLUS: stack[sp].val = setvar(stack[sp].lval, - stack[sp].val+1); break; - case PREMINUS: stack[sp].val = setvar(stack[sp].lval, - stack[sp].val-1); break; - default: fprintf(stderr,"whoops.\n"); exit(1); - } -} - -void bop(int tok) -{ - switch (tok) { - case DAND: case DANDEQ: if (!stack[sp].val) noeval++; break; - case DOR: case DOREQ: if (stack[sp].val) noeval++; break; - }; -} - -long matheval(char *s) -{ -int t0; - - for (t0 = 0; t0 != LVCOUNT; t0++) - lvals[t0] = NULL; - lvc = 0; - ptr = s; - sp = -1; - mathparse(TOPPREC); - if (!errflag && sp) - zerr("arithmetic error: unbalanced stack"); - for (t0 = 0; t0 != lvc; t0++) - free(lvals[t0]); - return stack[0].val; -} - -/* operator-precedence parse the string and execute */ - -void mathparse(int pc) -{ - if (errflag) - return; - tok = yylex(); - while (prec[tok] <= pc) - { - if (errflag) - return; - if (tok == NUM) - push(yyval,-1); - else if (tok == ID) - push(getvar(yylval),yylval); - else if (tok == INPAR) - { - mathparse(TOPPREC); - if (tok != OUTPAR) - exit(1); - } - else if (tok == QUEST) - { - int q = stack[sp].val; - if (!q) noeval++; - mathparse(prec[QUEST]-1); - if (!q) noeval--; else noeval++; - mathparse(prec[QUEST]); - if (q) noeval--; - op(QUEST); - continue; - } - else - { - int otok = tok,onoeval = noeval; - - if (type[otok] == BOO) - bop(otok); - mathparse(prec[otok]-(type[otok] != RL)); - noeval = onoeval; - op(otok); - continue; - } - tok = yylex(); - } -} - End of math.c echo math.pro 1>&2 sed 's/^-//' >math.pro <<'End of math.pro' -INPAR, OUTPAR, NOT, COMP, POSTPLUS,; -POSTMINUS, UPLUS, UMINUS, AND, XOR,; -OR, MUL, DIV, MOD, PLUS,; -MINUS, SHLEFT, SHRIGHT, LES, LEQ,; -GRE, GEQ, DEQ, NEQ, DAND,; -DOR, DXOR, QUEST, COLON, EQ,; -PLUSEQ, MINUSEQ, MULEQ, DIVEQ, MODEQ,; -ANDEQ, XOREQ, OREQ, SHLEFTEQ, SHRIGHTEQ,; -DANDEQ, DOREQ, DXOREQ, COMMA, EOI,; -PREPLUS, PREMINUS, NUM, ID, TOKCOUNT; -LR,LR,RL,RL,RL,; -RL,RL,RL,LR,LR,; -LR,LR,LR,LR,LR,; -LR,LR,LR,LR,LR,; -LR,LR,LR,LR,BOO,; -BOO,LR,RL,RL,RL,; -RL,RL,RL,RL,RL,; -RL,RL,RL,RL,RL,; -BOO,BOO,RL,RL,RL,; -RL,RL,LR,LR,; -int yylex(void); -void push(long val,LV lval); -long getvar(LV s); -long setvar(LV s,long v); -int notzero(int a); -void op(int what); -void bop(int tok); -long matheval(char *s); -void mathparse(int pc); End of math.pro echo parse.c 1>&2 sed 's/^-//' >parse.c <<'End of parse.c' -/* - - parse.c - parsing - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" - -/* parse a list, but return : instead of NULL */ - -list parlist(int nest) -{ -list l1; -list2 l2; -pline p; -comm c; - - if (l1 = parlist1(nest)) - return l1; - if (errflag) - return NULL; - c = alloc(sizeof *c); - c->cmd = strdup(""); - c->args = newtable(); - c->redir = newtable(); - c->type = SIMPLE; - p = alloc(sizeof *p); - p->left = c; - p->type = END; - l2 = alloc(sizeof *l2); - l2->left = p; - l2->type = END; - l1 = alloc(sizeof *l1); - l1->left = l2; - l1->type = SYNC; - return l1; -} - -/* parse a list */ - -list parlist1(int nest) -{ -list l1 = (list) alloc(sizeof *l1); -int isnl; - - incmd = 0; - if (peek == EMPTY) - matchit(); - if (nest) - while (peek == NEWLIN || peek == SEMI) - matchit(); - if (!(l1->left = parlist2())) - { - free(l1); - return NULL; - } - l1->type = (peek == AMPER) ? ASYNC : SYNC; - if ((isnl = peek == NEWLIN) || peek == SEMI || peek == AMPER) - peek = EMPTY; - if ((nest || !isnl) && peek == EMPTY) - { - if (!(l1->right = parlist1(nest))) - { - if (!errflag) - { - if (peek == NEWLIN) - peek = EMPTY; - return l1; - } - freelist2(l1->left); - free(l1); - return NULL; - } - } - else - l1->right = NULL; - return l1; -} - -/* parse a sublist */ - -list2 parlist2(void) ---cut here---cut here---cut here---
pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (12/15/90)
---cut here---cut here---cut here--- -{ -list2 l2 = (list2) alloc(sizeof *l2); -int iter = 0; - - for (;;) - { - if (peek == BANG) - { - l2->flags |= PFLAG_NOT; - matchit(); - } - else if (peek == TIME) - { - l2->flags |= PFLAG_TIMED; - matchit(); - } - else if (peek == COPROC) - { - l2->flags |= PFLAG_COPROC; - matchit(); - } - else - break; - iter = 1; - } - if (!(l2->left = parpline())) - { - free(l2); - if (!errflag && iter) - { - zerr("parse error: pipeline expected"); - errflag = 1; - } - return NULL; - } - if (peek == DAMPER || peek == DBAR) - { - l2->type = (peek == DAMPER) ? ANDNEXT : ORNEXT; - matchit(); - while (peek == NEWLIN) - matchit(); - if (!(l2->right = parlist2())) - { - if (!errflag) - { - zerr("invalid null command"); - errflag = 1; - } - freepline(l2->left); - free(l2); - return NULL; - } - } - else - { - l2->type = END; - l2->right = NULL; - } - return l2; -} - -/* parse a pipeline */ - -pline parpline(void) -{ -pline p = (pline) alloc(sizeof *p); - - if (!(p->left = parcmd())) - { - free(p); - return NULL; - } - if (peek == HERR) - { - freecmd(p->left); - free(p); - return NULL; - } - if (peek == BAR || peek == BARAMP) - { - if (peek == BARAMP) - { - struct fnode *f; - - f = alloc(sizeof *f); - f->type = MERGEOUT; - f->fd1 = 2; - f->u.fd2 = 1; - addnode(p->left->redir,f); - } - matchit(); - while (peek == NEWLIN) - matchit(); - p->type = PIPE; - if (!(p->right = parpline())) - { - if (!errflag) - { - zerr("invalid null command"); - errflag = 1; - } - freecmd(p->left); - free(p); - return NULL; - } - } - else - { - p->type = END; - p->right = NULL; - } - return p; -} - -/* parse a command */ - -comm parcmd(void) -{ -comm c = (comm) alloc(sizeof *c); -list l; -char *str; -int flag,iter = 0; - - incmd = 0; - c->left = NULL; - c->cmd = NULL; - c->args = newtable(); - c->redir = newtable(); - c->type = SIMPLE; - c->vars = NULL; - if (peek == EOF) - return NULL; -foo: - switch (peek) - { - case HERR: - return NULL; - case ENVSTRING: - if (!c->vars) - c->vars = newtable(); /* FIX */ - for (str = tstr; *str != '='; str++); - *str++ = '\0'; - addnode(c->vars,tstr); - addnode(c->vars,strdup(str)); - matchit(); - goto foo; - case FOR: - incmd = 1; - matchit(); - if (parfor(c,1)) - return NULL; - break; - case SELECT: - incmd = 1; - matchit(); - if (parfor(c,0)) - return NULL; - break; - case CASE: - incmd = 1; - matchit(); - if (parcase(c)) - return NULL; - break; - case IF: - matchit(); - if (parif(c)) - return NULL; - break; - case WHILE: - matchit(); - if (parwhile(c,0)) - return NULL; - break; - case UNTIL: - matchit(); - if (parwhile(c,1)) - return NULL; - break; - case REPEAT: - incmd = 1; - matchit(); - if (parrepeat(c)) - return NULL; - break; - case INPAR: - matchit(); - c->type = SUBSH; - if (!(c->left = parlist(1))) - { - freecmd(c); - return NULL; - } - if (peek != OUTPAR) - { - freecmd(c); - zerr("parse error: '}' expected"); - return NULL; - } - matchit(); - break; - case INBRACE: - matchit(); - c->type = CURSH; - if (!(c->left = parlist(1))) - { - freecmd(c); - return NULL; - } - if (peek != OUTBRACE) - { - freecmd(c); - zerr("parse error: '}' expected"); - return NULL; - } - matchit(); - break; - case FUNC: - matchit(); - str = tstr; - if (peek != STRING && peek != ENVSTRING) - { - c->cmd = strdup("function"); - incmd = 1; - if (isredir()) - goto jump1; - else - goto jump2; - } - do - matchit(); - while (peek == NEWLIN); - if (peek != INBRACE) - { - freecmd(c); - zerr("parse error: '{' expected"); - return NULL; - } - matchit(); - flag = peek == OUTBRACE; - if (!(l = parlist(1))) - { - freecmd(c); - return NULL; - } - if (peek != OUTBRACE) - { - freelist(l); - freecmd(c); - zerr("parse error: '}' expected"); - return NULL; - } - matchit(); - settrap(str,flag); - addhnode(str,l,shfunchtab,freeshfunc); - c->cmd = strdup(""); - c->type = SIMPLE; - break; - case EXEC: - c->flags |= CFLAG_EXEC; - matchit(); - iter = 1; - goto foo; - case COMMAND: - c->flags |= CFLAG_COMMAND; - matchit(); - iter = 1; - goto foo; - default: -jump1: - if (isredir()) - { - if (parredir(c)) - { - freecmd(c); - return NULL; - } - goto foo; - } - if (!(peek == STRING || peek == ENVSTRING)) - { - if (full(c->redir)) - { - c->cmd = strdup("cat"); - return c; - } - if (c->vars) - { - c->cmd = strdup(""); - return c; - } - free(c->args); - free(c->redir); - free(c); - if (iter && !errflag) - { - errflag = 1; - zerr("parse error: command expected"); - } - return NULL; - } -jump2: - while (peek == STRING || peek == ENVSTRING || isredir()) - if (isredir()) - { - if (parredir(c)) - { - freecmd(c); - return NULL; - } - } - else - { - if (tstr[0] == Inpar && tstr[1] == Outpar && !tstr[2]) - { - free(tstr); - incmd = 0; - matchit(); - if (full(c->args)) - { - zerr("illegal function definition"); - freecmd(c); - return NULL; - } - while (peek == NEWLIN) - matchit(); - if (peek != INBRACE) - { - freecmd(c); - zerr("parse error: '{' expected"); - return NULL; - } - matchit(); - flag = peek == OUTBRACE; - if (!(l = parlist(1))) - { - freecmd(c); - return NULL; - } - if (peek != OUTBRACE) - { - freelist(l); - freecmd(c); - zerr("parse error: '}' expected"); - return NULL; - } - matchit(); - settrap(c->cmd,flag); - addhnode(c->cmd,l,shfunchtab,freeshfunc); - c->cmd = strdup(""); - c->type = SIMPLE; - incmd = 0; - return c; - } - if (peek == ENVSTRING && (!incmd || opts[KEYWORD] == OPT_SET)) - { - if (!c->vars) - c->vars = newtable(); /* FIX */ - for (str = tstr; *str != '='; str++); - *str++ = '\0'; - addnode(c->vars,tstr); - addnode(c->vars,strdup(str)); - } - else if (c->cmd) - addnode(c->args,tstr); - else - { - c->cmd = tstr; - incmd = 1; - } - matchit(); - } - break; - } - while (isredir()) - if (parredir(c)) - { - freecmd(c); - return NULL; - } - incmd = 0; - if (peek == HERR) - { - freecmd(c); - return NULL; - } - return c; -} - -/* != 0 if peek is a redirection operator */ - -int isredir(void) -{ - return (peek >= OUTANG && peek <= DOUTANGAMPBANG); -} - -/* get fd associated with str */ - -int getfdstr(char *s) -{ - if (s[1]) - return -1; - if (isdigit(*s)) - return *s-'0'; - if (*s == 'p') - return -2; - return -1; -} - -int parredir(comm c) -{ -struct fnode *fn = (struct fnode *) alloc(sizeof *fn); -int pk = peek,ic = incmd,mrg2 = 0; - - fn->type = peek-OUTANG+WRITE; - if (peek == OUTANGAMP) - fn->type = MERGEOUT; - if (peekfd != -1) - fn->fd1 = peekfd; - else if (peek <= DOUTANGBANG || peek >= OUTANGAMP) - fn->fd1 = 1; - else - fn->fd1 = 0; - incmd = 1; - matchit(); - incmd = ic; - if (peek != STRING) - { - zerr("parse error: filename expected"); - return 1; - } - - if ((*tstr == Inang || *tstr == Outang) && tstr[1] == Inpar) - { - if (fn->type == WRITE) - fn->type = OUTPIPE; - else if (fn->type == READ) - fn->type = INPIPE; - else - { - zerr("parse error: bad process redirection"); - return 1; - } - fn->u.name = tstr; - } - else if (fn->type == HEREDOC) - fn->u.fd2 = gethere(tstr); - else if (pk >= OUTANGAMP && getfdstr(tstr) == -1) - { - mrg2 = 1; - fn->u.name = tstr; - fn->type = pk-OUTANGAMP; - } - else if (pk > OUTANGAMPBANG) - { - zerr("parse error: filename expected"); - return 1; - } - else if (pk == OUTANGAMPBANG) - { - struct fnode *fe = alloc(sizeof *fe); - - fe->fd1 = fn->fd1; - fe->type = CLOSE; - addnode(c->redir,fe); - fn->u.fd2 = getfdstr(tstr); - if (fn->u.fd2 == -2) - fn->u.fd2 = spout; - fn->type = MERGEOUT; - } - else if (fn->type == MERGE || fn->type == MERGEOUT) - { - if (*tstr == '-') - fn->type = CLOSE; - else - { - fn->u.fd2 = getfdstr(tstr); - if (fn->u.fd2 == -2) - fn->u.fd2 = (pk == OUTANGAMP) ? spout : spin; - } - } - else - fn->u.name = tstr; - addnode(c->redir,fn); - if (mrg2) - { - struct fnode *fe = alloc(sizeof *fe); - - fe->fd1 = 2; - fe->u.fd2 = fn->fd1; - fe->type = MERGEOUT; - addnode(c->redir,fe); - } - matchit(); - return 0; -} - End of parse.c echo parse.pro 1>&2 sed 's/^-//' >parse.pro <<'End of parse.pro' -list parlist(int nest); -list parlist1(int nest); -list2 parlist2(void); -pline parpline(void); -comm parcmd(void); -int isredir(void); -int getfdstr(char *s); -int parredir(comm c); End of parse.pro echo subst.c 1>&2 sed 's/^-//' >subst.c <<'End of subst.c' -/* - - subst.c - various substitution - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include <pwd.h> -#define MAXPATHLEN 1024 - -#define magicerr() { if (magic) putc('\n',stderr); } - -/* do substitutions before fork */ - -void prefork(table list) -{ -Node node = list->first; - - while (node) - { - char *str,*str3; - - str = str3 = node->dat; - if (!magic && str[1] == Inpar && (*str == Inang || - *str == Outang || *str == Equals)) - { - if (*str == Inang) - node->dat = getoutproc(str+2); /* <(...) */ - else if (*str == Equals) - node->dat = getoutputfile(str+2); /* =(...) */ - else - node->dat = getinproc(str+2); /* >(...) */ - free(str); - if (!node->dat) - { - zerr("parse error in process substitution"); - errflag = 1; - return; - } - } - else while (*str) - { - if (*str == String || *str == Qstring) - if (str[1] != Inpar) - if (str[1] == '*' || str[1] == Star) - parminsall(list,&node,&str,&str3); /* $* */ - else if (str[1] == Inbrack) - { - arithsuber((void **) &str,&str3); /* $[...] */ - if (magic) - magic = 2; - node->dat = str3; - } - else - { - parmsuber(str,&str3); /* $foo */ - node->dat = str = str3; - if (errflag) - return; - continue; - } - str++; - if (errflag) - return; - } - node = node->next; - } -} - -void postfork(table list,int globstat) -{ -Node node = list->first; -int glb = 1; - - if (isset(NOGLOBOPT) || globstat != GLOB) - glb = 0; - while (node) - { - char *str,*str3; - - str = str3 = node->dat; - while (*str) - { - if (((*str == String || *str == Qstring) && str[1] == Inpar) || - *str == Tick || *str == Qtick) - comminsall(list,&node,&str,&str3); /* `...`,$(...) */ - str++; - if (errflag) - return; - } - - /* now we remove the Nulargs tokens if this is not a null - arguments. The lexical analyzer throws these in so that - zsh will not look at this: - - $PA"TH" - - and expand it to $PATH. But after parameter substitution - these are only a nuisance, so we remove them. */ - - if (*(char *) node->dat) - remnulargs(node->dat); - - if (unset(IGNOREBRACES)) - while (hasbraces(node->dat)) - xpandbraces(list,&node); - filesub(&node->dat); - if (errflag) - return; - if (glb) - { - if (haswilds(node->dat)) - glob(list,&node); - if (errflag) - return; - } - else if (globstat == MOSTGLOB && *(char *) node->dat != '-') - glb = 1; - node = node->next; - } -} - -/* strdup, but returns "Nularg" if this is a null string */ - -void *nstrdup(void *s) -{ -char *t = s,u[] = {Nularg,'\0'}; - - if (!*t) - return strdup(u); - return strdup(t); -} - -/* $* */ - -void parminsall(table l,Node *nn,char **aptr,char **bptr) -{ -char *str3 = *aptr,*str = *bptr; -Node n = *nn,where = n->last; -table pl; - - if (magic) - magic = 2; - *str3 = '\0'; - str3 += 2; - remnode(l,n); - pl = duptable(pparms,nstrdup); - free(getnode(pl)); - if (pl->first) /* if $# > 1 */ - { - char *ptr; - Node tmp; - - ptr = pl->first->dat; - pl->first->dat = dyncat(str,ptr); - free(ptr); - ptr = pl->last->dat; - *bptr = pl->last->dat = dyncat(ptr,str3); - *aptr = *bptr+strlen(str)+strlen(ptr)-1; - free(ptr); - tmp = where->next; - where->next = pl->first; - pl->last->next = tmp; - pl->first->last = where; - if (tmp) - tmp->last = pl->last; - else - l->last = pl->last; - *nn = pl->last; - } - else /* just remove the $* */ - { - insnode(l,where,*bptr = dyncat(str,str3)); - *nn = where->next; - *aptr = *bptr+strlen(str)-1; - } -} - -char *dynread(char stop) -{ -int bsiz = 256,ct = 0,c; -char *buf = zalloc(bsiz),*ptr; - - ptr = buf; - while ((c = hgetc()) != stop) - { - *ptr++ = c; - if (++ct == bsiz) - { - buf = realloc(buf,bsiz *= 2); - ptr = buf+ct; - } - } - *ptr = 0; - return buf; -} - -int filesub(void **namptr) -{ -char *str = *namptr,*cnam; - - if (*str == Tilde && str[1] != '=') - { - if (str[1] == '+') - { - char *foo = strdup(cwd),*t = str; /* ~+ */ - - str+=2; - modify((void **) &foo,&str); - *namptr = dyncat(cwd,str); - free(foo); - free(t); - return 1; - } - else if (str[1] == '-') /* ~- */ - { - char *foo,*t = str; - - if (cnam = getparm("OLDPWD")) - foo = cnam; - else - foo = cwd; - str += 2; - foo = strdup(foo); - modify((void **) &foo,&str); - *namptr = dyncat(foo,str); - free(t); - free(foo); - return 1; - } - if (isalpha(str[1])) /* ~foo */ - { - char *ptr,*home; - - for (ptr = ++str; *ptr && !istok(*ptr) && (isalnum(*ptr) || *ptr == '-'); ptr++) - if (*ptr == '-') - *ptr = '-'; - if (!(home = gethome(str,ptr-str))) - { - if (magic) - home = completehome(str,ptr-str); - if (!home) - { - magicerr(); - zerr("user not found: %l",ptr-str,str); - errflag = 1; - return 0; - } - } - modify((void **) &home,&ptr); - *namptr = dyncat(home,ptr); - free(home); - free(str-1); - return 1; - } - else if (str[1] == '/') /* ~/foo */ - { - *namptr = dyncat(home,str+1); - free(str); - return 1; - } - else if (!str[1]) /* ~ by itself */ - { - free(str); - *namptr = strdup(home); - return 1; - } - } - if (*str == Equals && !istok(str[1]) && (isalnum(str[1]) || str[1] == '-')) - { - char *ptr,*s,*ds; - int val; - - untokenize(str); - if (isalpha(str[1])) /* =foo */ - { - struct chnode *chn; - struct anode *t; - char sav,*pp; - - for (pp = str+1; *pp && *pp != ':'; pp++); - sav = *pp; - *pp = '\0'; - if ((t = gethnode(str+1,alhtab)) && t->cmd) - if (t->cmd >= 0) - cnam = strdup(t->text); - else - { - magicerr(); - zerr("%s: shell reserved word",str+1); - errflag = 1; - return 0; - } - else if (chn = gethnode(str+1,chtab)) - if (chn->type != BUILTIN) - cnam = strdup(chn->u.nam); - else - { - magicerr(); - zerr("%s: shell built-in command",str+1); - errflag = 1; - return 0; - } - else if (!(cnam = findcmd(str+1))) - { - magicerr(); - zerr("%s not found",str+1); - errflag = 1; - return 0; - } - *namptr = cnam; - if ((*pp = sav) == ':') - { - modify(namptr,&pp); - s = *namptr; - *namptr = dyncat(*namptr,pp); - free(s); - } - free(str); - return 1; - } - if (str[1] == '-') /* =- */ - { - val = -1; - ptr = str+2; - } - else - val = strtol(str+1,&ptr,10); /* =# */ - ds = dstackent(val); - if (!ds) - return 1; - s = strdup(ds); - modify((void **) &s,&ptr); - *namptr = dyncat(s,ptr); - free(s); - free(str); - return 1; - } - return 0; -} - -/* get a user's directory */ - -char *gethome(char *user,int len) -{ -char sav,*str; -struct passwd *pw; - - sav = user[len]; - user[len] = '\0'; - if (!(pw = getpwnam(user))) - { - user[len] = sav; - return NULL; - } - str = xsymlink(pw->pw_dir); - user[len] = sav; - return str; -} - -/* complete a user and try to get his home directory */ - -char *completehome(char *user,int len) -{ -FILE *in; -char buf[MAXPATHLEN],*str; - - sprintf(buf,"%s/.zfriends",getparm("HOME")); - if (!(in = fopen(buf,"r"))) - return NULL; - while (fgetline(buf,MAXPATHLEN,in)) - if (!strncmp(user,buf,len)) - if (str = gethome(buf,strlen(buf))) - { - fclose(in); - return str; - } - fclose(in); - return NULL; -} - -/* get the value of the parameter specified by the first len - characters of s */ - -char *getsparmval(char *s,int len) -{ -char sav = s[len]; -char *val; -char buf[50]; -int t0; - - if (len == 1 && (istok(*s) || !isalnum(*s))) - switch(*s) - { - case Pound: - case '#': - sprintf(buf,"%d",ppcount()); - return strdup(buf); - case '-': - for (val = buf, t0 = ' '; t0 <= 'z'; t0++) - if (opts[t0] == OPT_SET) - *val++ = t0; - *val = '\0'; - return strdup(buf); - case '?': - case Quest: - sprintf(buf,"%d",lastval); - return strdup(buf); - case '$': - case String: - sprintf(buf,"%d",procnum); - return strdup(buf); - case '!': - sprintf(buf,"%d",proclast); - return strdup(buf); - default: - return NULL; - } - s[len] = '\0'; - if (isdigit(*s)) - { - int num; - Node node; - - num = atoi(s); - s[len] = sav; - for (node = pparms->first; node && num; num--,node = node->next); - return (node) ? strdup(node->dat) : NULL; - } - val = getparm(s); - s[len] = sav; - return (val) ? strdup(val) : NULL; -} - -/* set the parameter associated with the first len characters of s - to v. */ - -void setparml(char *s,int len,char *v) -{ -char c; - - c = s[len]; - s[len] = 0; - if (isdigit(*s)) - { - int num; - Node node; - - num = atoi(s); - for (node = pparms->first; node && num; num--,node = node->next); - if (node) - { - free(node->dat); - node->dat = v; - } - else - { - while (num--) - addnode(pparms,strdup("")); - addnode(pparms,v); - } - } - else - setparm(strdup(s),v,0,0); - s[len] = c; -} - -/* `...`, $(...) */ - -void comminsall(table l,Node *nn,char **aptr,char **bptr) -{ -char *str3 = *aptr,*str = *bptr,*str2; -Node n = *nn,where = n->last; -table pl; -int s31 = (*str3 == Qtick || *str3 == Qstring); - - if (magic) magic = 2; - if (*str3 == Tick || *str3 == Qtick) - { - *str3 = '\0'; - for (str2 = ++str3; *str3 != Tick && *str3 != Qtick; str3++); - *str3++ = '\0'; - } - else - { - *str3++ = '\0'; - for (str2 = ++str3; *str3 != Outpar; str3++); - *str3++ = '\0'; - } - remnode(l,n); - if (!(pl = getoutput(str2,s31))) - { - magicerr(); - zerr("parse error in command substitution"); - errflag = 1; - return; - } - if (pl->first) - { - char *ptr; - Node tmp; - - ptr = pl->first->dat; - pl->first->dat = dyncat(str,ptr); - free(ptr); - ptr = pl->last->dat; - *bptr = pl->last->dat = dyncat(ptr,str3); - *aptr = *bptr+strlen(str)+strlen(ptr)-1; - free(ptr); - tmp = where->next; - where->next = pl->first; - pl->last->next = tmp; - pl->first->last = where; - if (tmp) - tmp->last = pl->last; - else - l->last = pl->last; - /* free(tmp); */ - *nn = pl->last; - free(pl); - } - else - { - insnode(l,where,*bptr = dyncat(str,str3)); - *nn = where->next; - *aptr = *bptr+strlen(str)-1; - } -} - -/* do simple parameter substitution */ - -/* - consider an argument like this: - - abcde${fgh:-ijk}lmnop - - aptr will point to the $. - *bptr,ostr will point to the a. - t will point to the f. - u will point to the i. - s will point to the l (eventually). -*/ - -void parmsuber(char *aptr,char **bptr) -{ -char *s = aptr,*t,*u,*val,*ostr = *bptr; -int brs; /* != 0 means ${...}, otherwise $... */ -int vlen; /* the length of the name of the parameter */ -int colf; /* != 0 means we found a colon after the name */ -int doub = 0; /* != 0 means we have %%, not %, or ##, not # */ - - /* first, remove the $ so *bptr is pointing to a null-terminated - string containing the stuff before the $. Then check for braces, - and get the parameter name and value, if any. */ - - *s++ = '\0'; - if (brs = (*s == '{' || *s == Inbrace)) - s++; - t = s; - if (istok(*s) || !isalnum(*s)) - { - val = getsparmval(t,vlen = 1); - if (!val) - { - *(char *) aptr = '$'; - if (brs) - s[-1] = '{'; - return; - } - s++; - } - else - { - while (!istok(*s) && (isalnum(*s) || *s == '_')) - s++; - val = getsparmval(t,vlen = s-t); - } - - /* val can still be NULL at this point. */ - - if (colf = *s == ':') - s++; - - /* check for ${..?...} or ${..=..} or one of those. Only works - if the name is in braces. */ - - if (brs && (*s == '-' || *s == '=' || *s == '?' || *s == '+' || *s == '#' || - *s == '%' || *s == Quest || *s == Pound)) - { - if (*s == s[1]) - { - s++; - doub = 1; - } - u = ++s; - if (brs) - while (*s != '}' && *s != Outbrace) - s++; - else - { - while (*s++); - s--; - } - *s = '\0'; - switch (u[-1]) - { - case '-': - if (!val || (colf && !*val)) - val = strdup(u); - break; - case '=': - if (!val || (colf && !*val)) - setparml(t,vlen,val = strdup(u)); - break; - case '?': - case Quest: - if (!val || (colf && !*val)) - { - magicerr(); - zerr("%s",(*u) ? u : "parameter not set"); - if (!interact) - exit(1); - else - errflag = 1; - return; - } - break; - case '+': - if (!val || (colf && !*val)) - val = strdup(""); - else - val = strdup(u); - break; - case '#': - case Pound: - if (!val) - val = strdup(""); - getmatch(&val,u,doub); - break; - case '%': - if (!val) - val = strdup(""); - getmatch(&val,u,doub+2); - break; - } - } - else /* no ${...=...} or anything, but possible modifiers. */ - { - if (!val) - { - if (isset(NOUNSET)) - { - zerr("parameter not set: %l",vlen,t); - errflag = 1; - return; - } - val = strdup(""); - } - if (colf) - { - s--; - modify((void **) &val,&s); /* do modifiers */ - } - if (brs) - { - if (*s != '}' && *s != Outbrace) - { - zerr("closing brace expected"); - errflag = 1; - return; - } - s++; - } - } - if (errflag) - { - free(ostr); - return; - } - *bptr = zalloc((char *) aptr-(*bptr)+strlen(val)+strlen(s)+1); - strcpy(*bptr,ostr); - strcat(*bptr,val); - strcat(*bptr,s); - free(ostr); - if (magic) - magic = 2; -} - -/* arithmetic substitution */ - -void arithsuber(void **aptr,char **bptr) -{ -char *s = *aptr,*t,buf[16]; -long v; - - *s = '\0'; - for (; *s != Outbrack; s++); - *s++ = '\0'; - v = matheval(*aptr+2); - sprintf(buf,"%ld",v); - t = zalloc(strlen(*bptr)+strlen(buf)+strlen(s)+1); - strcpy(t,*bptr); - strcat(t,buf); - strcat(t,s); - free(*bptr); - *bptr = t; -} - -void modify(void **str,char **ptr) -{ -char *ptr1,*ptr2,*ptr3,del,*lptr; -int gbal; - - while (**ptr == ':') - { - lptr = *ptr; - (*ptr)++; - gbal = 0; -here: - switch(*(*ptr)++) - { - case 'h': - while (remtpath(str) && gbal); - break; - case 'r': - while (remtext(str) && gbal); - break; - case 'e': - while (rembutext(str) && gbal); - break; - case 't': - while (remlpaths(str) && gbal); - break; - case 's': - if (last) - free(last); - if (rast) - free(rast); - ptr1 = *ptr; - del = *ptr1++; - for (ptr2 = ptr1; *ptr2 != del && *ptr2; ptr2++); - if (!*ptr2) - { - magicerr(); - zerr("bad subtitution"); - errflag = 1; - return; - } - *ptr2++ = '\0'; - for (ptr3 = ptr2; *ptr3 != del && *ptr3; ptr3++); - if (*ptr3) - *ptr3++ = '\0'; - last = strdup(ptr1); - rast = strdup(ptr2); - *ptr = ptr3; - case '&': - if (last && rast) - subststr(str,last,rast,gbal); - break; - case 'g': - gbal = 1; - goto here; - default: - *ptr = lptr; - return; - } - } -} - -/* get a directory stack entry */ - -char *dstackent(int val) -{ -Node node; - - if ((val < 0 && !dirstack->first) || !val--) - return cwd; - if (val < 0) - node = dirstack->last; - else - for (node = dirstack->first; node && val; val--,node = node->next); - if (!node) - { - magicerr(); - zerr("not enough dir stack entries."); - errflag = 1; - return NULL; - } - return node->dat; -} - -void execshfunc(comm comm) -{ -table tab,oldlocals; -Node n; -char *s; - - tab = pparms; - oldlocals = locallist; - locallist = newtable(); - for (n = tab->first; n; n = n->next); - pparms = comm->args; - runlist(comm->left); - retflag = 0; - comm->left = NULL; - pparms = tab; - while (s = getnode(locallist)) - { - void *z = remhnode(s,parmhtab); - if (z) - freepm(z); - } - free(locallist); - locallist = oldlocals; -} - -/* make an alias hash table node */ - -struct anode *mkanode(char *txt,int cmflag) -{ -struct anode *ptr = (void *) alloc(sizeof(struct anode)); - - ptr->text = txt; - ptr->cmd = cmflag; - ptr->inuse = 0; - return ptr; -} - -/* perform TAB substitution */ - -char *docompsubs(char *str,int *i) -{ -table fake,curt = curtab; -char *s,*t; -int ct = 0; - - for (s = str; *s; s++) - for (t = tokens; *t; t++) - if (*s == *t) - { - *s = (t-tokens)+Pound; - break; - } - curtab = NULL; - magic = 1; - fake = newtable(); - addnode(fake,str); - prefork(fake); - if (!errflag) - postfork(fake,GLOB); - if (fake->first && fake->first->next) - ct = 1; - t = s = buildline(fake); - free(fake); - rl_prep_terminal(); - if (errflag) - { - rl_on_new_line(); - rl_redisplay(); - errflag = 0; - magic = 0; - curtab = curt; - *i = 0; - return NULL; - } - *i = (magic == 2) + ct; - magic = 0; - curtab = curt; - untokenize(s); - return s; -} - -/* perform substitution on the command name */ - -void docmdsubs(char **str) -{ -table fake; -char *s = strdup(*str); - - fake = newtable(); - addnode(fake,*str); - prefork(fake); - if (!errflag) postfork(fake,GLOB); - if (errflag) - { - free(fake); - free(s); - return; - } - if (fake->first && fake->first->next) - { - zerr("%s: ambiguous",s); - errflag = 1; - free(fake); - free(s); - return; - } - *str = getnode(fake); - free(s); - free(fake); -} - -/* perform substitution on the variables */ - -void dovarsubs(char **str) -{ -table fake; -char *s; - - fake = newtable(); - addnode(fake,*str); - prefork(fake); - if (!errflag) postfork(fake,GLOB); - if (errflag) - return; - s = buildline(fake); - untokenize(s); - *str = s; - free(fake); -} - End of subst.c echo subst.pro 1>&2 sed 's/^-//' >subst.pro <<'End of subst.pro' -void prefork(table list); -void postfork(table list,int globstat); -void *nstrdup(void *s); -void parminsall(table l,Node *nn,char **aptr,char **bptr); -char *dynread(char stop); -int filesub(void **namptr); -char *gethome(char *user,int len); -char *completehome(char *user,int len); -char *getsparmval(char *s,int len); -void setparml(char *s,int len,char *v); -void comminsall(table l,Node *nn,char **aptr,char **bptr); -void parmsuber(char *aptr,char **bptr); -void arithsuber(void **aptr,char **bptr); -void modify(void **str,char **ptr); -char *dstackent(int val); -void execshfunc(comm comm); -struct anode *mkanode(char *txt,int cmflag); -char *docompsubs(char *str,int *i); -void docmdsubs(char **str); -void dovarsubs(char **str); End of subst.pro echo table.c 1>&2 sed 's/^-//' >table.c <<'End of table.c' -/* - - table.c - linked list and hash table management - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" - -/* get an empty linked list header */ - -table newtable() -{ -table list; - - list = alloc(sizeof(*list)); - list->first = 0; - list->last = (Node) list; - return list; -} - -/* get an empty hash table */ - -htable newhtable(int size) -{ -htable ret; - - ret = alloc(sizeof(struct xhtab)); - ret->hsize = size; - ret->nodes = alloc(size*sizeof(struct hnode *)); - return ret; -} - -/* Peter Weinberger's hash function */ - -int hasher(char *s) -{ -unsigned hash = 0,g; - - for (; *s; s++) - { - hash = (hash << 4) + *s; - if (g = hash & 0xf0000000) - { - hash ^= g; - hash ^= g >> 24; - } - } - return hash; -} - -/* add a node to a hash table */ - -void addhnode(char *nam,void *dat,htable ht,void (*freefunc)(void *)) -{ -int hval = hasher(nam) % ht->hsize; -struct hnode *hp = ht->nodes[hval],*hn; - - for (; hp; hp = hp->hchain) - if (!strcmp(hp->nam,nam)) - { - freefunc(hp->dat); - hp->dat = dat; - free(nam); - return; - } - hn = (void *) alloc(sizeof(struct hnode)); - hn->nam = nam; - hn->dat = dat; - hn->hchain = ht->nodes[hval]; - ht->nodes[hval] = hn; - if (++ht->ct == ht->hsize*4) - expandhtab(ht); -} - -/* expand hash tables when they get too many entries */ - -void expandhtab(htable ht) -{ -struct hnode *hp,**arr,**ha,*hn; -int osize = ht->hsize,nsize = osize*8; - - ht->hsize = nsize; - arr = ht->nodes; - ht->nodes = alloc(nsize*sizeof(struct hnode *)); - for (ha = arr; osize; osize--,ha++) - for (hn = *ha; hn; ) - { - addhnode(hn->nam,hn->dat,ht,NULL); - hp = hn->hchain; - free(hn); - hn = hp; - } - free(arr); -} - -/* get an entry in a hash table */ - -void *gethnode(char *nam,htable ht) -{ -int hval = hasher(nam) % ht->hsize; -struct hnode *hn = ht->nodes[hval]; - - for (; hn; hn = hn->hchain) - if (!strcmp(hn->nam,nam)) - return hn->dat; - return NULL; -} - -void freehtab(htable ht,void (*freefunc)(void *)) -{ -int val; -struct hnode *hn,**hptr = &ht->nodes[0],*next; - - for (val = ht->hsize; val; val--,hptr++) - for (hn = *hptr; hn; ) - { - next = hn->hchain; - freefunc(hn); - hn = next; - } -} - -/* remove a hash table entry and return a pointer to it */ - -void *remhnode(char *nam,htable ht) -{ -int hval = hasher(nam) % ht->hsize; -struct hnode *hn = ht->nodes[hval],*hp; -void *dat; - - if (!hn) - return NULL; - if (!strcmp(hn->nam,nam)) - { - ht->nodes[hval] = hn->hchain; - dat = hn->dat; - free(hn->nam); - free(hn); - ht->ct--; - return dat; - } - for (hp = hn, hn = hn->hchain; hn; hn = (hp = hn)->hchain) - if (!strcmp(hn->nam,nam)) - { - hp->hchain = hn->hchain; - dat = hn->dat; - free(hn->nam); - free(hn); - ht->ct--; - return dat; - } - return NULL; -} - -void *zalloc(int l) -{ -void *z; - - if (!(z = malloc(l))) - { - zerr("fatal error: out of memory: restarting"); - execl(MYSELF,"zsh","-f",(void *) 0); - exit(1); - } - return z; -} - -void *alloc(int l) -{ -void *z; - - if (!(z = calloc(l,1))) - { - zerr("fatal error: out of memory: restarting"); - execl(MYSELF,"zsh","-f",(void *) 0); - exit(1); - } - return z; -} - -/* add a node to the end of a linked list */ - -void addnode(table list,void *str) -{ - insnode(list,list->last,str); -} - -/* insert a node in a linked list after 'last' */ - -void insnode(table list,Node last,void *dat) -{ -Node tmp; - - tmp = last->next; - last->next = alloc(sizeof(*tmp)); - last->next->last = last; - last->next->dat = dat; - last->next->next = tmp; - if (tmp) - tmp->last = last->next; - else - list->last = last->next; -} - -/* remove a node from a linked list */ - -void *remnode(table list,Node nd) -{ -void *dat; - - nd->last->next = nd->next; - if (nd->next) - nd->next->last = nd->last; - else - list->last = nd->last; - free(nd); - dat = nd->dat; - return dat; -} - -/* delete a character in a string */ - -void chuck(char *str) -{ - while (str[0] = str[1]) - str++; -} - -/* get a node in a linked list */ - -void *getnode(table list) -{ -void *dat; -Node node = list->first; - - if (!node) - return NULL; - dat = node->dat; - list->first = node->next; - if (node->next) - node->next->last = (Node) list; - else - list->last = (Node) list; - free(node); - return dat; -} - -/* != 0 if the linked list has at least one entry */ - -int full(table list) -{ - return list->first != NULL; -} - -void freetable(table tab,void (*freefunc)(void *)) -{ -Node node = tab->first,next; - - while (node) - { - next = node->next; - freefunc(node); - node = next; - } - free(tab); -} - -char *strdup(char *str) -{ -char *ret = zalloc(strlen(str)+1); - - strcpy(ret,str); - return ret; -} - -#ifndef STRSTR -const char *strstr(const char *s,const char *t) -{ -const char *p1,*p2; - - for (; *s; s++) - { - for (p1 = s, p2 = t; *p2; p1++,p2++) - if (*p1 != *p2) - break; - if (!*p2) - return (char *) s; - } - return NULL; -} -#endif - End of table.c echo table.pro 1>&2 sed 's/^-//' >table.pro <<'End of table.pro' -table newtable(); -htable newhtable(int size); -int hasher(char *s) /* copied from Programming in C++, p14 */; -void addhnode(char *nam,void *dat,htable ht,void (*freefunc)(void *)); -void expandhtab(htable ht); -void *gethnode(char *nam,htable ht); -void freehtab(htable ht,void (*freefunc)(void *)); -void *remhnode(char *nam,htable ht); -void *zalloc(int l); -void *alloc(int l); -void addnode(table list,void *str); -void insnode(table list,Node last,void *dat); -void *remnode(table list,Node nd); -void chuck(char *str); -void *getnode(table list); -int full(table list); -void freetable(table tab,void (*freefunc)(void *)); -char *strdup(char *str); -/*const char *strstr(const char *s,const char *t); */ End of table.pro echo test.c 1>&2 sed 's/^-//' >test.c <<'End of test.c' -/* - - test.c - the test builtin - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" - -#ifndef F_OK -#define F_OK 00 -#define R_OK 04 -#define W_OK 02 -#define X_OK 01 -#endif - -#include "test.pro" -#include "table.pro" - -static char **arg; -static int efg; - -void die(char *str) -{ - if (!efg) - zerrnam("test",str); - efg = 1; -} - -int test(comm comm) -{ -Node n; -int t0; -char **av,**ap; - - for (n = comm->args->first, t0 = 0; n; n = n->next,t0++); - ap = av = (char **) zalloc((sizeof(char *))*(t0+1)); - for (n = comm->args->first; n; n = n->next) - *ap++ = n->dat; - *ap = NULL; - t0 = testmain(av); - free(av); - return t0; -} - -int testmain(char **argv) -{ -int ret,isbrack; - - efg = 0; - arg = argv+1; - ret = testexpr(); - if (efg) - return 1; - isbrack = !strcmp(*argv,"["); - if (isbrack) - { - if (*arg && !strcmp(*arg,"]") && !arg[1]) - return !ret; - } - else - if (!*arg) - return !ret; - die("bad test format"); - return 1; -} - -int testexpr(void) -{ -int ret = testexpr2(),ret2; - - if (*arg && !strcmp(*arg,"-o")) - { - arg++; - ret2 = testexpr2(); - if (efg) - return 0; - ret = ret || ret2; - } - return ret; -} - -int testexpr2(void) -{ -int ret = testexpr3(),ret2; - - if (*arg && !strcmp(*arg,"-a")) - { - arg++; - ret2 = testexpr2(); - if (efg) - return 0; - ret = ret && ret2; - } - return ret; -} - -int testexpr3(void) -{ - if (*arg && !strcmp(*arg,"!")) - { - arg++; - return !testexpr3(); - } - return testexpr4(); -} - -int testexpr4(void) -{ -int ret,t0,t1; -struct stat *st; -char buf[16],*op; - - if (!*arg) - { - die("expression expected"); - return 0; - } - if (!strcmp(*arg,"(")) - { - arg++; - ret = testexpr(); - if (!*arg || strcmp(*arg,")")) - { - die("')' expected"); - return 0; - } - arg++; - return ret; - } - if (**arg == '-' && !(*arg)[2]) - { - switch((*arg++)[1]) - { - case 'a': return(doaccess(F_OK)); - case 'b': return(S_ISBLK(dostat())); - case 'c': return(S_ISCHR(dostat())); - case 'd': return(S_ISDIR(dostat())); - case 'f': return(S_ISREG(dostat())); - case 'g': return(!!(dostat() & S_ISGID)); - case 'k': return(!!(dostat() & S_ISVTX)); - case 'L': return(S_ISLNK(dostat())); - case 'p': return(S_ISFIFO(dostat())); - case 'r': return(doaccess(R_OK)); - case 's': return((st = getstat()) && !!(st->st_size)); - case 'S': return(S_ISSOCK(dostat())); - case 'u': return(!!(dostat() & S_ISUID)); - case 'w': return(doaccess(W_OK)); - case 'x': return(doaccess(X_OK)); - case 'O': return((st = getstat()) && st->st_uid == geteuid()); - case 'G': return((st = getstat()) && st->st_gid == getegid()); - case 't': { - int t0 = 1; - - if (*arg && isdigit(**arg)) - t0 = atoi(*arg++); - return isatty(t0); - } - case 'z': - if (!*arg) - { - die("string expected"); - return 0; - } - return !strlen(*arg++); - case 'n': - if (!*arg) - { - die("string expected"); - return 0; - } - return !!strlen(*arg++); - case 'l': - sprintf(buf,"%d",strlen(*arg)); - *arg = buf; - break; - } - } - if (!arg[1] || !strcmp(arg[1],"-o") || !strcmp(arg[1],"-a") || - !strcmp(arg[1],"]") || !strcmp(arg[1],")")) - return(!!strlen(*arg++)); - if (!arg[2]) - { - die("bad expression"); - return 0; - } - if (!strcmp(arg[1],"-nt")) - { - time_t a; - - if (!(st = getstat())) - { - arg += 2; - return 0; - } - a = st->st_mtime; - arg++; - if (!(st = getstat())) - { - arg += 2; - return 0; - } - return a > st->st_mtime; - } - if (!strcmp(arg[1],"-ot")) - { - time_t a; - - if (!(st = getstat())) - { - arg += 2; - return 0; - } - a = st->st_mtime; - arg++; - if (!(st = getstat())) - { - arg += 2; - return 0; - } - return a < st->st_mtime; - } - if (!strcmp(arg[1],"-ef")) - { - dev_t d; - ino_t i; - - if (!(st = getstat())) - { - arg += 2; - return 0; - } - d = st->st_dev; - i = st->st_ino; - arg++; - if (!(st = getstat())) - { - arg += 2; - return 0; - } - return d == st->st_dev && i == st->st_ino; - } - if (!strcmp(arg[1],"~=")) - { - arg += 3; - return patmatch(arg[-3],arg[-1]); - } - if (!strcmp(arg[1],"=")) - { - arg += 3; - return !strcmp(arg[-3],arg[-1]); - } - if (!strcmp(arg[1],"!=")) - { - arg += 3; - return !!strcmp(arg[-3],arg[-1]); - } - t0 = atoi(arg[0]); - op = arg[1]; - arg += 2; - if (!strcmp(*arg,"-l")) - { - if (!arg[1]) - { - die("string expected"); - return 0; - } - t1 = strlen(arg[1]); - arg += 2; - } - else - t1 = atoi(*arg++); - if (!strcmp(op,"-eq")) - return t0 == t1; - if (!strcmp(op,"-ne")) - return t0 != t1; - if (!strcmp(op,"-lt")) - return t0 < t1; - if (!strcmp(op,"-le")) - return t0 <= t1; - if (!strcmp(op,"-gt")) - return t0 > t1; - if (!strcmp(op,"-ge")) - return t0 >= t1; - if (!efg) - zerrnam("test","unrecognized operator: %s",op); - efg = 1; - return 0; -} - -int doaccess(int c) -{ - if (!*arg) - { - die("filename expected"); - return 0; - } - return !access(*arg++,c); -} - -struct stat *getstat(void) -{ -static struct stat st; - - if (!*arg) - { - die("filename expected"); - return NULL; - } - if (!strncmp(*arg,"/dev/fd/",8)) - { - if (fstat(atoi((*arg++)+8),&st)) - return NULL; - } - else if (lstat(*arg++,&st)) - return NULL; - return &st; -} - -unsigned short dostat(void) -{ -struct stat *st; - - if (!(st = getstat())) - return 0; - return st->st_mode; -} - End of test.c echo test.pro 1>&2 sed 's/^-//' >test.pro <<'End of test.pro' -void die(char *str); -int test(comm comm); -int testmain(char **argv); -int testexpr(void); -int testexpr2(void); -int testexpr3(void); -int testexpr4(void); -int doaccess(int c); -struct stat *getstat(void); -unsigned short dostat(void); End of test.pro echo utils.c 1>&2 sed 's/^-//' >utils.c <<'End of utils.c' -/* - - utils.c - miscellaneous utilities - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include <pwd.h> -#include <stdarg.h> /* had to change this to stdarg.h.old on one machine */ -#include <errno.h> -#include <sys/dir.h> -#include <fcntl.h> - -/* add vars to the parm hash table */ - -void addvars(table vars) -{ -char *s1,*s2; -Node node; - - for (node = vars->first; node; node = node->next) - { - s1 = node->dat; - untokenize(s1); - node = node->next; - s2 = node->dat; - dovarsubs(&s2); - if (errflag) - break; - untokenize(s2); - setparm(s1,s2,0,0); - } - free(vars); -} - -/* set a parameter to an integer value */ - -void setiparm(char *s,long v,int isint) -{ -struct pmnode *pmn,*pmo; - - if (!strcmp(s,"RANDOM")) - { - srand((unsigned long) v); - return; - } - if (!strcmp(s,"SECONDS")) - { - shtimer = v+time(NULL); - return; - } - if (pmo = gethnode(s,parmhtab)) - { - char buf[12]; - - pmn = alloc(sizeof *pmn); - if (pmn->isint = pmo->isint | isint) - pmn->u.val = v; - else - { - sprintf(buf,"%ld",v); - pmn->u.str = strdup(buf); - } - addhnode(s,pmn,parmhtab,freepm); - } - else if (getenv(s) || (opts[ALLEXPORT] == OPT_SET)) - { - char buf[12]; - - sprintf(buf,"%ld",v); - putenv(tricat(s,"=",buf)); - } - else - { - char buf[12]; - - pmn = alloc(sizeof *pmn); - if (pmn->isint = isint) - pmn->u.val = v; - else - { - sprintf(buf,"%ld",v); - pmn->u.str = strdup(buf); - } - addhnode(s,pmn,parmhtab,freepm); - addlocal(s); - } - if (!strcmp(s,"PERIOD")) - { - period = v*60; - lastperiod = time(NULL)+period; - } - if (!strcmp(s,"HISTSIZE")) - { - tevs = v; - if (tevs <= 2) - tevs = 2; - } -} - -/* set a parameter to a string value */ - -void setparm(char *s,char *t,int ex,int isint) -{ -struct pmnode *pmn,*pmo; - - if (!strcmp(s,"RANDOM")) - { - srand((unsigned long) atol(t)); - return; - } - if (!strcmp(s,"SECONDS")) - { - shtimer = atol(t)+time(NULL); - return; - } - if (ex && gethnode(s,parmhtab)) - freepm(remhnode(s,parmhtab)); - if (pmo = gethnode(s,parmhtab)) - { - pmn = alloc(sizeof *pmn); - if (pmn->isint = pmo->isint | isint) - { - pmn->u.val = matheval(t); - free(t); - t = NULL; - } - else - pmn->u.str = t; - addhnode(s,pmn,parmhtab,freepm); - } - else if (ex || getenv(s) || (opts[ALLEXPORT] == OPT_SET)) - putenv(tricat(s,"=",t)); - else - { - pmn = alloc(sizeof *pmn); - if (pmn->isint = isint) - { - pmn->u.val = matheval(t); - free(t); - t = NULL; - } - else - pmn->u.str = t; - addhnode(s,pmn,parmhtab,freepm); -#if 0 - addlocal(s); -#endif - } - if (!t) - return; - if (!strcmp(s,"PATH")) - parsepath(); - if (!strcmp(s,"CDPATH")) - parsecdpath(); - if (!strcmp(s,"IFS")) - { - free(ifs); - ifs = strdup(t); - } - if (!strcmp(s,"PERIOD")) - { - period = atoi(t)*60; - lastperiod = time(NULL)+period; - } - if (!strcmp(s,"HISTSIZE")) - { - tevs = atoi(t); - if (tevs <= 2) - tevs = 2; - } - if (!strcmp(s,"HOME")) - { - free(home); - home = xsymlink(t); - } - if (!strcmp(s,"MAIL") || !strcmp(s,"MAILCHECK") || !strcmp(s,"MAILPATH")) - lastmailcheck = 0; -} - -void unsetparm(char *s) -{ -char **pp; - - if (!strcmp(s,"HOME")) - return; - if (!strcmp(s,"PERIOD")) - period = 0; - if (!strcmp(s,"HISTSIZE")) - tevs = 1; - if (gethnode(s,parmhtab)) - { - freepm(remhnode(s,parmhtab)); - return; - } - for (pp = environ; *pp; pp++) - if (!strncmp(*pp,s,strlen(s)) && (*pp)[strlen(s)] == '=') - { - while (pp[0] = pp[1]) - pp++; - return; - } -} - -/* get the integer value of a parameter */ - -long getiparm(char *s) -{ -struct pmnode *pmn; -char *t; - - if (!isalpha(*s) && !s[1]) - { - t = getsparmval(s,1); - return (t) ? atoi(t) : 0; - } - if (s[0] == 'T' && s[1] == 'C' && !s[4]) /* TCxx */ - return tgetnum(s+2); - if (!strcmp(s,"RANDOM")) - return rand() & 0x7fff; - if (!strcmp(s,"LINENO")) - return lineno; - if (!strcmp(s,"SECONDS")) - return time(NULL)-shtimer; - if (pmn = gethnode(s,parmhtab)) - { - if (pmn->isint) - return pmn->u.val; - return atol(pmn->u.str); - } - return atol(getenv(s)); -} - -/* get the string value of a parameter */ - -char *getparm(char *s) -{ -struct pmnode *pmn; - - if (!isalpha(*s) && !s[1]) - return getsparmval(s,1); - if (s[0] == 'T' && s[1] == 'C' && !s[4]) /* TCxx */ - { - static char buf[1024]; - char *ss = buf; - int t0; - - if (tgetstr(s+2,&ss)) - return buf; - if ((t0 = tgetnum(s+2)) != -1) - { - sprintf(buf,"%d",t0); - return buf; - } - return NULL; - } - if (!strcmp(s,"LINENO")) - { - static char buf[8]; - - sprintf(buf,"%d",lineno); - return buf; - } - if (!strcmp(s,"RANDOM")) - { - static char buf[8]; - - sprintf(buf,"%d",rand() & 0x7fff); - return buf; - } - if (!strcmp(s,"SECONDS")) - { - static char buf[12]; - - sprintf(buf,"%ld",time(NULL)-shtimer); - return buf; - } - if (pmn = gethnode(s,parmhtab)) - { - static char buf[12]; - - if (pmn->isint) - { - sprintf(buf,"%ld",pmn->u.val); - return buf; - } - return pmn->u.str; - } - return getenv(s); -} - -/* parse the PATH parameter into directory names in a array of - strings and create the command hash table */ - -void parsepath(void) -{ -char *pptr = getparm("PATH"),*ptr; - - if (path) - { - while(pathct) - free(path[--pathct]); - free(path); - } - for (pathct = 1, ptr = pptr; *ptr; ptr++) - if (*ptr == ':') - pathct++; - path = (char **) zalloc(pathct*sizeof(char *)); - pathct = 0; - ptr = pptr; - while(pptr) - { - ptr = strchr(pptr,':'); - if (ptr) - *ptr = '\0'; - path[pathct] = strdup(pptr); - if (ptr) - { - *ptr = ':'; - pptr = ptr+1; - } - else - pptr = NULL; - if (!*path[pathct]) - { - free(path[pathct]); - path[pathct] = strdup("."); - } - pathsub(&path[pathct]); - if (*path[pathct] != '/' && strcmp(path[pathct],".")) - { -#ifdef PATH_WARNINGS - zerr("PATH component not absolute pathname: %s",path[pathct]); -#endif - free(path[pathct--]); - } - pathct++; - } - createchtab(); -} - -void parsecdpath(void) -{ -char *pptr = getparm("CDPATH"),*ptr; - - if (cdpath) - { - while(cdpathct) - free(cdpath[--cdpathct]); - free(cdpath); - } - if (pptr == NULL) - { - cdpath = (char **) zalloc(sizeof(char *)); - cdpath[0] = strdup("."); - cdpathct = 1; - return; - } - for (cdpathct = 2, ptr = pptr; *ptr; ptr++) - if (*ptr == ':') - cdpathct++; - cdpath = (char **) zalloc(cdpathct*sizeof(char *)); - cdpath[0] = strdup("."); - cdpathct = 1; - ptr = pptr; - while (pptr) - { - ptr = strchr(pptr,':'); - if (ptr) - *ptr = '\0'; - cdpath[cdpathct] = strdup(pptr); - if (ptr) - { - *ptr = ':'; - pptr = ptr+1; - } - else - pptr = NULL; - pathsub(&cdpath[cdpathct]); - if (*cdpath[cdpathct] != '/') - { -#ifdef PATH_WARNINGS - zerr("CDPATH component not absolute pathname: %s",cdpath[cdpathct]); -#endif - free(cdpath[cdpathct--]); - } - cdpathct++; - } -} - -/* source a file */ - -int source(char *s) -{ -int fd,cj = curjob,iact = opts[INTERACTIVE]; -FILE *obshin = bshin; - - fd = SHIN; - opts[INTERACTIVE] = OPT_UNSET; - if ((SHIN = movefd(open(s,O_RDONLY))) == -1) - { - SHIN = fd; - curjob = cj; - opts[INTERACTIVE] = iact; - return 1; - } - bshin = fdopen(SHIN,"r"); - loop(); - fclose(bshin); - opts[INTERACTIVE] = iact; - bshin = obshin; - SHIN = fd; - peek = EMPTY; - curjob = cj; - errflag = 0; - retflag = 0; - return 0; -} - -/* try to source a file in our home directory */ - -void sourcehome(char *s) -{ -char buf[MAXPATHLEN]; - - sprintf(buf,"%s/%s",getparm("HOME"),s); - (void) source(buf); -} - -/* print an error */ - -void zerrnam(char *cmd, char *fmt, ...) -{ -va_list ap; -char *str; -int num; - - va_start(ap,fmt); - fputs(cmd,stderr); - putc(':',stderr); - putc(' ',stderr); - while (*fmt) - if (*fmt == '%') - { - fmt++; - switch(*fmt++) - { - case 's': /* string */ - str = va_arg(ap,char *); - while (*str) - niceputc(*str++,stderr); - break; - case 'l': /* string with a length */ - num = va_arg(ap,int); - str = va_arg(ap,char *); - while (num--) - niceputc(*str++,stderr); - break; - case 'd': /* number */ - num = va_arg(ap,int); - fprintf(stderr,"%d",num); - break; - case '%': - putc('%',stderr); - break; - case 'c': /* char */ - num = va_arg(ap,int); - niceputc(num,stderr); - break; - case 'e': /* system error */ - num = va_arg(ap,int); - if (num == EINTR) - { - fputs("interrupt\n",stderr); - errflag = 1; - return; - } - fputc(tolower(sys_errlist[num][0]),stderr); - fputs(sys_errlist[num]+1,stderr); - break; - } - } - else - putc(*fmt++,stderr); - putc('\n',stderr); - va_end(ap); -} - -void zerr(char *fmt,...) -{ -va_list ap; -char *str; -int num; - - va_start(ap,fmt); - fputs("zsh: ",stderr); - while (*fmt) - if (*fmt == '%') - { - fmt++; - switch(*fmt++) - { - case 's': - str = va_arg(ap,char *); - while (*str) - niceputc(*str++,stderr); - break; - case 'l': - num = va_arg(ap,int); - str = va_arg(ap,char *); - while (num--) - niceputc(*str++,stderr); - break; - case 'd': - num = va_arg(ap,int); - fprintf(stderr,"%d",num); - break; - case '%': - putc('%',stderr); - break; - case 'c': - num = va_arg(ap,int); - niceputc(num,stderr); - break; - case 'e': - num = va_arg(ap,int); - if (num == EINTR) - { - fputs("interrupt\n",stderr); - errflag = 1; - return; - } - fputc(tolower(sys_errlist[num][0]),stderr); - fputs(sys_errlist[num]+1,stderr); - break; - } - } - else - putc(*fmt++,stderr); - putc('\n',stderr); - va_end(ap); -} - -void niceputc(int c,FILE *f) -{ - if (istok(c)) - { - if (c >= Pound && c <= Qtick) - putc(tokens[c-Pound],f); - return; - } - c &= 0x7f; - if (c >= ' ' && c < '\x7f') - putc(c,f); - else if (c == '\n') - { - putc('\\',f); - putc('n',f); - } - else - { - putc('^',f); - putc(c|'A',f); - } -} - -/* enable ^C interrupts */ - -void intr(void) -{ -struct sigvec vec = { handler,sigmask(SIGINT),SV_INTERRUPT }; - - if (interact) - sigvec(SIGINT,&vec,NULL); - sigsetmask(0); -} - -void noholdintr(void) -{ - intr(); -} - -void holdintr(void) -{ -struct sigvec vec = { handler,sigmask(SIGINT),0 }; - - if (interact) - { - sigvec(SIGINT,&vec,NULL); - sigsetmask(0); - } -} - -char *fgetline(char *buf,int len,FILE *in) -{ - if (!fgets(buf,len,in)) - return NULL; - buf[len] = '\0'; - buf[strlen(buf)-1] = '\0'; - return buf; -} - -/* get a symlink-free pathname for s relative to PWD */ - -char *findcwd(char *s) -{ -char *t; - - if (*s == '/') - return xsymlink(s); - s = tricat((cwd[1]) ? cwd : "","/",s); - t = xsymlink(s); - free(s); - return t; -} - -static char xbuf[MAXPATHLEN]; - -/* expand symlinks in s, and remove other weird things */ - -char *xsymlink(char *s) -{ - if (*s != '/') - return NULL; - strcpy(xbuf,""); - if (xsymlinks(s+1)) - return strdup(s); - if (!*xbuf) - return strdup("/"); - return strdup(xbuf); -} - -char **slashsplit(char *s) -{ -char *t,**r,**q; -int t0; - - if (!*s) - return (char **) calloc(sizeof(char **),1); - for (t = s, t0 = 0; *t; t++) - if (*t == '/') - t0++; - q = r = (char **) zalloc(sizeof(char **)*(t0+2)); - while (t = strchr(s,'/')) - { - *t = '\0'; - *q++ = strdup(s); - *t = '/'; - while (*t == '/') - t++; - if (!*t) - { - *q = NULL; - return r; - } - s = t; - } - *q++ = strdup(s); - *q = NULL; - return r; -} - -int islink(char *s) -{ -char xbuf[MAXPATHLEN]; - - if (readlink(s,xbuf,1) == -1 && errno == EINVAL) - return 0; - return 1; -} - -int xsymlinks(char *s) -{ -char **pp,**opp; -char xbuf2[MAXPATHLEN],xbuf3[MAXPATHLEN]; -int t0; - - opp = pp = slashsplit(s); - for (; *pp; pp++) - { - if (!strcmp(*pp,".")) - { - free(*pp); - continue; - } - if (!strcmp(*pp,"..")) - { - char *p; - - free(*pp); - if (!strcmp(xbuf,"/")) - continue; - p = xbuf+strlen(xbuf); - while (*--p != '/'); - *p = '\0'; - continue; - } - sprintf(xbuf2,"%s/%s",xbuf,*pp); - t0 = readlink(xbuf2,xbuf3,MAXPATHLEN); - if (t0 == -1) - { - if (errno != EINVAL) - { - while (*pp) - free(*pp++); - free(opp); - return 1; - } - strcat(xbuf,"/"); - strcat(xbuf,*pp); - free(*pp); - } - else - { - xbuf3[t0] = '\0'; /* STUPID */ - if (*xbuf3 == '/') - { - strcpy(xbuf,""); - if (xsymlinks(xbuf3+1)) - return 1; - } - else - if (xsymlinks(xbuf3)) - return 1; - free(*pp); - } - } - free(opp); - return 0; -} - -void printdir(char *s) -{ -int t0; - - if (!strncmp(s,home,t0 = strlen(home))) - { - putchar('~'); - fputs(s+t0,stdout); - } - else - fputs(s,stdout); -} - - -int ddifftime(time_t t1,time_t t2) -{ - return ((long) t2-(long) t1); -} - -/* see if jobs need printing */ - -void scanjobs(void) -{ -int t0; - - for (t0 = 1; t0 != MAXJOB; t0++) - if (jobtab[t0].stat & STAT_CHANGED) - printjob(jobtab+t0,0); -} - -/* do pre-prompt stuff */ - -void preprompt(void) -{ -int diff; -list list; -char *mc = getparm("MAILCHECK"),*wc = getparm("LOGCHECK"); -struct schnode *sch,*schl; - - if (unset(NOTIFY)) - scanjobs(); - if (errflag) - return; - if (list = gethnode("precmd",shfunchtab)) - newrunlist(list); - if (errflag) - return; - if (period && (time(NULL) > lastperiod+period) && - (list = gethnode("periodic",shfunchtab))) - { - newrunlist(list); - lastperiod = time(NULL); - } - if (errflag) - return; - if (getparm("WATCH")) - { - diff = (int) ddifftime(lastwatch,time(NULL)); - if (diff > ((wc) ? atoi(wc)*60 : 300)) - { - lastwatch = time(NULL); - watch(); - } - } - if (errflag) - return; - diff = (int) ddifftime(lastmailcheck,time(NULL)); - if (diff > ((mc) ? atoi(mc) : 60)) - { - lastmailcheck = time(NULL); - if (getparm("MAILPATH")) - checkmailpath(); - else - checkmail(); - } - for (schl = (struct schnode *) &scheds, sch = scheds; sch; - sch = (schl = sch)->next) - { - if (sch->time < time(NULL)) - { - execstring(sch->cmd); - schl->next = sch->next; - free(sch); - } - if (errflag) - return; - } -} - -void checkmail(void) -{ -struct stat st; -char *s; - - if (!(s = getparm("MAIL"))) - return; - if (stat(s,&st) == -1) - { - if (errno != ENOENT) - zerr("%e: %s",errno,getparm("MAIL")); - lastmailval = 0; - lastmailsize = 0; - return; - } - else - if (lastmailval != -1 && lastmailval < st.st_mtime && - lastmailsize < st.st_size) - zerr("you have new mail."); - lastmailval = st.st_mtime; - lastmailsize = st.st_size; -} - -void checkfirstmail(void) -{ -struct stat st; -char *s; - - if (!(s = getparm("MAIL"))) - return; - if (stat(s,&st) == -1) - { - if (errno != ENOENT) - zerr("%e: %s",errno,getparm("MAIL")); - lastmailval = 0; - lastmailsize = 0; - return; - } - lastmailval = st.st_mtime; - lastmailsize = st.st_size; - zerr("you have mail."); -} - -void checkmailpath(void) -{ -struct stat st; -char *s = getparm("MAILPATH"),*v,*u,c,d; - - for (;;) - { - for (v = s; *v && *v != '?' && *v != ':'; v++); - c = *v; - *v = '\0'; - if (c != '?') - u = NULL; - else - { - for (u = v+1; *u && *u != ':'; u++); - d = *u; - *u = '\0'; - } - if (stat(s,&st) == -1) - { - if (errno != ENOENT) - zerr("%e: %s",errno,getparm("MAIL")); - } - else - if (lastmailval != -1 && lastmailval < st.st_mtime && - lastmailsize < st.st_size) - if (!u) - fprintf(stderr,"You have new mail.\n"); - else - { - char *z = u; - - while (*z) - if (*z == '$' && z[1] == '_') - { - fprintf(stderr,"%s",s); - z += 2; - } - else - fputc(*z++,stderr); - fputc('\n',stderr); - } - lastmailval = st.st_mtime; - lastmailsize = st.st_size; - *v = c; - if (u) - *u = d; - if (!c || (u && !d)) - break; - v = (u) ? u+1 : v+1; - } -} - -/* create command hash table */ - -void createchtab(void) -{ -int t0,dot = 0; -struct direct *de; -DIR *dir; -struct chnode *cc; - - holdintr(); - if (chtab) - freehtab(chtab,freechnode); - chtab = newhtable(101); - for (t0 = 0; t0 != pathct; t0++) - if (!strcmp(".",path[t0])) - { - dot = 1; - break; - } - for (t0 = pathct-1; t0 >= 0; t0--) - if (!strcmp(".",path[t0])) - dot = 0; - else - { - dir = opendir(path[t0]); - if (!dir) - { - zerr("%e: %s",errno,path[t0]); - continue; - } - readdir(dir); readdir(dir); - while (de = readdir(dir)) - { - cc = alloc(sizeof(struct chnode)); - cc->type = (dot) ? EXCMD_POSTDOT : EXCMD_PREDOT; - cc->globstat = GLOB; - cc->u.nam = tricat(path[t0],"/",de->d_name); - addhnode(strdup(de->d_name),cc,chtab,freechnode); - } - closedir(dir); - } - addintern(chtab); - noholdintr(); -} - -void freechnode(void *a) -{ -struct chnode *c = (struct chnode *) a; - - if (c->type != BUILTIN) - free(c->u.nam); - free(c); -} - -void freestr(void *a) -{ - free(a); -} - -void freeanode(void *a) -{ -struct anode *c = (struct anode *) a; - - free(c->text); - free(c); -} - -void freeredir(void *a) -{ -struct fnode *f = (struct fnode *) a; - - if (f) - { - if (f->type == HEREDOC) - close(f->u.fd2); - else - free(f->u.name); - free(f); - } -} - -void freeshfunc(void *a) -{ - freelist((list) a); -} - -void freepm(void *a) -{ -struct pmnode *pm = a; - - if (!pm->isint) - free(pm->u.str); - free(pm); -} - -void restoretty(void) -{ - settyinfo(&shttyinfo); -} - -void gettyinfo(struct ttyinfo *ti) -{ - if (jobbing) - { -#ifndef BUGGY_GCC -#ifdef TERMIOS - ioctl(SHTTY,TCGETS,&ti->termios); -#else - ioctl(SHTTY,TIOCGETP,&ti->sgttyb); - ioctl(SHTTY,TIOCGETC,&ti->tchars); - ioctl(SHTTY,TIOCGLTC,&ti->ltchars); -#endif - ioctl(SHTTY,TIOCGWINSZ,&ti->winsize); -#else -#ifdef TERMIOS - ioctl(SHTTY, ( 0x40000000 |((sizeof( struct termios)&0xff )<<16)|('T'<<8)| 8) ,&ti->termios); -#else - ioctl(SHTTY,(0x40000000|((sizeof(struct sgttyb)&0x1fff)<<16)| - ('t'<<8)|8),&ti->sgttyb); - ioctl(SHTTY,(0x40000000|((sizeof(struct tchars)&0x1fff)<<16)| - ('t'<<8)|18),&ti->tchars); - ioctl(SHTTY,(0x40000000|((sizeof(struct ltchars)&0x1fff)<<16)| - ('t'<<8)|116),&ti->ltchars); -#endif - ioctl(SHTTY,( 0x40000000 |((sizeof( struct winsize)&0xff )<<16)|('t'<<8)| 104) ,&ti->winsize); -#endif - } -} - -void settyinfo(struct ttyinfo *ti) -{ - if (jobbing) - { -#ifndef BUGGY_GCC -#ifdef TERMIOS - ioctl(SHTTY,TCSETS,&ti->termios); -#else - ioctl(SHTTY,TIOCSETP,&ti->sgttyb); - ioctl(SHTTY,TIOCSETC,&ti->tchars); - ioctl(SHTTY,TIOCSLTC,&ti->ltchars); -#endif - ioctl(SHTTY,TIOCSWINSZ,&ti->winsize); -#else -#ifdef TERMIOS - ioctl(SHTTY, ( 0x80000000 |((sizeof( struct termios)&0xff )<<16)|('T'<<8)| 9) ,&ti->termios); -#else - ioctl(SHTTY,(0x80000000|((sizeof( struct sgttyb)&0x1fff)<<16)| - ('t'<<8)|9),&ti->sgttyb); - ioctl(SHTTY,(0x80000000|((sizeof(struct tchars)&0x1fff)<<16)| - ('t'<<8)|17),&ti->tchars); - ioctl(SHTTY,(0x80000000|((sizeof(struct ltchars)&0x1fff)<<16)| - ('t'<<8)|117),&ti->ltchars); -#endif - ioctl(SHTTY,( 0x80000000 |((sizeof( struct winsize)&0xff )<<16)|('t'<<8)| 103) ,&ti->winsize); -#endif - } -} - -int zyztem(char *s,char *t) -{ -#ifdef WAITPID -int pid,statusp; - - if (!(pid = fork())) - { - s = tricat(s," ",t); - execl("/bin/sh","sh","-c",s,(char *) 0); - _exit(1); - } - waitpid(pid,&statusp,WUNTRACED); - if (WIFEXITED(SP(statusp))) - return WEXITSTATUS(SP(statusp)); - return 1; -#else - if (!waitfork()) - { - s = tricat(s," ",t); - execl("/bin/sh","sh","-c",s,(char *) 0); - _exit(1); - } - return 0; -#endif -} - -#ifndef WAITPID - -/* fork a process and wait for it to complete without confusing - the SIGCHLD handler */ - -int waitfork(void) -{ -int pipes[2]; -char x; - - pipe(pipes); - if (!fork()) - { - close(pipes[0]); - signal(SIGCHLD,SIG_DFL); - if (!fork()) - return 0; - wait(NULL); - _exit(0); - } - close(pipes[1]); - read(pipes[0],&x,1); - close(pipes[0]); - return 1; -} - -#endif - -/* move a fd to a place >= 10 */ - -int movefd(int fd) -{ -int fe; - - if (fd == -1) - return fd; - if ((fe = dup(fd)) < 10) - fe = movefd(fe); - close(fd); - return fe; -} - -/* move fd x to y */ - -void redup(int x,int y) -{ - if (x != y) - { - dup2(x,y); - close(x); - } -} - -void settrap(char *s,int empty) -{ -int t0; - - if (strncmp(s,"TRAP",4)) - return; - for (t0 = 0; t0 != SIGCOUNT+2; t0++) - if (!strcmp(s+4,sigs[t0])) - { - if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN - || t0 == SIGPIPE)) - { - zerr("can't trap SIG%s in interactive shells",s); - return; - } - if (empty) - { - sigtrapped[t0] = 2; - if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD) - { - signal(t0,SIG_IGN); - sigtrapped[t0] = 2; - } - } - else - { - if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD) - signal(t0,handler); - sigtrapped[t0] = 1; - } - return; ---cut here---cut here---cut here---
pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (12/15/90)
---cut here---cut here---cut here--- - } - zerr("warning: undefined signal name: SIG%s",s+4); -} - -void unsettrap(char *s) -{ -int t0; - - if (strncmp(s,"TRAP",4)) - return; - for (t0 = 0; t0 != SIGCOUNT+2; t0++) - if (!strcmp(s+4,sigs[t0])) - { - if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN - || t0 == SIGPIPE)) - { - zerr("can't trap SIG%s in interactive shells",s); - return; - } - sigtrapped[t0] = 0; - if (t0 == SIGINT) - intr(); - else if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD) - signal(t0,SIG_DFL); - return; - } - zerr("warning: undefined signal name: SIG%s",s+4); -} - -void dotrap(int sig) -{ -char buf[16]; -list l; -int sav; - - sav = sigtrapped[sig]; - if (sav == 2) - return; - sigtrapped[sig] = 2; - sprintf(buf,"TRAP%s",sigs[sig]); - if (l = gethnode(buf,shfunchtab)) - newrunlist(l); - sigtrapped[sig] = sav; -} - -/* get the text corresponding to a command */ - -char *gettext(comm comm) -{ -char *s,*t; - - switch(comm->type) - { - case SIMPLE: - return getsimptext(comm); - case SUBSH: - t = getltext(comm->left); - s = tricat("(",t,")"); - free(t); - return s; - case CURSH: - case SHFUNC: - t = getltext(comm->left); - s = tricat("{",t,"}"); - free(t); - return s; - case CFOR: - return getfortext((struct fornode *) comm->info,comm); - case CWHILE: - return getwhiletext((struct whilenode *) comm->info); - case CREPEAT: - return getrepeattext((struct repeatnode *) comm->info); - case CIF: - return getiftext((struct ifnode *) comm->info); - case CCASE: - return getcasetext((struct casenode *) comm->info,comm->args); - case CSELECT: - return getfortext((struct fornode *) comm->info,comm); - default: - return strdup("(...)"); - } - return NULL; -} - -char *getltext(list l) -{ -char *s,*t,*u; - - s = getl2text(l->left); - if (l->type == ASYNC) - { - t = dyncat(s," &"); - free(s); - s = t; - } - if (!l->right) - return s; - t = getltext(l->right); - u = tricat(s,(l->type == SYNC) ? "\n" : "",t); - free(s); - free(t); - return u; -} - -char *getl2text(list2 l) -{ -char *s,*t,*u; - - s = getptext(l->left); - if (!l->right) - return s; - t = getl2text(l->right); - u = tricat(s,(l->type == ORNEXT) ? " || " : " && ",t); - free(s); - free(t); - return u; -} - -char *getptext(pline p) -{ -char *s,*t,*u; - - s = gettext(p->left); - if (!p->right) - return s; - t = getptext(p->right); - u = tricat(s," | ",t); - free(s); - free(t); - return u; -} - -char *getsimptext(comm comm) -{ -int len = 0; -Node n; -char *fstr[] = { - ">",">!",">>",">>!","<","<<","<&",">&",">&-" - }; -struct fnode *f; -char *s,*t,u = '='; - - for (n = comm->args->first; n; n = n->next) - len += strlen(n->dat)+1; - if (comm->vars) - for (n = comm->vars->first; n; n = n->next) - len += strlen(n->dat)+1; - for (n = comm->redir->first; n; n = n->next) - { - f = n->dat; - switch(f->type) - { - case WRITE: case WRITENOW: case APP: case APPNOW: case READ: - len += strlen(fstr[f->type])+strlen(f->u.name)+8; - break; - case HEREDOC: case MERGE: case MERGEOUT: - len += strlen(fstr[f->type])+10; - break; - case CLOSE: - len += 10; - break; - case INPIPE: - case OUTPIPE: - len += strlen(f->u.name)+10; - break; - } - } - len += strlen(comm->cmd); - s = t = zalloc(len+5); - if (comm->vars) - for (n = comm->vars->first; n; n = n->next) - { - strucpy(&t,n->dat); - *t++ = u; - u = ('='+' ')-u; - } - strucpy(&t,comm->cmd); - *t++ = ' '; - for (n = comm->args->first; n; n = n->next) - { - strucpy(&t,n->dat); - *t++ = ' '; - } - for (n = comm->redir->first; n; n = n->next) - { - f = n->dat; - switch(f->type) - { - case WRITE: case WRITENOW: case APP: case APPNOW: case READ: - if (f->fd1 != ((f->type == READ) ? 0 : 1)) - *t++ = '0'+f->fd1; - strucpy(&t,fstr[f->type]); - *t++ = ' '; - strucpy(&t,f->u.name); - *t++ = ' '; - break; - case HEREDOC: case MERGE: case MERGEOUT: - if (f->fd1 != ((f->type == MERGEOUT) ? 1 : 0)) - *t++ = '0'+f->fd1; - strucpy(&t,fstr[f->type]); - *t++ = ' '; - sprintf(t,"%d ",f->u.fd2); - t += strlen(t); - break; - case CLOSE: - *t++ = '0'+f->fd1; - strucpy(&t,">&- "); - break; - case INPIPE: - case OUTPIPE: - if (f->fd1 != ((f->type == INPIPE) ? 0 : 1)) - *t++ = '0'+f->fd1; - strucpy(&t,(f->type == INPIPE) ? "< " : "> "); - strucpy(&t,f->u.name); - strucpy(&t," "); - len += strlen(f->u.name)+6; - break; - } - } - t[-1] = '\0'; - return s; -} - -char *getfortext(struct fornode *n,comm comm) -{ -char *s,*t,*u,*v; - - s = getltext(n->list); - u = dyncat((comm->type == CFOR) ? "for " : "select ",n->name); - if (comm->args) - { - t = makehlist(comm->args,0); - v = tricat(u," in ",t); - free(u); - free(t); - u = v; - } - v = dyncat(u,"\n do "); - free(u); - u = tricat(v,s,"\n done"); - free(v); - free(s); - return u; -} - -char *getwhiletext(struct whilenode *n) -{ -char *s,*t,*u,*v; - - t = getltext(n->cont); - v = getltext(n->loop); - s = tricat((!n->cond) ? "while " : "until ",t,"\n do "); - u = tricat(s,v,"\n done"); - free(s); - free(t); - free(v); - return u; -} - -char *getrepeattext(struct repeatnode *n) -{ -char buf[100]; -char *s,*t,*u; - - s = getltext(n->list); - sprintf(buf,"%d",n->count); - t = tricat("repeat ",buf," do "); - u = tricat(t,s,"\n done"); - free(s); - free(t); - return u; -} - -char *getiftext(struct ifnode *n) -{ -int fst = 1; -char *v = strdup(""); -char *s,*t,*u,*w; - - while (n && n->ifl) - { - s = getltext(n->ifl); - t = getltext(n->thenl); - u = tricat((fst) ? "if " : "elif ",s,"\n then "); - w = tricat(u,t,"\n "); - free(s); - free(t); - free(u); - s = dyncat(v,w); - free(v); - free(w); - v = s; - fst = 0; - n = n->next; - } - if (n) - { - s = getltext(n->thenl); - t = tricat(v,"else ",s); - u = dyncat(t,"\n fi"); - free(s); - free(t); - free(v); - return u; - } - u = dyncat(v,"\n fi"); - free(v); - return u; -} - -char *getcasetext(struct casenode *n,table l) -{ -char *s,*t,*u,*v; - - s = tricat("case ",l->first->dat," in "); - while (n) - { - u = getltext(n->list); - t = tricat(n->pat,") ",u); - v = tricat(s,t," ;;\n"); - free(s); - free(t); - free(u); - s = v; - n = n->next; - } - t = dyncat(s,"esac\n"); - free(s); - return t; -} - -/* copy t into *s and update s */ - -void strucpy(char **s,char *t) -{ -char *u = *s; - - while (*u++ = *t++); - *s = u-1; -} - -void checkrmall(void) -{ - fflush(stdin); - fprintf(stderr,"zsh: are you sure you want to delete " - "all the files? "); - fflush(stderr); - ding(); - errflag |= !getquery(); -} - -int getquery(void) -{ -char c; -int yes = 0; - - setcbreak(); - if (read(SHTTY,&c,1) == 1 && (c == 'y' || c == 'Y')) - yes = 1; - unsetcbreak(); - if (c != '\n') - write(2,"\n",1); - return yes; -} - -static int d; -static char *guess,*best; - -void spscan(char *s,char *junk) -{ -int nd; - - nd = spdist(s,guess); - if (nd <= d && nd != 3) - { - best = s; - d = nd; - } -} - -/* spellcheck a command */ - -void spckcmd(char **s) -{ -char *t; - - if (gethnode(*s,chtab) || gethnode(*s,shfunchtab)) - return; - for (t = *s; *t; t++) - if (*t == '/') - return; - if (access(*s,F_OK) == 0) - return; - best = NULL; - guess = *s; - d = 3; - listhtable(chtab,spscan); - listhtable(shfunchtab,spscan); - if (best) - { - fprintf(stderr,"zsh: correct to `%s' (y/n)? ",best); - fflush(stderr); - ding(); - if (getquery()) - { - free(*s); - *s = strdup(best); - } - } -} - -void addlocal(char *s) -{ - if (locallist) - addnode(locallist,strdup(s)); -} - -/* perform pathname substitution on a PATH or CDPATH component */ - -void pathsub(char **s) -{ - if (**s == '=') - **s = Equals; - if (**s == '~') - **s = Tilde; - filesub((void **) s); -} - -#ifndef STRFTIME -int strftime(char *buf,int bufsize,char *fmt,struct tm *tm) -{ -char *astr[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -char *estr[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul", - "Aug","Sep","Oct","Nov","Dec"}; -char *lstr[] = {"12"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9","10","11"}; - - while (*fmt) - if (*fmt == '%') - { - fmt++; - switch(*fmt++) - { - case 'a': - strucpy(&buf,astr[tm->tm_wday]); - break; - case 'b': - strucpy(&buf,estr[tm->tm_mon]); - break; - case 'd': - *buf++ = '0'+tm->tm_mday/10; - *buf++ = '0'+tm->tm_mday%10; - break; - case 'e': - *buf++ = (tm->tm_mday > 9) ? '0'+tm->tm_mday/10 : ' '; - *buf++ = '0'+tm->tm_mday%10; - break; - case 'k': - *buf++ = (tm->tm_hour > 9) ? '0'+tm->tm_hour/10 : ' '; - *buf++ = '0'+tm->tm_hour%10; - break; - case 'l': - strucpy(&buf,lstr[tm->tm_hour%12]); - break; - case 'm': - *buf++ = '0'+tm->tm_mon/10; - *buf++ = '0'+tm->tm_mon%10; - break; - case 'M': - *buf++ = '0'+tm->tm_min/10; - *buf++ = '0'+tm->tm_min%10; - break; - case 'p': - *buf++ = (tm->tm_hour > 11) ? 'P' : 'A'; - *buf++ = 'M'; - break; - case 'S': - *buf++ = '0'+tm->tm_sec/10; - *buf++ = '0'+tm->tm_sec%10; - break; - case 'y': - *buf++ = '0'+tm->tm_year/10; - *buf++ = '0'+tm->tm_year%10; - break; - default: - exit(20); - } - } - else - *buf++ = *fmt++; - *buf = '\0'; - return 0; -} -#endif - -#ifndef PUTENV -int putenv(char *a) -{ -char *b = a; - - while (*a++ != '='); - a[-1] = '\0'; - setenv(strdup(b),strdup(a)); - free(b); - return 0; -} -#endif - -int ppcount(void) -{ -Node n; -int val = -1; - - for (n = pparms->first; n; n = n->next,val++); - return val; -} - End of utils.c echo utils.pro 1>&2 sed 's/^-//' >utils.pro <<'End of utils.pro' -void addvars(table vars); -void setiparm(char *s,long v,int isint); -void setparm(char *s,char *t,int ex,int isint); -void unsetparm(char *s); -long getiparm(char *s); -char *getparm(char *s); -void parsepath(void); -void parsecdpath(void); -int source(char *s); -void sourcehome(char *s); -void zerrnam(char *cmd, char *fmt, ...); -void zerr(char *fmt,...); -void niceputc(int c,FILE *f); -void intr(void); -void noholdintr(void); -void holdintr(void); -char *fgetline(char *buf,int len,FILE *in); -char *findcwd(char *s); -char *xsymlink(char *s); -char **slashsplit(char *s); -int islink(char *s); -int xsymlinks(char *s); -void printdir(char *s); -int ddifftime(time_t t1,time_t t2); -void scanjobs(void); -void preprompt(void); -void checkmail(void); -void checkfirstmail(void); -void checkmailpath(void); -void createchtab(void); -void freechnode(void *a); -void freestr(void *a); -void freeanode(void *a); -void freeredir(void *a); -void freeshfunc(void *a); -void freepm(void *a); -void restoretty(void); -void gettyinfo(struct ttyinfo *ti); -void settyinfo(struct ttyinfo *ti); -int zyztem(char *s,char *t); -int waitfork(void); -int movefd(int fd); -void redup(int x,int y); -void settrap(char *s,int empty); -void unsettrap(char *s); -void dotrap(int sig); -char *gettext(comm comm); -char *getltext(list l); -char *getl2text(list2 l); -char *getptext(pline p); -char *getsimptext(comm comm); -char *getfortext(struct fornode *n,comm comm); -char *getwhiletext(struct whilenode *n); -char *getrepeattext(struct repeatnode *n); -char *getiftext(struct ifnode *n); -char *getcasetext(struct casenode *n,table l); -void strucpy(char **s,char *t); -void checkrmall(void); -int getquery(void); -void spscan(char *s,char *junk); -void spckcmd(char **s); -void addlocal(char *s); -void pathsub(char **s); -int strftime(char *buf,int bufsize,char *fmt,struct tm *tm); End of utils.pro echo vars.c 1>&2 sed 's/^-//' >vars.c <<'End of vars.c' -/* - - vars.c - variable declarations - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" - -/* buffered shell input for non-interactive shells */ - -FILE *bshin; - -/* null-terminated array of pointers to strings containing elements - of PATH and CDPATH */ - -char **path,**cdpath; - -/* number of elements in aforementioned array */ - -int pathct,cdpathct; - -/* error/break flag */ - -int errflag = 0; - -/* current history event number */ - -int cev = 0; - -/* if != 0, this is the first line of the command */ - -int firstln; - -/* if != 0, this is the first char of the command (not including - white space */ - -int firstch; - -/* first event number in the history table */ - -int tfev = 1; - -/* capacity of history table */ - -int tevs = 20; - -/* if = 1, we have performed history substitution on the current line - if = 2, we have used the 'p' modifier */ - -int hflag; - -/* default event (usually cev-1, that is, "!!") */ - -int dev = 0; - -/* != 0 if we are in the middle of parsing a command (== 0 if we - have not yet parsed the command word */ - -int incmd = 0; - -/* the list of history events */ - -table histlist; - -/* the current history event (can be NULL) */ - -table curtab; - -/* the directory stack */ - -table dirstack; - -/* a string containing all the ungot characters (hungetch()) */ - -char *ungots; - -/* the pointer to the next character to read from ungots */ - -char *ungotptr; - -/* the contents of the IFS parameter */ - -char *ifs; - -/* != 0 if this is a subshell */ - -int subsh; - -/* # of break levels (break builtin) */ - -int breaks; - -/* != 0 if we have a return pending (return builtin) */ - -int retflag; - -/* # of nested loops we are in */ - -int loops; - -/* # of continue levels */ - -int contflag; - -/* the job currently being created/waited for (not current job in the sense - of '+' and '-', that's topjob */ - -int curjob; - -/* the current job (+) */ - -int topjob = -1; - -/* the previous job (-) */ - -int prevjob = -1; - -/* hash table containing the aliases and reserved words */ - -htable alhtab; - -/* hash table containing the parameters */ - -htable parmhtab; - -/* hash table containing the builtins/hashed commands */ - -htable chtab; - -/* hash table containing the shell functions */ - -htable shfunchtab; - -/* the job table */ - -struct jobnode jobtab[MAXJOB]; - -/* the list of sched jobs pending */ - -struct schnode *scheds = NULL; - -/* the last l for s/l/r/ history substitution */ - -char *last; - -/* the last r for s/l/r/ history substitution */ - -char *rast; - -/* if peek == STRING or ENVSTRING, the next token */ - -char *tstr; - -/* who am i */ - -char *username; - -/* the return code of the last command */ - -int lastval; - -/* != 0 if this is a login shell */ - -int islogin; - -/* the next token (enum xtok) */ - -int peek; - -/* the file descriptor associated with the next token, if it - is something like '<' or '>>', etc. */ - -int peekfd; - -/* input fd from the coprocess */ - -int spin = -1; - -/* output fd from the coprocess */ - -int spout = -1; - -/* the last time we checked mail */ - -time_t lastmailcheck; - -/* the last modified date on the mail file last time we checked */ - -time_t lastmailval; - -/* the last time we checked the people in the WATCH variable */ - -time_t lastwatch; - -/* the last time we did the periodic() shell function */ - -time_t lastperiod; - -/* $SECONDS = time(NULL) - shtimer */ - -time_t shtimer; - -/* the size of the mail file last time we checked */ - -off_t lastmailsize; - -/* $$ */ - -long procnum; - -/* $! (the pid of the last background command invoked */ - -long proclast; - -/* the process group of the shell */ - -long shpgrp; - -/* the current working directory */ - -char *cwd; - -/* the hostname, truncated after the '.' */ - -char *hostM; - -/* the hostname */ - -char *hostm; - -/* the home directory */ - -char *home; - -/* the positional parameters */ - -table pparms; - -/* the list of local variables we have to destroy */ - -table locallist; - -/* the shell input fd */ - -int SHIN; - -/* the shell tty fd */ - -int SHTTY; - -/* the stack of aliases we are expanding */ - -struct anode *alstack[MAXAL]; - -/* the alias stack pointer; also, the number of aliases currently - being expanded */ - -int alix = 0; - -/* != 0 means we are reading input from a string */ - -int strin = 0; - -/* == 1 means we are doing TAB expansion - == 2 means expansion has occurred during TAB expansion */ - -int magic = 0; - -/* period between periodic() commands, in seconds */ - -int period = 0; - -/* != 0 means history is turned off (through !" or setopt nobanghist) */ - -int stophist = 0; - -/* != 0 means we have removed the current event from the history list */ - -int histremmed = 0; - -/* the options; e.g. if opts['a'] is nonzero, -a is turned on */ - -int opts[128]; - -/* LINENO */ - -int lineno; - -/* != 0 means we have called execlist() and then intend to exit(), - so don't fork if not necessary */ - -int exiting = 0; - -/* the limits for child processes */ - -struct rlimit limits[RLIM_NLIMITS]; - -/* the tokens */ - -char *tokens = "#$^*()$=|{}[]`<>?~`,"; - -/* the current word in the history list */ - -char *hlastw; - -/* the pointer to the current character in the current word - in the history list */ - -char *hlastp; - -/* the size of the current word in the history list */ - -int hlastsz; - -/* the alias expansion status - if == ALSTAT_MORE, we just finished - expanding an alias ending with a space */ - -int alstat; - -/* we have printed a 'you have stopped (running) jobs.' message */ - -int stopmsg; - -/* the default tty state */ - -struct ttyinfo shttyinfo; - -/* signal names */ - -char *sigs[] = { "EXIT", - "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "EMT", "FPE", "KILL", - "BUS", "SEGV", "SYS", "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", - "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", "XFSZ", "VTALRM", "PROF", - "WINCH", "LOST", "USR1", "USR2", "ERR", "DEBUG" -}; - -/* signals that are trapped = 1, signals ignored =2 */ - -int sigtrapped[SIGCOUNT+2]; - End of vars.c echo vars.pro 1>&2 sed 's/^-//' >vars.pro <<'End of vars.pro' End of vars.pro echo zhistory.c 1>&2 sed 's/^-//' >zhistory.c <<'End of zhistory.c' -/* - - zhistory.c - interface between readline an zsh's ideas of history - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include "readline/history.h" - -/* bindings to make zsh and readline get along */ - -static int histline; - -void using_history(void) -{ - histline = cev; -} - -int where_history(void) -{ - return histline; -} - -int history_set_pos(int pos) -{ - histline = pos; - return 0; -} - -HIST_ENTRY *current_history(void) -{ -table tab; -char *str; -HIST_ENTRY *he; - - tab = quietgetevent(histline); - if (!tab) - return NULL; - str = makehlist(tab,0); - he = (HIST_ENTRY *) malloc(sizeof *he); - he->line = str; - he->data = NULL; - return he; -} - -HIST_ENTRY *previous_history(void) -{ - if (histline == tfev) - return NULL; - histline--; - return current_history(); -} - -HIST_ENTRY *next_history(void) -{ - if (histline == cev) - return NULL; - histline++; - return current_history(); -} - -char *extracthistarg(int num) -{ -Node n; - - if (histlist->last == (Node) histlist || - histlist->last->last == (Node) histlist) - return NULL; - n = ((table) (histlist->last->last))->first; - for (; n && num; num--,n = n->next); - if (!n) - return NULL; - return strdup(n->dat); -} - End of zhistory.c echo readline/chardefs.h 1>&2 sed 's/^-//' >readline/chardefs.h <<'End of readline/chardefs.h' -/* chardefs.h -- Character definitions for readline. */ -#ifndef _CHARDEFS_ - -#ifndef savestring -#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) -#endif - -#ifndef whitespace -#define whitespace(c) (((c) == ' ') || ((c) == '\t')) -#endif - -#ifdef CTRL -#undef CTRL -#endif - -/* Some character stuff. */ -#define control_character_threshold 0x020 /* smaller than this is control */ -#define meta_character_threshold 0x07f /* larger than this is Meta. */ -#define control_character_bit 0x40 /* 0x000000, must be off. */ -#define meta_character_bit 0x080 /* x0000000, must be on. */ - -#define CTRL(c) ((c) & (~control_character_bit)) -#define META(c) ((c) | meta_character_bit) - -#define UNMETA(c) ((c) & (~meta_character_bit)) -#define UNCTRL(c) to_upper(((c)|control_character_bit)) - -#define lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1))) -#define uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1))) - -#define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c)) - -#ifndef to_upper -#define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c)) -#define to_lower(c) (uppercase_p(c) ? ((c) + 32) : (c)) -#endif - -#define CTRL_P(c) ((c) < control_character_threshold) -#define META_P(c) ((c) > meta_character_threshold) - -#define NEWLINE '\n' -#define RETURN CTRL('M') -#define RUBOUT 0x07f -#define TAB '\t' -#define ABORT_CHAR CTRL('G') -#define PAGE CTRL('L') -#define SPACE 0x020 -#define ESC CTRL('[') - -#endif /* _CHARDEFS_ */ End of readline/chardefs.h echo readline/emacs_keymap.c 1>&2 sed 's/^-//' >readline/emacs_keymap.c <<'End of readline/emacs_keymap.c' -/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */ - -/* Copyright (C) 1988,1989 Free Software Foundation, Inc. - - This file is part of GNU Readline, a library for reading lines - of text with interactive input and history editing. - - Readline is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 1, or (at your option) any - later version. - - Readline is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline; see the file COPYING. If not, write to the Free - Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef FILE -#include <stdio.h> -#endif /* FILE */ - -#include "readline.h" - -/* An array of function pointers, one for each possible key. - If the type byte is ISKMAP, then the pointer is the address of - a keymap. */ - -KEYMAP_ENTRY_ARRAY emacs_standard_keymap = { - - /* Control keys. */ - { ISFUNC, (Function *)0x0 }, /* Control-@ */ - { ISFUNC, rl_beg_of_line }, /* Control-a */ - { ISFUNC, rl_backward }, /* Control-b */ - { ISFUNC, (Function *)0x0 }, /* Control-c */ - { ISFUNC, rl_delete }, /* Control-d */ - { ISFUNC, rl_end_of_line }, /* Control-e */ - { ISFUNC, rl_forward }, /* Control-f */ - { ISFUNC, rl_abort }, /* Control-g */ - { ISFUNC, rl_rubout }, /* Control-h */ /* pjf */ - { ISFUNC, rl_complete }, /* Control-i */ - { ISFUNC, rl_newline }, /* Control-j */ - { ISFUNC, rl_kill_line }, /* Control-k */ - { ISFUNC, rl_clear_screen }, /* Control-l */ - { ISFUNC, rl_newline }, /* Control-m */ - { ISFUNC, rl_get_next_history }, /* Control-n */ - { ISFUNC, (Function *)0x0 }, /* Control-o */ - { ISFUNC, rl_get_previous_history }, /* Control-p */ - { ISFUNC, rl_quoted_insert }, /* Control-q */ - { ISFUNC, (Function *)0x0 }, /* Control-r */ - { ISFUNC, (Function *)0x0 }, /* Control-s */ - { ISFUNC, rl_transpose_chars }, /* Control-t */ - { ISFUNC, rl_unix_line_discard }, /* Control-u */ - { ISFUNC, rl_quoted_insert }, /* Control-v */ - { ISFUNC, rl_unix_word_rubout }, /* Control-w */ - { ISKMAP, (Function *)emacs_ctlx_keymap }, /* Control-x */ - { ISFUNC, rl_yank }, /* Control-y */ - { ISFUNC, (Function *)0x0 }, /* Control-z */ - { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */ - { ISFUNC, (Function *)0x0 }, /* Control-\ */ - { ISFUNC, (Function *)0x0 }, /* Control-] */ - { ISFUNC, (Function *)0x0 }, /* Control-^ */ - { ISFUNC, rl_undo_command }, /* Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, rl_insert }, /* SPACE */ - { ISFUNC, rl_insert }, /* ! */ - { ISFUNC, rl_insert }, /* " */ - { ISFUNC, rl_insert }, /* # */ - { ISFUNC, rl_insert }, /* $ */ - { ISFUNC, rl_insert }, /* % */ - { ISFUNC, rl_insert }, /* & */ - { ISFUNC, rl_insert }, /* ' */ - { ISFUNC, rl_insert }, /* ( */ - { ISFUNC, rl_insert }, /* ) */ - { ISFUNC, rl_insert }, /* * */ - { ISFUNC, rl_insert }, /* + */ - { ISFUNC, rl_insert }, /* , */ - { ISFUNC, rl_insert }, /* - */ - { ISFUNC, rl_insert }, /* . */ - { ISFUNC, rl_insert }, /* / */ - - /* Regular digits. */ - { ISFUNC, rl_insert }, /* 0 */ - { ISFUNC, rl_insert }, /* 1 */ - { ISFUNC, rl_insert }, /* 2 */ - { ISFUNC, rl_insert }, /* 3 */ - { ISFUNC, rl_insert }, /* 4 */ - { ISFUNC, rl_insert }, /* 5 */ - { ISFUNC, rl_insert }, /* 6 */ - { ISFUNC, rl_insert }, /* 7 */ - { ISFUNC, rl_insert }, /* 8 */ - { ISFUNC, rl_insert }, /* 9 */ - - /* A little more punctuation. */ - { ISFUNC, rl_insert }, /* : */ - { ISFUNC, rl_insert }, /* ; */ - { ISFUNC, rl_insert }, /* < */ - { ISFUNC, rl_insert }, /* = */ - { ISFUNC, rl_insert }, /* > */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* @ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_insert }, /* A */ - { ISFUNC, rl_insert }, /* B */ - { ISFUNC, rl_insert }, /* C */ - { ISFUNC, rl_insert }, /* D */ - { ISFUNC, rl_insert }, /* E */ - { ISFUNC, rl_insert }, /* F */ - { ISFUNC, rl_insert }, /* G */ - { ISFUNC, rl_insert }, /* H */ - { ISFUNC, rl_insert }, /* I */ - { ISFUNC, rl_insert }, /* J */ - { ISFUNC, rl_insert }, /* K */ - { ISFUNC, rl_insert }, /* L */ - { ISFUNC, rl_insert }, /* M */ - { ISFUNC, rl_insert }, /* N */ - { ISFUNC, rl_insert }, /* O */ - { ISFUNC, rl_insert }, /* P */ - { ISFUNC, rl_insert }, /* Q */ - { ISFUNC, rl_insert }, /* R */ - { ISFUNC, rl_insert }, /* S */ - { ISFUNC, rl_insert }, /* T */ - { ISFUNC, rl_insert }, /* U */ - { ISFUNC, rl_insert }, /* V */ - { ISFUNC, rl_insert }, /* W */ - { ISFUNC, rl_insert }, /* X */ - { ISFUNC, rl_insert }, /* Y */ - { ISFUNC, rl_insert }, /* Z */ - - /* Some more punctuation. */ - { ISFUNC, rl_insert }, /* [ */ - { ISFUNC, rl_insert }, /* \ */ - { ISFUNC, rl_insert }, /* ] */ - { ISFUNC, rl_insert }, /* ^ */ - { ISFUNC, rl_insert }, /* _ */ - { ISFUNC, rl_insert }, /* ` */ - - /* Lowercase alphabet. */ - { ISFUNC, rl_insert }, /* a */ - { ISFUNC, rl_insert }, /* b */ - { ISFUNC, rl_insert }, /* c */ - { ISFUNC, rl_insert }, /* d */ - { ISFUNC, rl_insert }, /* e */ - { ISFUNC, rl_insert }, /* f */ - { ISFUNC, rl_insert }, /* g */ - { ISFUNC, rl_insert }, /* h */ - { ISFUNC, rl_insert }, /* i */ - { ISFUNC, rl_insert }, /* j */ - { ISFUNC, rl_insert }, /* k */ - { ISFUNC, rl_insert }, /* l */ - { ISFUNC, rl_insert }, /* m */ - { ISFUNC, rl_insert }, /* n */ - { ISFUNC, rl_insert }, /* o */ - { ISFUNC, rl_insert }, /* p */ - { ISFUNC, rl_insert }, /* q */ - { ISFUNC, rl_insert }, /* r */ - { ISFUNC, rl_insert }, /* s */ - { ISFUNC, rl_insert }, /* t */ - { ISFUNC, rl_insert }, /* u */ - { ISFUNC, rl_insert }, /* v */ - { ISFUNC, rl_insert }, /* w */ - { ISFUNC, rl_insert }, /* x */ - { ISFUNC, rl_insert }, /* y */ - { ISFUNC, rl_insert }, /* z */ - - /* Final punctuation. */ - { ISFUNC, rl_insert }, /* { */ - { ISFUNC, rl_insert }, /* | */ - { ISFUNC, rl_insert }, /* } */ - { ISFUNC, rl_insert }, /* ~ */ - { ISFUNC, rl_rubout } /* RUBOUT */ -}; - -KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { - - /* Meta keys. Just like above, but the high bit is set. */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-a */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-b */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-c */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-d */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-e */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */ - { ISFUNC, rl_abort }, /* Meta-Control-g */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-h */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-i */ - { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */ - { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-n */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-o */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-p */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-q */ - { ISFUNC, rl_revert_line }, /* Meta-Control-r */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-s */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-t */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-u */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-v */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-w */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-x */ - { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-z */ - - { ISFUNC, (Function *)0x0 }, /* Meta-Control-[ */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-] */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */ - { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, (Function *)rl_magic_space }, /* Meta-SPACE */ - { ISFUNC, (Function *)0x0 }, /* Meta-! */ - { ISFUNC, (Function *)0x0 }, /* Meta-" */ - { ISFUNC, (Function *)0x0 }, /* Meta-# */ - { ISFUNC, rl_check_spelling }, /* Meta-$ */ - { ISFUNC, (Function *)0x0 }, /* Meta-% */ - { ISFUNC, (Function *)0x0 }, /* Meta-& */ - { ISFUNC, (Function *)0x0 }, /* Meta-' */ - { ISFUNC, (Function *)0x0 }, /* Meta-( */ - { ISFUNC, (Function *)0x0 }, /* Meta-) */ - { ISFUNC, (Function *)0x0 }, /* Meta-* */ - { ISFUNC, (Function *)0x0 }, /* Meta-+ */ - { ISFUNC, (Function *)0x0 }, /* Meta-, */ - { ISFUNC, rl_digit_argument }, /* Meta-- */ - { ISFUNC, (Function *)0x0 }, /* Meta-. */ - { ISFUNC, (Function *)0x0 }, /* Meta-/ */ - - /* Regular digits. */ - { ISFUNC, rl_digit_argument }, /* Meta-0 */ - { ISFUNC, rl_digit_argument }, /* Meta-1 */ - { ISFUNC, rl_digit_argument }, /* Meta-2 */ - { ISFUNC, rl_digit_argument }, /* Meta-3 */ - { ISFUNC, rl_digit_argument }, /* Meta-4 */ - { ISFUNC, rl_digit_argument }, /* Meta-5 */ - { ISFUNC, rl_digit_argument }, /* Meta-6 */ - { ISFUNC, rl_digit_argument }, /* Meta-7 */ - { ISFUNC, rl_digit_argument }, /* Meta-8 */ - { ISFUNC, rl_digit_argument }, /* Meta-9 */ - - /* A little more punctuation. */ - { ISFUNC, (Function *)0x0 }, /* Meta-: */ - { ISFUNC, (Function *)0x0 }, /* Meta-; */ - { ISFUNC, rl_beginning_of_history }, /* Meta-< */ - { ISFUNC, (Function *)0x0 }, /* Meta-= */ - { ISFUNC, rl_end_of_history }, /* Meta-> */ - { ISFUNC, rl_possible_completions }, /* Meta-? */ - { ISFUNC, (Function *)0x0 }, /* Meta-@ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-A */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-B */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-C */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-D */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-E */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-F */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-G */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-H */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-I */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-J */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-K */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-L */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-M */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-N */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-O */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-P */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-R */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-S */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-T */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-U */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-V */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-W */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-X */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */ - { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */ - - /* Some more punctuation. */ - { ISFUNC, rl_function_key }, /* Meta-[ */ - { ISFUNC, (Function *)0x0 }, /* Meta-\ */ - { ISFUNC, (Function *)0x0 }, /* Meta-] */ - { ISFUNC, (Function *)0x0 }, /* Meta-^ */ - { ISFUNC, (Function *)0x0 }, /* Meta-_ */ - { ISFUNC, (Function *)0x0 }, /* Meta-` */ - - /* Lowercase alphabet. */ - { ISFUNC, (Function *)0x0 }, /* Meta-a */ - { ISFUNC, rl_backward_word }, /* Meta-b */ - { ISFUNC, rl_capitalize_word }, /* Meta-c */ - { ISFUNC, rl_kill_word }, /* Meta-d */ - { ISFUNC, (Function *)0x0 }, /* Meta-e */ - { ISFUNC, rl_forward_word }, /* Meta-f */ - { ISFUNC, (Function *)0x0 }, /* Meta-g */ - { ISFUNC, (Function *)0x0 }, /* Meta-h */ - { ISFUNC, (Function *)0x0 }, /* Meta-i */ - { ISFUNC, (Function *)0x0 }, /* Meta-j */ - { ISFUNC, (Function *)0x0 }, /* Meta-k */ - { ISFUNC, rl_downcase_word }, /* Meta-l */ - { ISFUNC, (Function *)0x0 }, /* Meta-m */ - { ISFUNC, (Function *)0x0 }, /* Meta-n */ - { ISFUNC, (Function *)0x0 }, /* Meta-o */ - { ISFUNC, (Function *)0x0 }, /* Meta-p */ - { ISFUNC, (Function *)0x0 }, /* Meta-q */ - { ISFUNC, rl_revert_line }, /* Meta-r */ - { ISFUNC, (Function *)0x0 }, /* Meta-s */ - { ISFUNC, rl_transpose_words }, /* Meta-t */ - { ISFUNC, rl_upcase_word }, /* Meta-u */ - { ISFUNC, (Function *)0x0 }, /* Meta-v */ - { ISFUNC, (Function *)0x0 }, /* Meta-w */ - { ISFUNC, (Function *)0x0 }, /* Meta-x */ - { ISFUNC, rl_yank_pop }, /* Meta-y */ - { ISFUNC, (Function *)0x0 }, /* Meta-z */ - - /* Final punctuation. */ - { ISFUNC, (Function *)0x0 }, /* Meta-{ */ - { ISFUNC, (Function *)0x0 }, /* Meta-| */ - { ISFUNC, (Function *)0x0 }, /* Meta-} */ - { ISFUNC, (Function *)0x0 }, /* Meta-~ */ - { ISFUNC, rl_backward_kill_word } /* Meta-rubout */ -}; - -KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = { - - /* Control keys. */ - { ISFUNC, (Function *)0x0 }, /* Control-@ */ - { ISFUNC, (Function *)0x0 }, /* Control-a */ - { ISFUNC, (Function *)0x0 }, /* Control-b */ - { ISFUNC, (Function *)0x0 }, /* Control-c */ - { ISFUNC, (Function *)0x0 }, /* Control-d */ - { ISFUNC, (Function *)0x0 }, /* Control-e */ - { ISFUNC, (Function *)0x0 }, /* Control-f */ - { ISFUNC, rl_abort }, /* Control-g */ - { ISFUNC, (Function *)0x0 }, /* Control-h */ - { ISFUNC, (Function *)0x0 }, /* Control-i */ - { ISFUNC, (Function *)0x0 }, /* Control-j */ - { ISFUNC, (Function *)0x0 }, /* Control-k */ - { ISFUNC, (Function *)0x0 }, /* Control-l */ - { ISFUNC, (Function *)0x0 }, /* Control-m */ - { ISFUNC, (Function *)0x0 }, /* Control-n */ - { ISFUNC, (Function *)0x0 }, /* Control-o */ - { ISFUNC, (Function *)0x0 }, /* Control-p */ - { ISFUNC, (Function *)0x0 }, /* Control-q */ - { ISFUNC, rl_re_read_init_file }, /* Control-r */ - { ISFUNC, (Function *)0x0 }, /* Control-s */ - { ISFUNC, (Function *)0x0 }, /* Control-t */ - { ISFUNC, rl_undo_command }, /* Control-u */ - { ISFUNC, (Function *)0x0 }, /* Control-v */ - { ISFUNC, (Function *)0x0 }, /* Control-w */ - { ISFUNC, (Function *)0x0 }, /* Control-x */ - { ISFUNC, (Function *)0x0 }, /* Control-y */ - { ISFUNC, (Function *)0x0 }, /* Control-z */ - { ISFUNC, (Function *)0x0 }, /* Control-[ */ - { ISFUNC, (Function *)0x0 }, /* Control-\ */ - { ISFUNC, (Function *)0x0 }, /* Control-] */ - { ISFUNC, (Function *)0x0 }, /* Control-^ */ - { ISFUNC, (Function *)0x0 }, /* Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, (Function *)0x0 }, /* SPACE */ - { ISFUNC, (Function *)0x0 }, /* ! */ - { ISFUNC, (Function *)0x0 }, /* " */ - { ISFUNC, (Function *)0x0 }, /* # */ - { ISFUNC, (Function *)0x0 }, /* $ */ - { ISFUNC, (Function *)0x0 }, /* % */ - { ISFUNC, (Function *)0x0 }, /* & */ - { ISFUNC, (Function *)0x0 }, /* ' */ - { ISFUNC, rl_start_kbd_macro }, /* ( */ - { ISFUNC, rl_end_kbd_macro }, /* ) */ - { ISFUNC, (Function *)0x0 }, /* * */ - { ISFUNC, (Function *)0x0 }, /* + */ - { ISFUNC, (Function *)0x0 }, /* , */ - { ISFUNC, (Function *)0x0 }, /* - */ - { ISFUNC, (Function *)0x0 }, /* . */ - { ISFUNC, (Function *)0x0 }, /* / */ - - /* Regular digits. */ - { ISFUNC, (Function *)0x0 }, /* 0 */ - { ISFUNC, (Function *)0x0 }, /* 1 */ - { ISFUNC, (Function *)0x0 }, /* 2 */ - { ISFUNC, (Function *)0x0 }, /* 3 */ - { ISFUNC, (Function *)0x0 }, /* 4 */ - { ISFUNC, (Function *)0x0 }, /* 5 */ - { ISFUNC, (Function *)0x0 }, /* 6 */ - { ISFUNC, (Function *)0x0 }, /* 7 */ - { ISFUNC, (Function *)0x0 }, /* 8 */ - { ISFUNC, (Function *)0x0 }, /* 9 */ - - /* A little more punctuation. */ - { ISFUNC, (Function *)0x0 }, /* : */ - { ISFUNC, (Function *)0x0 }, /* ; */ - { ISFUNC, (Function *)0x0 }, /* < */ - { ISFUNC, (Function *)0x0 }, /* = */ - { ISFUNC, (Function *)0x0 }, /* > */ - { ISFUNC, (Function *)0x0 }, /* ? */ - { ISFUNC, (Function *)0x0 }, /* @ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_do_lowercase_version }, /* A */ - { ISFUNC, rl_do_lowercase_version }, /* B */ - { ISFUNC, rl_do_lowercase_version }, /* C */ - { ISFUNC, rl_do_lowercase_version }, /* D */ - { ISFUNC, rl_do_lowercase_version }, /* E */ - { ISFUNC, rl_do_lowercase_version }, /* F */ - { ISFUNC, rl_do_lowercase_version }, /* G */ - { ISFUNC, rl_do_lowercase_version }, /* H */ - { ISFUNC, rl_do_lowercase_version }, /* I */ - { ISFUNC, rl_do_lowercase_version }, /* J */ - { ISFUNC, rl_do_lowercase_version }, /* K */ - { ISFUNC, rl_do_lowercase_version }, /* L */ - { ISFUNC, rl_do_lowercase_version }, /* M */ - { ISFUNC, rl_do_lowercase_version }, /* N */ - { ISFUNC, rl_do_lowercase_version }, /* O */ - { ISFUNC, rl_do_lowercase_version }, /* P */ - { ISFUNC, rl_do_lowercase_version }, /* Q */ - { ISFUNC, rl_do_lowercase_version }, /* R */ - { ISFUNC, rl_do_lowercase_version }, /* S */ - { ISFUNC, rl_do_lowercase_version }, /* T */ - { ISFUNC, rl_do_lowercase_version }, /* U */ - { ISFUNC, rl_do_lowercase_version }, /* V */ - { ISFUNC, rl_do_lowercase_version }, /* W */ - { ISFUNC, rl_do_lowercase_version }, /* X */ - { ISFUNC, rl_do_lowercase_version }, /* Y */ - { ISFUNC, rl_do_lowercase_version }, /* Z */ - - /* Some more punctuation. */ - { ISFUNC, (Function *)0x0 }, /* [ */ - { ISFUNC, (Function *)0x0 }, /* \ */ - { ISFUNC, (Function *)0x0 }, /* ] */ - { ISFUNC, (Function *)0x0 }, /* ^ */ - { ISFUNC, (Function *)0x0 }, /* _ */ - { ISFUNC, (Function *)0x0 }, /* ` */ - - /* Lowercase alphabet. */ - { ISFUNC, (Function *)0x0 }, /* a */ - { ISFUNC, (Function *)0x0 }, /* b */ - { ISFUNC, (Function *)0x0 }, /* c */ - { ISFUNC, (Function *)0x0 }, /* d */ - { ISFUNC, rl_call_last_kbd_macro }, /* e */ - { ISFUNC, (Function *)0x0 }, /* f */ - { ISFUNC, (Function *)0x0 }, /* g */ - { ISFUNC, (Function *)0x0 }, /* h */ - { ISFUNC, (Function *)0x0 }, /* i */ - { ISFUNC, (Function *)0x0 }, /* j */ - { ISFUNC, (Function *)0x0 }, /* k */ - { ISFUNC, (Function *)0x0 }, /* l */ - { ISFUNC, (Function *)0x0 }, /* m */ - { ISFUNC, (Function *)0x0 }, /* n */ - { ISFUNC, (Function *)0x0 }, /* o */ - { ISFUNC, (Function *)0x0 }, /* p */ - { ISFUNC, (Function *)0x0 }, /* q */ - { ISFUNC, (Function *)0x0 }, /* r */ - { ISFUNC, (Function *)0x0 }, /* s */ - { ISFUNC, (Function *)0x0 }, /* t */ - { ISFUNC, (Function *)0x0 }, /* u */ - { ISFUNC, (Function *)0x0 }, /* v */ - { ISFUNC, (Function *)0x0 }, /* w */ - { ISFUNC, (Function *)0x0 }, /* x */ - { ISFUNC, (Function *)0x0 }, /* y */ - { ISFUNC, (Function *)0x0 }, /* z */ - - /* Final punctuation. */ - { ISFUNC, (Function *)0x0 }, /* { */ - { ISFUNC, (Function *)0x0 }, /* | */ - { ISFUNC, (Function *)0x0 }, /* } */ - { ISFUNC, (Function *)0x0 }, /* ~ */ - { ISFUNC, rl_backward_kill_line } /* RUBOUT */ -}; End of readline/emacs_keymap.c echo readline/funmap.c 1>&2 sed 's/^-//' >readline/funmap.c <<'End of readline/funmap.c' -/* funmap.c -- attach names to functions. */ - -/* Copyright (C) 1988,1989 Free Software Foundation, Inc. - - This file is part of GNU Readline, a library for reading lines - of text with interactive input and history editing. - - Readline is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 1, or (at your option) any - later version. - - Readline is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline; see the file COPYING. If not, write to the Free - Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#define STATIC_MALLOC -#ifndef STATIC_MALLOC -extern char *xmalloc (), *xrealloc (); -#else -static char *xmalloc (), *xrealloc (); -#endif - -#ifndef FILE -#include <stdio.h> -#endif /* FILE */ - -#include "readline.h" - -FUNMAP **funmap = (FUNMAP **)NULL; -static int funmap_size = 0; -static int funmap_entry = 0; - -static FUNMAP default_funmap[] = { - { "beginning-of-line", rl_beg_of_line }, - { "backward-char", rl_backward }, - { "delete-char", rl_delete }, - { "end-of-line", rl_end_of_line }, - { "forward-char", rl_forward }, - { "accept-line", rl_newline }, - { "kill-line", rl_kill_line }, - { "clear-screen", rl_clear_screen }, - { "next-history", rl_get_next_history }, - { "previous-history", rl_get_previous_history }, - { "quoted-insert", rl_quoted_insert }, - { "transpose-chars", rl_transpose_chars }, - { "unix-line-discard", rl_unix_line_discard }, - { "unix-word-rubout", rl_unix_word_rubout }, - { "yank", rl_yank }, - { "yank-pop", rl_yank_pop }, - { "yank-nth-arg", rl_yank_nth_arg }, - { "backward-delete-char", rl_rubout }, - { "backward-word", rl_backward_word }, - { "kill-word", rl_kill_word }, - { "forward-word", rl_forward_word }, - { "tab-insert", rl_tab_insert }, - { "backward-kill-word", rl_backward_kill_word }, - { "backward-kill-line", rl_backward_kill_line }, - { "transpose-words", rl_transpose_words }, - { "digit-argument", rl_digit_argument }, - { "complete", rl_complete }, - { "possible-completions", rl_possible_completions }, - { "do-lowercase-version", rl_do_lowercase_version }, - { "digit-argument", rl_digit_argument }, - { "universal-argument", rl_universal_argument }, - { "abort", rl_abort }, - { "undo", rl_undo_command }, - { "upcase-word", rl_upcase_word }, - { "downcase-word", rl_downcase_word }, - { "capitalize-word", rl_capitalize_word }, - { "revert-line", rl_revert_line }, - { "beginning-of-history", rl_beginning_of_history }, - { "end-of-history", rl_end_of_history }, - { "self-insert", rl_insert }, - { "start-kbd-macro", rl_start_kbd_macro }, - { "end-kbd-macro", rl_end_kbd_macro }, - { "re-read-init-file", rl_re_read_init_file }, - { "history-expand", rl_magic_space }, - { "check-spelling", rl_check_spelling }, -#ifdef VI_MODE - { "vi-movement-mode", rl_vi_movement_mode }, - { "vi-insertion-mode", rl_vi_insertion_mode }, - { "vi-arg-digit", rl_vi_arg_digit }, - { "vi-prev-word", rl_vi_prev_word }, - { "vi-next-word", rl_vi_next_word }, - { "vi-char-search", rl_vi_char_search }, - { "vi-editing-mode", rl_vi_editing_mode }, - { "vi-eof-maybe", rl_vi_eof_maybe }, - { "vi-append-mode", rl_vi_append_mode }, - { "vi-put", rl_vi_put }, - { "vi-append-eol", rl_vi_append_eol }, - { "vi-insert-beg", rl_vi_insert_beg }, - { "vi-delete", rl_vi_delete }, - { "vi-comment", rl_vi_comment }, - { "vi-first-print", rl_vi_first_print }, - { "vi-fword", rl_vi_fword }, - { "vi-fWord", rl_vi_fWord }, - { "vi-bword", rl_vi_bword }, - { "vi-bWord", rl_vi_bWord }, - { "vi-eword", rl_vi_eword }, - { "vi-eWord", rl_vi_eWord }, - { "vi-end-word", rl_vi_end_word }, - { "vi-change-case", rl_vi_change_case }, - { "vi-match", rl_vi_match }, - { "vi-bracktype", rl_vi_bracktype }, - { "vi-change-char", rl_vi_change_char }, - { "vi-yank-arg", rl_vi_yank_arg }, - { "vi-search", rl_vi_search }, - { "vi-search-again", rl_vi_search_again }, - { "vi-dosearch", rl_vi_dosearch }, - { "vi-subst", rl_vi_subst }, - { "vi-overstrike", rl_vi_overstrike }, - { "vi-overstrike-delete", rl_vi_overstrike_delete }, - { "vi-replace, ", rl_vi_replace }, - { "vi-column", rl_vi_column }, - { "vi-delete-to", rl_vi_delete_to }, - { "vi-change-to", rl_vi_change_to }, - { "vi-yank-to", rl_vi_yank_to }, - { "vi-complete", rl_vi_complete }, -#endif /* VI_MODE */ - - {(char *)NULL, (Function *)NULL } -}; - -rl_add_funmap_entry (name, function) - char *name; - Function *function; -{ - if (funmap_entry + 2 >= funmap_size) - if (!funmap) - funmap = (FUNMAP **)xmalloc ((funmap_size = 80) * sizeof (FUNMAP *)); - else - funmap = - (FUNMAP **)xrealloc (funmap, (funmap_size += 80) * sizeof (FUNMAP *)); - - funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP)); - funmap[funmap_entry]->name = name; - funmap[funmap_entry]->function = function; - - funmap[++funmap_entry] = (FUNMAP *)NULL; -} - -static int funmap_initialized = 0; - -/* Make the funmap contain all of the default entries. */ -rl_initialize_funmap () -{ - register int i; - - if (funmap_initialized) - return; - - for (i = 0; default_funmap[i].name; i++) - rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function); - - funmap_initialized = 1; -} - -/* Things that mean `Control'. */ -char *possible_control_prefixes[] = { - "Control-", "C-", "CTRL-", (char *)NULL -}; - -char *possible_meta_prefixes[] = { - "Meta", "M-", (char *)NULL -}; - -#ifdef STATIC_MALLOC - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "history: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ End of readline/funmap.c echo readline/history.h 1>&2 sed 's/^-//' >readline/history.h <<'End of readline/history.h' -/* History.h -- the names of functions that you can call in history. */ -/* modified by pjf */ - -typedef struct _hist_entry { - char *line; - char *data; -} HIST_ENTRY; - -/* For convenience only. You set this when interpreting history commands. - It is the logical offset of the first history element. */ -extern int tfev; -#define history_base tfev - -/* Begin a session in which the history functions might be used. This - just initializes the interactive variables. */ -extern void using_history (); - -/* Place STRING at the end of the history list. - The associated data field (if any) is set to NULL. */ -/* extern void add_history (); */ - -/* Returns the number which says what history element we are now - looking at. */ -extern int where_history (); - -/* Set the position in the history list to POS. */ -int history_set_pos (); - -/* Search for STRING in the history list, starting at POS, an - absolute index into the list. DIR, if negative, says to search - backwards from POS, else forwards. - Returns the absolute index of the history element where STRING - was found, or -1 otherwise. */ -extern int history_search_pos (); - -/* A reasonably useless function, only here for completeness. WHICH - is the magic number that tells us which element to delete. The - elements are numbered from 0. */ -/* inline HIST_ENTRY *remove_history () {return NULL;} */ - -/* Stifle the history list, remembering only MAX number of entries. */ -/* extern void stifle_history (); */ - -/* Stop stifling the history. This returns the previous amount the - history was stifled by. The value is positive if the history was - stifled, negative if it wasn't. */ -/* extern int unstifle_history (); */ - -/* Add the contents of FILENAME to the history list, a line at a time. - If FILENAME is NULL, then read from ~/.history. Returns 0 if - successful, or errno if not. */ -/* extern int read_history (); */ - -/* Append the current history to FILENAME. If FILENAME is NULL, - then append the history list to ~/.history. Values returned - are as in read_history (). */ -/* extern int write_history (); */ - - -/* Make the history entry at WHICH have LINE and DATA. This returns - the old entry so you can dispose of the data. In the case of an - invalid WHICH, a NULL pointer is returned. */ -/* extern HIST_ENTRY *replace_history_entry (); */ - -/* Return the history entry at the current position, as determined by - history_offset. If there is no entry there, return a NULL pointer. */ -HIST_ENTRY *current_history (); - -/* Back up history_offset to the previous history entry, and return - a pointer to that entry. If there is no previous entry, return - a NULL pointer. */ -extern HIST_ENTRY *previous_history (); - -/* Move history_offset forward to the next item in the input_history, - and return the a pointer to that entry. If there is no next entry, - return a NULL pointer. */ -extern HIST_ENTRY *next_history (); - -/* Return a NULL terminated array of HIST_ENTRY which is the current input - history. Element 0 of this list is the beginning of time. If there - is no history, return NULL. */ -/*extern HIST_ENTRY **history_list ();*/ - -/* Search the history for STRING, starting at history_offset. - If DIRECTION < 0, then the search is through previous entries, - else through subsequent. If the string is found, then - current_history () is the history entry, and the value of this function - is the offset in the line of that history entry that the string was - found in. Otherwise, nothing is changed, and a -1 is returned. */ -/* extern int history_search (); */ - -/* Expand the string STRING, placing the result into OUTPUT, a pointer - to a string. Returns: - - 0) If no expansions took place (or, if the only change in - the text was the de-slashifying of the history expansion - character) - 1) If expansions did take place - -1) If there was an error in expansion. - - If an error ocurred in expansion, then OUTPUT contains a descriptive - error message. */ -/*extern int history_expand ();*/ - -/* Extract a string segment consisting of the FIRST through LAST - arguments present in STRING. Arguments are broken up as in - the shell. pjf: only 1-segment strings are supported. */ -extern char *history_arg_extract (); - - End of readline/history.h echo readline/keymaps.c 1>&2 sed 's/^-//' >readline/keymaps.c <<'End of readline/keymaps.c' -/* keymaps.c -- Functions and keymaps for the GNU Readline library. */ - -/* Copyright (C) 1988,1989 Free Software Foundation, Inc. - - This file is part of GNU Readline, a library for reading lines - of text with interactive input and history editing. - - Readline is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 1, or (at your option) any - later version. - - Readline is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline; see the file COPYING. If not, write to the Free - Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "keymaps.h" -#include "emacs_keymap.c" - -#ifdef VI_MODE -#include "vi_keymap.c" -#endif - -/* Remove these declarations when we have a complete libgnu.a. */ -#define STATIC_MALLOC -#ifndef STATIC_MALLOC -extern char *xmalloc (), *xrealloc (); -#else -static char *xmalloc (), *xrealloc (); -#endif - -/* **************************************************************** */ -/* */ -/* Functions for manipulating Keymaps. */ -/* */ -/* **************************************************************** */ - - -/* Return a new, empty keymap. - Free it with free() when you are done. */ -Keymap -rl_make_bare_keymap () -{ - register int i; - Keymap keymap = (Keymap)xmalloc (128 * sizeof (KEYMAP_ENTRY)); - - for (i = 0; i < 128; i++) - { - keymap[i].type = ISFUNC; - keymap[i].function = (Function *)NULL; - } - - for (i = 'A'; i < ('Z' + 1); i++) - { - keymap[i].type = ISFUNC; - keymap[i].function = rl_do_lowercase_version; - } - - return (keymap); -} - -/* Return a new keymap which is a copy of MAP. */ -Keymap -rl_copy_keymap (map) - Keymap map; -{ - register int i; - Keymap temp = rl_make_bare_keymap (); - - for (i = 0; i < 128; i++) - { - temp[i].type = map[i].type; - temp[i].function = map[i].function; - } - return (temp); -} - -/* Return a new keymap with the printing characters bound to rl_insert, - the uppercase Meta characters bound to run their lowercase equivalents, - and the Meta digits bound to produce numeric arguments. */ -Keymap -rl_make_keymap () -{ - extern rl_insert (), rl_rubout (), rl_do_lowercase_version (); - extern rl_digit_argument (); - register int i; - Keymap newmap; - - newmap = rl_make_bare_keymap (); - - /* All printing characters are self-inserting. */ - for (i = ' '; i < 126; i++) - newmap[i].function = rl_insert; - - newmap[TAB].function = rl_insert; - newmap[RUBOUT].function = rl_rubout; - - return (newmap); -} - -/* Free the storage associated with MAP. */ -rl_discard_keymap (map) - Keymap (map); -{ - int i; - - if (!map) - return; - - for (i = 0; i < 128; i++) - { - switch (map[i].type) - { - case ISFUNC: - break; - - case ISKMAP: - rl_discard_keymap ((Keymap)map[i].function); - break; - - case ISMACR: - free ((char *)map[i].function); - break; - } - } -} - -#ifdef STATIC_MALLOC - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) - int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - char *temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "readline: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ End of readline/keymaps.c echo readline/keymaps.h 1>&2 sed 's/^-//' >readline/keymaps.h <<'End of readline/keymaps.h' -/* keymaps.h -- Manipulation of readline keymaps. */ - -#ifndef _KEYMAPS_H_ -#define _KEYMAPS_H_ - -#include <readline/chardefs.h> - -#ifndef __FUNCTION_DEF -typedef int Function (); -#define __FUNCTION_DEF -#endif - -/* A keymap contains one entry for each key in the ASCII set. - Each entry consists of a type and a pointer. - POINTER is the address of a function to run, or the - address of a keymap to indirect through. - TYPE says which kind of thing POINTER is. */ -typedef struct _keymap_entry { - char type; - Function *function; -} KEYMAP_ENTRY; - -/* I wanted to make the above structure contain a union of: - union { Function *function; struct _keymap_entry *keymap; } value; - but this made it impossible for me to create a static array. - Maybe I need C lessons. */ - -typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[128]; -typedef KEYMAP_ENTRY *Keymap; - -/* The values that TYPE can have in a keymap entry. */ -#define ISFUNC 0 -#define ISKMAP 1 -#define ISMACR 2 - -extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; -extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap; - -/* Return a new, empty keymap. - Free it with free() when you are done. */ -Keymap rl_make_bare_keymap (); - -/* Return a new keymap which is a copy of MAP. */ -Keymap rl_copy_keymap (); - -/* Return a new keymap with the printing characters bound to rl_insert, - the lowercase Meta characters bound to run their equivalents, and - the Meta digits bound to produce numeric arguments. */ -Keymap rl_make_keymap (); - -#endif /* _KEYMAPS_H_ */ - - End of readline/keymaps.h echo readline/readline.c 1>&2 sed 's/^-//' >readline/readline.c <<'End of readline/readline.c' -/* readline.c -- a general facility for reading lines of input - with emacs style editing and completion. */ - -/* Copyright (C) 1987,1989 Free Software Foundation, Inc. - - This file contains the Readline Library (the Library), a set of - routines for providing Emacs style line input to programs that ask - for it. - - The Library is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. - - The Library is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* Remove these declarations when we have a complete libgnu.a. */ -#define STATIC_MALLOC -#ifndef STATIC_MALLOC -extern char *xmalloc (), *xrealloc (); -#else -static char *xmalloc (), *xrealloc (); -#endif - -char *docompsubs(); -extern int errno,errflag; - -#include <stdio.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/file.h> -#include <sys/param.h> -#include <signal.h> - -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else -#if defined (sparc) && defined (sun) -#include <alloca.h> -#endif -#endif - -#define NEW_TTY_DRIVER -#if defined (SYSV) || defined (hpux) -#undef NEW_TTY_DRIVER -#include <termio.h> -#else -#include <sgtty.h> -#endif - -#include <errno.h> -extern int errno; - -#include <setjmp.h> - -/* These next are for filename completion. Perhaps this belongs - in a different place. */ -#include <sys/stat.h> - -#include <pwd.h> -#ifdef SYSV -struct passwd *getpwuid (), *getpwent (); -#endif - -#define HACK_TERMCAP_MOTION - -#ifndef SYSV -#include <sys/dir.h> -#else /* SYSV */ -#if defined (xenix) -#include <sys/ndir.h> -#else -#ifdef hpux -#include <ndir.h> -#else -#include <dirent.h> -#define direct dirent -#define d_namlen d_reclen -#endif /* hpux */ -#endif /* xenix */ -#endif /* SYSV */ - -#ifndef O_CBREAK -#define O_CBREAK CBREAK -#define O_ECHO ECHO -#define O_RAW RAW -#endif - -/* Some standard library routines. */ -#include "readline.h" -#include "history.h" - -#ifndef digit -#define digit(c) ((c) >= '0' && (c) <= '9') -#endif - -#ifndef isletter -#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z')) -#endif - -#ifndef digit_value -#define digit_value(c) ((c) - '0') -#endif - -#ifndef member -char *index (); -#define member(c, s) ((c) ? index ((s), (c)) : 0) -#endif - -#ifndef isident -#define isident(c) ((isletter(c) || digit(c) || c == '_')) -#endif - -#ifndef exchange -#define exchange(x, y) {int temp = x; x = y; y = temp;} -#endif - -static update_line (); -static void output_character_function (); -static delete_chars (); -static delete_chars (); -static insert_some_chars (); - -void rl_safe_insert_text(); - -#ifdef VOID_SIGHANDLER -#define sighandler void -#else -#define sighandler int -#endif - -/* This typedef is equivalant to the one for Function; it allows us - to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ -typedef sighandler SigHandler (); - -#ifdef SIGWINCH -static sighandler rl_handle_sigwinch (); -static SigHandler *old_sigwinch = (SigHandler *)NULL; -#endif - -/* If on, then readline handles signals in a way that doesn't screw. */ -#define HANDLE_SIGNALS - -#if defined (SYSV) -#ifdef HANDLE_SIGNALS -#undef HANDLE_SIGNALS -#endif -#endif - - -/* **************************************************************** */ -/* */ -/* Line editing input utility */ -/* */ -/* **************************************************************** */ - -/* A pointer to the keymap that is currently in use. - By default, it is the standard emacs keymap. */ -Keymap keymap = emacs_standard_keymap; - -#define vi_mode 0 -#define emacs_mode 1 - -/* The current style of editing. */ -int rl_editing_mode = emacs_mode; - -/* Non-zero if the previous command was a kill command. */ -static int last_command_was_kill = 0; - -/* The current value of the numeric argument specified by the user. */ -int rl_numeric_arg = 1; - -/* Non-zero if an argument was typed. */ -int rl_explicit_arg = 0; - -/* Temporary value used while generating the argument. */ -static int arg_sign = 1; - -/* Non-zero means we have been called at least once before. */ -static int rl_initialized = 0; - -/* If non-zero, this program is running in an EMACS buffer. */ -static char *running_in_emacs = (char *)NULL; - -/* The current offset in the current input line. */ -int rl_point; - -/* Mark in the current input line. */ -int rl_mark; - -/* Length of the current input line. */ -int rl_end; - -/* Make this non-zero to return the current input_line. */ -int rl_done; - -/* The last function executed by readline. */ -Function *rl_last_func = (Function *)NULL; - -/* Top level environment for readline_internal (). */ -static jmp_buf readline_top_level; - -/* The streams we interact with. */ -static FILE *in_stream, *out_stream; - -/* The names of the streams that we do input and output to. */ -FILE *rl_instream = stdin, *rl_outstream = stdout; - -/* Non-zero means echo characters as they are read. */ -int readline_echoing_p = 1; - -/* Current prompt. */ -char *rl_prompt; - -/* The number of characters read in order to type this complete command. */ -int rl_key_sequence_length = 0; - -/* 1 means the line editor is active. */ -int rl_active = 0; - -/* 1 means we are waiting for a character. */ -int rl_waiting = 0; - -/* If non-zero, then this is the address of a function to call just - before readline_internal () prints the first prompt. */ -Function *rl_startup_hook = (Function *)NULL; - -/* What we use internally. You should always refer to RL_LINE_BUFFER. */ -static char *the_line; - -/* The character that can generate an EOF. Really read from - the terminal driver... just defaulted here. */ -static int eof_char = CTRL ('D'); - -/* Non-zero makes this the next keystroke to read. */ -int rl_pending_input = 0; - -/* Pointer to a useful terminal name. */ -char *rl_terminal_name = (char *)NULL; - -/* Line buffer and maintenence. */ -char *rl_line_buffer = (char *)NULL; -static int rl_line_buffer_len = 0; -#define DEFAULT_BUFFER_SIZE 256 - - -/* **************************************************************** */ -/* */ -/* `Forward' declarations */ -/* */ -/* **************************************************************** */ - -/* Non-zero means do not parse any lines other than comments and - parser directives. */ -static unsigned char parsing_conditionalized_out = 0; - -/* Caseless strcmp (). */ -static int stricmp (), strnicmp (); - -/* Non-zero means to save keys that we dispatch on in a kbd macro. */ -static int defining_kbd_macro = 0; - - -/* **************************************************************** */ -/* */ -/* Top Level Functions */ -/* */ -/* **************************************************************** */ - -/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means - none. A return value of NULL means that EOF was encountered. */ -char * -readline (prompt) -char *prompt; -{ - int rl_prep_terminal (), rl_deprep_terminal (); - char *readline_internal (); - char *value; - - rl_prompt = prompt; - - /* If we are at EOF return a NULL string. */ - if (rl_pending_input == EOF) - { - rl_pending_input = 0; - return ((char *)NULL); - } - - rl_initialize (); - rl_prep_terminal (); - -#ifdef SIGWINCH - old_sigwinch = (SigHandler *)signal (SIGWINCH, rl_handle_sigwinch); -#endif - -#ifdef HANDLE_SIGNALS - rl_set_signals (); -#endif - - rl_active = 1; - rl_waiting = 0; - value = readline_internal (); - rl_active = 0; - rl_deprep_terminal (); - -#ifdef SIGWINCH - signal (SIGWINCH, old_sigwinch); -#endif - -#ifdef HANDLE_SIGNALS - rl_clear_signals (); -#endif - - return (value); -} - -/* Read a line of input from the global rl_instream, doing output on - the global rl_outstream. - If rl_prompt is non-null, then that is our prompt. */ -char * -readline_internal () -{ - int lastc, c, eof_found; - - in_stream = rl_instream; - out_stream = rl_outstream; - lastc = eof_found = 0; - - if (rl_startup_hook) - (*rl_startup_hook) (); - - if (!readline_echoing_p) - { - if (rl_prompt) - { - fprintf (out_stream, "%s", rl_prompt); - fflush (out_stream); - } - } - else - { - rl_on_new_line (); - rl_redisplay (); -#ifdef VI_MODE - if (rl_editing_mode == vi_mode) - rl_vi_insertion_mode (); -#endif /* VI_MODE */ - } - - while (!rl_done) - { - int lk = last_command_was_kill; - int code = setjmp (readline_top_level); - - if (code) - rl_redisplay (); - - if (!rl_pending_input) - { - /* Then initialize the argument and number of keys read. */ - rl_init_argument (); - rl_key_sequence_length = 0; - } - - c = rl_read_key (); - if (c == EOF) - { - eof_found = 1; - putc('\n',stderr); - break; - } - - /* EOF typed to a non-blank line is a <NL>. */ - if (c == EOF && rl_end) - c = NEWLINE; - - if (errflag) - { - eof_found = 1; - break; - } - - /* The character eof_char typed to blank line, and not as the - previous character is interpreted as EOF. */ - if (((c == eof_char && lastc != c) || c == EOF) && !rl_end) - { - eof_found = 1; - break; - } - - lastc = c; - rl_dispatch (c, keymap); - - /* If there was no change in last_command_was_kill, then no kill - has taken place. Note that if input is pending we are reading - a prefix command, so nothing has changed yet. */ - if (!rl_pending_input) - { - if (lk == last_command_was_kill) - last_command_was_kill = 0; - } - -#ifdef VI_MODE - /* In vi mode, when you exit insert mode, the cursor moves back - over the previous character. We explicitly check for that here. */ - if (rl_editing_mode == vi_mode && keymap == vi_movement_keymap) - rl_vi_check (); -#endif - if (!rl_done) - rl_redisplay (); - } - - /* Restore the original of this history line, iff the line that we - are editing was originally in the history, AND the line has changed. */ - { - HIST_ENTRY *entry = current_history (); - - if (entry && rl_undo_list) - { - char *temp = savestring (the_line); - rl_revert_line (); - free_history_entry (entry); - - strcpy (the_line, temp); - free (temp); - } - } - - /* At any rate, it is highly likely that this line has an undo list. Get - rid of it now. */ - if (rl_undo_list) - free_undo_list (); - - if (eof_found) - return (char *)NULL; - else - return (savestring (the_line)); -} - - -/* **************************************************************** */ -/* */ -/* Signal Handling */ -/* */ -/* **************************************************************** */ - -#ifdef SIGWINCH -static sighandler -rl_handle_sigwinch (sig, code, scp) -int sig, code; -struct sigcontext *scp; -{ - char *term = rl_terminal_name, *getenv (); - - if (readline_echoing_p) - { - if (!term) - term = getenv ("TERM"); - if (!term) - term = "dumb"; - rl_reset_terminal (term); -#ifdef NEVER - crlf (); - rl_forced_update_display (); -#endif - } - - if (old_sigwinch && - old_sigwinch != (SigHandler *)SIG_IGN && - old_sigwinch != (SigHandler *)SIG_DFL) - (*old_sigwinch)(sig, code, scp); -} -#endif /* SIGWINCH */ - -#ifdef HANDLE_SIGNALS -/* Interrupt handling. */ -static SigHandler *old_int = (SigHandler *)NULL, -*old_tstp = (SigHandler *)NULL, -*old_ttou = (SigHandler *)NULL, -*old_ttin = (SigHandler *)NULL, -*old_cont = (SigHandler *)NULL; - -/* Handle an interrupt character. */ -static sighandler -rl_signal_handler (sig, code, scp) -int sig, code; -struct sigcontext *scp; -{ - rl_prep_terminal (), rl_deprep_terminal (); - - switch (sig) - { - case SIGINT: - free_undo_list (); - rl_clear_message (); - rl_init_argument (); -#ifdef SIGWINCH - signal (SIGWINCH, old_sigwinch); -#endif - -#ifdef SIGTSTP - case SIGTSTP: - case SIGTTOU: - case SIGTTIN: -#endif - - rl_clean_up_for_exit (); - rl_deprep_terminal (); - rl_clear_signals (); - rl_pending_input = 0; - - kill (getpid (), sig); - sigsetmask (0); - - rl_prep_terminal (); - rl_set_signals (); - } -} - -rl_set_signals () -{ - old_int = (SigHandler *)signal (SIGINT, rl_signal_handler); - if (old_int == (SigHandler *)SIG_IGN) - signal (SIGINT, SIG_IGN); - -#ifdef SIGTSTP - old_tstp = (SigHandler *)signal (SIGTSTP, rl_signal_handler); - if (old_tstp == (SigHandler *)SIG_IGN) - signal (SIGTSTP, SIG_IGN); -#endif -#ifdef SIGTTOU - old_ttou = (SigHandler *)signal (SIGTTOU, rl_signal_handler); - old_ttin = (SigHandler *)signal (SIGTTIN, rl_signal_handler); - - if (old_tstp == (SigHandler *)SIG_IGN) - { - signal (SIGTTOU, SIG_IGN); - signal (SIGTTIN, SIG_IGN); - } -#endif -} - -rl_clear_signals () -{ - signal (SIGINT, old_int); - -#ifdef SIGTSTP - signal (SIGTSTP, old_tstp); -#endif -#ifdef SIGTTOU - signal (SIGTTOU, old_ttou); - signal (SIGTTIN, old_ttin); -#endif -} -#endif /* HANDLE_SIGNALS */ - - -/* **************************************************************** */ -/* */ -/* Character Input Buffering */ -/* */ -/* **************************************************************** */ - -/* If the terminal was in xoff state when we got to it, then xon_char - contains the character that is supposed to start it again. */ -static int xon_char, xoff_state; -static int pop_index = 0, push_index = 0, ibuffer_len = 511; -static unsigned char ibuffer[512]; - -/* Non-null means it is a pointer to a function to run while waiting for - character input. */ -Function *rl_event_hook = (Function *)NULL; - -#define any_typein (push_index != pop_index) - -/* Add KEY to the buffer of characters to be read. */ -rl_stuff_char (key) -int key; -{ - if (key == EOF) - { - key = NEWLINE; - rl_pending_input = EOF; - } - ibuffer[push_index++] = key; - if (push_index >= ibuffer_len) - push_index = 0; -} - -/* Return the amount of space available in the - buffer for stuffing characters. */ -int -ibuffer_space () -{ - if (pop_index > push_index) - return (pop_index - push_index); - else - return (ibuffer_len - (push_index - pop_index)); -} - -/* Get a key from the buffer of characters to be read. - Return the key in KEY. - Result is KEY if there was a key, or 0 if there wasn't. */ -int -rl_get_char (key) -int *key; -{ - if (push_index == pop_index) - return (0); - - *key = ibuffer[pop_index++]; - - if (pop_index >= ibuffer_len) - pop_index = 0; - - return (1); -} - -/* Stuff KEY into the *front* of the input buffer. - Returns non-zero if successful, zero if there is - no space left in the buffer. */ -int -rl_unget_char (key) -int key; -{ - if (ibuffer_space ()) - { - pop_index--; - if (pop_index < 0) - pop_index = ibuffer_len - 1; - ibuffer[pop_index] = key; - return (1); - } - return (0); -} - -/* If a character is available to be read, then read it - and stuff it into IBUFFER. Otherwise, just return. */ -rl_gather_tyi () -{ - int tty = fileno (in_stream); - register int tem, result = -1; - long chars_avail; - char input; - -#ifdef FIONREAD - result = ioctl (tty, FIONREAD, &chars_avail); -#endif - - if (result == -1) - { - fcntl (tty, F_SETFL, O_NDELAY); - chars_avail = read (tty, &input, 1); - fcntl (tty, F_SETFL, 0); - if (chars_avail == -1 && errno == EAGAIN) - return; - } - - tem = ibuffer_space (); - - if (chars_avail > tem) - chars_avail = tem; - - /* One cannot read all of the available input. I can only read a single - character at a time, or else programs which require input can be - thwarted. If the buffer is larger than one character, I lose. - Damn! */ - if (tem < ibuffer_len) - chars_avail = 0; - - if (result != -1) - { - while (chars_avail--) - rl_stuff_char (rl_getc (in_stream)); - } - else - { - if (chars_avail) - rl_stuff_char (input); - } -} - -/* Read a key, including pending input. */ -int -rl_read_key () -{ - int c; - - rl_key_sequence_length++; - - if (rl_pending_input) - { - c = rl_pending_input; - rl_pending_input = 0; - } - else - { - static int next_macro_key (); - - /* If input is coming from a macro, then use that. */ - if (c = next_macro_key ()) - return (c); - - /* If the user has an event function, then call it periodically. */ - if (rl_event_hook) - { - while (rl_event_hook && !rl_get_char (&c)) - { - (*rl_event_hook) (); - rl_gather_tyi (); - } - } - else - { - if (!rl_get_char (&c)) - c = rl_getc (in_stream); - } - } - -#ifdef NEVER /* This breaks supdup to 4.0.3c machines. */ -#ifdef TIOCSTART - /* Ugh. But I can't think of a better way. */ - if (xoff_state && c == xon_char) - { - ioctl (fileno (in_stream), TIOCSTART, 0); - xoff_state = 0; - return (rl_read_key ()); - } -#endif /* TIOCSTART */ -#endif - - return (c); -} - -/* I'm beginning to hate the declaration rules for various compilers. */ -static void add_macro_char (); - -/* Do the command associated with KEY in MAP. - If the associated command is really a keymap, then read - another key, and dispatch into that map. */ -rl_dispatch (key, map) -register int key; -Keymap map; -{ - - if (defining_kbd_macro) - add_macro_char (key); - - if (key > 127 && key < 256) - { - if (map[ESC].type == ISKMAP) - { - map = (Keymap)map[ESC].function; - key -= 128; - rl_dispatch (key, map); - } - else - ding (); - return; - } - - switch (map[key].type) - { - case ISFUNC: - { - Function *func = map[key].function; - - if (func != (Function *)NULL) - { - /* Special case rl_do_lowercase_version (). */ - if (func == rl_do_lowercase_version) - { - rl_dispatch (to_lower (key), map); - return; - } - - (*map[key].function)(rl_numeric_arg * arg_sign, key); - } - else - { - ding (); - return; - } - } - break; - - case ISKMAP: - if (map[key].function != (Function *)NULL) - { - int newkey; - - rl_key_sequence_length++; - newkey = rl_read_key (); - rl_dispatch (newkey, (Keymap)map[key].function); - } - else - { - ding (); - return; - } - break; - - case ISMACR: - if (map[key].function != (Function *)NULL) - { - static with_macro_input (); - char *macro = savestring ((char *)map[key].function); - - with_macro_input (macro); - return; - } - break; - } - - /* If we have input pending, then the last command was a prefix - command. Don't change the state of rl_last_func. */ - if (!rl_pending_input) - rl_last_func = map[key].function; -} - - -/* **************************************************************** */ -/* */ -/* Hacking Keyboard Macros */ -/* */ -/* **************************************************************** */ - -/* The currently executing macro string. If this is non-zero, - then it is a malloc ()'ed string where input is coming from. */ -static char *executing_macro = (char *)NULL; - -/* The offset in the above string to the next character to be read. */ -static int executing_macro_index = 0; - -/* The current macro string being built. Characters get stuffed - in here by add_macro_char (). */ -static char *current_macro = (char *)NULL; - -/* The size of the buffer allocated to current_macro. */ -static int current_macro_size = 0; - -/* The index at which characters are being added to current_macro. */ -static int current_macro_index = 0; - -/* A structure used to save nested macro strings. - It is a linked list of string/index for each saved macro. */ -struct saved_macro { - struct saved_macro *next; - char *string; - int index; -}; - -/* The list of saved macros. */ -struct saved_macro *macro_list = (struct saved_macro *)NULL; - -/* Forward declarations of static functions. Thank you C. */ -static void push_executing_macro (), pop_executing_macro (); - -/* This one has to be declared earlier in the file. */ -/* static void add_macro_char (); */ - -/* Set up to read subsequent input from STRING. - STRING is free ()'ed when we are done with it. */ -static -with_macro_input (string) -char *string; -{ - push_executing_macro (); - executing_macro = string; - executing_macro_index = 0; -} - -/* Return the next character available from a macro, or 0 if - there are no macro characters. */ -static int -next_macro_key () -{ - if (!executing_macro) - return (0); - - if (!executing_macro[executing_macro_index]) - { - pop_executing_macro (); - return (next_macro_key ()); - } - - return (executing_macro[executing_macro_index++]); -} - -/* Save the currently executing macro on a stack of saved macros. */ -static void -push_executing_macro () -{ - struct saved_macro *saver; - - saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro)); - saver->next = macro_list; - saver->index = executing_macro_index; - saver->string = executing_macro; - - macro_list = saver; -} - -/* Discard the current macro, replacing it with the one - on the top of the stack of saved macros. */ -static void -pop_executing_macro () -{ - if (executing_macro) - free (executing_macro); - - executing_macro = (char *)NULL; - executing_macro_index = 0; - - if (macro_list) - { - struct saved_macro *disposer = macro_list; - executing_macro = macro_list->string; - executing_macro_index = macro_list->index; - macro_list = macro_list->next; - free (disposer); - } -} - -/* Add a character to the macro being built. */ -static void -add_macro_char (c) -int c; -{ - if (current_macro_index + 1 >= current_macro_size) - { - if (!current_macro) - current_macro = (char *)xmalloc (current_macro_size = 25); - else - current_macro = - (char *)xrealloc (current_macro, current_macro_size += 25); - } - - current_macro[current_macro_index++] = c; - current_macro[current_macro_index] = '\0'; -} - -/* Begin defining a keyboard macro. - Keystrokes are recorded as they are executed. - End the definition with rl_end_kbd_macro (). - If a numeric argument was explicitly typed, then append this - definition to the end of the existing macro, and start by - re-executing the existing macro. */ -rl_start_kbd_macro (ignore1, ignore2) -int ignore1, ignore2; -{ - if (defining_kbd_macro) - rl_abort (); - - if (rl_explicit_arg) - { - if (current_macro) - with_macro_input (savestring (current_macro)); - } - else - current_macro_index = 0; - - defining_kbd_macro = 1; -} - -/* Stop defining a keyboard macro. - A numeric argument says to execute the macro right now, - that many times, counting the definition as the first time. */ -rl_end_kbd_macro (count, ignore) -int count, ignore; -{ - if (!defining_kbd_macro) - rl_abort (); - - current_macro_index -= (rl_key_sequence_length - 1); - current_macro[current_macro_index] = '\0'; - - defining_kbd_macro = 0; - - rl_call_last_kbd_macro (--count, 0); -} - -/* Execute the most recently defined keyboard macro. - COUNT says how many times to execute it. */ -rl_call_last_kbd_macro (count, ignore) -int count, ignore; -{ - if (!current_macro) - rl_abort (); - - while (count--) - with_macro_input (savestring (current_macro)); -} - - -/* **************************************************************** */ -/* */ -/* Initializations */ -/* */ -/* **************************************************************** */ - -/* Initliaze readline (and terminal if not already). */ -rl_initialize () -{ - extern char *rl_display_prompt; - - /* If we have never been called before, initialize the - terminal and data structures. */ - if (!rl_initialized) - { - readline_initialize_everything (); - rl_initialized++; - } - - /* Initalize the current line information. */ - rl_point = rl_end = 0; - the_line = rl_line_buffer; - the_line[0] = 0; - - /* We aren't done yet. We haven't even gotten started yet! */ - rl_done = 0; - - /* Tell the history routines what is going on. */ - start_using_history (); - - /* Make the display buffer match the state of the line. */ - { - extern char *rl_display_prompt; - extern int forced_display; - - rl_on_new_line (); - - rl_display_prompt = rl_prompt ? rl_prompt : ""; - forced_display = 1; - } - - /* No such function typed yet. */ - rl_last_func = (Function *)NULL; - - /* Parsing of key-bindings begins in an enabled state. */ - parsing_conditionalized_out = 0; -} - -/* Initialize the entire state of the world. */ -readline_initialize_everything () -{ - /* Find out if we are running in Emacs. */ - running_in_emacs = (char *)getenv ("EMACS"); - - /* Allocate data structures. */ - if (!rl_line_buffer) - rl_line_buffer = - (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); - - /* Initialize the terminal interface. */ - init_terminal_io ((char *)NULL); - - /* Bind tty characters to readline functions. */ - readline_default_bindings (); - - /* Initialize the function names. */ - rl_initialize_funmap (); - - /* Read in the init file. */ - rl_read_init_file ((char *)NULL); - - /* If the completion parser's default word break characters haven't - been set yet, then do so now. */ - { - extern char *rl_completer_word_break_characters; - extern char *rl_basic_word_break_characters; - - if (rl_completer_word_break_characters == (char *)NULL) - rl_completer_word_break_characters = rl_basic_word_break_characters; - } -} - -/* If this system allows us to look at the values of the regular - input editing characters, then bind them to their readline - equivalents. */ -readline_default_bindings () -{ - -#ifdef NEW_TTY_DRIVER - struct sgttyb ttybuff; - int tty = fileno (rl_instream); - - if (ioctl (tty, TIOCGETP, &ttybuff) != -1) - { - int erase = ttybuff.sg_erase, kill = ttybuff.sg_kill; - - if (erase != -1 && keymap[erase].type == ISFUNC) - keymap[erase].function = rl_rubout; - - if (kill != -1 && keymap[kill].type == ISFUNC) - keymap[kill].function = rl_unix_line_discard; - } - -#ifdef TIOCGLTC - { - struct ltchars lt; - - if (ioctl (tty, TIOCGLTC, <) != -1) - { - int erase = lt.t_werasc, nextc = lt.t_lnextc; - - if (erase != -1 && keymap[erase].type == ISFUNC) - keymap[erase].function = rl_unix_word_rubout; - - if (nextc != -1 && keymap[nextc].type == ISFUNC) - keymap[nextc].function = rl_quoted_insert; - } - } -#endif /* TIOCGLTC */ -#else /* not NEW_TTY_DRIVER */ - struct termio ttybuff; - int tty = fileno (rl_instream); - - if (ioctl (tty, TCGETA, &ttybuff) != -1) - { - int erase = ttybuff.c_cc[VERASE]; - int kill = ttybuff.c_cc[VKILL]l - - if (erase != -1 && keymap[(unsigned char)erase].type == ISFUNC) - keymap[(unsigned char)erase].function = rl_rubout; - - if (kill != -1 && keymap[(unsigned char)kill].type == ISFUNC) - keymap[(unsigned char)kill].function = rl_unix_line_discard; - } -#endif /* NEW_TTY_DRIVER */ -} - - -/* **************************************************************** */ -/* */ -/* Numeric Arguments */ -/* */ -/* **************************************************************** */ - -/* Handle C-u style numeric args, as well as M--, and M-digits. */ - -/* Add the current digit to the argument in progress. */ -rl_digit_argument (ignore, key) -int ignore, key; -{ - rl_pending_input = key; - rl_digit_loop (); -} - -/* What to do when you abort reading an argument. */ -rl_discard_argument () -{ - ding (); - rl_clear_message (); - rl_init_argument (); -} - -/* Create a default argument. */ -rl_init_argument () -{ - rl_numeric_arg = arg_sign = 1; - rl_explicit_arg = 0; -} - -/* C-u, universal argument. Multiply the current argument by 4. - Read a key. If the key has nothing to do with arguments, then - dispatch on it. If the key is the abort character then abort. */ -rl_universal_argument () -{ - rl_numeric_arg *= 4; - rl_digit_loop (); -} - -rl_digit_loop () -{ - int key, c; - while (1) - { - rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg); - key = c = rl_read_key (); - - if (keymap[c].type == ISFUNC && - keymap[c].function == rl_universal_argument) - { - rl_numeric_arg *= 4; - continue; - } - c = UNMETA (c); - if (numeric (c)) - { - if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); - else - rl_numeric_arg = (c - '0'); - rl_explicit_arg = 1; - } - else - { - if (c == '-' && !rl_explicit_arg) - { - rl_numeric_arg = 1; - arg_sign = -1; - } - else - { - rl_clear_message (); - rl_dispatch (key, keymap); - return; - } - } - } -} - - -/* **************************************************************** */ -/* */ -/* Display stuff */ -/* */ -/* **************************************************************** */ - -/* This is the stuff that is hard for me. I never seem to write good - display routines in C. Let's see how I do this time. */ - -/* (PWP) Well... Good for a simple line updater, but totally ignores - the problems of input lines longer than the screen width. - - update_line and the code that calls it makes a multiple line, - automatically wrapping line update. Carefull attention needs - to be paid to the vertical position variables. - - handling of terminals with autowrap on (incl. DEC braindamage) - could be improved a bit. Right now I just cheat and decrement - screenwidth by one. */ - -/* Keep two buffers; one which reflects the current contents of the - screen, and the other to draw what we think the new contents should - be. Then compare the buffers, and make whatever changes to the - screen itself that we should. Finally, make the buffer that we - just drew into be the one which reflects the current contents of the - screen, and place the cursor where it belongs. - - Commands that want to can fix the display themselves, and then let - this function know that the display has been fixed by setting the - RL_DISPLAY_FIXED variable. This is good for efficiency. */ - -/* Termcap variables: */ -extern char *term_up, *term_dc, *term_cr; -extern int screenheight, screenwidth, terminal_can_insert; - ---cut here---cut here---cut here---
pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (12/15/90)
---cut here---cut here---cut here--- -/* What YOU turn on when you have handled all redisplay yourself. */ -int rl_display_fixed = 0; - -/* The visible cursor position. If you print some text, adjust this. */ -int last_c_pos = 0; -int last_v_pos = 0; - -/* The last left edge of text that was displayed. This is used when - doing horizontal scrolling. It shifts in thirds of a screenwidth. */ -static int last_lmargin = 0; - -/* The line display buffers. One is the line currently displayed on - the screen. The other is the line about to be displayed. */ -static char *visible_line = (char *)NULL; -static char *invisible_line = (char *)NULL; - -/* Number of lines currently on screen minus 1. */ -int vis_botlin = 0; - -/* A buffer for `modeline' messages. */ -char msg_buf[128]; - -/* Non-zero forces the redisplay even if we thought it was unnecessary. */ -int forced_display = 0; - -/* The stuff that gets printed out before the actual text of the line. - This is usually pointing to rl_prompt. */ -char *rl_display_prompt = (char *)NULL; - -/* Default and initial buffer size. Can grow. */ -static int line_size = 1024; - -/* Non-zero means to always use horizontal scrolling in line display. */ -int horizontal_scroll_mode = 0; - -/* I really disagree with this, but my boss (among others) insists that we - support compilers that don't work. I don't think we are gaining by doing - so; what is the advantage in producing better code if we can't use it? */ -/* The following two declarations belong inside the - function block, not here. */ -static void move_cursor_relative (); -static void output_some_chars (); -static void output_character_function (); -static int compare_strings (); - -/* Basic redisplay algorithm. */ -rl_redisplay () -{ - register int in, out, c, linenum; - register char *line = invisible_line; - int c_pos = 0; - int inv_botlin = 0; /* Number of lines in newly drawn buffer. */ - - extern int readline_echoing_p; - - if (!readline_echoing_p) - return; - - if (!rl_display_prompt) - rl_display_prompt = ""; - - if (!invisible_line) - { - visible_line = (char *)xmalloc (line_size); - invisible_line = (char *)xmalloc (line_size); - line = invisible_line; - for (in = 0; in < line_size; in++) - { - visible_line[in] = 0; - invisible_line[in] = 1; - } - rl_on_new_line (); - } - - /* Draw the line into the buffer. */ - c_pos = -1; - - /* Mark the line as modified or not. We only do this for history - lines. No we don't. -pjf */ - out = 0; - /*if (current_history () && rl_undo_list) - { - line[out++] = '*'; - line[out] = '\0'; - }*/ - - /* If someone thought that the redisplay was handled, but the currently - visible line has a different modification state than the one about - to become visible, then correct the callers misconception. */ - if (visible_line[0] != invisible_line[0]) - rl_display_fixed = 0; - - strncpy (line + out, rl_display_prompt, strlen (rl_display_prompt)); - out += strlen (rl_display_prompt); - line[out] = '\0'; - - for (in = 0; in < rl_end; in++) - { - c = the_line[in]; - - if (out + 1 >= line_size) - { - line_size *= 2; - visible_line = (char *)xrealloc (visible_line, line_size); - invisible_line = (char *)xrealloc (invisible_line, line_size); - line = invisible_line; - } - - if (in == rl_point) - c_pos = out; - - if (c > 127) - { - line[out++] = 'M'; - line[out++] = '-'; - line[out++] = c - 128; - } -#define DISPLAY_TABS -#ifdef DISPLAY_TABS - else if (c == '\t') - { - register int newout = (out | (int)7) + 1; - while (out < newout) - line[out++] = ' '; - } -#endif - else if (c == '\n') - { - line[out++] = '\\'; - line[out++] = 'n'; - } - else if (c < 32) - { - line[out++] = '^'; - line[out++] = c + 64; - } - else - line[out++] = c; - } - line[out] = '\0'; - if (c_pos < 0) - c_pos = out; - - /* PWP: now is when things get a bit hairy. The visible and invisible - line buffers are really multiple lines, which would wrap every - (screenwidth - 1) characters. Go through each in turn, finding - the changed region and updating it. The line order is top to bottom. */ - - /* If we can move the cursor up and down, then use multiple lines, - otherwise, let long lines display in a single terminal line, and - horizontally scroll it. */ - - if (!horizontal_scroll_mode && term_up && *term_up) - { - int total_screen_chars = (screenwidth * screenheight); - - if (!rl_display_fixed || forced_display) - { - forced_display = 0; - - /* If we have more than a screenful of material to display, then - only display a screenful. We should display the last screen, - not the first. I'll fix this in a minute. */ - if (out >= total_screen_chars) - out = total_screen_chars - 1; - - /* Number of screen lines to display. */ - inv_botlin = out / screenwidth; - - /* For each line in the buffer, do the updating display. */ - for (linenum = 0; linenum <= inv_botlin; linenum++) - update_line (linenum > vis_botlin ? "" - : &visible_line[linenum * screenwidth], - &invisible_line[linenum * screenwidth], - linenum); - - /* We may have deleted some lines. If so, clear the left over - blank ones at the bottom out. */ - if (vis_botlin > inv_botlin) - { - char *tt; - for (; linenum <= vis_botlin; linenum++) - { - tt = &visible_line[linenum * screenwidth]; - move_vert (linenum); - move_cursor_relative (0, tt); - clear_to_eol ((linenum == vis_botlin)? - strlen (tt) : screenwidth); - } - } - vis_botlin = inv_botlin; - - /* Move the cursor where it should be. */ - move_vert (c_pos / screenwidth); - move_cursor_relative (c_pos % screenwidth, - &invisible_line[(c_pos / screenwidth) * screenwidth]); - } - } - else /* Do horizontal scrolling. */ - { - int lmargin; - - /* Always at top line. */ - last_v_pos = 0; - - /* If the display position of the cursor would be off the edge - of the screen, start the display of this line at an offset that - leaves the cursor on the screen. */ - if (c_pos - last_lmargin > screenwidth - 2) - lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3); - else if (c_pos - last_lmargin < 1) - lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3); - else - lmargin = last_lmargin; - - /* If the first character on the screen isn't the first character - in the display line, indicate this with a special character. */ - if (lmargin > 0) - line[lmargin] = '<'; - - if (lmargin + screenwidth < out) - line[lmargin + screenwidth - 1] = '>'; - - if (!rl_display_fixed || forced_display || lmargin != last_lmargin) - { - forced_display = 0; - update_line (&visible_line[last_lmargin], - &invisible_line[lmargin], 0); - - move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); - last_lmargin = lmargin; - } - } - fflush (out_stream); - - /* Swap visible and non-visible lines. */ - { - char *temp = visible_line; - visible_line = invisible_line; - invisible_line = temp; - rl_display_fixed = 0; - } -} - -/* PWP: update_line() is based on finding the middle difference of each - line on the screen; vis: - - /old first difference - /beginning of line | /old last same /old EOL - v v v v -old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as -new: eddie> Oh, my little buggy says to me, as lurgid as - ^ ^ ^ ^ - \beginning of line | \new last same \new end of line - \new first difference - - All are character pointers for the sake of speed. Special cases for - no differences, as well as for end of line additions must be handeled. - - Could be made even smarter, but this works well enough */ -static -update_line (old, new, current_line) -register char *old, *new; -int current_line; -{ - register char *ofd, *ols, *oe, *nfd, *nls, *ne; - int lendiff, wsatend; - - /* Find first difference. */ - for (ofd = old, nfd = new; - (ofd - old < screenwidth) && *ofd && (*ofd == *nfd); - ofd++, nfd++) - ; - - /* Move to the end of the screen line. */ - for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++); - for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++); - - /* If no difference, continue to next line. */ - if (ofd == oe && nfd == ne) - return; - - wsatend = 1; /* flag for trailing whitespace */ - ols = oe - 1; /* find last same */ - nls = ne - 1; - while ((*ols == *nls) && (ols > ofd) && (nls > nfd)) - { - if (*ols != ' ') - wsatend = 0; - ols--; - nls--; - } - - if (wsatend) - { - ols = oe; - nls = ne; - } - else if (*ols != *nls) - { - if (*ols) /* don't step past the NUL */ - ols++; - if (*nls) - nls++; - } - - move_vert (current_line); - move_cursor_relative (ofd - old, old); - - /* if (len (new) > len (old)) */ - lendiff = (nls - nfd) - (ols - ofd); - - /* Insert (diff(len(old),len(new)) ch */ - if (lendiff > 0) - { - if (terminal_can_insert) - { - extern char *term_IC; - - /* Sometimes it is cheaper to print the characters rather than - use the terminal's capabilities. */ - if ((2 * (ne - nfd)) < lendiff && !term_IC) - { - output_some_chars (nfd, (ne - nfd)); - last_c_pos += (ne - nfd); - } - else - { - if (*ols) - { - insert_some_chars (nfd, lendiff); - last_c_pos += lendiff; - } - else - { - /* At the end of a line the characters do not have to - be "inserted". They can just be placed on the screen. */ - output_some_chars (nfd, lendiff); - last_c_pos += lendiff; - } - /* Copy (new) chars to screen from first diff to last match. */ - if (((nls - nfd) - lendiff) > 0) - { - output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff)); - last_c_pos += ((nls - nfd) - lendiff); - } - } - } - else - { /* cannot insert chars, write to EOL */ - output_some_chars (nfd, (ne - nfd)); - last_c_pos += (ne - nfd); - } - } - else /* Delete characters from line. */ - { - /* If possible and inexpensive to use terminal deletion, then do so. */ - if (term_dc && (2 * (ne - nfd)) >= (-lendiff)) - { - if (lendiff) - delete_chars (-lendiff); /* delete (diff) characters */ - - /* Copy (new) chars to screen from first diff to last match */ - if ((nls - nfd) > 0) - { - output_some_chars (nfd, (nls - nfd)); - last_c_pos += (nls - nfd); - } - } - /* Otherwise, print over the existing material. */ - else - { - output_some_chars (nfd, (ne - nfd)); - last_c_pos += (ne - nfd); - clear_to_eol ((oe - old) - (ne - new)); - } - } -} - -/* (PWP) tell the update routines that we have moved onto a - new (empty) line. */ -rl_on_new_line () -{ - if (visible_line) - visible_line[0] = '\0'; - - last_c_pos = last_v_pos = 0; - vis_botlin = last_lmargin = 0; -} - -/* Actually update the display, period. */ -rl_forced_update_display () -{ - if (visible_line) - { - register char *temp = visible_line; - - while (*temp) *temp++ = '\0'; - } - rl_on_new_line (); - forced_display++; - rl_redisplay (); -} - -/* Move the cursor from last_c_pos to NEW, which are buffer indices. - DATA is the contents of the screen line of interest; i.e., where - the movement is being done. */ -static void -move_cursor_relative (new, data) -int new; -char *data; -{ - register int i; - - /* It may be faster to output a CR, and then move forwards instead - of moving backwards. */ - if (new + 1 < last_c_pos - new) - { - tputs (term_cr, 1, output_character_function); - last_c_pos = 0; - } - - if (last_c_pos == new) return; - - if (last_c_pos < new) - { - /* Move the cursor forward. We do it by printing the command - to move the cursor forward if there is one, else print that - portion of the output buffer again. Which is cheaper? */ - - /* The above comment is left here for posterity. It is faster - to print one character (non-control) than to print a control - sequence telling the terminal to move forward one character. - That kind of control is for people who don't know what the - data is underneath the cursor. */ -#ifdef HACK_TERMCAP_MOTION - extern char *term_forward_char; - - if (term_forward_char) - for (i = last_c_pos; i < new; i++) - tputs (term_forward_char, 1, output_character_function); - else - for (i = last_c_pos; i < new; i++) - putc (data[i], out_stream); -#else - for (i = last_c_pos; i < new; i++) - putc (data[i], out_stream); -#endif /* HACK_TERMCAP_MOTION */ - } - else - backspace (last_c_pos - new); - last_c_pos = new; -} - -/* PWP: move the cursor up or down. */ -move_vert (to) -int to; -{ - void output_character_function (); - register int delta, i; - - if (last_v_pos == to) return; - - if (to > screenheight) - return; - - if ((delta = to - last_v_pos) > 0) - { - for (i = 0; i < delta; i++) - putc ('\n', out_stream); - tputs (term_cr, 1, output_character_function); - last_c_pos = 0; /* because crlf() will do \r\n */ - } - else - { /* delta < 0 */ - if (term_up && *term_up) - for (i = 0; i < -delta; i++) - tputs (term_up, 1, output_character_function); - } - last_v_pos = to; /* now to is here */ -} - -/* Physically print C on out_stream. This is for functions which know - how to optimize the display. */ -rl_show_char (c) -int c; -{ - if (c > 127) - { - fprintf (out_stream, "M-"); - c -= 128; - } - -#ifdef DISPLAY_TABS - if (c < 32 && c != '\t') -#else - if (c < 32) -#endif - { - - c += 64; - } - - putc (c, out_stream); - fflush (out_stream); -} - -#ifdef DISPLAY_TABS -int -rl_character_len (c, pos) -register int c, pos; -{ - if (c < ' ' || c > 126) - { - if (c == '\t') - return (((pos | (int)7) + 1) - pos); - else - return (3); - } - else - return (1); -} -#else -int -rl_character_len (c) -int c; -{ - if (c < ' ' || c > 126) - return (3); - else - return (1); -} -#endif /* DISPLAY_TAB */ - -/* How to print things in the "echo-area". The prompt is treated as a - mini-modeline. */ -rl_message (string, arg1, arg2) -char *string; -{ - sprintf (msg_buf, string, arg1, arg2); - rl_display_prompt = msg_buf; - rl_redisplay (); -} - -/* How to clear things from the "echo-area". */ -rl_clear_message () -{ - rl_display_prompt = rl_prompt; - rl_redisplay (); -} - -/* **************************************************************** */ -/* */ -/* Terminal and Termcap */ -/* */ -/* **************************************************************** */ - -static char *term_buffer = (char *)NULL; -static char *term_string_buffer = (char *)NULL; - -/* Non-zero means this terminal can't really do anything. */ -int dumb_term = 0; - -char PC; -char *BC, *UP; - -/* Some strings to control terminal actions. These are output by tputs (). */ -char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace; - -int screenwidth, screenheight; - -/* Non-zero if we determine that the terminal can do character insertion. */ -int terminal_can_insert = 0; - -/* How to insert characters. */ -char *term_im, *term_ei, *term_ic, *term_ip, *term_IC; - -/* How to delete characters. */ -char *term_dc, *term_DC; - -#ifdef HACK_TERMCAP_MOTION -char *term_forward_char; -#endif /* HACK_TERMCAP_MOTION */ - -/* How to go up a line. */ -char *term_up; - -/* Re-initialize the terminal considering that the TERM/TERMCAP variable - has changed. */ -rl_reset_terminal (terminal_name) -char *terminal_name; -{ - init_terminal_io (terminal_name); -} - -init_terminal_io (terminal_name) -char *terminal_name; -{ - char *term = (terminal_name? terminal_name : (char *)getenv ("TERM")); - char *tgetstr (), *buffer; - - - if (!term_string_buffer) - term_string_buffer = (char *)xmalloc (2048); - - if (!term_buffer) - term_buffer = (char *)xmalloc (2048); - - buffer = term_string_buffer; - - term_clrpag = term_cr = term_clreol = (char *)NULL; - - if (!term) - term = "dumb"; - - if (tgetent (term_buffer, term) < 0) - { - dumb_term = 1; - return; - } - - BC = tgetstr ("pc", &buffer); - PC = buffer ? *buffer : 0; - - term_backspace = tgetstr ("le", &buffer); - - term_cr = tgetstr ("cr", &buffer); - term_clreol = tgetstr ("ce", &buffer); - term_clrpag = tgetstr ("cl", &buffer); - - if (!term_cr) - term_cr = "\r"; - -#ifdef HACK_TERMCAP_MOTION - term_forward_char = tgetstr ("nd", &buffer); -#endif /* HACK_TERMCAP_MOTION */ - - screenwidth = tgetnum ("co"); - if (screenwidth <= 0) - screenwidth = 80; - screenwidth--; /* PWP: avoid autowrap bugs */ - - screenheight = tgetnum ("li"); - if (screenheight <= 0) - screenheight = 24; - - term_im = tgetstr ("im", &buffer); - term_ei = tgetstr ("ei", &buffer); - term_IC = tgetstr ("IC", &buffer); - term_ic = tgetstr ("ic", &buffer); - - /* "An application program can assume that the terminal can do - character insertion if *any one of* the capabilities `IC', - `im', `ic' or `ip' is provided." But we can't do anything if - only `ip' is provided, so... */ - terminal_can_insert = (term_IC || term_im || term_ic); - - term_up = tgetstr ("up", &buffer); - term_dc = tgetstr ("dc", &buffer); - term_DC = tgetstr ("DC", &buffer); -} - -/* A function for the use of tputs () */ -static void -output_character_function (c) -int c; -{ - putc (c, out_stream); -} - -/* Write COUNT characters from STRING to the output stream. */ -static void -output_some_chars (string, count) -char *string; -int count; -{ - fwrite (string, 1, count, out_stream); -} - - -/* Delete COUNT characters from the display line. */ -static -delete_chars (count) -int count; -{ - if (count > screenwidth) - return; - - if (term_DC && *term_DC) - { - char *tgoto (), *buffer; - buffer = tgoto (term_DC, 0, count); - tputs (buffer, 1, output_character_function); - } - else - { - if (term_dc && *term_dc) - while (count--) - tputs (term_dc, 1, output_character_function); - } -} - -/* Insert COUNT character from STRING to the output stream. */ -static -insert_some_chars (string, count) -char *string; -int count; -{ - /* If IC is defined, then we do not have to "enter" insert mode. */ - if (term_IC) - { - char *tgoto (), *buffer; - buffer = tgoto (term_IC, 0, count); - tputs (buffer, 1, output_character_function); - output_some_chars (string, count); - } - else - { - register int i; - - /* If we have to turn on insert-mode, then do so. */ - if (term_im && *term_im) - tputs (term_im, 1, output_character_function); - - /* If there is a special command for inserting characters, then - use that first to open up the space. */ - if (term_ic && *term_ic) - { - for (i = count; i--; ) - tputs (term_ic, 1, output_character_function); - } - - /* Print the text. */ - output_some_chars (string, count); - - /* If there is a string to turn off insert mode, we had best use - it now. */ - if (term_ei && *term_ei) - tputs (term_ei, 1, output_character_function); - } -} - -/* Move the cursor back. */ -backspace (count) -int count; -{ - register int i; - - if (term_backspace) - for (i = 0; i < count; i++) - tputs (term_backspace, 1, output_character_function); - else - for (i = 0; i < count; i++) - putc ('\b', out_stream); -} - -/* Move to the start of the next line. */ -crlf () -{ - tputs (term_cr, 1, output_character_function); - putc ('\n', out_stream); -} - -/* Clear to the end of the line. COUNT is the minimum - number of character spaces to clear, */ -clear_to_eol (count) -int count; -{ - if (term_clreol) - { - tputs (term_clreol, 1, output_character_function); - } - else - { - register int i; - - /* Do one more character space. */ - count++; - - for (i = 0; i < count; i++) - putc (' ', out_stream); - - backspace (count); - } -} - - -/* **************************************************************** */ -/* */ -/* Saving and Restoring the TTY */ -/* */ -/* **************************************************************** */ - -#ifdef NEW_TTY_DRIVER - -/* We use this to get and set the tty_flags. */ -static struct sgttyb the_ttybuff; - -/* Put the terminal in CBREAK mode so that we can detect key presses. */ -rl_prep_terminal () -{ -int original_tty_flags,local_mode_flags; - - static int firsttime = 1; - int tty = fileno (rl_instream); - - /* We always get the latest tty values. Maybe stty changed them. */ - ioctl (tty, TIOCGETP, &the_ttybuff); - original_tty_flags = ((the_ttybuff.sg_flags)&~(O_CBREAK|O_RAW))|O_ECHO; - - readline_echoing_p = (original_tty_flags & ECHO); - - /* If this terminal doesn't care how the 8th bit is used, - then we can use it for the meta-key. - We check by seeing if BOTH odd and even parity are allowed. */ - if ((the_ttybuff.sg_flags & ODDP) && (the_ttybuff.sg_flags & EVENP)) - { -#ifdef PASS8 - the_ttybuff.sg_flags |= PASS8; -#endif - } - - /* Hack on local mode flags if we can. */ -#if defined (TIOCLGET) && defined (LPASS8) - { - int flags; - - ioctl (tty, TIOCLGET, &local_mode_flags); - flags = local_mode_flags | LPASS8; - ioctl (tty, TIOCLSET, &flags); - } -#endif - -#ifdef TIOCGETC - { - struct tchars temp; - - ioctl (tty, TIOCGETC, &temp); - - /* Get rid of C-s and C-q. - We remember the value of startc (C-q) so that if the terminal is in - xoff state, the user can xon it by pressing that character. */ - xon_char = temp.t_startc; - temp.t_stopc = -1; - temp.t_startc = -1; - - /* If there is an XON character, bind it to restart the output. */ - if (xon_char != -1) - rl_bind_key (xon_char, rl_restart_output); - - /* If there is an EOF char, bind eof_char to it. */ - if (temp.t_eofc != -1) - eof_char = temp.t_eofc; - -#ifdef NEVER - /* Get rid of C-\ and C-c. */ - temp.t_intrc = temp.t_quitc = -1; -#endif - - ioctl (tty, TIOCSETC, &temp); - } -#endif /* TIOCGETC */ - -#ifdef TIOCGLTC - { - struct ltchars temp; - - ioctl (tty, TIOCGLTC, &temp); - - /* Make the interrupt keys go away. Just enough to make people happy. */ - temp.t_dsuspc = -1; /* C-y */ - temp.t_lnextc = -1; /* C-v */ - - ioctl (tty, TIOCSLTC, &temp); - } -#endif /* TIOCGLTC */ - - the_ttybuff.sg_flags &= ~ECHO; - the_ttybuff.sg_flags |= CBREAK; - ioctl (tty, TIOCSETN, &the_ttybuff); -} - - -#else /* !defined (NEW_TTY_DRIVER) */ - -#if !defined (VMIN) -#define VMIN VEOF -#endif - -#if !defined (VTIME) -#define VTIME VEOL -#endif - -static struct termio otio; - -rl_prep_terminal () -{ - int tty = fileno (rl_instream); - struct termio tio; - - ioctl (tty, TCGETA, &tio); - ioctl (tty, TCGETA, &otio); - - readline_echoing_p = (tio.c_lflag & ECHO); - - tio.c_lflag &= ~(ICANON|ECHO); - tio.c_iflag &= ~(IXON|IXOFF|IXANY|ISTRIP|INPCK); - -#if !defined (HANDLE_SIGNALS) - tio.c_lflag &= ~ISIG; -#endif - - tio.c_cc[VMIN] = 1; - tio.c_cc[VTIME] = 0; - ioctl (tty, TCSETAW, &tio); - ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ -} - -#endif /* NEW_TTY_DRIVER */ - -/* Restore the terminal to its original state. */ -rl_deprep_terminal () -{ - rl_active = 0; - restoretty(); -} - - -/* **************************************************************** */ -/* */ -/* Utility Functions */ -/* */ -/* **************************************************************** */ - -/* Return 0 if C is not a member of the class of characters that belong - in words, or 1 if it is. */ - -int allow_pathname_alphabetic_chars = 0; -char *pathname_alphabetic_chars = "/-_=~.#$"; - -int -alphabetic (c) -int c; -{ - char *rindex (); - if (pure_alphabetic (c) || (numeric (c))) - return (1); - - if (allow_pathname_alphabetic_chars) - return ((int)rindex (pathname_alphabetic_chars, c)); - else - return (0); -} - -/* Return non-zero if C is a numeric character. */ -int -numeric (c) -int c; -{ - return (c >= '0' && c <= '9'); -} - -/* Ring the terminal bell. */ -int -ding () -{ -extern int opts[128]; - - if (readline_echoing_p && opts['B'] == 0) - { - fprintf (stderr, "\007"); - fflush (stderr); - } - return (-1); -} - -/* How to abort things. */ -rl_abort () -{ - ding (); - rl_clear_message (); - rl_init_argument (); - rl_pending_input = 0; - - defining_kbd_macro = 0; - while (executing_macro) - pop_executing_macro (); - - longjmp (readline_top_level, 1); -} - -/* Return a copy of the string between FROM and TO. - FROM is inclusive, TO is not. */ -static char * -rl_copy (from, to) -int from, to; -{ - register int length; - char *copy; - - /* Fix it if the caller is confused. */ - if (from > to) { - int t = from; - from = to; - to = t; - } - - length = to - from; - copy = (char *)xmalloc (1 + length); - strncpy (copy, the_line + from, length); - copy[length] = '\0'; - return (copy); -} - - -/* **************************************************************** */ -/* */ -/* Insert and Delete */ -/* */ -/* **************************************************************** */ - - -/* Insert a string of text into the line at point. This is the only - way that you should do insertion. rl_insert () calls this - function. */ -rl_insert_text (string) -char *string; -{ - extern int doing_an_undo; - register int i, l = strlen (string); - while (rl_end + l >= rl_line_buffer_len) - { - rl_line_buffer = - (char *)xrealloc (rl_line_buffer, - rl_line_buffer_len += DEFAULT_BUFFER_SIZE); - the_line = rl_line_buffer; - } - - for (i = rl_end; i >= rl_point; i--) - the_line[i + l] = the_line[i]; - strncpy (the_line + rl_point, string, l); - - /* Remember how to undo this if we aren't undoing something. */ - if (!doing_an_undo) - { - /* If possible and desirable, concatenate the undos. */ - if ((strlen (string) == 1) && - rl_undo_list && - (rl_undo_list->what == UNDO_INSERT) && - (rl_undo_list->end == rl_point) && - (rl_undo_list->end - rl_undo_list->start < 20)) - rl_undo_list->end++; - else - rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL); - } - rl_point += l; - rl_end += l; - the_line[rl_end] = '\0'; -} - -/* Delete the string between FROM and TO. FROM is - inclusive, TO is not. */ -rl_delete_text (from, to) -int from, to; -{ - extern int doing_an_undo; - register char *text; - - /* Fix it if the caller is confused. */ - if (from > to) { - int t = from; - from = to; - to = t; - } - text = rl_copy (from, to); - strncpy (the_line + from, the_line + to, rl_end - to); - - /* Remember how to undo this delete. */ - if (!doing_an_undo) - rl_add_undo (UNDO_DELETE, from, to, text); - else - free (text); - - rl_end -= (to - from); - the_line[rl_end] = '\0'; -} - - -/* **************************************************************** */ -/* */ -/* Readline character functions */ -/* */ -/* **************************************************************** */ - -/* This is not a gap editor, just a stupid line input routine. No hair - is involved in writing any of the functions, and none should be. */ - -/* Note that: - - rl_end is the place in the string that we would place '\0'; - i.e., it is always safe to place '\0' there. - - rl_point is the place in the string where the cursor is. Sometimes - this is the same as rl_end. - - Any command that is called interactively receives two arguments. - The first is a count: the numeric arg pased to this command. - The second is the key which invoked this command. -*/ - - -/* **************************************************************** */ -/* */ -/* Movement Commands */ -/* */ -/* **************************************************************** */ - -/* Note that if you `optimize' the display for these functions, you cannot - use said functions in other functions which do not do optimizing display. - I.e., you will have to update the data base for rl_redisplay, and you - might as well let rl_redisplay do that job. */ - -/* Move forward COUNT characters. */ -rl_forward (count) -int count; -{ - if (count < 0) - rl_backward (-count); - else - while (count) - { -#ifdef VI_MODE - if (rl_point == (rl_end - (rl_editing_mode == vi_mode))) -#else - if (rl_point == rl_end) -#endif - { - ding (); - return; - } - else - rl_point++; - --count; - } -} - -/* Move backward COUNT characters. */ -rl_backward (count) -int count; -{ - if (count < 0) - rl_forward (-count); - else - while (count) - { - if (!rl_point) - { - ding (); - return; - } - else - --rl_point; - --count; - } -} - -/* Move to the beginning of the line. */ -rl_beg_of_line () -{ - rl_point = 0; -} - -/* Move to the end of the line. */ -rl_end_of_line () -{ - rl_point = rl_end; -} - -/* Move forward a word. We do what Emacs does. */ -rl_forward_word (count) -int count; -{ - int c; - - if (count < 0) - { - rl_backward_word (-count); - return; - } - - while (count) - { - if (rl_point == rl_end) - return; - - /* If we are not in a word, move forward until we are in one. - Then, move forward until we hit a non-alphabetic character. */ - c = the_line[rl_point]; - if (!alphabetic (c)) - { - while (++rl_point < rl_end) - { - c = the_line[rl_point]; - if (alphabetic (c)) break; - } - } - if (rl_point == rl_end) return; - while (++rl_point < rl_end) - { - c = the_line[rl_point]; - if (!alphabetic (c)) break; - } - --count; - } -} - -/* Move backward a word. We do what Emacs does. */ -rl_backward_word (count) -int count; -{ - int c; - - if (count < 0) - { - rl_forward_word (-count); - return; - } - - while (count) - { - if (!rl_point) - return; - - /* Like rl_forward_word (), except that we look at the characters - just before point. */ - - c = the_line[rl_point - 1]; - if (!alphabetic (c)) - { - while (--rl_point) - { - c = the_line[rl_point - 1]; - if (alphabetic (c)) break; - } - } - - while (rl_point) - { - c = the_line[rl_point - 1]; - if (!alphabetic (c)) - break; - else --rl_point; - } - --count; - } -} - -/* Clear the current line. Numeric argument to C-l does this. */ -rl_refresh_line () -{ - int curr_line = last_c_pos / screenwidth; - extern char *term_clreol; - - move_vert(curr_line); - move_cursor_relative (0, the_line); /* XXX is this right */ - - if (term_clreol) - tputs (term_clreol, 1, output_character_function); - - rl_forced_update_display (); - rl_display_fixed = 1; -} - -/* C-l typed to a line without quoting clears the screen, and then reprints - the prompt and the current input line. Given a numeric arg, redraw only - the current line. */ -rl_clear_screen () -{ - extern char *term_clrpag; - - if (rl_explicit_arg) - { - rl_refresh_line (); - return; - } - - if (term_clrpag) - tputs (term_clrpag, 1, output_character_function); - else - crlf (); - - rl_forced_update_display (); - rl_display_fixed = 1; -} - - -/* **************************************************************** */ -/* */ -/* Text commands */ -/* */ -/* **************************************************************** */ - -/* Insert the character C at the current location, moving point forward. */ -rl_insert (count, c) -int count, c; -{ - register int i; - char *string; - - if (count <= 0) - return; - - /* If we can optimize, then do it. But don't let people crash - readline because of extra large arguments. */ - if (count > 1 && count < 1024) - { - string = (char *)alloca (1 + count); - - for (i = 0; i < count; i++) - string[i] = c; - - string[i] = '\0'; - rl_insert_text (string); - return; - } - - if (count > 1024) - { - int decreaser; - - string = (char *)alloca (1024 + 1); - - for (i = 0; i < 1024; i++) - string[i] = c; - - while (count) - { - decreaser = (count > 1024 ? 1024 : count); - string[decreaser] = '\0'; - rl_insert_text (string); - count -= decreaser; - } - return; - } - - /* We are inserting a single character. - If there is pending input, then make a string of all of the - pending characters that are bound to rl_insert, and insert - them all. */ - if (any_typein) - { - int key = 0, t; - - i = 0; - string = (char *)alloca (ibuffer_len + 1); - string[i++] = c; - - while ((t = rl_get_char (&key)) && - (keymap[key].type == ISFUNC && - keymap[key].function == rl_insert)) - string[i++] = key; - - if (t) - rl_unget_char (key); - - string[i] = '\0'; - rl_insert_text (string); - return; - } - else - { - /* Inserting a single character. */ - string = (char *)alloca (2); - - string[1] = '\0'; - string[0] = c; - rl_insert_text (string); - } -} - -/* Insert the next typed character verbatim. */ -rl_quoted_insert (count) -int count; -{ - int c = rl_read_key (); - rl_insert (count, c); -} - -/* Insert a tab character. */ -rl_tab_insert (count) -int count; -{ - rl_insert (count, '\t'); -} - -/* What to do when a NEWLINE is pressed. We accept the whole line. - KEY is the key that invoked this command. I guess it could have - meaning in the future. */ -rl_newline (count, key) -int count, key; -{ - - rl_done = 1; -#ifdef VI_MODE - { - extern int vi_doing_insert; - if (vi_doing_insert) - { - rl_end_undo_group (); - vi_doing_insert = 0; - } - } -#endif /* VI_MODE */ - - if (readline_echoing_p) - { - move_vert (vis_botlin); - vis_botlin = 0; - crlf (); - fflush (out_stream); - rl_display_fixed++; - } - rl_end_of_line(); - rl_insert(1,'\n'); /* added by pjf */ -} - -rl_clean_up_for_exit () -{ - if (readline_echoing_p) - { - move_vert (vis_botlin); - vis_botlin = 0; - fflush (out_stream); - rl_restart_output (); - } -} - -/* What to do for some uppercase characters, like meta characters, - and some characters appearing in emacs_ctlx_keymap. This function - is just a stub, you bind keys to it and the code in rl_dispatch () - is special cased. */ -rl_do_lowercase_version (ignore1, ignore2) -int ignore1, ignore2; -{ -} - -/* Rubout the character behind point. */ -rl_rubout (count) -int count; -{ - if (count < 0) - { - rl_delete (-count); - return; - } - - if (!rl_point) - { - ding (); - return; - } - - if (count > 1) - { - int orig_point = rl_point; - rl_backward (count); - rl_kill_text (orig_point, rl_point); - } - else - { - int c = the_line[--rl_point]; - rl_delete_text (rl_point, rl_point + 1); - - if (rl_point == rl_end && alphabetic (c) && last_c_pos) - { - backspace (1); - putc (' ', out_stream); - backspace (1); - last_c_pos--; - rl_display_fixed++; - } - } -} - -/* Delete the character under the cursor. Given a numeric argument, - kill that many characters instead. */ -rl_delete (count, invoking_key) -int count, invoking_key; -{ - if (count < 0) - { - rl_rubout (-count); - return; - } - - if (rl_point == rl_end) - { - ding (); - return; - } - - if (count > 1) - { - int orig_point = rl_point; - rl_forward (count); - rl_kill_text (orig_point, rl_point); - rl_point = orig_point; - } - else - rl_delete_text (rl_point, rl_point + 1); -} - - -/* **************************************************************** */ -/* */ -/* Kill commands */ -/* */ -/* **************************************************************** */ - -/* The next two functions mimic unix line editing behaviour, except they - save the deleted text on the kill ring. This is safer than not saving - it, and since we have a ring, nobody should get screwed. */ - -/* This does what C-w does in Unix. We can't prevent people from - using behaviour that they expect. */ -rl_unix_word_rubout () -{ - if (!rl_point) ding (); - else { - int orig_point = rl_point; - while (rl_point && whitespace (the_line[rl_point - 1])) - rl_point--; - while (rl_point && !whitespace (the_line[rl_point - 1])) - rl_point--; - rl_kill_text (rl_point, orig_point); - } -} - -/* Here is C-u doing what Unix does. You don't *have* to use these - key-bindings. We have a choice of killing the entire line, or - killing from where we are to the start of the line. We choose the - latter, because if you are a Unix weenie, then you haven't backspaced - into the line at all, and if you aren't, then you know what you are - doing. (pjf: I disagree*/ -rl_unix_line_discard () -{ - rl_end_of_line(); - if (!rl_point) ding (); - else { - rl_kill_text (rl_point, 0); - rl_point = 0; - } -} - - - -/* **************************************************************** */ -/* */ -/* Commands For Typos */ -/* */ -/* **************************************************************** */ - -/* Random and interesting things in here. */ - - -/* **************************************************************** */ -/* */ -/* Changing Case */ -/* */ -/* **************************************************************** */ - -/* The three kinds of things that we know how to do. */ -#define UpCase 1 -#define DownCase 2 -#define CapCase 3 - -/* Uppercase the word at point. */ -rl_upcase_word (count) -int count; -{ - rl_change_case (count, UpCase); -} - -/* Lowercase the word at point. */ -rl_downcase_word (count) -int count; -{ - rl_change_case (count, DownCase); -} - -/* Upcase the first letter, downcase the rest. */ -rl_capitalize_word (count) -int count; -{ - rl_change_case (count, CapCase); -} - -/* The meaty function. - Change the case of COUNT words, performing OP on them. - OP is one of UpCase, DownCase, or CapCase. - If a negative argument is given, leave point where it started, - otherwise, leave it where it moves to. */ -rl_change_case (count, op) -int count, op; -{ - register int start = rl_point, end; - int state = 0; - - rl_forward_word (count); - end = rl_point; - - if (count < 0) - { - int temp = start; - start = end; - end = temp; - } - - /* We are going to modify some text, so let's prepare to undo it. */ - rl_modifying (start, end); - - for (; start < end; start++) - { - switch (op) - { - case UpCase: - the_line[start] = to_upper (the_line[start]); - break; - - case DownCase: - the_line[start] = to_lower (the_line[start]); - break; - - case CapCase: - if (state == 0) - { - the_line[start] = to_upper (the_line[start]); - state = 1; - } - else - { - the_line[start] = to_lower (the_line[start]); - } - if (!pure_alphabetic (the_line[start])) - state = 0; - break; - - default: - abort (); - } - } - rl_point = end; -} - -/* **************************************************************** */ -/* */ -/* Transposition */ -/* */ -/* **************************************************************** */ - -/* Transpose the words at point. */ -rl_transpose_words (count) -int count; -{ - char *word1, *word2; - int w1_beg, w1_end, w2_beg, w2_end; - int orig_point = rl_point; - - if (!count) return; - - /* Find the two words. */ - rl_forward_word (count); - w2_end = rl_point; - rl_backward_word (1); - w2_beg = rl_point; - rl_backward_word (count); - w1_beg = rl_point; - rl_forward_word (1); - w1_end = rl_point; - - /* Do some check to make sure that there really are two words. */ - if ((w1_beg == w2_beg) || (w2_beg < w1_end)) - { - ding (); - rl_point = orig_point; - return; - } - - /* Get the text of the words. */ - word1 = rl_copy (w1_beg, w1_end); - word2 = rl_copy (w2_beg, w2_end); - - /* We are about to do many insertions and deletions. Remember them - as one operation. */ - rl_begin_undo_group (); - - /* Do the stuff at word2 first, so that we don't have to worry - about word1 moving. */ - rl_point = w2_beg; - rl_delete_text (w2_beg, w2_end); - rl_insert_text (word1); - - rl_point = w1_beg; - rl_delete_text (w1_beg, w1_end); - rl_insert_text (word2); - - /* This is exactly correct since the text before this point has not - changed in length. */ - rl_point = w2_end; - - /* I think that does it. */ - rl_end_undo_group (); - free (word1); - free (word2); -} - -/* Transpose the characters at point. If point is at the end of the line, - then transpose the characters before point. */ -rl_transpose_chars (count) -int count; -{ - if (!count) - return; - - if (!rl_point || rl_end < 2) { - ding (); - return; - } - - while (count) { - if (rl_point == rl_end) { - int t = the_line[rl_point - 1]; - the_line[rl_point - 1] = the_line[rl_point - 2]; - the_line[rl_point - 2] = t; - } else { - int t = the_line[rl_point]; - the_line[rl_point] = the_line[rl_point - 1]; - the_line[rl_point - 1] = t; - if (count < 0 && rl_point) - rl_point--; - else - rl_point++; - } - if (count < 0) - count++; - else - count--; - } -} - - -/* **************************************************************** */ -/* */ -/* Bogus Flow Control */ -/* */ -/* **************************************************************** */ - -rl_restart_output (count, key) -int count, key; -{ - int fildes = fileno (stdin); -#ifdef TIOCSTART - ioctl (fildes, TIOCSTART, 0); -#endif /* TIOCSTART */ -} - -/* **************************************************************** */ -/* */ -/* Completion matching, from readline's point of view. */ -/* */ -/* **************************************************************** */ - -/* Pointer to the generator function for completion_matches (). - NULL means to use filename_entry_function (), the default filename - completer. */ -Function *rl_completion_entry_function = (Function *)NULL; - -/* Pointer to alternative function to create matches. - Function is called with TEXT, START, and END. - START and END are indices in RL_LINE_BUFFER saying what the boundaries - of TEXT are. - If this function exists and returns NULL then call the value of - rl_completion_entry_function to try to match, otherwise use the - array of strings returned. */ -Function *rl_attempted_completion_function = (Function *)NULL; - -/* Complete the word at or before point. You have supplied the function - that does the initial simple matching selection algorithm (see - completion_matches ()). The default is to do filename completion. */ -rl_complete (ignore, invoking_key) -int ignore, invoking_key; -{ - rl_complete_internal (TAB); -} - -/* List the possible completions. See description of rl_complete (). */ -rl_possible_completions () -{ - rl_complete_internal ('?'); -} - -/* The user must press "y" or "n". Non-zero return means "y" pressed. */ -get_y_or_n () -{ - int c; -loop: - c = rl_read_key (); - if (c == 'y' || c == 'Y') return (1); - if (c == 'n' || c == 'N') return (0); - if (c == ABORT_CHAR) rl_abort (); - ding (); - goto loop; -} - -/* Up to this many items will be displayed in response to a - possible-completions call. After that, we ask the user if - she is sure she wants to see them all. */ -int rl_completion_query_items = 100; - -/* The basic list of characters that signal a break between words for the - completer routine. The contents of this variable is what breaks words - in the shell, i.e. " \t\n\"\\'`@><" */ -char *rl_basic_word_break_characters = " \t\n@><;("; - -/* The list of characters that signal a break between words for - rl_complete_internal. The default list is the contents of - rl_basic_word_break_characters. */ -char *rl_completer_word_break_characters = (char *)NULL; - -/* List of characters that are word break characters, but should be left - in TEXT when it is passed to the completion function. The shell uses - this to help determine what kind of completing to do. */ -char *rl_special_prefixes = (char *)NULL; - -/* If non-zero, then disallow duplicates in the matches. */ -int rl_ignore_completion_duplicates = 1; - -/* Non-zero means that the results of the matches are to be treated - as filenames. This is ALWAYS zero on entry, and can only be changed - within a completion entry finder function. */ -int rl_filename_completion_desired = 0; - -/* Complete the word at or before point. - WHAT_TO_DO says what to do with the completion. - `?' means list the possible completions. - TAB means do standard completion. - `*' means insert all of the possible completions. */ -rl_complete_internal (what_to_do) -int what_to_do; -{ - char *filename_completion_function (); - char **completion_matches (), **matches; - Function *our_func; - int start, end,did = 0; - char *text; - - if (rl_completion_entry_function) - our_func = rl_completion_entry_function; - else - our_func = (int (*)())filename_completion_function; - - /* Only the completion entry function can change this. */ - rl_filename_completion_desired = 0; - - /* We now look backwards for the start of a filename/variable word. */ - end = rl_point; - if (rl_point) - { - for(;;) { - while (--rl_point >= 0 && - !rindex (rl_completer_word_break_characters, the_line[rl_point])) - if (the_line[rl_point] == '`') - while(rl_point-- && the_line[rl_point] != '`'); - else if (the_line[rl_point] == '\'') - while(rl_point-- && the_line[rl_point] != '\''); - else if (the_line[rl_point] == '\"') - while(rl_point-- && the_line[rl_point] != '\"'); - - if (rl_point < 0) - { - rl_point = end; - ding(); - return 0; - } - if (rl_point == 0 || the_line[rl_point-1] != '\\') - break; - rl_point--; - } - /* If we are at a word break, then advance past it. */ - if (rindex (rl_completer_word_break_characters, (the_line[rl_point]))) - rl_point++; - } - - start = rl_point; - rl_point = end; - text = rl_copy (start, end); - text = docompsubs(text,&did); - rl_prep_terminal(); - if (!text) - return 0; - if (did) - { - rl_delete_text (start, rl_point); - rl_point = start; - if (what_to_do == '?') - puts(text); - else if (did == 2) - rl_insert_text(text); - else - rl_safe_insert_text (text); - free(text); - return 0; - } - /* If the user wants to TRY to complete, but then wants to give - up and use the default completion function, they set the - variable rl_attempted_completion_function. */ - if (rl_attempted_completion_function) - { - matches = - (char **)(*rl_attempted_completion_function) (text, start, end); - - if (matches) - goto after_usual_completion; - } - - matches = completion_matches (text, our_func, start, end); - -after_usual_completion: - free (text); - - if (!matches) - ding (); - else - { - register int i; - -some_matches: - - /* It seems to me that in all the cases we handle we would like - to ignore duplicate possiblilities. Scan for the text to - insert being identical to the other completions. */ - if (rl_ignore_completion_duplicates) - { - char *lowest_common; - int j, newlen = 0; - - /* Sort the items. */ - /* It is safe to sort this array, because the lowest common - denominator found in matches[0] will remain in place. */ - for (i = 0; matches[i]; i++); - qsort (matches, i, sizeof (char *), compare_strings); - - /* Remember the lowest common denimator for it may be unique. */ - lowest_common = savestring (matches[0]); - - for (i = 0; matches[i + 1]; i++) - { - if (strcmp (matches[i], matches[i + 1]) == 0) - { - free (matches[i]); - matches[i] = (char *)-1; - } - else - newlen++; - } - - /* We have marked all the dead slots with (char *)-1. - Copy all the non-dead entries into a new array. */ - { - char **temp_array = - (char **)malloc ((3 + newlen) * sizeof (char *)); - - for (i = 1, j = 1; matches[i]; i++) - if (matches[i] != (char *)-1) - temp_array[j++] = matches[i]; - temp_array[j] = (char *)NULL; - - if (matches[0] != (char *)-1) - free (matches[0]); - free (matches); - - matches = temp_array; - } - - /* Place the lowest common denominator back in [0]. */ - matches[0] = lowest_common; - - /* If there is one string left, and it is identical to the - lowest common denominator, then the LCD is the string to - insert. */ - if (j == 2 && strcmp (matches[0], matches[1]) == 0) - { - free (matches[1]); - matches[1] = (char *)NULL; - } - } - - switch (what_to_do) - { - case TAB: - if (matches[0]) - { - rl_delete_text (start, rl_point); - rl_point = start; - rl_safe_insert_text (matches[0]); - } - - /* If there are more matches, ring the bell to indicate. - If this was the only match, and we are hacking files, - check the file to see if it was a directory. If so, - add a '/' to the name. If not, and we are at the end - of the line, then add a space. */ - if (matches[1]) - { - extern int opts[128]; - - ding (); /* There are other matches remaining. */ - if (opts['9'] == 2) - goto autolist; - } - else - { - char temp_string[2]; - - temp_string[0] = ' '; - temp_string[1] = '\0'; - - if (rl_filename_completion_desired) - { - struct stat finfo; - char *tilde_expand (); - char *filename = tilde_expand (matches[0]); - - if ((stat (filename, &finfo) == 0) && - ((finfo.st_mode & S_IFMT) == S_IFDIR)) - { - if (the_line[rl_point] != '/') - rl_insert_text ("/"); - } - else - { - if (rl_point == rl_end) - rl_insert_text (temp_string); - } - free (filename); - } - else - { - if (rl_point == rl_end) - rl_insert_text (temp_string); - } - } - break; - - case '*': - { - int i = 1; - - rl_delete_text (start, rl_point); - rl_point = start; - rl_begin_undo_group (); - if (matches[1]) - { - while (matches[i]) - { - rl_safe_insert_text (matches[i++]); - rl_insert_text (" "); - } - } - else - { - rl_safe_insert_text (matches[0]); - rl_insert_text (" "); - } - rl_end_undo_group (); - } - break; - - - case '?': - { - int len, count, limit, max = 0; - int j, k, l; - -autolist: - /* Handle simple case first. What if there is only one answer? */ - if (!matches[1]) - { - char *rindex (), *temp; - - if (rl_filename_completion_desired) - temp = rindex (matches[0], '/'); - else - temp = (char *)NULL; - - if (!temp) - temp = matches[0]; - else - temp++; - - crlf (); - fprintf (out_stream, "%s", temp); - crlf (); - goto restart; - } - - /* There is more than one answer. Find out how many there are, - and find out what the maximum printed length of a single entry - is. */ - for (i = 1; matches[i]; i++) - { - char *rindex (), *temp = (char *)NULL; - - /* If we are hacking filenames, then only count the characters - after the last slash in the pathname. */ - if (rl_filename_completion_desired) - temp = rindex (matches[i], '/'); - else - temp = (char *)NULL; - - if (!temp) - temp = matches[i]; - else - temp++; - - if (strlen (temp) > max) - max = strlen (temp); - } - - len = i; - - /* If there are many items, then ask the user if she - really wants to see them all. */ - if (len >= rl_completion_query_items) - { - crlf (); - fprintf (out_stream, - "There are %d possibilities. Do you really", len); - crlf (); - fprintf (out_stream, "wish to see them all? (y or n)"); - fflush (out_stream); - if (!get_y_or_n ()) - { - crlf (); - goto restart; - } - } - /* How many items of MAX length can we fit in the screen window? */ - max += 2; - limit = screenwidth / max; - if (limit != 1 && (limit * max == screenwidth)) - limit--; - - /* How many iterations of the printing loop? */ - count = (len + (limit - 1)) / limit; - - /* Watch out for special case. If LEN is less than LIMIT, then - just do the inner printing loop. */ - if (len < limit) count = 1; - - /* Sort the items if they are not already sorted. */ - if (!rl_ignore_completion_duplicates) - qsort (matches, len, sizeof (char *), compare_strings); - - /* Print the sorted items, up-and-down alphabetically, like - ls might. */ - crlf (); - - for (i = 1; i < count + 1; i++) - { - for (j = 0, l = i; j < limit; j++) - { - if (l > len || !matches[l]) - { - break; - } - else - { - char *rindex (), *temp = (char *)NULL; - - if (rl_filename_completion_desired) - temp = rindex (matches[l], '/'); - else - temp = (char *)NULL; - - if (!temp) - temp = matches[l]; - else - temp++; - - fprintf (out_stream, "%s", temp); - for (k = 0; k < max - strlen (temp); k++) - putc (' ', out_stream); - } - l += count; - } - crlf (); - } -restart: - - rl_on_new_line (); - } - break; - - default: - abort (); - } - - for (i = 0; matches[i]; i++) - free (matches[i]); - free (matches); - } -} - -/* Stupid comparison routine for qsort () ing strings. */ -static int -compare_strings (s1, s2) -char **s1, **s2; -{ - return (strcmp (*s1, *s2)); -} - -/* If non-null, this contains the address of a function to call if the - standard meaning for expanding a tilde fails. The function is called - with the text (sans tilde, as in "foo"), and returns a malloc()'ed string - which is the expansion, or a NULL pointer if there is no expansion. */ -Function *rl_tilde_expander = (Function *)NULL; - -/* Expand FILENAME if it begins with a tilde. This always returns - a new string. */ -char * -tilde_expand (filename) -char *filename; -{ - char *dirname = filename ? savestring (filename) : (char *)NULL; - - if (dirname && *dirname == '~') - { - char *temp_name; - if (!dirname[1] || dirname[1] == '/') - { - /* Prepend $HOME to the rest of the string. */ - char *temp_home = (char *)getenv ("HOME"); - - temp_name = (char *)alloca (1 + strlen (&dirname[1]) - + (temp_home? strlen (temp_home) : 0)); - temp_name[0] = '\0'; - if (temp_home) - strcpy (temp_name, temp_home); - strcat (temp_name, &dirname[1]); - free (dirname); - dirname = savestring (temp_name); - } - else - { - struct passwd *getpwnam (), *user_entry; - char *username = (char *)alloca (257); - int i, c; - - for (i = 1; c = dirname[i]; i++) - { - if (c == '/') break; - else username[i - 1] = c; - } - username[i - 1] = '\0'; - - if (!(user_entry = getpwnam (username))) - { - /* If the calling program has a special syntax for - expanding tildes, and we couldn't find a standard - expansion, then let them try. */ - if (rl_tilde_expander) - { - char *expansion; - - expansion = (char *)(*rl_tilde_expander) (username); - - if (expansion) - { - temp_name = (char *)alloca (1 + strlen (expansion) - + strlen (&dirname[i])); - strcpy (temp_name, expansion); - strcat (temp_name, &dirname[i]); - free (expansion); - goto return_name; - } - } - /* - * We shouldn't report errors. - */ - } - else - { - temp_name = (char *)alloca (1 + strlen (user_entry->pw_dir) - + strlen (&dirname[i])); - strcpy (temp_name, user_entry->pw_dir); - strcat (temp_name, &dirname[i]); -return_name: - free (dirname); - dirname = savestring (temp_name); - } - } - } - return (dirname); -} - - -/* **************************************************************** */ -/* */ -/* Undo, and Undoing */ -/* */ -/* **************************************************************** */ - -/* Non-zero tells rl_delete_text and rl_insert_text to not add to - the undo list. */ -int doing_an_undo = 0; - -/* The current undo list for THE_LINE. */ -UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; - -/* Remember how to undo something. Concatenate some undos if that - seems right. */ -rl_add_undo (what, start, end, text) -enum undo_code what; -int start, end; -char *text; -{ - UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); - temp->what = what; - temp->start = start; - temp->end = end; - temp->text = text; - temp->next = rl_undo_list; - rl_undo_list = temp; -} - -/* Free the existing undo list. */ -free_undo_list () -{ - while (rl_undo_list) { - UNDO_LIST *release = rl_undo_list; - rl_undo_list = rl_undo_list->next; - - if (release->what == UNDO_DELETE) - free (release->text); - - free (release); - } -} - -/* Undo the next thing in the list. Return 0 if there - is nothing to undo, or non-zero if there was. */ -int -rl_do_undo () -{ - UNDO_LIST *release; - int waiting_for_begin = 0; - -undo_thing: - if (!rl_undo_list) - return (0); - - doing_an_undo = 1; - - switch (rl_undo_list->what) { - - /* Undoing deletes means inserting some text. */ - case UNDO_DELETE: - rl_point = rl_undo_list->start; - rl_insert_text (rl_undo_list->text); - free (rl_undo_list->text); - break; - - /* Undoing inserts means deleting some text. */ - case UNDO_INSERT: - rl_delete_text (rl_undo_list->start, rl_undo_list->end); - rl_point = rl_undo_list->start; - break; - - /* Undoing an END means undoing everything 'til we get to - a BEGIN. */ - case UNDO_END: - waiting_for_begin++; - break; - - /* Undoing a BEGIN means that we are done with this group. */ - case UNDO_BEGIN: - if (waiting_for_begin) - waiting_for_begin--; - else - abort (); - break; - } - - doing_an_undo = 0; - - release = rl_undo_list; - rl_undo_list = rl_undo_list->next; - free (release); - - if (waiting_for_begin) - goto undo_thing; - - return (1); -} - -/* Begin a group. Subsequent undos are undone as an atomic operation. */ -rl_begin_undo_group () -{ - rl_add_undo (UNDO_BEGIN, 0, 0, 0); -} - -/* End an undo group started with rl_begin_undo_group (). */ -rl_end_undo_group () -{ - rl_add_undo (UNDO_END, 0, 0, 0); -} - -/* Save an undo entry for the text from START to END. */ -rl_modifying (start, end) -int start, end; -{ - if (start > end) - { - int t = start; - start = end; - end = t; - } - - if (start != end) - { - char *temp = rl_copy (start, end); - rl_begin_undo_group (); - rl_add_undo (UNDO_DELETE, start, end, temp); - rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); - rl_end_undo_group (); - } -} - -/* Revert the current line to its previous state. */ -rl_revert_line () -{ - if (!rl_undo_list) ding (); - else { - while (rl_undo_list) - rl_do_undo (); - } -} - -/* Do some undoing of things that were done. */ -rl_undo_command (count) -{ - if (count < 0) return; /* Nothing to do. */ - - while (count) - { - if (rl_do_undo ()) - { - count--; - } - else - { - ding (); - break; - } - } -} - -/* **************************************************************** */ -/* */ -/* History Utilities */ -/* */ -/* **************************************************************** */ - -/* We already have a history library, and that is what we use to control - the history features of readline. However, this is our local interface - to the history mechanism. */ - -/* While we are editing the history, this is the saved - version of the original line. */ -HIST_ENTRY *saved_line_for_history = (HIST_ENTRY *)NULL; - -/* Set the history pointer back to the last entry in the history. */ -start_using_history () -{ - using_history (); - if (saved_line_for_history) - free_history_entry (saved_line_for_history); - - saved_line_for_history = (HIST_ENTRY *)NULL; -} - -/* Free the contents (and containing structure) of a HIST_ENTRY. */ -free_history_entry (entry) -HIST_ENTRY *entry; -{ - if (!entry) return; - if (entry->line) - free (entry->line); - free (entry); -} - -/* Perhaps put back the current line if it has changed. */ -maybe_replace_line () -{ - HIST_ENTRY *temp = current_history (); - - /* If the current line has changed, save the changes. */ - if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) { - free (temp->line); - free (temp); - } -} - -/* Put back the saved_line_for_history if there is one. */ -maybe_unsave_line () -{ - if (saved_line_for_history) { - strcpy (the_line, saved_line_for_history->line); - rl_undo_list = (UNDO_LIST *)saved_line_for_history->data; - free_history_entry (saved_line_for_history); - saved_line_for_history = (HIST_ENTRY *)NULL; - rl_end = rl_point = strlen (the_line); - } else { - ding (); - } -} - -/* Save the current line in saved_line_for_history. */ -maybe_save_line () -{ - if (!saved_line_for_history) { - saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); - saved_line_for_history->line = savestring (the_line); - saved_line_for_history->data = (char *)rl_undo_list; - } -} - - - -/* **************************************************************** */ -/* */ -/* History Commands */ -/* */ -/* **************************************************************** */ - -/* Meta-< goes to the start of the history. */ -rl_beginning_of_history () -{ - rl_get_previous_history (1 + where_history ()); -} - -/* Meta-> goes to the end of the history. (The current line). */ -rl_end_of_history () -{ - maybe_replace_line (); - using_history (); - maybe_unsave_line (); -} - -/* Move down to the next history line. */ -rl_get_next_history (count) -int count; -{ - HIST_ENTRY *temp = (HIST_ENTRY *)NULL; - - if (count < 0) - { - rl_get_previous_history (-count); - return; - } - - if (!count) - return; - - maybe_replace_line (); - - while (count) - { - temp = next_history (); - if (!temp) - break; - if (--count) - free(temp); - } - - if (!temp) - maybe_unsave_line (); - else - { - free(temp); - strcpy (the_line, temp->line); - rl_undo_list = (UNDO_LIST *)temp->data; - rl_end = rl_point = strlen (the_line); - } -} - -/* Get the previous item out of our interactive history, making it the current - line. If there is no previous history, just ding. */ -rl_get_previous_history (count) -int count; -{ - HIST_ENTRY *old_temp = (HIST_ENTRY *)NULL; - HIST_ENTRY *temp = (HIST_ENTRY *)NULL; - - if (count < 0) - { - rl_get_next_history (-count); - return; - } - - if (!count) - return; - - /* If we don't have a line saved, then save this one. */ - maybe_save_line (); - - /* If the current line has changed, save the changes. */ - maybe_replace_line (); - - while (count) - { - temp = previous_history (); - if (!temp) - break; - else - old_temp = temp; - if (--count) - free(temp); - } - - /* If there was a large argument, and we moved back to the start of the - history, that is not an error. So use the last value found. */ - if (!temp && old_temp) - temp = old_temp; - - if (!temp) - ding (); - else - { - strcpy (the_line, temp->line); - rl_undo_list = (UNDO_LIST *)temp->data; - rl_end = rl_point = strlen (the_line); -#ifdef VI_MODE - if (rl_editing_mode == vi_mode) - rl_point = 0; -#endif /* VI_MODE */ - } -} - -/* There is a command in ksh which yanks into this line, the last word - of the previous line. Here it is. We left it on M-. */ -rl_yank_previous_last_arg (ignore) -int ignore; -{ -} - -/* Make C be the next command to be executed. */ -rl_execute_next (c) -int c; -{ - rl_pending_input = c; -} - -/* **************************************************************** */ -/* */ -/* Killing Mechanism */ -/* */ -/* **************************************************************** */ - -/* What we assume for a max number of kills. */ -#define DEFAULT_MAX_KILLS 10 - -/* The real variable to look at to find out when to flush kills. */ -int rl_max_kills = DEFAULT_MAX_KILLS; - -/* Where to store killed text. */ -char **rl_kill_ring = (char **)NULL; - -/* Where we are in the kill ring. */ -int rl_kill_index = 0; - -/* How many slots we have in the kill ring. */ -int rl_kill_ring_length = 0; - -/* How to say that you only want to save a certain amount - of kill material. */ -rl_set_retained_kills (num) -int num; -{ -} - -/* The way to kill something. This appends or prepends to the last - kill, if the last command was a kill command. if FROM is less - than TO, then the text is appended, otherwise prepended. If the - last command was not a kill command, then a new slot is made for - this kill. */ -rl_kill_text (from, to) -int from, to; -{ - int slot; - char *text = rl_copy (from, to); - - /* Is there anything to kill? */ - if (from == to) { - free (text); - last_command_was_kill++; - return; - } - - /* Delete the copied text from the line. */ - rl_delete_text (from, to); - - /* First, find the slot to work with. */ - if (!last_command_was_kill) { - - /* Get a new slot. */ - if (!rl_kill_ring) { - - /* If we don't have any defined, then make one. */ - rl_kill_ring = - (char **)xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *)); - slot = 1; - - } else { - - /* We have to add a new slot on the end, unless we have exceeded - the max limit for remembering kills. */ - slot = rl_kill_ring_length; - if (slot == rl_max_kills) { - register int i; - free (rl_kill_ring[0]); - for (i = 0; i < slot; i++) - rl_kill_ring[i] = rl_kill_ring[i + 1]; - } else { - rl_kill_ring = - (char **)xrealloc (rl_kill_ring, - ((slot = (rl_kill_ring_length += 1)) + 1) - * sizeof (char *)); - } - } - slot--; - } else { - slot = rl_kill_ring_length - 1; - } - - /* If the last command was a kill, prepend or append. */ - if (last_command_was_kill) { - char *old = rl_kill_ring[slot]; - char *new = (char *)xmalloc (1 + strlen (old) + strlen (text)); - - if (from < to) { - strcpy (new, old); - strcat (new, text); - } else { - strcpy (new, text); - strcat (new, old); - } - free (old); - free (text); - rl_kill_ring[slot] = new; - } else { - rl_kill_ring[slot] = text; - } - rl_kill_index = slot; - last_command_was_kill++; -} - -/* Now REMEMBER! In order to do prepending or appending correctly, kill - commands always make rl_point's original position be the FROM argument, - and rl_point's extent be the TO argument. */ - - -/* **************************************************************** */ -/* */ -/* Killing Commands */ -/* */ -/* **************************************************************** */ - -/* Delete the word at point, saving the text in the kill ring. */ -rl_kill_word (count) -int count; -{ - int orig_point = rl_point; - - if (count < 0) - rl_backward_kill_word (-count); - else - { - rl_forward_word (count); - - if (rl_point != orig_point) - rl_kill_text (orig_point, rl_point); - - rl_point = orig_point; - } -} - -/* Rubout the word before point, placing it on the kill ring. */ -rl_backward_kill_word (count) -int count; -{ - int orig_point = rl_point; - - if (count < 0) - rl_kill_word (-count); - else - { - rl_backward_word (count); - - if (rl_point != orig_point) - rl_kill_text (orig_point, rl_point); - } -} - -/* Kill from here to the end of the line. If DIRECTION is negative, kill - back to the line start instead. */ -rl_kill_line (direction) -int direction; -{ - int orig_point = rl_point; - - if (direction < 0) - rl_backward_kill_line (1); - else - { - rl_end_of_line (); - if (orig_point != rl_point) - rl_kill_text (orig_point, rl_point); - rl_point = orig_point; - } -} - -/* Kill backwards to the start of the line. If DIRECTION is negative, kill - forwards to the line end instead. */ -rl_backward_kill_line (direction) -int direction; -{ - int orig_point = rl_point; - - if (direction < 0) - rl_kill_line (1); - else - { - if (!rl_point) - ding (); - else - { - rl_beg_of_line (); - rl_kill_text (orig_point, rl_point); - } - } -} - -/* Yank back the last killed text. This ignores arguments. */ -rl_yank () -{ - if (!rl_kill_ring) rl_abort (); - rl_insert_text (rl_kill_ring[rl_kill_index]); -} - -/* If the last command was yank, or yank_pop, and the text just - before point is identical to the current kill item, then - delete that text from the line, rotate the index down, and - yank back some other text. */ -rl_yank_pop () -{ - int l; - - if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) || - !rl_kill_ring) - { - rl_abort (); - } - - l = strlen (rl_kill_ring[rl_kill_index]); - if (((rl_point - l) >= 0) && - (strncmp (the_line + (rl_point - l), - rl_kill_ring[rl_kill_index], l) == 0)) - { - rl_delete_text ((rl_point - l), rl_point); - rl_point -= l; - rl_kill_index--; - if (rl_kill_index < 0) - rl_kill_index = rl_kill_ring_length - 1; - rl_yank (); - } - else - rl_abort (); - -} - -extern char *extracthistarg(); - -/* Yank the COUNTth argument from the previous history line. */ -rl_yank_nth_arg (count, ignore) -int count; -{ -char *arg; - - arg = extracthistarg(count); - if (!arg || !*arg) - { - ding (); - return; - } - - rl_begin_undo_group (); - if (rl_point && the_line[rl_point - 1] != ' ') - rl_insert_text (" "); - rl_insert_text (arg); - free (arg); - rl_end_undo_group (); -} - -/* Vi Mode. */ -#ifdef VI_MODE -#include "vi_mode.c" -#endif /* VI_MODE */ - -/* How to toggle back and forth between editing modes. */ -rl_vi_editing_mode () -{ -#ifdef VI_MODE - rl_editing_mode = vi_mode; - rl_vi_insertion_mode (); -#endif /* VI_MODE */ -} - -rl_emacs_editing_mode () -{ - rl_editing_mode = emacs_mode; - keymap = emacs_standard_keymap; -} - - -/* **************************************************************** */ -/* */ -/* Completion */ -/* */ -/* **************************************************************** */ - -/* Non-zero means that case is not significant in completion. */ -int completion_case_fold = 0; - -/* Return an array of (char *) which is a list of completions for TEXT. - If there are no completions, return a NULL pointer. - The first entry in the returned array is the substitution for TEXT. - The remaining entries are the possible completions. - The array is terminated with a NULL pointer. - - ENTRY_FUNCTION is a function of two args, and returns a (char *). - The first argument is TEXT. - The second is a state argument; it should be zero on the first call, and - non-zero on subsequent calls. It returns a NULL pointer to the caller - when there are no more matches. - */ -char ** -completion_matches (text, entry_function) -char *text; -char *(*entry_function) (); -{ - /* Number of slots in match_list. */ - int match_list_size; - - /* The list of matches. */ - char **match_list = - (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *)); - - /* Number of matches actually found. */ - int matches = 0; - - /* Temporary string binder. */ - char *string; - - match_list[1] = (char *)NULL; - - while (string = (*entry_function) (text, matches)) - { - if (matches + 1 == match_list_size) - match_list = - (char **)xrealloc (match_list, - ((match_list_size += 10) + 1) * sizeof (char *)); - - match_list[++matches] = string; - match_list[matches + 1] = (char *)NULL; - } - - /* If there were any matches, then look through them finding out the - lowest common denominator. That then becomes match_list[0]. */ - if (matches) - { - register int i = 1; - int low = 100000; /* Count of max-matched characters. */ - - /* If only one match, just use that. */ - if (matches == 1) - { - match_list[0] = match_list[1]; - match_list[1] = (char *)NULL; - } - else - { - /* Otherwise, compare each member of the list with - the next, finding out where they stop matching. */ - - while (i < matches) - { - register int c1, c2, si; - - if (completion_case_fold) - { - for (si = 0; - (c1 = to_lower(match_list[i][si])) && - (c2 = to_lower(match_list[i + 1][si])); - si++) - if (c1 != c2) break; - } - else - { - for (si = 0; - (c1 = match_list[i][si]) && - (c2 = match_list[i + 1][si]); - si++) - if (c1 != c2) break; - } - - if (low > si) low = si; - i++; - } - match_list[0] = (char *)xmalloc (low + 1); - strncpy (match_list[0], match_list[1], low); - match_list[0][low] = '\0'; - } - } - else /* There were no matches. */ - { - free (match_list); - match_list = (char **)NULL; - } - return (match_list); -} - -/* Okay, now we write the entry_function for filename completion. In the - general case. Note that completion in the shell is a little different - because of all the pathnames that must be followed when looking up the - completion for a command. */ -char * -filename_completion_function (text, state) -int state; -char *text; -{ - static DIR *directory; - static char *filename = (char *)NULL; - static char *dirname = (char *)NULL; - static char *users_dirname = (char *)NULL; - static int filename_len; - - struct direct *entry = (struct direct *)NULL; - - /* If we don't have any state, then do some initialization. */ - if (!state) - { - char *rindex (), *temp; - - if (dirname) free (dirname); - if (filename) free (filename); - if (users_dirname) free (users_dirname); - - filename = savestring (text); - if (!*text) text = "."; - dirname = savestring (text); - - temp = rindex (dirname, '/'); - - if (temp) - { - strcpy (filename, ++temp); - *temp = '\0'; - } - else - strcpy (dirname, "."); - - /* We aren't done yet. We also support the "~user" syntax. */ - - /* Save the version of the directory that the user typed. */ - users_dirname = savestring (dirname); - directory = opendir (dirname); - filename_len = strlen (filename); - - rl_filename_completion_desired = 1; - } - - /* At this point we should entertain the possibility of hacking wildcarded - filenames, like /usr/man*\/te<TAB>. If the directory name contains - globbing characters, then build an array of directories to glob on, and - glob on the first one. */ - - /* Now that we have some state, we can read the directory. */ - - while (directory && (entry = readdir (directory))) - { - /* Special case for no filename. - All entries except "." and ".." match. */ - if (!filename_len) - { - if ((strcmp (entry->d_name, ".") != 0) && - (strcmp (entry->d_name, "..") != 0)) - break; - } - else - { - /* Otherwise, if these match upto the length of filename, then - it is a match. */ -#ifdef TMB_SYSV - if ((strlen (entry->d_name) >= filename_len) && - (strncmp (filename, entry->d_name, filename_len) == 0)) -#else - if ((entry->d_namlen >= filename_len) && - (strncmp (filename, entry->d_name, filename_len) == 0)) -#endif /* TMB_SYSV */ - { - break; - } - } - } - - if (!entry) - { - if (directory) - { - closedir (directory); - directory = (DIR *)NULL; - } - return (char *)NULL; - } - else - { - char *temp; - - if (dirname && (strcmp (dirname, ".") != 0)) - { -#ifdef TMB_SYSV - temp = (char *)xmalloc (1 + strlen (users_dirname) - + strlen (entry->d_name)); -#else - temp = (char *)xmalloc (1 + strlen (users_dirname) - + entry->d_namlen); -#endif /* TMB_SYSV */ - strcpy (temp, users_dirname); - strcat (temp, entry->d_name); - } - else - { - temp = (savestring (entry->d_name)); - } - return (temp); - } -} - - -/* **************************************************************** */ -/* */ -/* Binding keys */ -/* */ -/* **************************************************************** */ - -/* rl_add_defun (char *name, Function *function, int key) - Add NAME to the list of named functions. Make FUNCTION - be the function that gets called. - If KEY is not -1, then bind it. */ -rl_add_defun (name, function, key) -char *name; -Function *function; -int key; -{ - if (key != -1) - rl_bind_key (key, function); - rl_add_funmap_entry (name, function); -} - -/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */ -int -rl_bind_key (key, function) -int key; -Function *function; -{ - if (key < 0) - return (key); - - if (key > 127 && key < 256) - { - if (keymap[ESC].type == ISKMAP) - { - Keymap escmap = (Keymap)keymap[ESC].function; - - key -= 128; - escmap[key].type = ISFUNC; - escmap[key].function = function; - return (0); - } - return (key); - } - - keymap[key].type = ISFUNC; - keymap[key].function = function; - return (0); -} - -/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid - KEY. */ -int -rl_bind_key_in_map (key, function, map) -int key; -Function *function; -Keymap map; -{ - int result; - Keymap oldmap = keymap; - - keymap = map; - result = rl_bind_key (key, function); - keymap = oldmap; - return (result); -} - -/* Make KEY do nothing in the currently selected keymap. - Returns non-zero in case of error. */ -int -rl_unbind_key (key) -int key; -{ - return (rl_bind_key (key, (Function *)NULL)); -} - -/* Make KEY do nothing in MAP. - Returns non-zero in case of error. */ -int -rl_unbind_key_in_map (key, map) -int key; -Keymap map; -{ - return (rl_bind_key_in_map (key, (Function *)NULL, map)); -} - -/* Bind the key sequence represented by the string KEYSEQ to - FUNCTION. This makes new keymaps as necessary. The initial - place to do bindings is in MAP. */ -rl_set_key (keyseq, function, map) -char *keyseq; -Function *function; -Keymap map; -{ - rl_generic_bind (ISFUNC, keyseq, function, map); -} - -/* Bind the key sequence represented by the string KEYSEQ to - the string of characters MACRO. This makes new keymaps as - necessary. The initial place to do bindings is in MAP. */ -rl_macro_bind (keyseq, macro, map) -char *keyseq, *macro; -Keymap map; -{ - char *macro_keys = (char *)xmalloc (2 * (strlen (macro))); - int macro_keys_len; - - if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len)) - { - free (macro_keys); - return; - } - rl_generic_bind (ISMACR, keyseq, macro_keys, map); -} - -/* Bind the key sequence represented by the string KEYSEQ to - the arbitrary pointer DATA. TYPE says what kind of data is - pointed to by DATA, right now this can be a function (ISFUNC), - a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps - as necessary. The initial place to do bindings is in MAP. */ -rl_generic_bind (type, keyseq, data, map) -int type; -char *keyseq, *data; -Keymap map; -{ - char *keys; - int keys_len; - register int i; - - /* If no keys to bind to, exit right away. */ - if (!keyseq || !*keyseq) - { - if (type == ISMACR) - free (data); - return; - } - - keys = (char *)alloca (1 + (2 * strlen (keyseq))); - - /* Translate the ASCII representation of KEYSEQ into an array - of characters. Stuff the characters into ARRAY, and the - length of ARRAY into LENGTH. */ - if (rl_translate_keyseq (keyseq, keys, &keys_len)) - return; - - /* Bind keys, making new keymaps as necessary. */ - for (i = 0; i < keys_len; i++) - { - if (i + 1 < keys_len) - { - if (map[keys[i]].type != ISKMAP) - { - if (map[i].type == ISMACR) - free ((char *)map[i].function); - - map[keys[i]].type = ISKMAP; - map[keys[i]].function = (Function *)rl_make_bare_keymap (); - } - map = (Keymap)map[keys[i]].function; - } - else - { - if (map[keys[i]].type == ISMACR) - free ((char *)map[keys[i]].function); - - map[keys[i]].function = (Function *)data; - map[keys[i]].type = type; - } - } -} - -/* Translate the ASCII representation of SEQ, stuffing the - values into ARRAY, an array of characters. LEN gets the - final length of ARRAY. Return non-zero if there was an - error parsing SEQ. */ -rl_translate_keyseq (seq, array, len) -char *seq, *array; -int *len; -{ - register int i, c, l = 0; - - for (i = 0; c = seq[i]; i++) - { - if (c == '\\') - { - c = seq[++i]; - - if (!c) - break; - - if (((c == 'C' || c == 'M') && seq[i + 1] == '-') || - (c == 'e')) - { - /* Handle special case of backwards define. */ - if (strncmp (&seq[i], "C-\\M-", 5) == 0) - { - array[l++] = ESC; - i += 5; - array[l++] = CTRL (to_upper (seq[i])); - if (!seq[i]) - i--; - continue; - } - - switch (c) - { - case 'M': - i++; - array[l++] = ESC; - break; - - case 'C': - i += 2; - array[l++] = CTRL (to_upper (seq[i])); - break; - - case 'e': - array[l++] = ESC; - } - - continue; - } - } - array[l++] = c; - } - - *len = l; - array[l] = '\0'; - return (0); -} - -/* Return a pointer to the function that STRING represents. - If STRING doesn't have a matching function, then a NULL pointer - is returned. */ -Function * -rl_named_function (string) -char *string; -{ - register int i; - - for (i = 0; funmap[i]; i++) - if (stricmp (funmap[i]->name, string) == 0) - return (funmap[i]->function); - return ((Function *)NULL); -} - ---cut here---cut here---cut here---
pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (12/15/90)
---cut here---cut here---cut here--- -/* The last key bindings file read. */ -static char *last_readline_init_file = "~/.inputrc"; - -/* Re-read the current keybindings file. */ -rl_re_read_init_file (count, ignore) -int count, ignore; -{ - rl_read_init_file (last_readline_init_file); -} - -/* Do key bindings from a file. If FILENAME is NULL it defaults - to `~/.inputrc'. If the file existed and could be opened and - read, 0 is returned, otherwise errno is returned. */ -int -rl_read_init_file (filename) -char *filename; -{ - extern int errno; - int line_size, line_index; - char *line = (char *)xmalloc (line_size = 100); - char *openname; - FILE *file; - - int c; - - /* Default the filename. */ - if (!filename) - filename = "~/.inputrc"; - - openname = tilde_expand (filename); - - /* Open the file. */ - file = fopen (openname, "r"); - free (openname); - - if (!file) - return (errno); - - last_readline_init_file = filename; - - /* Loop reading lines from the file. Lines that start with `#' are - comments, all other lines are commands for readline initialization. */ - while ((c = rl_getc (file)) != EOF) - { - /* If comment, flush to EOL. */ - if (c == '#') - { - while ((c = rl_getc (file)) != EOF && c != '\n'); - if (c == EOF) - goto function_exit; - continue; - } - - /* Otherwise, this is the start of a line. Read the - line from the file. */ - line_index = 0; - while (c != EOF && c != '\n') - { - line[line_index++] = c; - if (line_index == line_size) - line = (char *)xrealloc (line, line_size += 100); - c = rl_getc (file); - } - line[line_index] = '\0'; - - /* Parse the line. */ - rl_parse_and_bind (line); - } - -function_exit: - - free (line); - /* Close up the file and exit. */ - fclose (file); - return (0); -} - - -/* **************************************************************** */ -/* */ -/* Parser Directives */ -/* */ -/* **************************************************************** */ - -/* Conditionals. */ - -/* Calling programs set this to have their argv[0]. */ -char *rl_readline_name = "other"; - -/* Stack of previous values of parsing_conditionalized_out. */ -static unsigned char *if_stack = (unsigned char *)NULL; -static int if_stack_depth = 0; -static int if_stack_size = 0; - -/* Push parsing_conditionalized_out, and set parser state based on ARGS. */ -parser_if (args) -char *args; -{ - register int i; - - /* Push parser state. */ - if (if_stack_depth + 1 >= if_stack_size) - { - if (!if_stack) - if_stack = (unsigned char *)xmalloc (if_stack_size = 20); - else - if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20); - } - if_stack[if_stack_depth++] = parsing_conditionalized_out; - - /* We only check to see if the first word in ARGS is the same as the - value stored in rl_readline_name. */ - - /* Isolate first argument. */ - for (i = 0; args[i] && !whitespace (args[i]); i++); - - if (args[i]) - args[i++] = '\0'; - - if (stricmp (args, rl_readline_name) == 0) - parsing_conditionalized_out = 0; - else - parsing_conditionalized_out = 1; -} - -/* Invert the current parser state if there is anything on the stack. */ -parser_else (args) -char *args; -{ - if (if_stack_depth) - parsing_conditionalized_out = !parsing_conditionalized_out; - else - { - /* *** What, no error message? *** */ - } -} - -/* Terminate a conditional, popping the value of - parsing_conditionalized_out from the stack. */ -parser_endif (args) -char *args; -{ - if (if_stack_depth) - parsing_conditionalized_out = if_stack[--if_stack_depth]; - else - { - /* *** What, no error message? *** */ - } -} - -/* Associate textual names with actual functions. */ -static struct { - char *name; - Function *function; -} parser_directives [] = { - { "if", parser_if }, - { "endif", parser_endif }, - { "else", parser_else }, - { (char *)0x0, (Function *)0x0 } -}; - - -/* Handle a parser directive. STATEMENT is the line of the directive - without any leading `$'. */ -static int -handle_parser_directive (statement) -char *statement; -{ - register int i; - char *directive, *args; - - /* Isolate the actual directive. */ - - /* Skip whitespace. */ - for (i = 0; whitespace (statement[i]); i++); - - directive = &statement[i]; - - for (; statement[i] && !whitespace (statement[i]); i++); - - if (statement[i]) - statement[i++] = '\0'; - - for (; statement[i] && whitespace (statement[i]); i++); - - args = &statement[i]; - - /* Lookup the command, and act on it. */ - for (i = 0; parser_directives[i].name; i++) - if (stricmp (directive, parser_directives[i].name) == 0) - { - (*parser_directives[i].function) (args); - return (0); - } - - /* *** Should an error message be output? */ - return (1); -} - -/* Read the binding command from STRING and perform it. - A key binding command looks like: Keyname: function-name\0, - a variable binding command looks like: set variable value. - A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */ -rl_parse_and_bind (string) -char *string; -{ - extern char *possible_control_prefixes[], *possible_meta_prefixes[]; - char *rindex (), *funname, *kname; - static int substring_member_of_array (); - register int c; - int key, i; - - if (!string || !*string || *string == '#') - return; - - /* If this is a parser directive, act on it. */ - if (*string == '$') - { - handle_parser_directive (&string[1]); - return; - } - - /* If we are supposed to be skipping parsing right now, then do it. */ - if (parsing_conditionalized_out) - return; - - i = 0; - /* If this keyname is a complex key expression surrounded by quotes, - advance to after the matching close quote. */ - if (*string == '"') - { - for (i = 1; c = string[i]; i++) - { - if (c == '"' && string[i - 1] != '\\') - break; - } - } - - /* Advance to the colon (:) or whitespace which separates the two objects. */ - for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ ); - - /* Mark the end of the command (or keyname). */ - if (string[i]) - string[i++] = '\0'; - - /* If this is a command to set a variable, then do that. */ - if (stricmp (string, "set") == 0) - { - char *var = string + i; - char *value; - - /* Make VAR point to start of variable name. */ - while (*var && whitespace (*var)) var++; - - /* Make value point to start of value string. */ - value = var; - while (*value && !whitespace (*value)) value++; - if (*value) - *value++ = '\0'; - while (*value && whitespace (*value)) value++; - - rl_variable_bind (var, value); - return; - } - - /* Skip any whitespace between keyname and funname. */ - for (; string[i] && whitespace (string[i]); i++); - funname = &string[i]; - - /* Now isolate funname. - For straight function names just look for whitespace, since - that will signify the end of the string. But this could be a - macro definition. In that case, the string is quoted, so skip - to the matching delimiter. */ - if (*funname == '\'' || *funname == '"') - { - int delimiter = string[i++]; - - for (; c = string[i]; i++) - { - if (c == delimiter && string[i - 1] != '\\') - break; - } - if (c) - i++; - } - - /* Advance to the end of the string. */ - for (; string[i] && !whitespace (string[i]); i++); - - /* No extra whitespace at the end of the string. */ - string[i] = '\0'; - - /* If this is a new-style key-binding, then do the binding with - rl_set_key (). Otherwise, let the older code deal with it. */ - if (*string == '"') - { - char *seq = (char *)alloca (1 + strlen (string)); - register int j, k = 0; - - for (j = 1; string[j]; j++) - { - if (string[j] == '"' && string[j - 1] != '\\') - break; - - seq[k++] = string[j]; - } - seq[k] = '\0'; - - /* Binding macro? */ - if (*funname == '\'' || *funname == '"') - { - j = strlen (funname); - - if (j && funname[j - 1] == *funname) - funname[j - 1] = '\0'; - - rl_macro_bind (seq, &funname[1], keymap); - } - else - rl_set_key (seq, rl_named_function (funname), keymap); - - return; - } - - /* Get the actual character we want to deal with. */ - kname = rindex (string, '-'); - if (!kname) - kname = string; - else - kname++; - - key = glean_key_from_name (kname); - - /* Add in control and meta bits. */ - if (substring_member_of_array (string, possible_control_prefixes)) - key = CTRL (to_upper (key)); - - if (substring_member_of_array (string, possible_meta_prefixes)) - key = META (key); - - /* Temporary. Handle old-style keyname with macro-binding. */ - if (*funname == '\'' || *funname == '"') - { - char seq[2]; - int fl = strlen (funname); - - seq[0] = key; - seq[1] = '\0'; - if (fl && funname[fl - 1] == *funname) - funname[fl - 1] = '\0'; - - rl_macro_bind (seq, &funname[1], keymap); - } - else - rl_bind_key (key, rl_named_function (funname)); -} - -rl_variable_bind (name, value) -char *name, *value; -{ - if (stricmp (name, "editing-mode") == 0) - { - if (strnicmp (value, "vi", 2) == 0) - { -#ifdef VI_MODE - keymap = vi_insertion_keymap; - rl_editing_mode = vi_mode; -#endif /* VI_MODE */ - } - else if (strnicmp (value, "emacs", 5) == 0) - { - keymap = emacs_standard_keymap; - rl_editing_mode = emacs_mode; - } - } - else if (stricmp (name, "horizontal-scroll-mode") == 0) - { - if (!*value || stricmp (value, "On") == 0) - horizontal_scroll_mode = 1; - else - horizontal_scroll_mode = 0; - } -} - -/* Return the character which matches NAME. - For example, `Space' returns ' '. */ - -typedef struct { - char *name; - int value; -} assoc_list; - -assoc_list name_key_alist[] = { - { "Space", ' ' }, - { "SPC", ' ' }, - { "Rubout", 0x7f }, - { "DEL", 0x7f }, - { "Tab", 0x09 }, - { "Newline", '\n' }, - { "Return", '\r' }, - { "RET", '\r' }, - { "LFD", '\n' }, - { "Escape", '\033' }, - { "ESC", '\033' }, - { (char *)0x0, 0 } -}; - - -int -glean_key_from_name (name) -char *name; -{ - register int i; - - for (i = 0; name_key_alist[i].name; i++) - if (stricmp (name, name_key_alist[i].name) == 0) - return (name_key_alist[i].value); - - return (*name); -} - - -/* **************************************************************** */ -/* */ -/* String Utility Functions */ -/* */ -/* **************************************************************** */ - -/* Return non-zero if any members of ARRAY are a substring in STRING. */ -static int -substring_member_of_array (string, array) -char *string, **array; -{ - static char *strindex (); - - while (*array) - { - if (strindex (string, *array)) - return (1); - array++; - } - return (0); -} - -/* Whoops, Unix doesn't have strnicmp. */ - -/* Compare at most COUNT characters from string1 to string2. Case - doesn't matter. */ -static int -strnicmp (string1, string2, count) -char *string1, *string2; -{ - register char ch1, ch2; - - while (count) - { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) == to_upper(ch2)) - count--; - else break; - } - return (count); -} - -/* strcmp (), but caseless. */ -static int -stricmp (string1, string2) -char *string1, *string2; -{ - register char ch1, ch2; - - while (*string1 && *string2) - { - ch1 = *string1++; - ch2 = *string2++; - if (to_upper(ch1) != to_upper(ch2)) - return (1); - } - return (*string1 | *string2); -} - -/* Determine if s2 occurs in s1. If so, return a pointer to the - match in s1. The compare is case insensitive. */ -static char * -strindex (s1, s2) -register char *s1, *s2; -{ - register int i, l = strlen (s2); - register int len = strlen (s1); - - for (i = 0; (len - i) >= l; i++) - if (strnicmp (&s1[i], s2, l) == 0) - return (s1 + i); - return ((char *)NULL); -} - - -/* **************************************************************** */ -/* */ -/* SYSV Support */ -/* */ -/* **************************************************************** */ - -/* Since system V reads input differently than we do, I have to - make a special version of getc for that. */ - -#include <sys/errno.h> - -int -rl_getc (stream) -FILE *stream; -{ - int result; - unsigned char c; - - rl_waiting = 1; - result = read (fileno (stream), &c, sizeof (char)); - rl_waiting = 0; - if (result == sizeof (char)) - return (c); - - if (errno != EINTR) - return EOF; - rl_done = rl_end = errflag = 1; - return EOF; -} - -#ifdef STATIC_MALLOC - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static void memory_error_and_abort (); - -static char * -xmalloc (bytes) -int bytes; -{ - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) -char *pointer; -int bytes; -{ - char *temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static void -memory_error_and_abort () -{ - fprintf (stderr, "readline: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ -/* - * Local variables: - * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap" - * end: - */ - -rl_function_key(count) /* pjf */ -{ - switch(rl_getc(rl_instream)) - { - case 'A': - rl_get_previous_history(count); - break; - case 'B': - rl_get_next_history(count); - break; - case 'C': - rl_forward(count); - break; - case 'D': - rl_backward(count); - break; - default: - ding(); - break; - } -} - -static char *spname(); - -rl_check_spelling() -{ - char *match; - int start, end, delimiter = 0; - char *text; - - /* We now look backwards for the start of a filename/variable word. */ - end = rl_point; - if (rl_point) - { - while (--rl_point && - !rindex (rl_completer_word_break_characters, the_line[rl_point])); - - /* If we are at a word break, then advance past it. */ - if (rindex (rl_completer_word_break_characters, (the_line[rl_point]))) - { - /* If the character that caused the word break was a quoting - character, then remember it as the delimiter. */ - if (rindex ("\"'", the_line[rl_point]) && (end - rl_point) > 1) - delimiter = the_line[rl_point]; - - /* If the character isn't needed to determine something special - about what kind of completion to perform, then advance past it. */ - - if (!rl_special_prefixes || - !rindex (rl_special_prefixes, the_line[rl_point])) - rl_point++; - } - } - - start = rl_point; - rl_point = end; - text = rl_copy (start, end); - - match = spname(text); - - free (text); - - if (!match) - ding (); - else - { - rl_delete_text (start, rl_point); - rl_point = start; - rl_insert_text (match); - } -} - -/* next 3 functions stolen from Kernighan & Pike */ -/* "The UNIX Programming Environment" (w/o permission) */ - -static char *spname (oldname) char *oldname; -{ - char *p,guess[MAXPATHLEN+1],best[MAXPATHLEN+1]; - char newname[MAXPATHLEN+1]; - char *new = newname, *old = oldname; - - for (;;) - { - while (*old == '/') - *new++ = *old++; - *new = '\0'; - if (*old == '\0') - return newname; - p = guess; - for (; *old != '/' && *old != '\0'; old++) - if (p < guess+MAXPATHLEN) - *p++ = *old; - *p = '\0'; - if (mindist(newname,guess,best) >= 3) - return oldname; - for (p = best; *new = *p++; ) - new++; - } -} - -mindist(dir,guess,best) char *dir,*guess,*best; -{ - int d,nd; - DIR *dd; - struct direct *de; - - if (dir[0] == '\0') - dir = "."; - d = 3; - if (!(dd = opendir(dir))) - return d; - while (de = readdir(dd)) - { - nd = spdist(de->d_name,guess); - if (nd <= d && nd != 3) { - strcpy(best,de->d_name); - d = nd; - if (d == 0) - break; - } - } - closedir(dd); - return d; -} - -#define EQ(s,t) (strcmp(s,t) == 0) - -spdist(s,t) char *s, *t; -{ - while (*s++ == *t) - if (*t++ == '\0') - return 0; - if (*--s) - { - if (*t) - { - if (s[1] && t[1] && *s == t[1] && *t == s[1] && - EQ(s+2,t+2)) - return 1; - if (EQ(s+1,t+1)) - return 2; - } - if (EQ(s+1,t)) - return 2; - } - if (*t && EQ(s,t+1)) - return 2; - return 3; -} - -char *strpbrk(s,t) char *s,*t; -{ - char *u = t; - - while (*s) - { - for (t = u; *t; t++) - if (*s == *t) - return s; - s++; - } - return NULL; -} - -void rl_safe_insert_text(s) char *s; -{ - char *bad = " \\!#$^*()|=[]{}`\'\";?><"; - char *t; - - for(;;) - if (t = strpbrk(s,bad)) - { - char a = *t; - - *t = '\0'; - rl_insert_text(s); - rl_insert_text("\\"); - *t = a; - a = t[1]; - t[1] = '\0'; - rl_insert_text(t); - t[1] = a; - s = t+1; - } - else - { - rl_insert_text(s); - return; - } -} - -#define HERR -125 - -extern int magic; -char *strdup(); -int hgetc(); - -rl_magic_space () -{ - int c,pt = 0; - char *str; - - the_line[rl_end] = '\0'; /* necessary? */ - str = strdup(the_line); - strinbeg(); - magic = 1; - hungets(strdup("\n")); - hungets(strdup(the_line)); - while ((c = hgetc()) != EOF) - { - if (c == HERR) - { - strcpy(the_line,str); - free(str); - hflush(); - magic = 0; - strinend(); - rl_on_new_line(); - rl_redisplay(); - return 0; - } - if (c == '!') - the_line[pt++] = '\\'; - the_line[pt++] = c; - } - if (!pt) - fprintf(stderr,"Whoops.\n"); - the_line[rl_end = rl_point = pt-1] = '\0'; - magic = 0; - strinend(); - free(str); -} End of readline/readline.c echo readline/readline.h 1>&2 sed 's/^-//' >readline/readline.h <<'End of readline/readline.h' -/* Readline.h -- the names of functions callable from within readline. */ - -#ifndef _READLINE_H_ -#define _READLINE_H_ - -#include <readline/keymaps.h> - -#ifndef __FUNCTION_DEF -typedef int Function (); -#define __FUNCTION_DEF -#endif - -/* The functions for manipulating the text of the line within readline. -Most of these functions are bound to keys by default. */ -extern int -rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (), -rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (), -rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (), -rl_quoted_insert (), rl_transpose_chars -(), rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout -(), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (), -rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (), -rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words -(), rl_complete (), rl_possible_completions (), rl_do_lowercase_version -(), rl_digit_argument (), rl_universal_argument (), rl_abort (), -rl_undo_command (), rl_revert_line (), rl_beginning_of_history (), -rl_end_of_history (), rl_insert (), -rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (), -rl_restart_output (), rl_re_read_init_file (); - -extern int rl_function_key(); /* pjf */ -extern int rl_check_spelling(),rl_magic_space(); -extern int rl_break_c(); - -/* These are *both* defined even when VI_MODE is not. */ -extern int rl_vi_editing_mode (), rl_emacs_editing_mode (); - -#ifdef VI_MODE -/* Things for vi mode. */ -extern int rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (), -rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (), -rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (), -rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (), -rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (), -rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (), -rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), rl_vi_change_char (), -rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (), -rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (), -rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (), -rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete (); -#endif /* VI_MODE */ - -/* Keyboard macro commands. */ -extern int -rl_start_kbd_macro (), rl_end_kbd_macro (), rl_call_last_kbd_macro (); - -/* Maintaining the state of undo. We remember individual deletes and inserts - on a chain of things to do. */ - -/* The actions that undo knows how to undo. Notice that UNDO_DELETE means - to insert some text, and UNDO_INSERT means to delete some text. I.e., - the code tells undo what to undo, not how to undo it. */ -enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END }; - -/* What an element of THE_UNDO_LIST looks like. */ -typedef struct undo_list { - struct undo_list *next; - int start, end; /* Where the change took place. */ - char *text; /* The text to insert, if undoing a delete. */ - enum undo_code what; /* Delete, Insert, Begin, End. */ -} UNDO_LIST; - -/* The current undo list for RL_LINE_BUFFER. */ -extern UNDO_LIST *rl_undo_list; - -/* The data structure for mapping textual names to code addresses. */ -typedef struct { - char *name; - Function *function; -} FUNMAP; - -extern FUNMAP **funmap; - -/* **************************************************************** */ -/* */ -/* Well Published Variables */ -/* */ -/* **************************************************************** */ - -/* The name of the calling program. You should initialize this to - whatever was in argv[0]. It is used when parsing conditionals. */ -extern char *rl_readline_name; - -/* The line buffer that is in use. */ -extern char *rl_line_buffer; - -/* The location of point, and end. */ -extern int rl_point, rl_end; - -/* The name of the terminal to use. */ -extern char *rl_terminal_name; - -/* The input and output streams. */ -extern FILE *rl_instream, *rl_outstream; - -/* The basic list of characters that signal a break between words for the - completer routine. The contents of this variable is what breaks words - in the shell, i.e. "n\"\\'`@$>". */ -extern char *rl_basic_word_break_characters; - -/* The list of characters that signal a break between words for - rl_complete_internal. The default list is the contents of - rl_basic_word_break_characters. */ -extern char *rl_completer_word_break_characters; - -/* List of characters that are word break characters, but should be left - in TEXT when it is passed to the completion function. The shell uses - this to help determine what kind of completing to do. */ -extern char *rl_special_prefixes; - -/* Pointer to the generator function for completion_matches (). - NULL means to use filename_entry_function (), the default filename - completer. */ -extern Function *rl_completion_entry_function; - -/* Pointer to alternative function to create matches. - Function is called with TEXT, START, and END. - START and END are indices in RL_LINE_BUFFER saying what the boundaries - of TEXT are. - If this function exists and returns NULL then call the value of - rl_completion_entry_function to try to match, otherwise use the - array of strings returned. */ -extern Function *rl_attempted_completion_function; - -/* If non-null, this contains the address of a function to call if the - standard meaning for expanding a tilde fails. The function is called - with the text (sans tilde, as in "foo"), and returns a malloc()'ed string - which is the expansion, or a NULL pointer if there is no expansion. */ -extern Function *rl_tilde_expander; - -/* If non-zero, then this is the address of a function to call just - before readline_internal () prints the first prompt. */ -extern Function *rl_startup_hook; - -/* If non-zero, then this is the address of a function to call when - completing on a directory name. The function is called with - the address of a string (the current directory name) as an arg. */ -extern Function *rl_symbolic_link_hook; - -/* Non-zero means that modified history lines are preceded - with an asterisk. */ -extern int rl_show_star; - -/* **************************************************************** */ -/* */ -/* Well Published Functions */ -/* */ -/* **************************************************************** */ - -/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */ -extern char *readline (); - -/* Return an array of strings which are the result of repeatadly calling - FUNC with TEXT. */ -extern char **completion_matches (); - -/* rl_add_defun (char *name, Function *function, int key) - Add NAME to the list of named functions. Make FUNCTION - be the function that gets called. - If KEY is not -1, then bind it. */ -extern int rl_add_defun (); - - -#endif /* _READLINE_H_ */ - End of readline/readline.h echo readline/vi_keymap.c 1>&2 sed 's/^-//' >readline/vi_keymap.c <<'End of readline/vi_keymap.c' -/* vi_keymap.c -- the keymap for vi_mode in readline (). */ - -/* Copyright (C) 1988,1989 Free Software Foundation, Inc. - - This file is part of GNU Readline, a library for reading lines - of text with interactive input and history editing. - - Readline is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 1, or (at your option) any - later version. - - Readline is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Readline; see the file COPYING. If not, write to the Free - Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef FILE -#include <stdio.h> -#endif /* FILE */ - -#include "readline.h" - -extern KEYMAP_ENTRY_ARRAY vi_escape_keymap; - -/* The keymap arrays for handling vi mode. */ -KEYMAP_ENTRY_ARRAY vi_movement_keymap = { - - /* The regular control keys come first. */ - { ISFUNC, (Function *)0x0 }, /* Control-@ */ - { ISFUNC, (Function *)0x0 }, /* Control-a */ - { ISFUNC, (Function *)0x0 }, /* Control-b */ - { ISFUNC, (Function *)0x0 }, /* Control-c */ - { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ - { ISFUNC, rl_emacs_editing_mode }, /* Control-e */ - { ISFUNC, (Function *)0x0 }, /* Control-f */ - { ISFUNC, rl_abort }, /* Control-g */ - { ISFUNC, rl_rubout }, /* Control-h */ /* pjf */ - { ISFUNC, (Function *)0x0 }, /* Control-i */ - { ISFUNC, rl_newline }, /* Control-j */ - { ISFUNC, rl_kill_line }, /* Control-k */ - { ISFUNC, rl_clear_screen }, /* Control-l */ - { ISFUNC, rl_newline }, /* Control-m */ - { ISFUNC, rl_get_next_history }, /* Control-n */ - { ISFUNC, (Function *)0x0 }, /* Control-o */ - { ISFUNC, rl_get_previous_history }, /* Control-p */ - { ISFUNC, rl_quoted_insert }, /* Control-q */ - { ISFUNC, (Function *)0x0 }, /* Control-r */ - { ISFUNC, (Function *)0x0 }, /* Control-s */ - { ISFUNC, rl_transpose_chars }, /* Control-t */ - { ISFUNC, rl_unix_line_discard }, /* Control-u */ - { ISFUNC, rl_quoted_insert }, /* Control-v */ - { ISFUNC, rl_unix_word_rubout }, /* Control-w */ - { ISFUNC, (Function *)0x0 }, /* Control-x */ - { ISFUNC, rl_yank }, /* Control-y */ - { ISFUNC, (Function *)0x0 }, /* Control-z */ - - { ISKMAP, (Function *)vi_escape_keymap }, /* Control-[ */ - { ISFUNC, (Function *)0x0 }, /* Control-\ */ - { ISFUNC, (Function *)0x0 }, /* Control-] */ - { ISFUNC, (Function *)0x0 }, /* Control-^ */ - { ISFUNC, rl_undo_command }, /* Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, rl_forward }, /* SPACE */ - { ISFUNC, (Function *)0x0 }, /* ! */ - { ISFUNC, (Function *)0x0 }, /* " */ - { ISFUNC, rl_vi_comment }, /* # */ - { ISFUNC, rl_end_of_line }, /* $ */ - { ISFUNC, rl_vi_match }, /* % */ - { ISFUNC, (Function *)0x0 }, /* & */ - { ISFUNC, (Function *)0x0 }, /* ' */ - { ISFUNC, (Function *)0x0 }, /* ( */ - { ISFUNC, (Function *)0x0 }, /* ) */ - { ISFUNC, rl_vi_complete }, /* * */ - { ISFUNC, rl_get_next_history}, /* + */ - { ISFUNC, rl_vi_char_search }, /* , */ - { ISFUNC, rl_get_previous_history }, /* - */ - { ISFUNC, (Function *)0x0 }, /* . */ - { ISFUNC, rl_vi_search }, /* / */ - - /* Regular digits. */ - { ISFUNC, rl_vi_arg_digit }, /* 0 */ - { ISFUNC, rl_vi_arg_digit }, /* 1 */ - { ISFUNC, rl_vi_arg_digit }, /* 2 */ - { ISFUNC, rl_vi_arg_digit }, /* 3 */ - { ISFUNC, rl_vi_arg_digit }, /* 4 */ - { ISFUNC, rl_vi_arg_digit }, /* 5 */ - { ISFUNC, rl_vi_arg_digit }, /* 6 */ - { ISFUNC, rl_vi_arg_digit }, /* 7 */ - { ISFUNC, rl_vi_arg_digit }, /* 8 */ - { ISFUNC, rl_vi_arg_digit }, /* 9 */ - - /* A little more punctuation. */ - { ISFUNC, (Function *)0x0 }, /* : */ - { ISFUNC, rl_vi_char_search }, /* ; */ - { ISFUNC, (Function *)0x0 }, /* < */ - { ISFUNC, (Function *)0x0 }, /* = */ - { ISFUNC, (Function *)0x0 }, /* > */ - { ISFUNC, rl_vi_search }, /* ? */ - { ISFUNC, (Function *)0x0 }, /* @ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_vi_append_eol }, /* A */ - { ISFUNC, rl_vi_prev_word}, /* B */ - { ISFUNC, rl_vi_change_to }, /* C */ - { ISFUNC, rl_vi_delete_to }, /* D */ - { ISFUNC, rl_vi_end_word }, /* E */ - { ISFUNC, rl_vi_char_search }, /* F */ - { ISFUNC, (Function *)0x0 }, /* G */ - { ISFUNC, (Function *)0x0 }, /* H */ - { ISFUNC, rl_vi_insert_beg }, /* I */ - { ISFUNC, (Function *)0x0 }, /* J */ - { ISFUNC, (Function *)0x0 }, /* K */ - { ISFUNC, (Function *)0x0 }, /* L */ - { ISFUNC, (Function *)0x0 }, /* M */ - { ISFUNC, rl_vi_search_again }, /* N */ - { ISFUNC, (Function *)0x0 }, /* O */ - { ISFUNC, rl_vi_put }, /* P */ - { ISFUNC, (Function *)0x0 }, /* Q */ - { ISFUNC, rl_vi_replace }, /* R */ - { ISFUNC, rl_vi_subst }, /* S */ - { ISFUNC, rl_vi_char_search }, /* T */ - { ISFUNC, rl_revert_line }, /* U */ - { ISFUNC, (Function *)0x0 }, /* V */ - { ISFUNC, rl_vi_next_word }, /* W */ - { ISFUNC, rl_rubout }, /* X */ - { ISFUNC, rl_vi_yank_to }, /* Y */ - { ISFUNC, (Function *)0x0 }, /* Z */ - - /* Some more punctuation. */ - { ISFUNC, (Function *)0x0 }, /* [ */ - { ISFUNC, (Function *)0x0 }, /* \ */ - { ISFUNC, (Function *)0x0 }, /* ] */ - { ISFUNC, rl_vi_first_print }, /* ^ */ - { ISFUNC, rl_vi_yank_arg }, /* _ */ - { ISFUNC, (Function *)0x0 }, /* ` */ - - /* Lowercase alphabet. */ - { ISFUNC, rl_vi_append_mode }, /* a */ - { ISFUNC, rl_vi_prev_word }, /* b */ - { ISFUNC, rl_vi_change_to }, /* c */ - { ISFUNC, rl_vi_delete_to }, /* d */ - { ISFUNC, rl_vi_end_word }, /* e */ - { ISFUNC, rl_vi_char_search }, /* f */ - { ISFUNC, (Function *)0x0 }, /* g */ - { ISFUNC, rl_backward }, /* h */ - { ISFUNC, rl_vi_insertion_mode }, /* i */ - { ISFUNC, rl_get_next_history }, /* j */ - { ISFUNC, rl_get_previous_history }, /* k */ - { ISFUNC, rl_forward }, /* l */ - { ISFUNC, (Function *)0x0 }, /* m */ - { ISFUNC, rl_vi_search_again }, /* n */ - { ISFUNC, (Function *)0x0 }, /* o */ - { ISFUNC, rl_vi_put }, /* p */ - { ISFUNC, (Function *)0x0 }, /* q */ - { ISFUNC, rl_vi_change_char }, /* r */ - { ISFUNC, rl_vi_subst }, /* s */ - { ISFUNC, rl_vi_char_search }, /* t */ - { ISFUNC, rl_undo_command }, /* u */ - { ISFUNC, (Function *)0x0 }, /* v */ - { ISFUNC, rl_vi_next_word }, /* w */ - { ISFUNC, rl_vi_delete }, /* x */ - { ISFUNC, rl_vi_yank_to }, /* y */ - { ISFUNC, (Function *)0x0 }, /* z */ - - /* Final punctuation. */ - { ISFUNC, (Function *)0x0 }, /* { */ - { ISFUNC, rl_vi_column }, /* | */ - { ISFUNC, (Function *)0x0 }, /* } */ - { ISFUNC, rl_vi_change_case }, /* ~ */ - { ISFUNC, rl_backward } /* RUBOUT */ -}; - - -KEYMAP_ENTRY_ARRAY vi_insertion_keymap = { - - /* The regular control keys come first. */ - { ISFUNC, (Function *)0x0 }, /* Control-@ */ - { ISFUNC, rl_insert }, /* Control-a */ - { ISFUNC, rl_insert }, /* Control-b */ - { ISFUNC, rl_insert }, /* Control-c */ - { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ - { ISFUNC, rl_insert }, /* Control-e */ - { ISFUNC, rl_insert }, /* Control-f */ - { ISFUNC, rl_insert }, /* Control-g */ - { ISFUNC, rl_rubout }, /* Control-h */ - { ISFUNC, rl_complete }, /* Control-i */ - { ISFUNC, rl_newline }, /* Control-j */ - { ISFUNC, rl_insert }, /* Control-k */ - { ISFUNC, rl_insert }, /* Control-l */ - { ISFUNC, rl_newline }, /* Control-m */ - { ISFUNC, rl_insert }, /* Control-n */ - { ISFUNC, rl_insert }, /* Control-o */ - { ISFUNC, rl_insert }, /* Control-p */ - { ISFUNC, rl_insert }, /* Control-q */ - { ISFUNC, (Function *)0x0 }, - { ISFUNC, (Function *)0x0 }, - { ISFUNC, rl_transpose_chars }, /* Control-t */ - { ISFUNC, rl_unix_line_discard }, /* Control-u */ - { ISFUNC, rl_quoted_insert }, /* Control-v */ - { ISFUNC, rl_unix_word_rubout }, /* Control-w */ - { ISFUNC, rl_insert }, /* Control-x */ - { ISFUNC, rl_yank }, /* Control-y */ - { ISFUNC, rl_insert }, /* Control-z */ - - { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ - { ISFUNC, rl_insert }, /* Control-\ */ - { ISFUNC, rl_insert }, /* Control-] */ - { ISFUNC, rl_insert }, /* Control-^ */ - { ISFUNC, rl_undo_command }, /* Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, rl_insert }, /* SPACE */ - { ISFUNC, rl_insert }, /* ! */ - { ISFUNC, rl_insert }, /* " */ - { ISFUNC, rl_insert }, /* # */ - { ISFUNC, rl_insert }, /* $ */ - { ISFUNC, rl_insert }, /* % */ - { ISFUNC, rl_insert }, /* & */ - { ISFUNC, rl_insert }, /* ' */ - { ISFUNC, rl_insert }, /* ( */ - { ISFUNC, rl_insert }, /* ) */ - { ISFUNC, rl_insert }, /* * */ - { ISFUNC, rl_insert }, /* + */ - { ISFUNC, rl_insert }, /* , */ - { ISFUNC, rl_insert }, /* - */ - { ISFUNC, rl_insert }, /* . */ - { ISFUNC, rl_insert }, /* / */ - - /* Regular digits. */ - { ISFUNC, rl_insert }, /* 0 */ - { ISFUNC, rl_insert }, /* 1 */ - { ISFUNC, rl_insert }, /* 2 */ - { ISFUNC, rl_insert }, /* 3 */ - { ISFUNC, rl_insert }, /* 4 */ - { ISFUNC, rl_insert }, /* 5 */ - { ISFUNC, rl_insert }, /* 6 */ - { ISFUNC, rl_insert }, /* 7 */ - { ISFUNC, rl_insert }, /* 8 */ - { ISFUNC, rl_insert }, /* 9 */ - - /* A little more punctuation. */ - { ISFUNC, rl_insert }, /* : */ - { ISFUNC, rl_insert }, /* ; */ - { ISFUNC, rl_insert }, /* < */ - { ISFUNC, rl_insert }, /* = */ - { ISFUNC, rl_insert }, /* > */ - { ISFUNC, rl_insert }, /* ? */ - { ISFUNC, rl_insert }, /* @ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_insert }, /* A */ - { ISFUNC, rl_insert }, /* B */ - { ISFUNC, rl_insert }, /* C */ - { ISFUNC, rl_insert }, /* D */ - { ISFUNC, rl_insert }, /* E */ - { ISFUNC, rl_insert }, /* F */ - { ISFUNC, rl_insert }, /* G */ - { ISFUNC, rl_insert }, /* H */ - { ISFUNC, rl_insert }, /* I */ - { ISFUNC, rl_insert }, /* J */ - { ISFUNC, rl_insert }, /* K */ - { ISFUNC, rl_insert }, /* L */ - { ISFUNC, rl_insert }, /* M */ - { ISFUNC, rl_insert }, /* N */ - { ISFUNC, rl_insert }, /* O */ - { ISFUNC, rl_insert }, /* P */ - { ISFUNC, rl_insert }, /* Q */ - { ISFUNC, rl_insert }, /* R */ - { ISFUNC, rl_insert }, /* S */ - { ISFUNC, rl_insert }, /* T */ - { ISFUNC, rl_insert }, /* U */ - { ISFUNC, rl_insert }, /* V */ - { ISFUNC, rl_insert }, /* W */ - { ISFUNC, rl_insert }, /* X */ - { ISFUNC, rl_insert }, /* Y */ - { ISFUNC, rl_insert }, /* Z */ - - /* Some more punctuation. */ - { ISFUNC, rl_insert }, /* [ */ - { ISFUNC, rl_insert }, /* \ */ - { ISFUNC, rl_insert }, /* ] */ - { ISFUNC, rl_insert }, /* ^ */ - { ISFUNC, rl_insert }, /* _ */ - { ISFUNC, rl_insert }, /* ` */ - - /* Lowercase alphabet. */ - { ISFUNC, rl_insert }, /* a */ - { ISFUNC, rl_insert }, /* b */ - { ISFUNC, rl_insert }, /* c */ - { ISFUNC, rl_insert }, /* d */ - { ISFUNC, rl_insert }, /* e */ - { ISFUNC, rl_insert }, /* f */ - { ISFUNC, rl_insert }, /* g */ - { ISFUNC, rl_insert }, /* h */ - { ISFUNC, rl_insert }, /* i */ - { ISFUNC, rl_insert }, /* j */ - { ISFUNC, rl_insert }, /* k */ - { ISFUNC, rl_insert }, /* l */ - { ISFUNC, rl_insert }, /* m */ - { ISFUNC, rl_insert }, /* n */ - { ISFUNC, rl_insert }, /* o */ - { ISFUNC, rl_insert }, /* p */ - { ISFUNC, rl_insert }, /* q */ - { ISFUNC, rl_insert }, /* r */ - { ISFUNC, rl_insert }, /* s */ - { ISFUNC, rl_insert }, /* t */ - { ISFUNC, rl_insert }, /* u */ - { ISFUNC, rl_insert }, /* v */ - { ISFUNC, rl_insert }, /* w */ - { ISFUNC, rl_insert }, /* x */ - { ISFUNC, rl_insert }, /* y */ - { ISFUNC, rl_insert }, /* z */ - - /* Final punctuation. */ - { ISFUNC, rl_insert }, /* { */ - { ISFUNC, rl_insert }, /* | */ - { ISFUNC, rl_insert }, /* } */ - { ISFUNC, rl_insert }, /* ~ */ - { ISFUNC, rl_rubout } /* RUBOUT */ -}; - -KEYMAP_ENTRY_ARRAY vi_escape_keymap = { - - /* The regular control keys come first. */ - { ISFUNC, (Function *)0x0 }, /* Control-@ */ - { ISFUNC, (Function *)0x0 }, /* Control-a */ - { ISFUNC, (Function *)0x0 }, /* Control-b */ - { ISFUNC, (Function *)0x0 }, /* Control-c */ - { ISFUNC, (Function *)0x0 }, /* Control-d */ - { ISFUNC, (Function *)0x0 }, /* Control-e */ - { ISFUNC, (Function *)0x0 }, /* Control-f */ - { ISFUNC, (Function *)0x0 }, /* Control-g */ - { ISFUNC, (Function *)0x0 }, /* Control-h */ - { ISFUNC, rl_tab_insert}, /* Control-i */ - { ISFUNC, rl_emacs_editing_mode}, /* Control-j */ - { ISFUNC, rl_kill_line }, /* Control-k */ - { ISFUNC, (Function *)0x0 }, /* Control-l */ - { ISFUNC, rl_emacs_editing_mode}, /* Control-m */ - { ISFUNC, (Function *)0x0 }, /* Control-n */ - { ISFUNC, (Function *)0x0 }, /* Control-o */ - { ISFUNC, (Function *)0x0 }, /* Control-p */ - { ISFUNC, (Function *)0x0 }, /* Control-q */ - { ISFUNC, (Function *)0x0 }, /* Control-r */ - { ISFUNC, (Function *)0x0 }, /* Control-s */ - { ISFUNC, (Function *)0x0 }, /* Control-t */ - { ISFUNC, (Function *)0x0 }, /* Control-u */ - { ISFUNC, (Function *)0x0 }, /* Control-v */ - { ISFUNC, (Function *)0x0 }, /* Control-w */ - { ISFUNC, (Function *)0x0 }, /* Control-x */ - { ISFUNC, (Function *)0x0 }, /* Control-y */ - { ISFUNC, (Function *)0x0 }, /* Control-z */ - - { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ - { ISFUNC, (Function *)0x0 }, /* Control-\ */ - { ISFUNC, (Function *)0x0 }, /* Control-] */ - { ISFUNC, (Function *)0x0 }, /* Control-^ */ - { ISFUNC, rl_undo_command }, /* Control-_ */ - - /* The start of printing characters. */ - { ISFUNC, (Function *)0x0 }, /* SPACE */ - { ISFUNC, (Function *)0x0 }, /* ! */ - { ISFUNC, (Function *)0x0 }, /* " */ - { ISFUNC, (Function *)0x0 }, /* # */ - { ISFUNC, (Function *)0x0 }, /* $ */ - { ISFUNC, (Function *)0x0 }, /* % */ - { ISFUNC, (Function *)0x0 }, /* & */ - { ISFUNC, (Function *)0x0 }, /* ' */ - { ISFUNC, (Function *)0x0 }, /* ( */ - { ISFUNC, (Function *)0x0 }, /* ) */ - { ISFUNC, (Function *)0x0 }, /* * */ - { ISFUNC, (Function *)0x0 }, /* + */ - { ISFUNC, (Function *)0x0 }, /* , */ - { ISFUNC, (Function *)0x0 }, /* - */ - { ISFUNC, (Function *)0x0 }, /* . */ - { ISFUNC, (Function *)0x0 }, /* / */ - - /* Regular digits. */ - { ISFUNC, rl_vi_arg_digit }, /* 0 */ - { ISFUNC, rl_vi_arg_digit }, /* 1 */ - { ISFUNC, rl_vi_arg_digit }, /* 2 */ - { ISFUNC, rl_vi_arg_digit }, /* 3 */ - { ISFUNC, rl_vi_arg_digit }, /* 4 */ - { ISFUNC, rl_vi_arg_digit }, /* 5 */ - { ISFUNC, rl_vi_arg_digit }, /* 6 */ - { ISFUNC, rl_vi_arg_digit }, /* 7 */ - { ISFUNC, rl_vi_arg_digit }, /* 8 */ - { ISFUNC, rl_vi_arg_digit }, /* 9 */ - - /* A little more punctuation. */ - { ISFUNC, (Function *)0x0 }, /* : */ - { ISFUNC, (Function *)0x0 }, /* ; */ - { ISFUNC, (Function *)0x0 }, /* < */ - { ISFUNC, (Function *)0x0 }, /* = */ - { ISFUNC, (Function *)0x0 }, /* > */ - { ISFUNC, (Function *)0x0 }, /* ? */ - { ISFUNC, (Function *)0x0 }, /* @ */ - - /* Uppercase alphabet. */ - { ISFUNC, rl_do_lowercase_version }, /* A */ - { ISFUNC, rl_do_lowercase_version }, /* B */ - { ISFUNC, rl_do_lowercase_version }, /* C */ - { ISFUNC, rl_do_lowercase_version }, /* D */ - { ISFUNC, rl_do_lowercase_version }, /* E */ - { ISFUNC, rl_do_lowercase_version }, /* F */ - { ISFUNC, rl_do_lowercase_version }, /* G */ - { ISFUNC, rl_do_lowercase_version }, /* H */ - { ISFUNC, rl_do_lowercase_version }, /* I */ - { ISFUNC, rl_do_lowercase_version }, /* J */ - { ISFUNC, rl_do_lowercase_version }, /* K */ - { ISFUNC, rl_do_lowercase_version }, /* L */ - { ISFUNC, rl_do_lowercase_version }, /* M */ - { ISFUNC, rl_do_lowercase_version }, /* N */ - { ISFUNC, rl_do_lowercase_version }, /* O */ - { ISFUNC, rl_do_lowercase_version }, /* P */ - { ISFUNC, rl_do_lowercase_version }, /* Q */ - { ISFUNC, rl_do_lowercase_version }, /* R */ - { ISFUNC, rl_do_lowercase_version }, /* S */ - { ISFUNC, rl_do_lowercase_version }, /* T */ - { ISFUNC, rl_do_lowercase_version }, /* U */ - { ISFUNC, rl_do_lowercase_version }, /* V */ - { ISFUNC, rl_do_lowercase_version }, /* W */ - { ISFUNC, rl_do_lowercase_version }, /* X */ - { ISFUNC, rl_do_lowercase_version }, /* Y */ - { ISFUNC, rl_do_lowercase_version }, /* Z */ - - /* Some more punctuation. */ - { ISFUNC, (Function *)0x0 }, /* [ */ - { ISFUNC, (Function *)0x0 }, /* \ */ - { ISFUNC, (Function *)0x0 }, /* ] */ - { ISFUNC, (Function *)0x0 }, /* ^ */ - { ISFUNC, (Function *)0x0 }, /* _ */ - { ISFUNC, (Function *)0x0 }, /* ` */ - - /* Lowercase alphabet. */ - { ISFUNC, (Function *)0x0 }, /* a */ - { ISFUNC, (Function *)0x0 }, /* b */ - { ISFUNC, (Function *)0x0 }, /* c */ - { ISFUNC, (Function *)0x0 }, /* d */ - { ISFUNC, (Function *)0x0 }, /* e */ - { ISFUNC, (Function *)0x0 }, /* f */ - { ISFUNC, (Function *)0x0 }, /* g */ - { ISFUNC, (Function *)0x0 }, /* h */ - { ISFUNC, (Function *)0x0 }, /* i */ - { ISFUNC, (Function *)0x0 }, /* j */ - { ISFUNC, (Function *)0x0 }, /* k */ - { ISFUNC, (Function *)0x0 }, /* l */ - { ISFUNC, (Function *)0x0 }, /* m */ - { ISFUNC, (Function *)0x0 }, /* n */ - { ISFUNC, (Function *)0x0 }, /* o */ - { ISFUNC, (Function *)0x0 }, /* p */ - { ISFUNC, (Function *)0x0 }, /* q */ - { ISFUNC, (Function *)0x0 }, /* r */ - { ISFUNC, (Function *)0x0 }, /* s */ - { ISFUNC, (Function *)0x0 }, /* t */ - { ISFUNC, (Function *)0x0 }, /* u */ - { ISFUNC, (Function *)0x0 }, /* v */ - { ISFUNC, (Function *)0x0 }, /* w */ - { ISFUNC, (Function *)0x0 }, /* x */ - { ISFUNC, (Function *)0x0 }, /* y */ - { ISFUNC, (Function *)0x0 }, /* z */ - - /* Final punctuation. */ - { ISFUNC, (Function *)0x0 }, /* { */ - { ISFUNC, (Function *)0x0 }, /* | */ - { ISFUNC, (Function *)0x0 }, /* } */ - { ISFUNC, (Function *)0x0 }, /* ~ */ - { ISFUNC, rl_backward_kill_word } /* RUBOUT */ -}; End of readline/vi_keymap.c echo readline/vi_mode.c 1>&2 sed 's/^-//' >readline/vi_mode.c <<'End of readline/vi_mode.c' -/* vi_mode.c -- A vi emulation mode for Bash. - - Derived from code written by Jeff Sparkes (jeff1@????). - */ - - -/* **************************************************************** */ -/* */ -/* VI Emulation Mode */ -/* */ -/* **************************************************************** */ - -/* Last string searched for from `/' or `?'. */ -static char *vi_last_search = (char *)NULL; -static int vi_histpos; - -/* Non-zero means enter insertion mode. */ -int vi_doing_insert = 0; - -/* *** UNCLEAN *** */ -/* Command keys which do movement for xxx_to commands. */ -static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; - -/* Keymap used for vi replace characters. Created dynamically since - rarely used. */ -static Keymap vi_replace_map = (Keymap)NULL; - -/* The number of characters inserted in the last replace operation. */ -static vi_replace_count = 0; - -/* Yank the nth arg from the previous line into this line at point. */ -rl_vi_yank_arg (count) - int count; -{ - rl_yank_nth_arg (count, 0); -} - -/* Search again for the last thing searched for. */ -rl_vi_search_again (ignore, key) - int ignore, key; -{ - switch (key) - { - case 'n': - rl_vi_dosearch (vi_last_search, -1); - break; - - case 'N': - rl_vi_dosearch (vi_last_search, 1); - break; - } -} - -/* Do a vi style search. */ -rl_vi_search (count, key) - int count, key; -{ - int dir, c, save_pos; - char *p; - - switch (key) - { - case '?': - dir = 1; - break; - - case '/': - dir = -1; - break; - - default: - ding (); - return; - } - - vi_histpos = where_history (); - maybe_save_line (); - save_pos = rl_point; - - /* Reuse the line input buffer to read the search string. */ - the_line[0] = 0; - rl_end = rl_point = 0; - p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0)); - - sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key); - - rl_message (p, 0, 0); - - while (c = rl_read_key ()) - { - switch (c) - { - case CTRL('H'): - case RUBOUT: - if (rl_point == 0) - { - maybe_unsave_line (); - rl_clear_message (); - rl_point = save_pos; - return; - } - - case CTRL('W'): - case CTRL('U'): - rl_dispatch (c, keymap); - break; - - case ESC: - case RETURN: - case NEWLINE: - goto dosearch; - break; - - case CTRL('C'): - maybe_unsave_line (); - rl_clear_message (); - rl_point = 0; - ding (); - return; - - default: - rl_insert (1, c); - break; - } - rl_redisplay (); - } - dosearch: - if (vi_last_search) - free (vi_last_search); - - vi_last_search = savestring (the_line); - rl_vi_dosearch (the_line, dir); -} - -rl_vi_dosearch (string, dir) - char *string; - int dir; -{ -#ifdef 0 - int old, save = vi_histpos; - HIST_ENTRY *h; - - if (string == 0 || *string == 0 || vi_histpos < 0) - { - ding (); - return; - } - - if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1) - { - maybe_unsave_line (); - rl_clear_message (); - rl_point = 0; - ding (); - return; - } - - vi_histpos = save; - - old = where_history (); - history_set_pos (vi_histpos); - h = current_history (); - history_set_pos (old); - - strcpy (the_line, h->line); - rl_undo_list = (UNDO_LIST *)h->data; - rl_end = strlen (the_line); - rl_point = 0; - rl_clear_message (); -#endif -} - -/* Completion, from vi's point of view. */ -rl_vi_complete (ignore, key) - int ignore, key; -{ - if (!whitespace (the_line[rl_point])) - { - if (!whitespace (the_line[rl_point + 1])) - rl_vi_end_word (1, 'E'); - rl_point++; - } - - if (key == '*') - rl_complete_internal ('*'); - else - rl_complete (0, key); - - rl_vi_insertion_mode (); -} - -/* Previous word in vi mode. */ -rl_vi_prev_word (count, key) - int count, key; -{ - if (count < 0) - { - rl_vi_next_word (-count, key); - return; - } - - if (uppercase_p (key)) - rl_vi_bWord (count); - else - rl_vi_bword (count); -} - -/* Next word in vi mode. */ -rl_vi_next_word (count, key) - int count; -{ - if (count < 0) - { - rl_vi_prev_word (-count, key); - return; - } - - if (uppercase_p (key)) - rl_vi_fWord (count); - else - rl_vi_fword (count); -} - -/* Move to the end of the ?next? word. */ -rl_vi_end_word (count, key) - int count, key; -{ - if (count < 0) - { - ding (); - return; - } - - if (uppercase_p (key)) - rl_vi_eWord (count); - else - rl_vi_eword (count); -} - -/* Move forward a word the way that 'W' does. */ -rl_vi_fWord (count) - int count; -{ - while (count-- && rl_point < (rl_end - 1)) - { - /* Skip until whitespace. */ - while (!whitespace (the_line[rl_point]) && rl_point < rl_end) - rl_point++; - - /* Now skip whitespace. */ - while (whitespace (the_line[rl_point]) && rl_point < rl_end) - rl_point++; - } -} - -rl_vi_bWord (count) - int count; -{ - while (count-- && rl_point > 0) - { - while (rl_point-- >= 0 && whitespace (the_line[rl_point])); - while (rl_point >= 0 && !whitespace (the_line[rl_point])) - rl_point--; - rl_point++; - } -} - -rl_vi_eWord (count) - int count; -{ - while (count -- && rl_point < (rl_end - 1)) - { - while (rl_point++ < rl_end && whitespace (the_line[rl_point])); - while (rl_point++ < rl_end && !whitespace (the_line[rl_point])); - rl_point--; - } -} - -rl_vi_fword (count) - int count; -{ - while (count -- && rl_point < (rl_end - 1)) - { - if (isident (the_line[rl_point])) - { - while (isident (the_line[rl_point]) && rl_point < rl_end) - rl_point += 1; - } - else if (!whitespace (the_line[rl_point])) - { - while (!isident (the_line[rl_point]) && - !whitespace (the_line[rl_point]) && rl_point < rl_end) - rl_point += 1; - } - - while (whitespace (the_line[rl_point]) && rl_point < rl_end) - rl_point++; - } -} - -rl_vi_bword (count) - int count; -{ - while (count -- && rl_point > 0) - { - while (--rl_point > 0 && whitespace (the_line[rl_point])); - if (rl_point > 0) - { - if (isident (the_line[rl_point])) - while (--rl_point >= 0 && isident (the_line[rl_point])); - else - while (--rl_point >= 0 && !isident (the_line[rl_point]) && - !whitespace (the_line[rl_point])); - rl_point++; - } - } -} - -rl_vi_eword (count) - int count; -{ - while (count -- && rl_point < rl_end - 1) - { - while (++rl_point < rl_end && whitespace (the_line[rl_point])); - - if (rl_point < rl_end) - { - if (isident (the_line[rl_point])) - while (++rl_point < rl_end && isident (the_line[rl_point])); - else - while (++rl_point < rl_end && !isident (the_line[rl_point]) - && !whitespace (the_line[rl_point])); - rl_point--; - } - } -} - -rl_vi_insert_beg () -{ - rl_beg_of_line (); - rl_vi_insertion_mode (); - return 0; -} - -rl_vi_append_mode () -{ - if (rl_point < rl_end) - rl_point += 1; - rl_vi_insertion_mode (); - return 0; -} - -rl_vi_append_eol () -{ - rl_end_of_line (); - rl_vi_append_mode (); - return 0; -} - -/* What to do in the case of C-d. */ -rl_vi_eof_maybe (count, c) - int count, c; -{ - rl_newline (1, '\n'); -} - -/* Insertion mode stuff. */ - -/* Switching from one mode to the other really just involves - switching keymaps. */ -rl_vi_insertion_mode () -{ - keymap = vi_insertion_keymap; -} - -rl_vi_movement_mode () -{ - if (rl_point > 0) - rl_backward (1); - - keymap = vi_movement_keymap; - vi_done_inserting (); -} - -vi_done_inserting () -{ - if (vi_doing_insert) - { - rl_end_undo_group (); - vi_doing_insert = 0; - } -} - -rl_vi_arg_digit (count, c) - int count, c; -{ - if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) - rl_beg_of_line (); - else - rl_digit_argument (count, c); -} - -/* Doesn't take an arg count in vi */ -rl_vi_change_case (ignore1, ignore2) - int ignore1, ignore2; -{ - char c = 0; - - if (uppercase_p (the_line[rl_point])) - c = to_lower (the_line[rl_point]); - else if (lowercase_p (the_line[rl_point])) - c = to_upper (the_line[rl_point]); - - /* Vi is kind of strange here. */ - if (c) - { - rl_begin_undo_group (); - rl_delete (1, c); - rl_insert (1, c); - rl_end_undo_group (); - rl_vi_check (); - } - else - rl_forward (1); -} - -rl_vi_put (count, key) - int count, key; -{ - if (!uppercase_p (key)) - rl_forward (1); - - rl_yank (); - rl_backward (1); -} - -rl_vi_check () -{ - if (rl_point && rl_point == rl_end) - rl_point--; -} - -rl_vi_column (count) -{ - if (count > rl_end) - rl_end_of_line (); - else - rl_point = count - 1; -} - -int -rl_vi_domove (key, nextkey) - int key, *nextkey; -{ - int c, save; - - rl_mark = rl_point; - c = rl_read_key (); - *nextkey = c; - - if (!member (c, vi_motion)) - { - if (digit (c)) - { - save = rl_numeric_arg; - rl_digit_loop1 (); - rl_numeric_arg *= save; - } - else if ((key == 'd' && c == 'd') || - (key == 'c' && c == 'c')) - { - rl_mark = rl_end; - rl_beg_of_line (); - return (0); - } - else - return (-1); - } - - rl_dispatch (c, keymap); - - /* No change in position means the command failed. */ - if (rl_mark == rl_point) - return (-1); - - if ((c == 'w' || c == 'W') && rl_point < rl_end) - rl_point--; - - if (rl_mark < rl_point) - exchange (rl_point, rl_mark); - - return (0); -} - -/* A simplified loop for vi. Don't dispatch key at end. - Don't recognize minus sign? */ -rl_digit_loop1 () -{ - int key, c; - - while (1) - { - rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0); - key = c = rl_read_key (); - - if (keymap[c].type == ISFUNC && - keymap[c].function == rl_universal_argument) - { - rl_numeric_arg *= 4; - continue; - } - c = UNMETA (c); - if (numeric (c)) - { - if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); - else - rl_numeric_arg = (c - '0'); - rl_explicit_arg = 1; - } - else - { - rl_clear_message (); - rl_stuff_char (key); - } - } -} - -rl_vi_delete_to (count, key) - int count, key; -{ - int c; - - if (uppercase_p (key)) - rl_stuff_char ('$'); - - if (rl_vi_domove (key, &c)) - { - ding (); - return; - } - - if ((c != '|') && (c != 'h') && rl_mark < rl_end) - rl_mark++; - - rl_kill_text (rl_point, rl_mark); -} - -rl_vi_change_to (count, key) - int count, key; -{ - int c; - - if (uppercase_p (key)) - rl_stuff_char ('$'); - - if (rl_vi_domove (key, &c)) - { - ding (); - return; - } - - if ((c != '|') && (c != 'h') && rl_mark < rl_end) - rl_mark++; - - rl_begin_undo_group (); - vi_doing_insert = 1; - rl_kill_text (rl_point, rl_mark); - rl_vi_insertion_mode (); -} - -rl_vi_yank_to (count, key) - int count, key; -{ - int c, save = rl_point; - - if (uppercase_p (key)) - rl_stuff_char ('$'); - - if (rl_vi_domove (key, &c)) - { - ding (); - return; - } - - rl_begin_undo_group (); - rl_kill_text (rl_point, rl_mark); - rl_end_undo_group (); - rl_do_undo (); - rl_point = save; -} - -rl_vi_delete (count) -{ - if (rl_point >= rl_end - 1) - { - rl_delete (count, 0); - if (rl_point > 0) - rl_backward (1); - } - else - rl_delete (count, 0); -} - -/* Turn the current line into a comment in shell history. A ksh function */ -rl_vi_comment () -{ - rl_beg_of_line (); - rl_insert_text (": "); /* # doesn't work in interactive mode */ - rl_redisplay (); - rl_newline (1, '\010'); -} - -rl_vi_first_print () -{ - rl_back_to_indent (); -} - -rl_back_to_indent (ignore1, ignore2) - int ignore1, ignore2; -{ - rl_beg_of_line (); - while (rl_point < rl_end && whitespace (the_line[rl_point])) - rl_point++; -} - -/* NOTE: it is necessary that opposite directions are inverses */ -#define FTO 1 /* forward to */ -#define BTO -1 /* backward to */ -#define FFIND 2 /* forward find */ -#define BFIND -2 /* backward find */ - -rl_vi_char_search (count, key) - int count, key; -{ - static char target; - static int orig_dir, dir; - int pos; - - if (key == ';' || key == ',') - dir = (key == ';' ? orig_dir : -orig_dir); - else - { - target = rl_getc (in_stream); - - switch (key) - { - case 't': - orig_dir = dir = FTO; - break; - - case 'T': - orig_dir = dir = BTO; - break; - - case 'f': - orig_dir = dir = FFIND; - break; - - case 'F': - orig_dir = dir = BFIND; - break; - } - } - - pos = rl_point; - - if (dir < 0) - { - pos--; - do - { - if (the_line[pos] == target) - { - if (dir == BTO) - rl_point = pos + 1; - else - rl_point = pos; - return; - } - } - while (pos--); - - if (pos < 0) - { - ding (); - return; - } - } - else - { /* dir > 0 */ - pos++; - do - { - if (the_line[pos] == target) - { - if (dir == FTO) - rl_point = pos - 1; - else - rl_point = pos; - return; - } - } - while (++pos < rl_end); - - if (pos >= (rl_end - 1)) - ding (); - } -} - -/* Match brackets */ -rl_vi_match () -{ - int count = 1, brack, pos; - - pos = rl_point; - if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0) - { - while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 && - rl_point < rl_end - 1) - rl_forward (1); - - if (brack <= 0) - { - rl_point = pos; - ding (); - return; - } - } - - pos = rl_point; - - if (brack < 0) - { - while (count) - { - if (--pos >= 0) - { - int b = rl_vi_bracktype (the_line[pos]); - if (b == -brack) - count--; - else if (b == brack) - count++; - } - else - { - ding (); - return; - } - } - } - else - { /* brack > 0 */ - while (count) - { - if (++pos < rl_end) - { - int b = rl_vi_bracktype (the_line[pos]); - if (b == -brack) - count--; - else if (b == brack) - count++; - } - else - { - ding (); - return; - } - } - } - rl_point = pos; -} - -int -rl_vi_bracktype (c) - int c; -{ - switch (c) - { - case '(': return 1; - case ')': return -1; - case '[': return 2; - case ']': return -2; - case '{': return 3; - case '}': return -3; - default: return 0; - } -} - -rl_vi_change_char () -{ - int c; - - c = rl_getc (in_stream); - - switch (c) - { - case '\033': - case CTRL('C'): - return; - - default: - rl_begin_undo_group (); - rl_delete (1, c); - rl_insert (1, c); - rl_end_undo_group (); - break; - } -} - -rl_vi_subst (count, key) - int count, key; -{ - rl_begin_undo_group (); - vi_doing_insert = 1; - - if (uppercase_p (key)) - { - rl_beg_of_line (); - rl_kill_line (1); - } - else - rl_delete (1, key); - - rl_vi_insertion_mode (); -} - -rl_vi_overstrike (count, key) - int count, key; -{ - int i; - - if (vi_doing_insert == 0) - { - vi_doing_insert = 1; - rl_begin_undo_group (); - } - - for (i = 0; i < count; i++) - { - vi_replace_count++; - rl_begin_undo_group (); - - if (rl_point < rl_end) - { - rl_delete (1, key); - rl_insert (1, key); - } - else - rl_insert (1, key); - - rl_end_undo_group (); - } -} - -rl_vi_overstrike_delete (count) - int count; -{ - int i, s; - - for (i = 0; i < count; i++) - { - if (vi_replace_count == 0) - { - ding (); - break; - } - s = rl_point; - - if (rl_do_undo ()) - vi_replace_count--; - - if (rl_point == s) - rl_backward (1); - } - - if (vi_replace_count == 0 && vi_doing_insert) - { - rl_end_undo_group (); - rl_do_undo (); - vi_doing_insert = 0; - } -} - -rl_vi_replace () -{ - int i; - - vi_replace_count = 0; - - vi_replace_map = rl_make_bare_keymap (); - - for (i = ' '; i < 127; i++) - vi_replace_map[i].function = rl_vi_overstrike; - - vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; - vi_replace_map[ESC].function = rl_vi_movement_mode; - vi_replace_map[RETURN].function = rl_newline; - vi_replace_map[NEWLINE].function = rl_newline; - keymap = vi_replace_map; -} - -/* - * Try to complete the word we are standing on or the word that ends with - * the previous character. A space matches everything. - * Word delimiters are space and ;. - */ -rl_vi_possible_completions() -{ - int save_pos = rl_point; - - if (!index (" ;", the_line[rl_point])) - { - while (!index(" ;", the_line[++rl_point])) - ; - } - else if (the_line[rl_point-1] == ';') - { - ding (); - return (0); - } - - rl_possible_completions (); - rl_point = save_pos; - - return (0); -} End of readline/vi_mode.c echo readline/Makefile 1>&2 sed 's/^-//' >readline/Makefile <<'End of readline/Makefile' -## -*- text -*- #################################################### -# # -# Makefile for readline and history libraries. # -# # -#################################################################### - -# Here is a rule for making .o files from .c files that doesn't force -# the type of the machine (like -sun3) into the flags. -.c.o: - $(CC) -c $(CFLAGS) $(LOCAL_INCLUDES) $(CPPFLAGS) $*.c - -# Destination installation directory. The libraries are copied to DESTDIR -# when you do a `make install', and the header files to INCDIR/readline/*.h. -DESTDIR = /usr/gnu/lib -INCDIR = /usr/gnu/include - -# Define TYPES as -DVOID_SIGHANDLER if your operating system uses -# a return type of "void" for signal handlers. -TYPES = -DVOID_SIGHANDLER - -# Define SYSV as -DSYSV if you are using a System V operating system. -#SYSV = -DSYSV - -# HP-UX compilation requires the BSD library. -#LOCAL_LIBS = -lBSD - -# Xenix compilation requires -ldir -lx -#LOCAL_LIBS = -ldir -lx - -# Comment this out if you don't think that anyone will ever desire -# the vi line editing mode and features. -READLINE_DEFINES = -DVI_MODE - -DEBUG_FLAGS = -LDFLAGS = $(DEBUG_FLAGS) -CFLAGS = $(DEBUG_FLAGS) $(TYPE) $(SYSV) -I. - -# A good alternative is gcc -traditional. -CC = gcc -traditional -RANLIB = /usr/bin/ranlib -AR = ar -RM = rm -CP = cp - -LOCAL_INCLUDES = -I../ - -CSOURCES = readline.c history.c funmap.c keymaps.c vi_mode.c \ - emacs_keymap.c vi_keymap.c keymaps.c - -HSOURCES = readline.h chardefs.h history.h keymaps.h -SOURCES = $(CSOURCES) $(HSOURCES) - -DOCUMENTATION = readline.texinfo inc-readline.texinfo \ - history.texinfo inc-history.texinfo - -SUPPORT = COPYING Makefile $(DOCUMENTATION) ChangeLog - -THINGS_TO_TAR = $(SOURCES) $(SUPPORT) - -########################################################################## - -all: readline.o funmap.o keymaps.o -# all: libreadline.a - -libreadline.a: readline.o history.o funmap.o keymaps.o - $(RM) -f libreadline.a - $(AR) clq libreadline.a readline.o history.o funmap.o keymaps.o - -if [ -f $(RANLIB) ]; then $(RANLIB) libreadline.a; fi - -readline.o: readline.h chardefs.h keymaps.h history.h readline.c vi_mode.c - $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ - $(LOCAL_INCLUDES) $*.c - -history.o: history.c history.h - $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ - $(LOCAL_INCLUDES) $*.c - -funmap.o: readline.h - $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ - $(LOCAL_INCLUDES) $*.c - -keymaps.o: emacs_keymap.c vi_keymap.c keymaps.h chardefs.h keymaps.c - $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ - $(LOCAL_INCLUDES) $*.c - -libtest: libreadline.a libtest.c - $(CC) -o libtest $(CFLAGS) $(CPPFLAGS) -L. libtest.c -lreadline -ltermcap - -readline: readline.c history.o keymaps.o funmap.o readline.h chardefs.h - $(CC) $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ - $(LOCAL_INCLUDES) -DTEST -o readline readline.c funmap.o \ - keymaps.o history.o -L. -ltermcap - -readline.tar: $(THINGS_TO_TAR) - tar -cf readline.tar $(THINGS_TO_TAR) - -readline.tar.Z: readline.tar - compress -f readline.tar - -install: $(DESTDIR)/libreadline.a includes - -includes: - if [ ! -r $(INCDIR)/readline ]; then\ - mkdir $(INCDIR)/readline;\ - chmod a+r $(INCDIR)/readline;\ - fi - $(CP) readline.h keymaps.h chardefs.h $(INCDIR)/readline/ -clean: - rm -f *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc - -$(DESTDIR)/libreadline.a: libreadline.a - -mv $(DESTDIR)/libreadline.a $(DESTDIR)/libreadline.old - cp libreadline.a $(DESTDIR)/libreadline.a - $(RANLIB) -t $(DESTDIR)/libreadline.a End of readline/Makefile echo zsh.h 1>&2 sed 's/^-//' >zsh.h <<'End of zsh.h' -/* - - zsh.h - the header file, basically - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "config.h" -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/file.h> -#include <signal.h> -#ifdef TERMIOS -#include <sys/termios.h> -#else -#include <sgtty.h> -#endif -#include <sys/param.h> -#include <sys/stat.h> - -#define VERSIONSTR "zsh v1.0" - -#define FOREVER for(;;) - -/* size of job table */ - -#define MAXJOB 16 - -void *realloc(void *,int),*malloc(int),*calloc(int,int); - -char *getenv(char *); - -/* the tokens */ - -enum xfubar { - HQUOT = -127, /* quote char used for history */ - ALPOP, /* marker, causes parser to pop alias stack */ - HERR, /* history error indicator */ - Pound, /* # */ - String, /* $ */ - Hat, /* ^ */ - Star, /* * */ - Inpar, /* ( */ - Outpar, /* ) */ - Qstring, /* $, in quotes */ - Equals, /* = (initial) */ - Bar, /* |, except when used as a pipe char */ - Inbrace, /* {, except when used for current shells */ - Outbrace, /* }, except when used for current shells */ - Inbrack, /* [ */ - Outbrack, /* ] */ - Tick, /* ` */ - Inang, /* <, except when used for redirection */ - Outang, /* >, except when used for redirection */ - Quest, /* ? */ - Tilde, /* ~ (initial) */ - Qtick, /* `, in quotes */ - Comma, /* , */ - Nularg /* marker, keeps explicit null arguments around, - does some other stuff */ - }; - -/* HQUOT separately defined in readline.c */ - -/* returns true if X is a token */ - -#define istok(X) (((char) (X)) <= Nularg) - -/* HQUOT in the form of a string */ - -#define HQUOTS "\x81" - -/* ALPOP in the form of a string */ - -#define ALPOPS " \x82" - -extern char **environ; - -/* list of tokens */ - -extern char *tokens; - -/* tokens used in peek variable with gettok/matchit */ -/* do not confuse with above tokens; above tokens appear in strings, - following tokens possible values of 'peek' variable */ - -enum xpeek { - EMPTY, /* nothing gotten yet */ - SEMI, /* ; */ - DSEMI, /* ;; */ - AMPER, /* & */ - DAMPER, /* && */ - NEWLIN, /* \n */ - INPAR, /* ( */ - INBRACE, /* { */ - OUTPAR, /* ) */ - OUTBRACE, /* } */ - OUTANG, /* > */ - OUTANGBANG, /* >! */ - DOUTANG, /* >> */ - DOUTANGBANG, /* >>! */ - INANG, /* < */ - DINANG, /* << */ - INANGAMP, /* <& */ - OUTANGAMP, /* >& */ - OUTANGAMPBANG, /* >&! */ - DOUTANGAMP, /* >>& */ - DOUTANGAMPBANG, /* >>&! */ - BAR, /* | */ - DBAR, /* || */ - BARAMP, /* |& */ - BANG, /* ! */ - STRING, /* string of chars and tokens */ - ENVSTRING, /* string of chars and tokens with a = in it */ - /* the below are all reserved words */ - DO, - DONE, - ESAC, - THEN, - ELIF, - ELSE, - FI, - FOR, - CASE, - IF, - WHILE, - FUNC, - REPEAT, - TIME, - UNTIL, - EXEC, - COMMAND, - SELECT, - COPROC - }; - -/* linked list data type */ - -typedef struct xlist *table; -typedef struct xnode *Node; - -struct xnode { - Node next,last; - void *dat; - }; -struct xlist { - Node first,last; - }; - - -typedef struct pnode *pline; -typedef struct lnode *list; -typedef struct l2node *list2; -typedef struct cnode *comm; -typedef struct jobnode *job; - -/* tree element for lists */ - -struct lnode { - struct l2node *left; - struct lnode *right; - int type; - }; - -enum ltype { - SYNC, /* ; */ - ASYNC /* & */ - }; - -/* tree element for sublists */ - -struct l2node { - struct pnode *left; - struct l2node *right; - int type; - int flags; /* one of PFLAGS below; applies to pnode *left */ - }; - -enum l2type { - ORNEXT = 10, /* || */ - ANDNEXT /* && */ - }; - -#define PFLAG_TIMED 4 /* time ... */ -#define PFLAG_NOT 1 /* ! ... */ -#define PFLAG_COPROC 32 /* coproc ... */ - -/* tree element for pipes */ - -struct pnode { - struct cnode *left; - struct pnode *right; - int type; - }; - -enum ptype { - END, /* pnode *right is null */ - PIPE /* pnode *right is the rest of the pipeline */ - }; - -/* tree element for commands */ - -struct cnode { - struct lnode *left; /* for SUBSH/CURSH/SHFUNC */ - char *cmd; /* command name */ - table args; /* argmument list (char *'s) */ - table redir; /* i/o redirections (struct fnode *'s) */ - table vars; /* parameter list (char *'s), can be null; - two entries in table for each parameter - assignment; "name" and "value" */ - int type; - int flags; - void *info; /* pointer to appropriate control structure, - if this is a CFOR, CWHILE, etc. */ - }; - -enum ctype { - SIMPLE, /* simple command */ - SUBSH, /* ( left ) */ - CURSH, /* { left } */ - SHFUNC, /* converted to { left } in execcomm */ - CFOR, - CWHILE, - CREPEAT, - CIF, - CCASE, - CSELECT - }; -#define CFLAG_EXEC 1 /* exec ... */ -#define CFLAG_COMMAND 2 /* command ... */ - -struct fnode { - union { - char *name; /* source/dest filename */ - int fd2; /* source/dest file descriptor */ - } u; - int type; - int fd1; /* affected file descriptor */ - }; - -enum ftype { - WRITE, /* #> name */ - WRITENOW, /* #>! name */ - APP, /* #>> name */ - APPNOW, /* #>>! name */ - READ, /* #< name */ - HEREDOC, /* #<< fd2 */ - MERGE, /* #<& fd2 */ - MERGEOUT, /* #>& fd2 */ - CLOSE, /* #>&-, #<&- */ - INPIPE, /* #< name, where name is <(...) */ - OUTPIPE, /* #> name, where name is >(...) */ - NONE - }; - -struct fornode { /* for/select */ - char *name; /* parameter to assign values to */ - list list; /* list of names to loop through */ - int inflag; /* != 0 if 'in ...' was specified */ - }; -struct casenode { /* arg list of cnode struct contains word to test */ - struct casenode *next; /* next pattern */ - char *pat; - list list; /* list to execute */ - }; -struct ifnode { - struct ifnode *next; - list ifl; /* if/elif test list (can be null in case of else) */ - list thenl; /* then list */ - }; -struct whilenode { - list cont; /* condition */ - list loop; /* list to execute until condition met */ - int cond; /* 0 for while, 1 for until */ - }; -struct repeatnode { - int count; /* # of iterations */ - list list; - }; - - -/* structure used for multiple i/o redirection */ -/* one for each fd open */ - -struct mnode { - int ct; /* # of redirections on this fd */ - int rflag; /* 0 if open for reading, 1 if open for writing */ - int pipe; /* fd of pipe if ct > 1 */ - int fds[NOFILE]; - }; - -/* node used in command hash table */ - -struct chnode -{ - int type; - int globstat; /* status of filename gen for this command */ - union { - char *nam; /* full pathname if type != BUILTIN */ - int (*func)(); /* func to exec if type == BUILTIN */ - } u; - }; - -enum chtype { - EXCMD_PREDOT, /* external command in PATH before . */ - EXCMD_POSTDOT, /* external command in PATH after . */ - BUILTIN - }; - -/* value for globstat field in chnode - - sample command: foo -xyz -pdq bar ble boz */ - -enum globx { - GLOB, /* all args globbed */ - MOSTGLOB, /* ble, boz globbed */ - NOGLOB /* no args globbed */ - }; - -/* node used in parameter hash table */ - -struct pmnode { - union { - char *str; /* value */ - long val; /* value if declared integer */ - } u; - int isint; /* != 0 if declared integer */ - }; - -/* tty state structure */ - -struct ttyinfo { -#ifdef TERMIOS - struct termios termios; -#else - struct sgttyb sgttyb; - struct tchars tchars; - struct ltchars ltchars; -#endif - struct winsize winsize; - }; - -extern struct ttyinfo shttyinfo; - -/* entry in job table */ - -struct jobnode { - long gleader; /* process group leader of this job */ - int stat; - char *cwd; /* current working dir of shell when - this job was spawned */ - struct procnode *procs; /* list of processes */ - table filelist; /* list of files to delete when done */ - struct ttyinfo ttyinfo; /* saved tty state */ - }; - -#define STAT_CHANGED 1 /* status changed and not reported */ -#define STAT_STOPPED 2 /* all procs stopped or exited */ -#define STAT_TIMED 4 /* job is being timed */ -#define STAT_DONE 8 -#define STAT_LOCKED 16 /* shell is finished creating this job, - may be deleted from job table */ -#define STAT_INUSE 64 /* this job entry is in use */ - -#define SP_RUNNING -1 /* fake statusp for running jobs */ - -/* node in job process lists */ - -struct procnode { - struct procnode *next; - long pid; - char *text; /* text to print when 'jobs' is run */ - int statusp; /* return code from wait3() */ - int lastfg; /* set if this procnode represents a - fragment of a pipeline run in a subshell - for commands like: - - foo | bar | ble - - where foo is a current shell function - or control structure. The command - actually executed is: - - foo | (bar | ble) - - That's two procnodes in the parent - shell, the latter having this flag set. */ - struct timeval ru_utime; - struct timeval ru_stime; - time_t bgtime; /* time job was spawned */ - time_t endtime; /* time job exited */ - }; - -/* node in alias hash table */ - -struct anode { - char *text; /* expansion of alias */ - int cmd; /* one for regular aliases, - zero for -a aliases, - negative for reserved words */ - int inuse; /* alias is being expanded */ - }; - -/* node in sched list */ - -struct schnode { - struct schnode *next; - char *cmd; /* command to run */ - time_t time; /* when to run it */ - }; - -#define MAXAL 20 /* maximum number of aliases expanded at once */ - -typedef struct xhtab *htable; - -/* node in hash table */ - -struct hnode { - struct hnode *hchain; - char *nam; - void *dat; - }; - -/* hash table structure */ - -struct xhtab { - int hsize,ct; - struct hnode **nodes; /* array of size hsize */ - }; - -typedef struct xpath *qath; /* used in globbing - see glob.c */ -typedef struct xcomp *comp; /* "" */ - -extern char *sys_errlist[]; -extern int errno; - -#define pushnode(X,Y) insnode(X,(Node) X,Y) - -#define OPT_INVALID 1 /* opt is invalid, like -$ */ -#define OPT_UNSET 0 -#define OPT_SET 2 - -#define CLOBBER '1' -#define NOBADPATTERN '2' -#define NONOMATCH '3' -#define GLOBDOTS '4' -#define NOTIFY '5' -#define ALLEXPORT 'a' -#define ERREXIT 'e' -#define BGNICE '6' -#define IGNOREEOF '7' -#define KEYWORD 'k' -#define MARKDIRS '8' -#define MONITOR 'm' -#define NOEXEC 'n' -#define NOGLOBOPT 'F' -#define NORCS 'f' -#define SHINSTDIN 's' -#define NOUNSET 'u' -#define VERBOSE 'v' -#define XTRACE 'x' -#define INTERACTIVE 'i' -#define AUTOLIST '9' -#define CORRECT '0' -#define DEXTRACT 'A' -#define NOBEEP 'B' -#define PRINTEXITVALUE 'C' -#define PUSHDTOHOME 'D' -#define PUSHDSILENT 'E' -#define NULLGLOB 'G' -#define RMSTARSILENT 'H' -#define IGNOREBRACES 'I' -#define CDABLEVARS 'J' -#define NOBANGHIST 'K' - -#define ALSTAT_MORE 1 /* last alias ended with ' ' */ -#define ALSTAT_JUNK 2 /* don't put word in history list */ - -#undef isset -#define isset(X) (opts[X]) -#define unset(X) (!opts[X]) -#define interact (isset(INTERACTIVE)) -#define jobbing (isset(MONITOR)) -#define nointr() signal(SIGINT,SIG_IGN) - -#define SIGCOUNT (SIGUSR2+1) -#define SIGERR (SIGUSR2+1) -#define SIGDEBUG (SIGUSR2+2) -#define SIGEXIT 0 - -#define SP(x) (*((union wait *) &(x))) - -#ifndef WEXITSTATUS -#define WEXITSTATUS(x) (((union wait*)&(x))->w_retcode) -#define WTERMSIG(x) (((union wait*)&(x))->w_termsig) -#define WSTOPSIG(x) (((union wait*)&(x))->w_stopsig) -#endif - -#ifndef S_ISBLK -#define _IFMT 0170000 -#define _IFDIR 0040000 -#define _IFCHR 0020000 -#define _IFBLK 0060000 -#define _IFREG 0100000 -#define _IFLNK 0120000 -#define _IFSOCK 0140000 -#define _IFIFO 0010000 -#define S_ISBLK(m) (((m)&_IFMT) == _IFBLK) -#define S_ISCHR(m) (((m)&_IFMT) == _IFCHR) -#define S_ISDIR(m) (((m)&_IFMT) == _IFDIR) -#define S_ISFIFO(m) (((m)&_IFMT) == _IFIFO) -#define S_ISREG(m) (((m)&_IFMT) == _IFREG) -#define S_ISLNK(m) (((m)&_IFMT) == _IFLNK) -#define S_ISSOCK(m) (((m)&_IFMT) == _IFSOCK) -#endif - -/* buffered shell input for non-interactive shells */ - -extern FILE *bshin; - -/* null-terminated array of pointers to strings containing elements - of PATH and CDPATH */ - -extern char **path,**cdpath; - -/* number of elements in aforementioned array */ - -extern int pathct,cdpathct; - -/* error/break flag */ - -extern int errflag; - -/* current history event number */ - -extern int cev; - -/* if != 0, this is the first line of the command */ - -extern int firstln; - -/* if != 0, this is the first char of the command (not including - white space */ - -extern int firstch; - -/* first event number in the history table */ - -extern int tfev; - -/* capacity of history table */ - -extern int tevs; - -/* if = 1, we have performed history substitution on the current line - if = 2, we have used the 'p' modifier */ - -extern int hflag; - -/* default event (usually cev-1, that is, "!!") */ - -extern int dev; - -/* != 0 if we are in the middle of parsing a command (== 0 if we - have not yet parsed the command word */ - -extern int incmd; - -/* the list of history events */ - -extern table histlist; - -/* the current history event (can be NULL) */ - -extern table curtab; - -/* the directory stack */ - -extern table dirstack; - -/* a string containing all the ungot characters (hungetch()) */ - -extern char *ungots; - -/* the pointer to the next character to read from ungots */ - -extern char *ungotptr; - -/* the contents of the IFS parameter */ - -extern char *ifs; - -/* != 0 if this is a subshell */ - -extern int subsh; - -/* # of break levels (break builtin) */ - -extern int breaks; - -/* != 0 if we have a return pending (return builtin) */ - -extern int retflag; - -/* # of nested loops we are in */ - -extern int loops; - -/* # of continue levels */ - -extern int contflag; - -/* the job currently being created/waited for (not current job in the sense - of '+' and '-', that's topjob */ - -extern int curjob; - -/* the current job (+) */ - -extern int topjob; - -/* the previous job (-) */ - -extern int prevjob; - -/* hash table containing the aliases and reserved words */ - -extern htable alhtab; - -/* hash table containing the parameters */ - -extern htable parmhtab; - -/* hash table containing the builtins/hashed commands */ - -extern htable chtab; - -/* hash table containing the shell functions */ - -extern htable shfunchtab; - -/* the job table */ - -extern struct jobnode jobtab[MAXJOB]; - -/* the list of sched jobs pending */ - -extern struct schnode *scheds; - -/* the last l for s/l/r/ history substitution */ - -extern char *last; - -/* the last r for s/l/r/ history substitution */ - -extern char *rast; - -/* if peek == STRING or ENVSTRING, the next token */ - -extern char *tstr; - -/* who am i */ - -extern char *username; - -/* the return code of the last command */ - -extern int lastval; - -/* != 0 if this is a login shell */ - -extern int islogin; - -/* the next token (enum xtok) */ - -extern int peek; - -/* the file descriptor associated with the next token, if it - is something like '<' or '>>', etc. */ - -extern int peekfd; - -/* input fd from the coprocess */ - -extern int spin; - -/* output fd from the coprocess */ - -extern int spout; - -/* the last time we checked mail */ - -extern time_t lastmailcheck; - -/* the last modified date on the mail file last time we checked */ - -extern time_t lastmailval; - -/* the last time we checked the people in the WATCH variable */ - -extern time_t lastwatch; - -/* the last time we did the periodic() shell function */ - -extern time_t lastperiod; - -/* $SECONDS = time(NULL) - shtimer */ - -extern time_t shtimer; - -/* the size of the mail file last time we checked */ - -extern off_t lastmailsize; - -/* $$ */ - -extern long procnum; - -/* $! (the pid of the last background command invoked */ - -extern long proclast; - -/* the process group of the shell */ - -extern long shpgrp; - -/* the current working directory */ - -extern char *cwd; - -/* the hostname, truncated after the '.' */ - -extern char *hostM; - -/* the hostname */ - -extern char *hostm; - -/* the home directory */ - -extern char *home; - -/* the positional parameters */ - -extern table pparms; - -/* the list of local variables we have to destroy */ - -extern table locallist; - -/* the shell input fd */ - -extern int SHIN; - -/* the shell tty fd */ - -extern int SHTTY; - -/* the stack of aliases we are expanding */ - -extern struct anode *alstack[MAXAL]; - -/* the alias stack pointer; also, the number of aliases currently - being expanded */ - -extern int alix; - -/* != 0 means we are reading input from a string */ - -extern int strin; - -/* == 1 means we are doing TAB expansion - == 2 means expansion has occurred during TAB expansion */ - -extern int magic; - -/* period between periodic() commands, in seconds */ - -extern int period; - -/* != 0 means history is turned off (through !" or setopt nobanghist) */ - -extern int stophist; - -/* != 0 means we have removed the current event from the history list */ - -extern int histremmed; - -/* the options; e.g. if opts['a'] is nonzero, -a is turned on */ - -extern int opts[128]; - -/* LINENO */ - -extern int lineno; - -/* != 0 means we have called execlist() and then intend to exit(), - so don't fork if not necessary */ - -extern int exiting; - -/* the limits for child processes */ - -extern struct rlimit limits[RLIM_NLIMITS]; - -/* the tokens */ - -extern char *tokens; - -/* the current word in the history list */ - -extern char *hlastw; - -/* the pointer to the current character in the current word - in the history list */ - -extern char *hlastp; - -/* the size of the current word in the history list */ - -extern int hlastsz; - -/* the alias expansion status - if == ALSTAT_MORE, we just finished -extern expanding an alias ending with a space */ - -extern int alstat; - -/* we have printed a 'you have stopped (running) jobs.' message */ - -extern int stopmsg; - -/* the default tty state */ - -extern struct ttyinfo shttyinfo; - -/* signal names */ - -extern char *sigs[]; - -/* signals that are trapped = 1, signals ignored =2 */ - -extern int sigtrapped[]; - End of zsh.h echo proto 1>&2 sed 's/^-//' >proto <<'End of proto' -#! /bin/sh -# -# proto - prototype generating script -# -# This file is part of zsh, the Z shell. -# -# zsh is free software etc etc. -# -for i -do - rm $i.pro - grep -v '[{};:#]' $i.c | grep '^[A-Za-z]' | - grep -v '^[ ]' | - grep -v static | sed 's/$/;/' >$i.pro -done - End of proto ---cut here---cut here---cut here---